├── .gitignore
├── COPYING.txt
├── Gruntfile.js
├── LICENSE.txt
├── README.md
├── doc
├── 2PC.svg
├── 2PC.xml
├── hsm.grammar
├── send_item.html
├── send_item.png
├── send_item_interaction.svg
├── send_item_interaction.xml
├── send_item_lhs.png
├── send_item_rhs.png
└── shop.png
├── lib
└── statechart.js
├── models
├── .shop
├── auction.hsm
├── auction.rules
├── exhaustive.hsm
├── injection.data
├── injection.rules
├── send_item.hsm
├── send_item.rules
├── send_item.svg
├── send_item.xml
├── shop.hsm
└── shop.rules
├── package.json
├── properties.js
├── src
├── execute.js
├── execute.template
├── execute_externs.js
├── firebase_io.js
├── firesafe-cli.js
├── firesafe_main.js
├── hsm_to_client.js
├── hsm_to_rules.js
└── hsm_to_rules_parser.js
└── test
├── assets
└── deadcode.js
├── auction_test.js
├── authentication_test.js
├── closure_test.js
├── exhaustive_hsm_test.js
├── firebase_test.js
├── hsm_to_rules_test.js
├── injection_test.js
├── send_item_test.js
└── test_utils.js
/.gitignore:
--------------------------------------------------------------------------------
1 | properties.js
2 | README.html
3 | .idea*
4 | node_modules/*
5 | *.sublime-*
6 |
--------------------------------------------------------------------------------
/COPYING.txt:
--------------------------------------------------------------------------------
1 | Copyright (C) 2013-2014 Tom Larkworthy. All rights reserved.
2 |
3 | This program may be distributed and modified under the terms of the
4 | GNU General Public License as published by the Free Software Foundation,
5 | either version 3 of the License, or (at your option) any later version.
6 |
7 | Alternatively, this program may be distributed and modified under the
8 | terms of Quantum Leaps commercial licenses, which expressly supersede
9 | the GNU General Public License and are specifically designed for
10 | licensees interested in retaining the proprietary status of their code.
11 |
12 | This program is distributed in the hope that it will be useful, but
13 | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 | for more details.
16 |
17 | You should have received a copy of the GNU General Public License
18 | along with this program. If not, see .
19 |
20 |
21 | Contact information:
22 | --------------------
23 | Firesafe hosting: https://github.com/tomlarkworthy/firesafe
24 | e-mail: tom.larkworthy@gmail.com
25 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 | // Project configuration.
3 | grunt.initConfig({
4 | pkg: grunt.file.readJSON('package.json'),
5 |
6 | //see https://github.com/gruntjs/grunt-contrib-nodeunit
7 | //only files ending in _test.js in directory and subdirectories of test are run
8 | nodeunit: {
9 | all: ['test/**/*_test.js'],
10 | send_item: ['test/send_item_test.js'],
11 | auction: ['test/auction_test.js'],
12 | firebase: ['test/firebase_test.js'],
13 | authentication: ['test/authentication_test.js'],
14 | hsm_to_rules: ['test/hsm_to_rules_test.js'],
15 | exhaustive: ['test/exhaustive_hsm_test.js'],
16 | injection: ['test/injection_test.js'],
17 | closure: ['test/closure_test.js']
18 | },pandoc: {
19 | toHtml: {
20 | configs: {
21 | "publish" : 'HTML'
22 | },
23 | files: {
24 | "from": [
25 | "README.md"
26 | ]
27 | }
28 | }
29 | },peg: {
30 | hsm_to_rules: {
31 | src: "doc/hsm.grammar",
32 | dest: "src/hsm_to_rules_parser.js",
33 | options: { exportVar: "exports.parser" }
34 | }
35 | }
36 |
37 | });
38 |
39 | // Load the plugins for this project
40 | grunt.loadNpmTasks('grunt-contrib-nodeunit');
41 | grunt.loadNpmTasks('grunt-pandoc');
42 | grunt.loadNpmTasks('grunt-peg');
43 |
44 | // Default task(s).
45 | grunt.registerTask('default', ['nodeunit']);
46 |
47 | // generate documentation
48 | grunt.registerTask('doc', ['pandoc']);
49 |
50 | // generate parsers
51 | grunt.registerTask('parser', ['peg']);
52 |
53 | grunt.registerTask('test_parser', ['peg', "nodeunit:hsm_to_rules"]);
54 | grunt.registerTask('test_exhaustive', ['peg', "nodeunit:exhaustive"]);
55 | grunt.registerTask('test', ['peg', "nodeunit:all"]);
56 | };
57 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Firesafe
2 | by Tom Larkworthy
3 |
4 | Firesafe is a technology to enforce data integrity, and enable complex transactions, on Firebase.
5 |
6 | Firesafe compiles hierarchical state machines (HSM) definitions into Firebase security rules. The Firesafe HSM language is expressive, and a super set of the Firebase security language. Adding consistent, concurrent and fail safe protocols to Firebase is now a whole lot simpler (e.g. cross-tree transactions).
7 |
8 | Firebase is already the future of databases, offering scalable low latency database-as-a-service. Firesafe compliments this amazing technology with an expressive syntax to get the most out of its security model. (Firesafe is not endorsed by Firebase). Development of secure protocols in Firesafe is supported by a static analyser (see https://github.com/tomlarkworthy/firesafe/wiki/Send-Item)
9 |
10 | ## Motivation
11 |
12 | In multiplayer apps/games, people cheat. It's a loss of direct sales, AND the free loaders also diminish the fun for everyone else. Multiplayer games are web-scale, which means the old solutions to data integrity and transactions don't work (e.g. SQL).
13 |
14 | Firebase solved one problem of the cost of providing low latency persistent data storage to mobile and desktop games. It's the first scalable NoSQL hosted solution that didn't suck. It also provided an unorthodox security and transactions abstraction. Turns out that abstraction has enough purchase to do some really cool things not possible in many NoSQL environments. Unfortunately, properly configuring the security layer is extremely verbose and error prone.
15 |
16 | Proper data integrity is very important, especially when users have *something to gain*. A classic game exploit is the "item clone". In this exploit, a player gives an item to a friend, and yanks their connection to the game. Now, the player and the friend have the item. Various variations exist, some not even requiring a friend.
17 |
18 | * Zynga: http://gamersunite.coolchaser.com/topics/31432-farmville-how-to-duplicate-items-no-scam-or-hack
19 | * Kixeye: http://bpoutpost.com/battle-pirates-glitches-cheats-ghosting-cloning-fleets.html
20 | * World of Warcraft: http://eu.battle.net/wow/en/forum/topic/3313135576
21 |
22 | The reason why many games are affected by the same type of bug is that a difficult technical issue lies behind the exploit. It is very had to enforce the semantics of a **cross user transaction**.
23 |
24 | Firebase *can* solve this with a **two phase commit protocol**. Classic literature on 2 phase commits state it *can* become deadlocked. However, normal deadlock issues don't arise in this case, because Firebase is a central authority, and client's states are persisted on disconnect. Unfortunately, actually writing a two phase commit protocol in Firebase security rules is actually really hard and error prone, and the 2-phase commit protocol was one motivation for creating the Firesafe abstraction of Hierarchical State Machines (HSM) in Firebase.
25 |
26 | However, while HSM will prevent silly mistakes, it still can't prevent high level protocol errors. We have connected Firesafe to a theorem prover which allows **proveing non-blocking properties and protocol invariants for arbitrary HSMs**. Our long term goal is to make **"provably secure, deadlock free, multi-user interactions"** simple.
27 |
28 |
29 | #The HSM Language
30 |
31 | In Firesafe we provide the Hierarchical State Machines (HSM) language. A similar language (UML statecharts) is often used in protocol design. A machine is a set of states and a set of transitions between them. Each machine gets compiled down to a single, massive ".write" rule.
32 |
33 | The language has a very natural graphical representation. To explain the language let's start with simple examples and build up to a two phase commit protocol for secure exchange of items between players.
34 |
35 | ## Simple Example: Shop
36 |
37 | One common source of complaints and support headaches is buying items in-game. If it goes wrong players could lose currency, or, if it's exploitable, cheaters profit and devalue the currency. This is an acute problem if the currency is bought with real world money.
38 |
39 | 
40 |
41 | In a normal Firebase setting user accounts are represented as wild card ($user) children of "users". By placing our state machine as a child of "$user", Firesafe will generate an state (and signal) variable as a child of any "$user" nodes.
42 |
43 | We create secure Firesafe variables: gold, swords and water, at the same hierarchical level as the state machine. This indicates those variables values are protected by Firesafe. They can only ever be tampered with by a connected client *if* explicitly mentioned in a "guard" of "effect" clause of the machine.
44 |
45 | In the shopping scenario a user has just a single state, "playing". New players won't have Firebase data initially, so the black circle represents the initialization. New clients cannot initialize their new user accounts to anything though (a source of cheating). **Effect clauses denote post conditions of Firesafe variables, which must evaluate to true**. **Any Firesafe variable not mentioned in an effect is locked**. Guard and effect clauses are expressed as normal Firebase security expressions. In the shop case, the diagram forces clients to initialise their accounts with:
46 |
47 | ```
48 | {
49 | state:"playing",
50 | gold:100,
51 | swords:0,
52 | water:0
53 | }
54 | ```
55 |
56 | Once a player is playing, they have two options in the shop, buying a sword or water. Both these transition are labelled, which indicated the client must state which signal they are using. In this example we use a guard to ensure the player has enough gold to make a purchase and they do not exceed a maximum for the items (max(swords) 2, max(water) 20).
57 |
58 | **Guard clauses (diamond) prevent transitions unless the guard evaluates to true**. The guard in the shop ensure the player has the money and space in their inventory. So to buy a sword after initialization when the user has 100 gold and 0 swords, the new player can update
59 | ```
60 | {
61 | signal:"BUY_SWORD",
62 | gold:90,
63 | swords:1
64 | }
65 | ```
66 | on their "/user/" Firebase reference. The player *cannot* sneak in an update to "water" at the same time, as Firebase enforces no variable mentioned outside the effect clause can change.
67 |
68 | The final diagrammatic feature worth mentioning is the unattached red arrow. Unattached arrows on a digram denote a *transition role*. **Transitions only occur if their role clause evaluates to true, which commonly is used to express permissions**. In the shop we only allow the owner of the user record to invoke transitions. The transition role in particular is an excellent building block for complex multi-user interactions, because you can easily express that some transitions can only be performed by certain user roles.
69 |
70 | * complete hsm source file - https://github.com/tomlarkworthy/firesafe/blob/master/models/shop.hsm
71 | * generated validation rules - https://github.com/tomlarkworthy/firesafe/blob/master/models/shop.rules
72 |
73 | # Example: Item Trade
74 |
75 | Sending items from one player to another is problematic in many games and applications. Firebase natively does not offer much help, as Firebase transactions occur only on a subtree. To exchange items across users, you need to transfer data between different data trees (a **cross-tree transaction**). Firebase's atomic transactions cannot express this case, so the trade must be broken down into several smaller transactions that Firebase does support.
76 |
77 | One background issue is that a user might disconnect at any time (possible deliberately). One player disconnecting should not trap the other player in an unescapable state (a.k.a. **deadlock**).
78 |
79 | A cross tree transaction should either 1. occur, or 2. error and rollback. For a trade, an important invariant is the total number of objects in the world does not change. Drawing inspiration from existing literature, we adapt a **2-phase commit protocol** using in the banking sector for distributed balance trades, to implement trades in Firebase.
80 |
81 | Each user is either IDLE, sending an item (TX) or receiving an item (RX). Furthermore, the one partner in the trade must acknowledge the other's actions in a 2-phase commit, so some additional acknowledgement states are required (ACK_RX, ACK_TX).
82 |
83 | 
84 |
85 | The complete protocol is described step-by-step in the wiki (https://github.com/tomlarkworthy/firesafe/wiki/Send-Item). The final version in diagram form is as follows:
86 |
87 | 
88 |
89 | This protocol has been through a static analyser and shown to be correct. Sign up to our announcements if formal verification is important to you https://groups.google.com/forum/?hl=en-GB#!forum/firesafe-announce
90 |
91 | * complete hsm source file - https://github.com/tomlarkworthy/firesafe/blob/master/models/send_item.hsm
92 | * generated validation rules - https://github.com/tomlarkworthy/firesafe/blob/master/models/send_item.rules
93 |
94 | #Example: Hierarchical State Machines
95 |
96 | So far the machines discussed are flat. If you have ever tried to use a finite state machine in a real world setting you might have found yourself replicating arrows until your diagram is an unmanageable mess. Finite state machines suffer from *state space explosion*. Nesting states addresses this issue by reusing transitions via an inheritance-like mechanism.
97 |
98 | Miro Samek in the book *"Practical UML Statecharts for C/C++"* explains how to use state nesting, and explains common "patterns" for scalable state machine application. Slide 18 onwards of this online presentation explains in brief why HSMs are so much better than FSMs: http://www.slideshare.net/quantum-leaps/qp-qm-overviewnotes
99 |
100 | Note our HSMs do not map directly onto UML statecharts. In particular, UML statecharts are deterministic, whereas Firesafe's are not. In our HSM implementation, you do not need to specify signals at all, and can therefore leave the behaviour of the state chart ambiguous. While the behaviour of firesafe is ambiguous server side, the client still has to explicitly decide which states to move into. The client logic is often not modelable by state machines. Hence, non-deterministic hierarchical state machines are a better formalism for modeling server side data integrity than the deterministic formalism. That said, much of Miro's material is applicable to Firesafe's formalism, and the *"Practical UML Statecharts for C/C++"* book is a thoroughly recommended resource (Note: we are not in any way endorsed by either Miro Samek or Quantum Leaps, LLC, we just love their software!).
101 |
102 | #Firesafe Status
103 |
104 | ### current
105 | * .hsm -> Firebase rules command line compiler complete
106 |
107 | ### under development
108 | * Transitions with TIMESTAMP examples
109 | * Formal protocol verification
110 |
111 | ### on roadmap
112 | * .hsm -> client state machine generator
113 |
114 | Updates for major developments or calls for help! https://groups.google.com/forum/?hl=en-GB#!forum/firesafe-announce
115 |
116 | Requesting features, or just chat, at https://groups.google.com/forum/?hl=en-GB#!forum/firesafe-dev
117 |
118 | # Using Firesafe
119 |
120 | ### Install with NPM
121 |
122 | ```
123 | npm install -g firesafe
124 | ```
125 |
126 | ### Run
127 | ```
128 | firesafe
129 | ```
130 |
131 | upload the generated file to your Firebase security rules via the web API. We can automate this if it is a highly requested feature (we have a test driven framework).
132 |
133 |
134 |
135 |
136 |
137 |
--------------------------------------------------------------------------------
/doc/2PC.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/doc/2PC.xml:
--------------------------------------------------------------------------------
1 | 7ZlNk6IwEIZ/jcfZgoQPOarzsYfZqqnaw+4eo0RMTTRUiDP67zdIQKFxRxkEtmouVuiE2P3mSXeiIzxb754kiVc/REj5CFnhboTvRwiNLUt/poZ9xRBJFmYm2xi2LKRJyaSE4IrFZeNCbDZ0oUq2peDlyWISUWD4uSAcWn+xUK2Mc8g72r9TFq3yr7G9IOtJ1D6fI6RLsuXq7mBCaTd+GOGZFEJlrfVuRnmqRh5pFvrjmd7CJ0k36pIXUPbCG+Fb49KUbF61ZQJ8TVYkTpvbNZ8slJAjPH2jUjGtyDOZU/4iEqaY2Oghc6GUWJ8MmHAWpR1KxNBD43Q6lu5OTMbjJyrWVMm9HmJ6Xe+bm71jiMAGiPfjOjjGtDpZgrGxEUNDVMx8VEg3jEj1guFzgk0HLBge96iYAxSb6UgkScdMtmolJFP7AYuHbL8/8caN9uczW1LONvppGlPJ9LdSLeA9N+aXo23ahkBBRR8bQYFsq0YhbLUgUXCeL52K8Y7oKC/irFvV7MDuVTbbapTJuhUJe1a/ItlApDY2DAZLH8CoUE1QfhsxubeIya8uFMJudyF5IKRY0jQebRSaU3IoFVWsaagPdOaR8rl4fzgapgeD7siLSk19KQoP3YQTKQ/D51wsXg8mHcNvbbDzhz/6wfqG3LNiJ2IrF7QMniIyoqq8cKnblyzJHa4m5mJN6sQ287wIpv06pikffTRJ5rd5r7JohVeXrSMsdy2g6Vi9sgnr02DYtNpjc3wlm+DQgJyr2URONY8it6D1Azoh6JASOFkWchuoI1h+b1JZCoY/QL2Nw2oewklMJJJUg/4YssQ0u+R8x1SRgnU7o9y/kHIXUp4LdzHltjOurMfdv3LKwDGHk3nl2OxKbGK5TOindwq8cg+CKqsRVeM2qMKAKu9qqmpACPymVNUgCicbFlXOLfKvV61quOa6cquTRl6+T0JaiPWaaakepeB8TjS//9EZONeptFecr73S/V6B16uBgNXsAFsLln8tWAiA5bZQ2rHTGKwAJB8417C48m+Rg+F1r9MkDK+wne+Ozxx78wR7ujeCr63R+daAvxr0hVGjc26+tT+FkQ0wcq7GCK580PjuhFyAJJysT4wO9Tj/6zgbfvxHHT/8BQ==
--------------------------------------------------------------------------------
/doc/hsm.grammar:
--------------------------------------------------------------------------------
1 | /* PEG.js grammar
2 | * Representation of hierarchical state machines for generating validation rules
3 | *
4 | * special syntax is ".states", ".transitions", ".roles", ".variables"
5 | * we do not process ".write" if a machine is defined
6 | * you are free to add read and validate where you like
7 | */
8 |
9 | block
10 | = _ "{" _ bk1:block_item? _ bk2:("," _ block_item _?)* "}" _
11 | {
12 | var val = {};
13 | if (bk1.key != null){
14 | val[bk1.key] = bk1.val;
15 | }
16 | if (bk2 != null){
17 | for (var i =0;i
2 |
3 |
4 |
5 |
22 |
23 |
24 | This is a prototype to find a better visualisation for JSON data using D3. Its clearly needs some work, e.g. new line breaks in SVG
25 |
26 |
27 |
28 |
182 |
183 |
188 |