WorryFree Computers   »   [go: up one dir, main page]

Software Engineer

When we think of scaling we usually imagine spiky charts of users hitting a database or processing computationally expensive queries. What we don't always think about it is deleting data. Handling large amounts of deletes is an important part of scaling a database. Imagine a system that's required to delete historical records at a specific deadline. If these records are hundreds of gigabytes in size, it will likely be difficult to delete them all without bogging the database down for the rest of its users. This exact scenario hasn't always been easy with the Firebase Realtime Database, but we're excited to say that it just got a lot easier.

Today, we're introducing a new way to efficiently perform large deletes!

How to delete a large node without maxing out capacity

If you want to delete a large node, the new recommended approach is to use the Firebase CLI (> v6.4.0). The CLI automatically detects a large node and performs a chunked delete efficiently.

$ firebase database:remove /path/to/delete

Keep in mind that in order to delete a large node, the Firebase CLI has to break it down into chunks. This means that clients can see a partial state where part of the data is missing. Writes in the path that is being deleted will still succeed, but the CLI tool will eventually delete all data at this path. This behavior is acceptable if no app depends on this node. However, if there are active listeners within the delete path, please make sure the listener can gracefully handle partial documents.

If you want consistency and fast deletion, consider using a special field, a.k.a a tombstone to mark this document as hidden, and then run a cloud function cron job to asynchronously purge the data. You can use Firebase Rules to disallow access to hidden documents.

How to prevent large deletes from happening unintentionally

We've also added a configuration option (defaultWriteSizeLimit) to the Realtime Database that allows you to specify a write size limit. This limit allows you to prevent operations (large deletes and writes) from being executed on your database if they exceed this limit.

You can use this option to prevent app code from accidentally triggering a large operation, which would make your app unresponsive for a time. For more detail, please see our documentation about this option.

You can check and update the configuration via the CLI tool (version 6.4.0 and newer). There are four available thresholds. You can pick appropriate threshold based on your application requirement

  • small - Abort if the estimated write time is longer than 10s.
  • medium - Abort if the estimated write time is longer than 30s.
  • large - Abort if the estimated write time is longer than 1min.
  • unlimited - No write size limit. All requests will be processed, at the risk of maxing out capacity.

Note: The target time is not a guaranteed cutoff off. The estimated time may be off from the actual write time.

$ firebase database:settings:set defaultWriteSizeLimit unlimited --instance <database-name>
$ firebase database:settings:get defaultWriteSizeLimit --instance <database-name>

For REST requests, you can override defaultWriteSizeLimit with the writeSizeLimit query parameter. In addition, REST queries support a special writeSizeLimit value:

  • tiny - Abort if estimated time is longer than 1s. (Used by firebase database:remove to minimize limit resource consumption)

For example:

$ curl -X PUT \ "https://<database-name>.firebaseio.com/path.json?writeSizeLimit=medium"

The default defaultWriteSizeLimit for new databases is large. In order to avoid affecting existing apps, the setting will remain at unlimited for existing projects for now.

We do want to extend this protection to everyone. So this summer (June~August, 2019), will set defaultWriteSizeLimit to large for existing databases that have not configured defaultWriteSizeLimit. To avoid disruption, we will exclude any databases that have triggered at least one large delete in the past three months.

Consider setting defaultWriteSizeLimit now

These controls can help you keep your apps responsive and your users happy. We suggest setting defaultWriteSizeLimit for your existing apps today.

Let us know what you think of this new feature! Leave a message in our Google group.

Shobhit Chugh
Product Manager

In Firebase Crashlytics, you can view crashes and non-fatals by versions. Several of our customers take advantage of this filtering, especially to focus on their latest releases.

But sometimes too many versions can be a bad thing. Firebase Crashlytics - by default - shows you the last 100 versions we have seen. If you have a lot of debug versions created by developers, and by continuous Integration and deployment pipeline, you might soon start to not see the versions that really matter e.g., production builds.

So how do you make sure that this does not happen? Disabling Crash reporting initialization for debug builds is the simplest way of achieving this. Let's explore how to do this on iOS and Android.

