The routine below is a screenshot of one of my ongoing projects. It calls the plugin, flutter_twitter, but not before accessing the project’s Remote Config and supplying the two required String values. You can see I don’t offer too much information in the form of Strings in the code. Instead, this routine draws out the app’s package name and uses the first two parts, ‘com’ and ‘andrioussolutions’, to retrieve these particular Remote Config values.

Note, the lone String with a period, ".", highlighted by the first red arrow above. Admittedly, it would be better to assign that String elsewhere to a global variable or class property. You see, the bad guys are always looking for single and double quotes (or their obfuscated equivalent) throughout your code. Currently, it’s found in the very same routine it’s being used, and I shouldn’t have it there. I mean, why make it easier for them?

One further thing I did do in this utility class was to introduce encryption in the process. The function, getStringed(), will be of particular interest. It returns the String values from the Remote Config, but no before decrypting the retrieved value. The function is called for both the public key and the secret token as you can see highlighted in the screenshot below. Hence, back in the screenshot of the Remote Config screen for that particular Firebase project above, the values stored there are, in fact, the encrypted versions of the public key and secret token. Again, why make it easier for them?

Taking a peek at the class library, RemoteConfig, we can see the function calls its regular getString() function used to retrieve the String value from Firebase’s Remote Config, but then it passes that value to an asynchronous function called, de().

It’s an abbreviation form of the function, decrypt(), which in turn, calls this other function to perform the actual decryption. A screenshot of these functions is displayed below. Once again, it’s not recommended you store such sensitive information in Google’s cloud service, but if you must, encrypting will lessen the risk — if only somewhat. Storing such values in your own remote platform would be a better option, but that’s for another story.

Remote Configuration Routine

Let’s walk through the RemoteConfig class found in the library file, remote_config.dart, and explain what it does. There’s a screenshot below displaying the start of this class. Again, it works with the plugin that knows how to talk to Firebase’s Remote Config, and you can see it being imported with the prefix, ” r ”, in the screenshot below. Note, however, it also exports specific classes from the plugin file as well. This is so when using the library routine, you don’t have to import the plugin file as well, you just import this one file:

import remote_config.dart

Instead of:

import package:firebase_remote_config/firebase_remote_config.dart

import remote_config.dart

A further note in the constructor, I explicitly test the parameters if they’re assigned null. With such a utility class used by the general populace, null values could be passed in — by accident or otherwise. In addition, the named parameters, defaults, and expiration used by the enclosed plugin are assured to be assigned valid values. Lastly, the class doesn’t store the parameter values in instance variables. These values are instead passed to ‘private’ variables. They don’t need to be accessible again as a public class property. It’s a security precaution — another characteristic of such a utility class.

The next stretch of code lists the private variables and the getters used in this routine. The one of note, is the getter, instance, as it’s a reference to the Remote Config plugin itself. You likely won’t need it but is an option. If you’ve read my past articles, you know I like options.

Init Your Remote

The next stretch of code is the init() function. I decided to have a separate init() function in this routine so to remind any developer using this class to not only call the init() function to initialize things but to also call its corresponding dispose() function to then ‘clean things up.’ In the screenshot of the init() function below you can see it’s there where the Remote Config plugin is actually initialized. Further, any default values passed to the routine are then assigned to the plugin. Finally, it is there where the plugin’s fetch() function is called to ‘fetch’ the parameter values stored in the Remote Config.

You’ll notice an encryption key is conceived in the init() function as well. If this key was not explicitly passed to this function, the package name of your app is used to look up a possible key in Remote Config. Sneaky.

Further note, the whole operation in the init() function is enclosed in a try-catch statement and any exceptions recorded. Any such utility class should record any and all exceptions. Lastly, a boolean value of true is returned if everything goes successfully.

The next stretch of code will mirror the properties and functions found in the plugin itself. Again, being a utility class — made available for public use, you have to ensure the routine is used properly. In this case, the init() function has to be called before you can do anything else, and that’s what the series of assert() functions you see below are for. If the developer forgets to call the init() function, they’ll know it if they try to work with the routine any further.

What follows in the next bit of code is what you’ll be using most often. You’ll supply the appropriate key-value and retrieve parameter values from Firebase’s Remote Config using the following functions. The getStringed() function is found here. As always, if an exception occurs with the decryption, it’s recorded in this utility class.

The rest of the code below continues to mirror the functions available to the plugin itself. You can even add ‘listeners’ to introduce functions that will fire whenever a Remote Config value possibly changes during the app’s execution.

Remote Error

Lastly, in this RemoteConfig wrapper class, there’s the code for recording any exceptions. If something goes wrong, there are two getters, that you can use in your app itself to test if the wrapper class failed in any way. For instance, if either _remoteConfig.hasError or _remoteConfig.inError is set to true, there was an exception.

As you know by now, throughout the class and accompanying ever try-catch statement, the function, getError(), is called to record any exceptions. Well, your app can also call getError() without a parameter to retrieve the actual exception that has occurred and act accordingly. Nice.

Decrypt The Encrypted

Like the Remote Config routine, I had a need for a Cryptography routine. As it happens, the getStringed() function needed the means to decrypt the Remote Config values. Of course, using your favourite IDE and breakpoints, you’ll have to first encrypt those values and store them up there in the first place. The StringCrypt class does all this for you and is listed below. It works with another popular plugin called, flutter_string_encryption.dart, using the class, PlatformStringCryptor().

Again, like the Remote Config routine, this class doesn’t store it’s three parameters in class properties but instead takes them into private variables. You can also see its plugin is initialized in the constructor. Lastly, instead of explicitly providing the plugin a key parameter, you can instead provide a password and ‘salt’ to generate the key. Such keys are required to generate encryption.

The ‘salt’ parameter is an additional string that accompanies the password when generating a key for encryption and decryption. It’s an additional safeguard in case the password is ever compromised. It’s ‘one more component’ needed if a bad guy wants its access. That means it’s to be stored away from the password. In fact, the idea is the password is not stored anywhere but remembered by the user, and entered when your Flutter app starts up. Anyway, that too is another story.

Below, you now see the ‘decrypt’ routines used by the RemoteConfig class. In addition, you see the functions you would use to first generate a key you’d then store away on Remote Config for example.

The private function, _keyFromPassword(), is pretty self-explanatory. If there‘s a password and a salt provided, it’s called back up in the constructor and assigns a key to the private variable, _key.

Lastly, you’ll recognize the bit of code at the very end of this class. Again, such a utility class should catch any and all exceptions and save it for the developer to optionally retrieve and act upon accordingly. That code is listed below.

This utility class, RemoteConfig, was written up out of necessity — I needed to work with Firebase’s Remote Config service. I’ve supplied this class and the StringCrypt class to our fledgling Flutter community to use, to change, and to enhance. Hopefully, you’ll share any changes. Granted, the example I used to store passwords may not discourage the most determined attacker, but it’s better than storing such passwords in your Flutter app. No?

Cheers.

→ Other Stories by Greg Perry