Incident Commander Now Powered By Firebase For Remote Synchronization
Historically, my Incident Commander project has only written to and read from localStroage. I recently added an import / export feature; but, in the middle of an incident - when servers are on fire - no one wants to message around with JSON (JavaScript Object Notation) payloads. Today, I'm excited to announce that Incident Commander is now powered by Firebase. This means that your data will be written to your local Firebase instance as well as synchronized remotely with a shared Firebase backend. Now, you can copy-and-paste your Incident Commander URL directly to your teammates so that anyone and everyone on your team can participate in the timeline creation.
Run the Incident Commander application on GitHub.
View the Incident Commander code in my Incident Commander project on GitHub.
This is still a work in progress [WIP], so the code isn't nearly as clean as it could be. I see lots of duplication in the main app Controller; but, I can't quite see how to refactor for better organization. That said, the current Incident Commander application works in its current state - I can always clean things up later.
The Incident Commander application is now driven by the URL. It doesn't actually use true Routing - it just pulls the incident ID out of the location fragment. This incident ID is the reference key for the Firebase node in which your data is stored:
Now, when you start a new incident, a new ID is generated locally and pushed to Firebase. Or, if you are given an existing Incident Commander URL (via Slack, for example), the existing ID will be pulled out of the URL and the associated Firebase node will be synchronized down from the remote server where you can continue to update it.
Security Concerns
Ultimately, Incident Commander uses a public Firebase database with no user authentication. So, at the end of the day, this isn't a "secure" application and you should be mindful not to store overly-sensitive data in your incident timeline. That said, I have done my best to make it as secure as possible (and I'm certainly open to any additional suggestions).
The Firebase database rules prevent the incident collection from being iterated:
{
"rules": {
"incidents": {
// Anyone can create a new incident. But, no one can query the top-level
// incidents collection - only individual incidents can be retrieved.
".write": true,
"$incident": {
// Specific incidents can be both read from and written to. This requires
// incident IDs to be known ahead of time. Meaning, an attacker cannot
// attempt to load the entire incidents collection as a means to find
// other user's incidents.
".read": true
}
}
}
}
These rules prevent a potential attacker from downloading the entire "incidents" node as a means to find other user's incidents. Individual incident IDs have to be known ahead of time in order for the incident to be accessed.
That said, one could certainly attempt to generate incident IDs and check to see if they exist. To that end, I can only say that the IDs are large and hard to guess. On their own, the Firebase-generated IDs are extremely hard to guess - see their article titled, "The 2^120 Ways to Ensure Unique Identifiers". But, I'm also adding a random string of characters to the Firebase-generated ID to help increase the complexity:
// I generate an ID / key for a new incident reference.
private getNewID() : string {
// On their own, Firebase keys are not cryptographically secure; but, they are
// designed to be very hard to guess (read more: https://firebase.googleblog.com/2015/02/the-2120-ways-to-ensure-unique_68.html).
// That said, I'm prefixing them with a random string value. This is also not a
// cryptographically secure algorithm. But, together, there should be a
// significant amount of size and randomness to make them sufficiently hard to
// guess or iterate.
var ref = this.firebaseDB.ref( "/incidents/" ).push();
// Generate random suffix data.
var validChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ-abcdefghijklmnopqrstuvwxyz-0123456789-";
var randomChars = [];
for ( var i = 0 ; i < 30 ; i++ ) {
var random = Math.floor( Math.random() * 1234 );
// Select the random character from the valid characters collection.
randomChars.push( validChars.charAt( random % validChars.length ) );
}
return( "i" + randomChars.join( "" ) + ref.key + "c" );
}
Again, this is still not cryptographically secure; but, this is a public application hosted on GitHub pages with no user authentication - there's only so much I can do. The incident IDs are large and would have to be tested individually. If anyone has suggestions on how to make this more secure given the constraints, I'm very open to feedback.
Next, I'd like to add the ability to delete an incident from the remote Firebase database. And, perhaps even the ability to enter "offline mode", where you only use the local Firebase database (reverting back to the localStorage kind of approach). This should add additional peace-of-mind to those that are especially security focused.
Anyway, I hope someone finds this useful! More goodness to come.
Want to use code from this post? Check out the license.
Reader Comments