iOS

For iOS apps, first check if you are manually initializing Crashlytics (this happens for Fabric apps that were linked to a Firebase app).

If you use Swift, search for the line Fabric.with([Crashlytics.self]) in AppDelegate.swift. If this line is present, then you are manually initializing Crashlytics, otherwise you are using automatic initialization.

If you use ObjectiveC, search for the line [Fabric with:@[[Crashlytics class]]]; in AppDelegate.m. If this line is present, then you are manually initializing Crashlytics, otherwise you are using automatic initialization.

Apps with Manual initialization

For apps that are using manual initialization, you can just not initialize Crashlytics for DEBUG versions.

For Swift

#if !DEBUG 
Fabric.with([Crashlytics.self]) 
#endif

For ObjectiveC

#if !DEBUG 
[Fabric with:@[[Crashlytics class]]]; 
#endif

Apps that are auto initialized

Firebase Crashlytics apps are automatically initialized by Firebase. You can turn off automatic collection with a new key to your Info.plist file:

  • Key: firebase_crashlytics_collection_enabled
  • Value: no

Then you can initialize it as shown in the examples above for Swift and ObjectiveC

Android

For Android apps, first check if you are manually initializing Crashlytics (this happens for Fabric apps that were linked to a Firebase app). Search for Fabric.with in your project. If this line is present, then you are manually initializing Crashlytics. Otherwise, Crashlytics is being automatically initialized through Firebase.

Apps with Manual initialization

To disable Crashlytics in debug builds, you can make use of the BuildConfig.DEBUG flag. Edit the Fabric.with statement you found previously, adding a check for the DEBUG flag:.

if (!BuildConfig.DEBUG) { 
Fabric.with(this, new Crashlytics()); 
}

Apps that are auto initialized

Turn off Crashlytics initialization in your debug builds by creating a debug folder in your src directory and creating an AndroidManifest.xml with this snippet:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<application>
<meta-data
android:name="firebase_crashlytics_collection_enabled"
android:value="no" />
</application>
</manifest>

This snippet will be merged into the manifest of all of your debug variants, and will disable Crashlytics in those builds. If you'd prefer finer-grained control, you can use this approach for any variants you'd like to exclude.

Marc Jordan
Product Manager

Firebase Auth launches new sign-in method on mobile, adding Microsoft and Yahoo identity providers

Firebase Auth client SDKs make it possible to sign in as a Firebase user from federated identity providers, including Google, Facebook, and Twitter. The Firebase Auth team is always looking for opportunities to improve the auth experience for developers and users. We know that more sign-in options mean more opportunities to create the best app experience. That's why we are pleased to announce that you can now sign in to Firebase Auth using Microsoft and Yahoo!

New identity providers

Firebase Auth has added two new federated identity providers! Today, Microsoft and Yahoo join our growing list of providers. Applications that rely on these providers no longer have to handle custom credentials on the backend. With this simplified auth flow, developers can spend less time on implementing authentication and more time to spend on the core features of your application. Developers who implement Microsoft or Yahoo sign in for Firebase Auth will also get the benefit of a new, simpler way to get the provider credentials.

A simpler method for getting provider credentials

Signing in to Firebase with a given identity provider requires garnering a credential from that provider. This often involves including the provider's SDK and implementing the provider's sign-in methods before passing the credentials to Firebase Auth. For some providers, this can be particularly difficult on a native client, especially ones which do not support their own native SDKs. In order to remove the headache of implementing sign-in flows for these identity providers, we now offer generic OAuth2 provider sign-in.

Generic identity provider sign-in provides an easy means for developers to get that credential and use it to sign in by popping up a ChromeCustomTab on Android or a SafariViewController on iOS which will use the Web flow to generate the Identity Provider Credential, and then continue the sign in. Generic sign-in gives you many benefits:

  • Smaller application size - Because you don't have to import client SDKs to authenticate with providers using a web-based approach on mobile, your app size can be smaller than it otherwise would be.
  • Low setup cost - Compared with having to learn the mechanism to set up the client SDK for each provider that you want to support, having a single way that providers work is significantly easier to set up.
  • More unified sign-in experience - users can expect to use the Web flow no matter what providers they use to sign in.

