As the developer or the administrator of an app built on Firebase, you may need to perform various user management tasks. These include:
The Firebase Admin SDK provides a powerful API for performing these kinds of user management tasks from privileged environments. Using the Admin SDK, you can program these capabilities directly into your admin consoles, dashboards and other backend services. Unlike the Firebase client SDK, the Admin SDK is initialized with a service account credential, which grants the SDK elevated privileges necessary to perform user management operations.
This is not a brand new feature. The Firebase Admin Node.js SDK has had a user management API for a while. However, we are happy to announce that this API is now also available in our Admin Java SDK starting from version 5.1.0. This is one of the most requested features for the Admin Java SDK, and we are certain many Firebase app developers are going to find it useful.
The Java user management API closely mirrors its Node.js counterpart. Specifically, it consists of five new methods:
getUser()
getUserByEmail()
createUser()
updateUser()
deleteUser()
Following code snippet shows how to use some of these new methods in practice. In this example we retrieve an existing user account, and update some of its attributes:
final FirebaseAuth auth = FirebaseAuth.getInstance(); Task task = auth.getUserByEmail("editor@example.com") .addOnSuccessListener(userRecord -> { System.out.println("Successfully fetched user data: " + userRecord.getUid()); UpdateRequest update = userRecord.updateRequest() .setDisabled(false) // Enable the user account .setEmailVerified(true); // Set the email verification status auth.updateUser(update); }) .addOnFailureListener(e -> { System.err.println("Error fetching user data: " + e.getMessage()); });
You can learn more about the Firebase user management API from the Admin SDK documentation. Additionally, head over to our Github repo to see how it is implemented. (Yes, it's all open source!). You can also help us further improve this API by providing us feedback and reporting issues. As always, we are open to all sorts of contributions including pull requests to our codebase. Happy coding with Firebase!
Firebase Dynamic Links give you a single link that can send users either to your iOS or Android app, if they have it installed, or to the appropriate listing in the App Store or on Google Play, if they don't. Even better than that, Dynamic Links will deep link your users to the content they were looking for, even if they had to install the app in the process.
We've been working hard over the last year to make this experience smoother and more powerful for both developers and users, and we're happy to bring the latest set of improvements to developers in our iOS and Android SDKs.
Creating Dynamic Links through the Firebase Console was great for promotional campaigns, but we heard from our developers that they needed to be able to create user-to-user sharing campaigns programmatically from within their app.
To help you do just that, we've added support for generating both long and short dynamic links to the iOS and Android Firebase SDKs, which makes it quicker and easier to support these kind of use cases:
guard let deepLink = URL(string: "https://mydomain.com/page?param=value") else { return } let components = DynamicLinkComponents(link: deepLink, domain: domain) let iOSParams = DynamicLinkIOSParameters(bundleID: bundleID) iOSParams.minimumAppVersion = minVersion components.iOSParameters = iOSParams // Build the dynamic link let link = components.url // Or create a shortened dynamic link components.shorten { (shortURL, warnings, error) in if let error = error { print(error.localizedDescription) return } // TODO: Handle shortURL. }
String deepLink = "https://mydomain.com/page?param=value"; DynamicLink.Builder builder = FirebaseDynamicLinks.getInstance() .createDynamicLink() .setDynamicLinkDomain(domain) .setAndroidParameters(new DynamicLink.AndroidParameters.Builder() .setMinimumVersion(minVersion) .build()) .setLink(deepLink); // Build the dynamic link DynamicLink link = builder.buildDynamicLink(); // Or create a shortened dynamic link builder.buildShortDynamicLink() .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(ShortDynamicLink shortDynamicLink) { // } });
We've also rebuilt the Android API from the ground up to make it easier to handle incoming Dynamic Links into your app, with the new FirebaseDynamicLinks class. You can add the new library by adding the following to your build.gradle:
compile "com.google.firebase:firebase-dynamic-links:11.0.0"
Then processing an incoming Dynamic Link is easy in your launched activity:
FirebaseDynamicLinks.getInstance().getDynamicLink(getIntent()) .addOnSuccessListener( new OnSuccessListener() { @Override public void onSuccess(PendingDynamicLinkData data) { if (data == null || data.getLink() == null) { // No FDL pending for this app, don't do anything. return; } Intent launchIntent = data.getUpdateAppIntent(MainActivity.this); if (launchIntent != null) { startActivity(launchIntent); // launch upgrade flow. } Uri deepLink = dynamicLink.getLink(); String myAppItemId = deepLink.getQueryParameter("myAppItemId"); // TODO(developer): Display content for myAppItemId here! } });
As always, if you have any questions or feedback on the new API, please reach out through any of the channels on our support page.
.
Three years ago, we launched Firebase Hosting to make it easier for developers to deliver fast, engaging experiences on the web. Two months ago, we launched the beta of Cloud Functions for Firebase to let developers write custom backend logic without having to worry about servers or infrastructure. More recently at Google I/O, we brought Firebase Hosting and Cloud Functions together to provide a flexible set of tools to build Progressive Web Apps with world-class scale and performance.
You can connect an HTTPS Cloud Function to your Firebase Hosting app by adding a rewrite to the firebase.json configuration for your project:
firebase.json
{ "hosting": { "rewrites": [ {"source": "/function/**", "function":"myFunction"} ] } }
Once connected, matching requests seamlessly proxy to your Cloud Function (in the example above, a function named myFunction). This one-line change enables exciting new capabilities for Firebase Hosting users including:
myFunction
For Cloud Functions users, you can now run functions on an SSL-secured custom domain and get powerful caching to avoid unnecessary executions.
To get started using Cloud Functions on Firebase Hosting for your own Firebase project, take a look at our documentation. You can also learn more in our I/O session: Building Fast Web Experiences with Firebase Hosting.
In apps that allow users to post public content - for instance in forums, social networks and blogging platforms - there is always a risk that inappropriate content could get published. In this post, we'll look at ways you can automatically moderate offensive content in your Firebase app using Cloud Functions.
The most commonly used strategy to moderate content is "reactive moderation". Typically, you'll add a link allowing users to report inappropriate content so that you can manually review and take down the content that does comply with your house rules. You can better prevent offensive content from being publicly visible and complement your reactive moderation by adding automated moderation mechanisms. Let's see how you can easily add automatic checks for offensive content in text and photos published by users on your Firebase apps using Cloud Functions.
We'll perform two types of automatic content moderation:
Text moderation where we'll remove swearwords and all shouting (e.g. "SHOUTING!!!").
Image moderation where we'll blur images that contain either adult or violent content.
Automatic moderation, by nature, needs to be performed in a trusted environment (i.e. not on the client), so Cloud Functions for Firebase is a great, natural fit for this. Two functions will be needed to perform the two types of moderation.
The text moderation will be performed by a Firebase Realtime Database triggered function named moderator. When a user adds a new comment or post to the Realtime Database, a function is triggered which uses the bad-words npm package to remove swear words.We'll then use the capitalize-sentence npm package to fix the case of messages that contain too many uppercase letters (which typically meaning users are shouting). The final step will be to write back the moderated message to the Realtime Database.
moderator
To illustrate this we'll use a simple data structure that represents a list of messages that have been written by users of a chat room. These are made of an object with a text attribute that gets added to the /messages list:
text
/messages
/functions-project-12345 /messages /key-123456 text: "This is my first message!" /key-123457 text: "IN THIS MESSAGE I AM SHOUTING!!!"
Once the function has run on the newly added messages, we'll add two attributes: sanitized which is true when message has been verified by our moderation function and moderated which is true if it was detected that the message contained offensive content and was modified. For instance, after the function runs on the two sample messages above we should get:
sanitized
true
moderated
/functions-project-12345 /messages /key-123456 text: "This is my first message!", sanitized: true, moderated: false /key-123457 text: "In this message I am shouting." sanitized: true, moderated: true
Our moderator function will be triggered every time there is a write to one of the messages. We set this up by using the functions.database().path('/messages/{messageId}').onWrite(...) trigger rule. We'll moderate the message and write back the moderated message into the Realtime Database:
functions.database().path('/messages/{messageId}').onWrite(...)
exports.moderator = functions.database.ref('/messages/{messageId}') .onWrite(event => { const message = event.data.val(); if (message && !message.sanitized) { // Retrieved the message values. console.log('Retrieved message content: ', message); // Run moderation checks on on the message and moderate if needed. const moderatedMessage = moderateMessage(message.text); // Update the Firebase DB with checked message. console.log('Message has been moderated. Saving to DB: ', moderatedMessage); return event.data.adminRef.update({ text: moderatedMessage, sanitized: true, moderated: message.text !== moderatedMessage }); } });
In the moderateMessage function, we'll first check if the user is shouting and if so fix the case of the sentence and then remove all bad words using the bad-words package filter.
moderateMessage
bad-words
function moderateMessage(message) { // Re-capitalize if the user is Shouting. if (isShouting(message)) { console.log('User is shouting. Fixing sentence case...'); message = stopShouting(message); } // Moderate if the user uses SwearWords. if (containsSwearwords(message)) { console.log('User is swearing. moderating...'); message = moderateSwearwords(message); } return message; } // Returns true if the string contains swearwords. function containsSwearwords(message) { return message !== badWordsFilter.clean(message); } // Hide all swearwords. e.g: Crap => ****. function moderateSwearwords(message) { return badWordsFilter.clean(message); } // Detect if the current message is shouting. i.e. there are too many Uppercase // characters or exclamation points. function isShouting(message) { return message.replace(/[^A-Z]/g, '').length > message.length / 2 || message.replace(/[^!]/g, '').length >= 3; } // Correctly capitalize the string as a sentence (e.g. uppercase after dots) // and remove exclamation points. function stopShouting(message) { return capitalizeSentence(message.toLowerCase()).replace(/!+/g, '.'); }
Note: the bad-words package uses the badwords-list package's list of swear words which only contains around 400 of these. As you know the imagination of the user out there has no limit, so this is not an exhaustive list and you might want to extend the bad words dictionary.
To moderate images we'll set up a blurOffensiveImages function that will be triggered every time a file is uploaded to Cloud Storage. We set this up by using the functions.cloud.storage().onChange(...) trigger rule. We'll check if the image contains violent or adult content using the Google Cloud Vision API. The Cloud Vision API has a feature that specifically allows to detect inappropriate content in images. Then if the image is inappropriate we'll blur the image:
blurOffensiveImages
functions.cloud.storage().onChange(...)
exports.blurOffensiveImages = functions.storage.object().onChange(event => { const object = event.data; const file = gcs.bucket(object.bucket).file(object.name); // Exit if this is a move or deletion event. if (object.resourceState === 'not_exists') { return console.log('This is a deletion event.'); } // Check the image content using the Cloud Vision API. return vision.detectSafeSearch(file).then(data => { const safeSearch = data[0]; console.log('SafeSearch results on image', safeSearch); if (safeSearch.adult || safeSearch.violence) { return blurImage(object.name, object.bucket, object.metadata); } }); });
To blur the image stored in Cloud Storage, we'll first download it locally on the Cloud Functions instance, blur the image with ImageMagick, which is installed by default on all instances, then re-upload the image to Cloud Storage:
function blurImage(filePath, bucketName, metadata) { const filePathSplit = filePath.split('/'); filePathSplit.pop(); const fileDir = filePathSplit.join('/'); const tempLocalDir = `${LOCAL_TMP_FOLDER}${fileDir}`; const tempLocalFile = `${LOCAL_TMP_FOLDER}${filePath}`; const bucket = gcs.bucket(bucketName); // Create the temp directory where the storage file will be downloaded. return mkdirp(tempLocalDir).then(() => { console.log('Temporary directory has been created', tempLocalDir); // Download file from bucket. return bucket.file(filePath).download({ destination: tempLocalFile }); }).then(() => { console.log('The file has been downloaded to', tempLocalFile); // Blur the image using ImageMagick. return exec(`convert ${tempLocalFile} -channel RGBA -blur 0x8 ${tempLocalFile}`); }).then(() => { console.log('Blurred image created at', tempLocalFile); // Uploading the Blurred image. return bucket.upload(tempLocalFile, { destination: filePath, metadata: {metadata: metadata} // Keeping custom metadata. }); }).then(() => { console.log('Blurred image uploaded to Storage at', filePath); }); }
Cloud Functions for Firebase can be a great tool to reactively and automatically apply moderation rules. Feel free to have a look at our open source samples for text moderation and image moderation.