Generic sign-in is available for Microsoft and Yahoo, and will be a feature of other identity providers in the future.

Getting Started

Ready to get started with Microsoft and Yahoo sign-in for Firebase Auth? Check out the guides linked below:

Todd Kerpleman
Todd Kerpelman
Developer Advocate

Hey, there Firebase Developers! We wanted to let you know of a new feature we added to Cloud Firestore, and that's the ability to increment (or decrement) numeric values directly in the database! Why is this a big deal? Because previously, if you wanted to increment a value in the database, you would need to use a transaction to keep it safe from concurrent writes.

For instance, imagine that your fitness app has a feature that allows groups of friends to pool their steps together for a "team step counter". Then, imagine Bob and Alice both have their current team's total steps recorded locally and try to add their values to it…

If both clients send down these new values at around the same time, it's possible for Alice's changes to be written first...

...and then for Bob's changes to come in and overwrite Alice's changes.

In the past, if you wanted to prevent this from happening, you would have to use a transaction. And while transactions are still a fine solution, they are a little more difficult to write, they don't support cases where the user is offline, and frankly, they seem a bit heavy-handed for something as simple as adding two numbers together.

So now, if you want Bob to record his 500 steps in the app, you can simply do that by asking the server to increment the step_counter value. In an iOS app, for instance, you would write code that looks a little something like this.

document("fitness_teams/Team_1").
  updateData(["step_counter" : FieldValue.increment(500)])

With this call, the database would instantly make the change based on whatever value it has. So even if Alice sneaks in a change before Bob's request reaches the server, everything still works.

Now, there are two things to keep in mind when it comes to performing these operations:

First of all, if you do want to add some logic to your operation (like, for instance, making sure this new value doesn't go over or under a certain limit), you'll still need to use a transaction. Luckily, we will soon release a fantastic video all about transactions that I can heartily recommend as a completely unbiased observer.

Second, don't forget that documents are still limited to a sustained write limit of 1 QPS per document. I know it's tempting to look at these numeric functions and start making counters left and right in your database, but if you think these are values you're going to be updating more than once per second, you're still going to want to rely on something like our distributed counter solution.

As always, if you have questions, feel free to contact us on any of our support channels, or post questions on Stack Overflow with the google-cloud-firestore and firebase tags. Good luck, and have fun!

Sumit Chandel
Developer Advocate

Firebase is returning to the Game Developers Conference this year in San Francisco to share how we're making Firebase even more powerful for game developers!

At the Google Mobile Developer Day on Monday, we announced:

  • Firebase Crashlytics for Unity
  • Open-sourcing our C++ SDK
  • New AI-assisted Monkey Actions for Games on Android, and
  • Support for GameCenter Authentication on iOS

In case you missed these announcements on stage, read on below for a quick recap. We'll also be at booth #P1501 starting tomorrow until the end of the week, and have a special session on Firebase for Games in the Cloud Developer Day track, so if you're at the GDC this year, please come say hello! We're excited to get your feedback, and learn more about how we can make these features and Firebase for Games even better in the future.

Here's a recap of the new Firebase updates for games developers:

Firebase Crashlytics for Unity

Firebase Crashlytics is now available for Unity! Firebase Crashlytics helps you track, prioritize, and fix stability issues in real time. It synthesizes an avalanche of crashes into a manageable list of issues, provides contextual information, and highlights the severity and prevalence of crashes so you can pinpoint the root cause faster. You can also easily reproduce issues by reviewing breadcrumbs, a list of actions that the user performed before the error occurred.

Crashlytics was previously only available for Android and iOS, but you can now use that same powerful crash-reporting functionality in your Unity games!

With the same simplicity of all our Firebase for Unity SDKs, Crashlytics can be integrated directly via your Unity IDE with no extra steps required. Your team can also be alerted of issues using our Email, Slack, Jira and PagerDuty Integrations, or write your own triggers using Cloud Functions with Firebase Crashlytics triggers.

And last, but not least, you can export Crashlytics data into BigQuery for deeper-dives. For example, let's say you log a custom key when reporting a Crashlytics event like so:

Crashlytics.SetCustomKey("current_level", "3");

After you export your Crashlytics data to BigQuery, you will be able to see the distribution of crashes by level 3, or any other level or custom key you've used for your events! And you can use our Data Studio template to quickly analyze this data. This will make tracking and fixing issues in your Unity game development a whole lot easier.

Refer to our documentation to get started with Firebase Crashlytics for Unity.

We've open sourced our C++ SDKs

For C++ developers out there, you can now use an open source SDK for your Firebase for Games integration! This means more control than ever when integrating with the Firebase toolset. You can now easily dig into the code to see or change what's happening within the SDK to better suit your game, or maintain your own branch of the client SDK and cherry pick specific changes you care about. And if there are other platforms you want to use that we haven't yet built support for, you have the option to extend the SDK.

New AI-assisted Firebase Test Lab Monkey Actions for Games

Firebase Test Lab is a cloud-based app-testing infrastructure. With one operation, you can test your Android or iOS app across a wide variety of devices and device configurations, and see the results in the Firebase console. For native Android apps, what are called Robo tests can intelligently analyze the UI elements on-screen and crawl through them. For games, however, this isn't possible because all of your elements are typically in a GL/Vulkan/Metal View. Instead Robo will resort to Monkey Actions, where it will tap randomly.

It could take quite some time for a smoke test like this to complete though, which is why we're happy to announce new AI-assisted Monkey Actions to help test your games with Firebase Test Lab. This will significantly reduce the time it takes for a robot to make progress through your game's user interface and provide useful test results. Check out the before / after videos for Monkey Actions with and without AI-assistance to see the difference. Note the before video showing Monkey Actions without AI assistance takes about 35 seconds to start a game, versus 13 seconds with AI-assistance (the orange dots on the screen represent where the robot is tapping on the screen):

Monkey Actions without AI assistance starting a game.


AI-assisted Monkey Actions starting a game.

Support for GameCenter Authentication on iOS

Firebase Authentication provides an end-to-end identity solution for your app, which allows you to authenticate and verify users with passwords, phone numbers and popular federated identity providers like Google, Facebook and Twitter.

For iOS games developers, we are pleased to announce that Firebase Authentication now also supports Game Center Authentication, so if an iOS user is already signed into Game Center, they can also sign-in to your app without having to go through an additional sign-in flow.

Come chat with us to learn more!

We'll be at booth #P1501 all throughout the conference starting from March 20th - March 22nd, and have a special presentation on the Cloud Developer Day track on Wednesday at 5:00PM! We hope to see you there.

And of course, you can always learn more about Firebase for Games at:

https://firebase.google.com/games/

Hiranya Jayathilaka
Software Engineer
Rachel Myers
Developer Programs Engineer

Firebase is a great platform for developing rich mobile and web applications by leveraging the power and scale of the Google Cloud Platform. Firebase provides a wide range of composable backend services and SDKs that help developers overcome numerous challenges in app development including user authentication, data storage, notification delivery, and more.

In addition to the services and the SDKs, Firebase also offers security rules -- a powerful mechanism that helps enforce the security and logical correctness of your apps. The backend services use security rules to authorize and validate the requests made by client apps, and make sure they adhere to the policies that app developers have put in place. Today, you can use security rules to govern how your users interact with the Firebase Realtime Database, Cloud Storage, and Cloud Firestore. Rules in these Firebase products help you achieve two critical goals:

  1. Enforcing authorization: Rules can make sure that your users whose identity is verified by Firebase Authentication can only do things they are allowed to.
  2. Enforcing data validations and business logic: Both Realtime Database and Cloud Firestore are NoSQL, schemaless databases. But in most applications you would want certain integrity constraints imposed on your data.

If you're using any Firebase product mentioned above, rules are essential. But you may have questions about how they fit into your application architecture. In order to shed some light on this subject, we'd like to share a few tips related to security rules and the Admin SDK.

Tip #1: Admin SDK bypasses security rules

As you explore security rules in depth, you will eventually discover that requests from the Firebase Admin SDK are not gated by rules. The Admin SDK is initialized with a service account, which gives the SDK full access to your data. In Firebase Realtime Database, you can scope the Admin SDK's privileges to a user ID, and enforce rules as usual. But other products, most notably Google Cloud Firestore, don't support this feature yet. You should be mindful about that when implementing server-side data access operations.

Because of the elevated privileges of service accounts and the Admin SDK, you should also make sure that they only get deployed in environments that you trust with administrative control of your project. Typical environments include servers controlled by the developers, and managed cloud environments like Google Cloud Functions and App Engine. On the other hand, end-user devices and web browsers where the application code is open for modification are inherently untrusted, and the Admin SDK should never be deployed in them.

Tip #2: Make certain data read-only

Many applications have data that is critical to the operation of the app, but should never be modified by the users. Consider a forum app that promotes user engagement by awarding its participants points (think StackOverflow). Each forum post needs to be scored in near real-time so the users can track their progress, but the users themselves should never be able to change anyone's points, not even their own.

The simplest way to protect such application-managed data is to specify a rule that prevents all writes to the data from the users.

service cloud.firestore {
  match /databases/{database}/documents {
    function isAuthorized() {
      // Some function that grants users read access.
    }

    match /scores/{uid}/{document} {
     allow write: if false; // Nothing gets past me (except Admin of course).
     allow read: if isAuthorized(); // Grant read access as necessary.
    }
  }
}

Then you can use the Admin SDK to implement backend services that keep the data up-to-date. For instance, you can implement a serverless function using Cloud Functions for Firebase that automatically executes whenever a user posts something in the forum. This function can determine how many points to award the user, and update the respective entries in the read-only scores collection.

import * as admin from 'firebase-admin';

admin.initializeApp();

export const updateScores = functions.firestore.document('posts/{userId}/{postId}')
  .onCreate((snapshot, context) => {
    const score = calculateScore(snapshot);
    const userId = context.params.userId;
    const doc = admin.firestore().collection('scores').document(userId);
    return admin.firestore().runTransaction((txn) => {
      return txn.get(doc).then((snap) => {
        const current = snap.data().total || 0;
        txn.set(doc, {total: current + score}, {merge: true});
      });
    });
  });

Since Cloud Functions is a trusted environment, the backend code can continue to update your data, while keeping users from doing something they are not allowed to.

Tip #3: Role-based access control with custom claims

Many applications need to deal with users in different roles. What individual users can do in the app usually depends on their roles. Let's take a MOOC (Massively Open Online Courses) app as an example, where there are teachers, students and TAs. Teachers and TAs should be able to view and update course content, but students should only be able to view the material.

In a Firebase app, user roles can be managed by setting custom claims on user accounts. This is a privileged operation that can only be performed in a backend environment, typically using the Admin SDK. Custom claims are additional information that we associate with user accounts in Firebase Auth, and this information becomes available in the ID tokens that Firebase issues to users upon sign in. You can inspect these claims via security rules to facilitate role-based access control.

Going back to our example MOOC app, we can use the following backed code to grant a user teacher role.

import * as admin from 'firebase-admin';

admin.initializeApp();

async function grantTeacherRole(userId: string) {
  await admin.auth().setCustomUserClaims(userId, {role: 'teacher'});
}

Now you can define a rule that only allows teachers and TAs write-access to the courses collection.

service cloud.firestore {
  match /databases/{database}/documents {
    function isTeacher() {
      return request.auth.token.role == "teacher";
    }

    function isTA() {
      return request.auth.token.role == "ta";
    }

    match /courses/{doc} {
      allow write: if isTeacher() || isTA(); // Only teachers and TAs can write.
      allow read: if true; // But anybody can read.
    }
  }
}

Note that Firebase client SDKs cache ID tokens up to an hour. Therefore changes to a user's custom claims may take up to an hour to take effect.

Tip #4: Temporarily withhold sensitive data from users

Sometimes you want the ability to withhold some data from users until an administrator or a backend service determines it's time to release the data. For example, consider an automated process that grades tests in a MOOC app. You would want this process to finish grading all the tests before any scores are shared with the students. In this case the grading process should be able to update any Firestore document, and it can be deployed in a trusted backend environment. Therefore you can use the Admin SDK to implement it.

To make sure the intermediate states of data are not visible to users, you can create each document with a visibility attribute set to "private". Then in security rules, restrict access to only those documents whose visibility attribute is set to "public". Here's what this rule would look like:

service cloud.firestore {
  match /databases/{database}/documents {
    function isPublic() {
      return resource.data.visibility == "public";
    }

    match /grades/{document} {
     allow read: if isPublic(); // Cannot read unless marked as "public".
     allow write: if false; // Nobody except Admin can update the documents.
    }
  }
}

With the above rules configuration in place, all documents created with the visibility attribute set to "private" are inaccessible to the end-users. When the backend process is ready to release a document to the users, it can use the Admin SDK to change the visibility attribute of the target document to "public".

import * as admin from 'firebase-admin';

admin.initializeApp();

async function gradeTests() {
  // Create a new document and continue to write to it.
  const doc = await createNewDoc();
  await updateGrades(doc);

  // Later, make the document visible when ready.
  await releaseGrades(doc);
}

async function createNewDoc() {
  const doc = admin.firestore().collection('grades').document();
  // Make the new doc hidden by default
  await doc.set({visibility: 'private'});
  return doc;
}

async function releaseGrades(doc) {
  await doc.update({visibility: 'public'});
}

As soon as the visibility attribute is set to "public" on a document, it will start appearing in matching Firestore queries executed by users.

Tip #5: Minimize the rules that apply to a document

It can be tempting to write rules that apply across collections -- for example, writing a rule that grants teachers in the MOOC app access to all documents in the database. In such situations, remember that rules will grant access to a document if any match statement in the rules configuration grants access. When multiple rules apply to the same document, it is easy to forget that any rule that allows access, overrides all the other rules that deny access.

service cloud.firestore {
  match /databases/{database}/documents {
    match /reports/{document} {
     // This rule is intended to selectively grant users read-only access to the
     // documents in the 'reports' collection. But the rule below inadvertently
     // grants teachers read-write access to these documents.
     allow read: if isConditionMet();
     allow write: if false;
    }

    match /{document=**} {
     // This rule matches all documents in the database, including the 'reports'
     // collection. In case of teachers, this will override the previous rule.
     allow read, write: if isTeacher();
    }
  }
}

To avoid accidentally granting users access to protected data in your app, you should try to write rules in a manner so that each document only matches a single rules statement. One way to make that easier is to avoid wildcards that match collections ({document=**}), and only use wildcards that match documents ({document}). If you're tempted to define overarching rules, consider if the Admin SDK would be a better fit, because as we learned in the Tip #1, requests from the Admin SDK bypasses security rules.

Tip #6: Develop administrative tools using the Admin SDK

As your apps grow and evolve over time, you may implement various administrative tools to manage your app's data. For example, you may want to implement a tool that backs up certain Firestore collections or RTDB paths. Or you are trying to meet specific privacy requirements, and you want to implement a service that deletes user data when the data becomes obsolete or when the users demand it. Such tools typically require unrestricted access to large portions of your database.

At first this may look like a good reason to have a relaxed set of security rules. But you should strive to write the most detailed and restrictive rules that describe the access patterns of your app. Administrative tools should be implemented using the Admin SDK, and deployed in a privileged environment that you control. This way your admin tools can retain full access to all the data, while closely regulating what end-users can do in the app.

Tip #7: Implement dynamic access control lists

In some situations you may want to temporarily deny a user access to data. Perhaps the monitoring infrastructure of your forum app has just detected a user posting spam, and you want to prevent that user from posting any more content until you can conduct a thorough investigation of the incident. You can use security rules to implement a simple access control list (ACL) on top of Firestore, and use the Admin SDK to dynamically manage it. You would start by declaring a rule like the following:

service cloud.firestore {
  match /databases/{database}/documents {
    function isBlackListed() {
      return exists(/databases/$(database)/documents/blacklist/$(request.auth.uid))
    }

    // Collections are closed for reads and writes by default. This match block
    // is included for clarity.
    match /blacklist/{entry} {
      allow read: if false;
      allow write: if false;
    }

    match /posts/{postId} {
      allow write: if !isBlackListed()
    }
  }
}

This mentions a Firestore collection named blacklist that no user can read or write. It also uses the exists built-in function to check if a document with a given key exists in the Firestore database. If you haven't seen this pattern before, built-in functions like exists and get enable us to access Firestore documents from security rules. In this case, if we find a user ID in the blacklist collection, we prevent the corresponding user from writing to the posts collection. Now we can use the Admin SDK to add users to the blacklist collection, and revoke their write-access:

await revokeWriteAccess('bAdAgEnT');

async function revokeWriteAccess(userId) {
  const user = admin.firestore().collection('blacklist').document(userId)
  await user.set({
    reason: 'possible bad agent',
    blacklisted_at: admin.firestore.FieldValue.serverTimestamp(),
  });
}

Since you have already locked down all access to the blacklist collection, you can rest assured that only the Admin SDK (i.e. our backend code) can make modifications to it. Changes to the ACL take effect immediately. To grant a user access to the data again, simply remove the corresponding document with the user ID from the blacklist collection.

Note that we are also writing the current timestamp to the same document when adding a user to the blacklist. If you want, you can write a rule that references this property to automatically grant blacklisted users access after a cool off period.

service cloud.firestore {
  function isTwoDaysElapsed() {
    return request.time > timestamp.value(get(/databases/$(database)/documents/
         blacklist/$(request.auth.uid)).data.blacklisted_at.seconds*1000) +
         duration.value(2, 'd');
  }

  match /databases/{database}/documents {
    match /posts/{postId} {
        // allow if blacklisted more than 2 days ago
       allow write: if isTwoDaysElapsed();
    }
  }
}

In conclusion...

Firebase takes a declarative approach to ensuring the security and logical correctness of your apps. By keeping the rules separate from application code, you can easily update your security policies, while keeping the application code simple. As many developers know by experience, code changes are harder to make, and even harder to test and deploy. But with Firebase, you can rapidly iterate on your rules without having to touch the application code at all. Moreover, you can patch any detected security vulnerabilities instantly, without having to go through a long and arduous app rollout.

You can also use rules in conjunction with the Firebase Admin SDK to implement sophisticated use cases that involve server-side code. Admin SDK is not subjected to rules checks, but this extra degree of freedom enables some useful patterns that can be applied to multiple real world applications. You can implement any server-side components using the Admin SDK and deploy them in trusted environments like Google Cloud Functions, while subjecting the client-side apps to stricter constraints.

Read more about Firebase security rules and the Admin SDK in our documentation. If you have used these tools to solve any interesting problems, we'd love to hear about your experience. Happy coding with Firebase!

Jamie Niemasik
Product Manager

Here at Firebase, we work hard to keep your apps secure and protect your users. In keeping with that mission, we're proud to announce that we recently implemented Certificate Transparency for the Realtime Database.

Certificate Transparency makes it possible to detect SSL certificates that have been mistakenly issued by a certificate authority. It also makes it possible to identify certificate authorities that have gone rogue and are maliciously issuing certificates. These attack vectors are rare but serious ways of circumventing the protections that SSL/TLS grants to online communication.

Part of Certificate Transparency is the issuance of a Signed Certificate Timestamp (SCT), which Realtime Database responses now include. We have already been sending the SCT when browsers like Chrome requested it, but now it is always bundled in the response.

From today on, every connection from one of your users to your database will be protected by the SCT. Please be aware that the SCT creates a little more SSL overhead, so each response gets slightly larger. The percentage increase for your app is dependent on many factors, such as your average response size, and which clients your customers use. Since outgoing bandwidth (egress) is billed, you may see a slight bill increase as a result.

Certificate Transparency is a great enhancement to SSL/TLS, and we Firebasers are excited about what it means for the security of the internet going forward. We're delighted to bring this protection to you and your users.