blaze_compiler
Advanced tools
Comparing version 0.0.6 to 0.0.7
{ | ||
"name": "blaze_compiler", | ||
"version": "0.0.6", | ||
"version": "0.0.7", | ||
"description": "Transpiles extendable, schema orientated definitions into Firebase security rules", | ||
@@ -5,0 +5,0 @@ "author": "Tom Larkworthy", |
200
README.md
@@ -1,121 +0,58 @@ | ||
# Blaze compiler for Firebase | ||
# Blaze Security Compiler for Firebase | ||
The blaze compiler presents a higher level interface to Firebase security rules. | ||
The blaze compiler simplifies building security rules for Firebase. It drastically reduces the amount of copy and pasting involved. Blaze compiler security rules are shorter, and the syntax is less fussy. | ||
- write rules in <a href="#rules-specified-in-yaml">YAML</a>, trailing commas, unquoted strings and comments with tool support | ||
- terser security <a href="#terser-expression-syntax">expression</a> syntax | ||
- create reusable <a href="#predicates">predicates</a> (boolean functions) | ||
- specify Firebase layout with typed JSON <a href="#schema">schema models</a> | ||
- embed global functional <a href="#constraints">constraints</a> in the schema | ||
- <a href="#model-reuse">reuse</a> models in multiple locations in the data tree | ||
- <a href="#inline-testing">inline tests</a> to check and document what form data can be to be inserted | ||
- describe <a href="#access-control">access control</a> as a separate concern | ||
see the big <a href="#example">example</a> | ||
## Getting started | ||
## Changelog | ||
- 9th July 2014: | ||
- support for rules in JSON | ||
- 30th June 2014: | ||
- removed trailing /* from access location syntax | ||
- allowed untyped schema if type is not specified | ||
- 14th July 2014: | ||
- improved error reporting | ||
- updated installation | ||
## Install | ||
For exploration of the examples, running tests, and staying up to date it's probably best to clone the git repo and link symbolically | ||
``` | ||
git clone https://github.com/firebase/blaze_compiler.git | ||
npm install -g grunt-cli | ||
npm install | ||
npm link | ||
npm install -g blaze_compiler | ||
``` | ||
However if you want to quickly try it out then you can install from npm too | ||
create a rules.yaml containing the following code | ||
``` | ||
npm install -g blaze_compiler | ||
``` | ||
```YAML | ||
predicates: | ||
- isLoggedIn(): auth.id !== null | ||
<a id="run"></a> | ||
## Run | ||
schema: {} | ||
access: | ||
- location: / | ||
read: true | ||
write: true && isLoggedIn() | ||
``` | ||
blaze examples/structure.yaml | ||
blaze -v /usr/local/lib/node_modules/blaze_compiler/examples/mail_example.yaml | ||
blaze -v <your blaze file> | ||
``` | ||
this will save a rules.json in the current directory which you can upload to the Firebase website | ||
now compile it from the commandline with | ||
## Tests | ||
``` | ||
grunt nodeunit:all | ||
blaze rules.yaml | ||
``` | ||
## Rules specified in YAML | ||
A rules.json will be generated which you can upload to Firebase! | ||
find more about the [predicates](#predicates), [simpler rule expressions](#simple-security-expressions), the [schema definitions](#schema), [access control](#access-control) or [inline tests](#inline-testing). | ||
JSON is sometimes fiddly to get syntactically right. Forgetting to quote keys or leaving a trailing comma is a common cause of parsing errors. So for the blaze compiler, the input language is YAML. As YAML is a strict superset of JSON, you can still write all your rules in JSON if you prefer, however YAML has many nice features | ||
## Predicates | ||
- automatic quoting of keys | ||
- automatic quoting of string, and detection of multi-line strings | ||
- objects optionally defined without "{" using indentation instead | ||
- array syntax with - | ||
- comments with # | ||
Common expressions for reuse are defined in the *predicates* list. A predicate can take arguments (they are functions). | ||
For example, the following yaml | ||
```YAML | ||
predicates: | ||
- isLoggedIn(): auth.username !== null | ||
- isUser(username): auth.username === username | ||
``` | ||
my_object: #my_object will be the first and only propery of the root document object | ||
object_child: {"key":"value"} | ||
string_child: "you can quote strings if you want..." | ||
multiline_string: | ||
this is a | ||
multi-line string with no quotes | ||
You can then use them anywhere a security expression would be expected, for example, in the access control section:- | ||
array_child: | ||
- element1: {} | ||
- "element2" | ||
- element3 # also a string | ||
``` | ||
would be compiled to the following JSON (you can think of YAML as just a compact way of specifying JSON) | ||
access: | ||
location: /users/$userid/ | ||
write: isUser($userid) | ||
``` | ||
{ | ||
"my_object": { | ||
"object_child": { | ||
"key": "value" | ||
}, | ||
"string_child": "you can quote strings if you want...", | ||
"multiline_string": "this is a multi-line string with no quotes", | ||
"array_child": [ | ||
{ | ||
"element1": {} | ||
}, | ||
"element2", | ||
"element3" | ||
] | ||
} | ||
} | ||
``` | ||
The space after a colon is important! All indentation to denote keys or arrays is 2 spaces. | ||
## Simple Security Expressions | ||
You can work in JSON though if you prefer, just make sure your input file ends with ".json" | ||
Security expressions are the strings that used to go in write/read/validate portions of the old security rules. Blaze expressions have similar semantics but shorter syntax. | ||
## Terser Expression Syntax | ||
Security expressions are the values that used to go in write/read/validate portions of the old security rules. Blaze expressions have similar semantics but terser syntax. | ||
#### Variables renamed | ||
@@ -154,30 +91,13 @@ | ||
## Predicates | ||
To reduce repetition of common expressions, you can create reusable boolean functions with meaningful names to snippets of expression logic. The boolean functions are called predicates and are expressed as an array child of a top level key *predicates*. | ||
``` | ||
predicates: | ||
- isLoggedIn(): auth.username !== null | ||
- isUser(username): auth.username === username | ||
``` | ||
predicates can then be used in other expressions elsewhere: | ||
``` | ||
access: | ||
location: /users/$userid/ | ||
write: isUser($userid) | ||
``` | ||
## Schema | ||
We have separated out access control concerns (read/write) from describing the static structure of the Firebase. The schema portion of the blaze rules YAML file is for specifying the shape of valid data, **not** who can access it. The semantics are a subset of JSON schema v4. | ||
The schema section describes the layout of the data tree. | ||
#### Types | ||
A Firebase node is either a primitive leaf type (*string*, *number*, *boolean*) or an *object* which can have further child nodes. The type is specified with "type". Children of objects are specified as a map under "properties" | ||
A Firebase schema node is either a leaf type (*string*, *number*, *boolean*) or an *object* which contains more child schema nodes. The type is specified with "type". Children of objects are specified as a map under "properties" | ||
``` | ||
```YAML | ||
schema: | ||
@@ -189,2 +109,3 @@ type: object | ||
number_child: {type: number} | ||
anything_child: {} | ||
``` | ||
@@ -194,9 +115,9 @@ | ||
You can leave a schema untyped by not specifying anything. The non-typed schema will allow primative or object types to be written at that location. | ||
You can leave a schema unspecified with {} or with type: "any". | ||
#### required | ||
The required keyword states which children **must** be present for the parent object to be valid. Its value is an array. Required children do not *need* to be specified in the properties (although that would be good practice typically). The required keyword is only valid for object schemas. | ||
The required keyword states which children **must** be present. The required keyword is only valid for schema nodes with object types. | ||
``` | ||
```YAML | ||
schema: | ||
@@ -209,5 +130,5 @@ type: object | ||
By default, values not constrained by the schema are considered valid. So objects, by default, accept children not explicitly mentioned in the schema. If additionalProperties is set to false, however, only children explicitly mentioned in the properties are allowed. The additionalProperties keyword is only valid for object and non-typed schemas. | ||
By default, objects can have additional children not mentioned. If additionalProperties is set to false, however, only children explicitly mentioned in the properties are allowed. The additionalProperties keyword is only valid for object and non-typed schemas. | ||
``` | ||
```YAML | ||
schema: | ||
@@ -224,5 +145,5 @@ type: object | ||
The enum keyword constrains string types to be one of the mentioned array elements. enum keyword is only valid for string types. | ||
The enum keyword constrains the value of a string types to be one of the predefined array elements. | ||
``` | ||
```YAML | ||
schema: | ||
@@ -237,3 +158,3 @@ type: string | ||
``` | ||
```YAML | ||
schema: | ||
@@ -249,7 +170,7 @@ type: object | ||
The semantics of enforcing data integrity is quite different from the original rules. There is no overriding of constraints, nor separate read/write/validate expressions. There is just one field for expressing data integrity named *constraint*. All ancestors and descendant constraints must evaluate to true for a write to be allowed. | ||
The semantics of enforcing data integrity is different from the original rules. There is no overriding of constraints, nor separate read/write/validate expressions. There is just one field for expressing data integrity named *constraint*. All ancestors and descendant constraints must evaluate to true for a write to be allowed. | ||
The following example, fixes the id of a user to equal the key, and makes the account writable only at creation time. | ||
``` | ||
```YAML | ||
schema: | ||
@@ -266,6 +187,3 @@ type: object | ||
#The ! character has special meaning in YAML | ||
#so expression starting with ! have to be quoted | ||
constraint: "!prev.exists()" | ||
constraint: (!prev.exists()) | ||
``` | ||
@@ -281,3 +199,3 @@ | ||
``` | ||
```YAML | ||
schema: | ||
@@ -310,3 +228,3 @@ definitions: | ||
``` | ||
```YAML | ||
schema: | ||
@@ -333,3 +251,2 @@ type: object | ||
- {extra: "4.6"} #additionProperties is false, so no unexpected properties allowed | ||
``` | ||
@@ -339,5 +256,5 @@ | ||
The schema portion of the rules YAML file is for denoting integrity constraints. Read/write access is described in a separate access control list under "access". For each entry, the scope of the rule is a subtree at, or below, the path indicated in the *location* field. Read access is granted to that subtree if the *read* expression evaluates to true, and write access is granted if the *write* expression evaluates to true. | ||
The schema portion of the rules YAML file is for specifying the data layout and constraints. Read/write access is described in a separate access control list under "access". For each entry, the scope of the rule is a subtree at, or below, the path indicated in the *location* field. Read access is granted to that subtree if the *read* expression evaluates to true, and write access is granted if the *write* expression evaluates to true. | ||
``` | ||
```YAML | ||
predicates: | ||
@@ -360,4 +277,3 @@ - isLoggedIn(): auth !== null | ||
``` | ||
```YAML | ||
predicates: #reusable boolean functions | ||
@@ -423,4 +339,2 @@ - isLoggedIn(): auth.username !== null | ||
#write and delete is given to owners outbox | ||
#note that because only box owners can delete messages, | ||
#other users cannot use this entry point (see message constraint) | ||
- location: users/$userid/outbox/ | ||
@@ -433,1 +347,15 @@ write: true | ||
``` | ||
## Changelog | ||
- 9th July 2014: | ||
- support for rules in JSON | ||
- 30th June 2014: | ||
- removed trailing /* from access location syntax | ||
- allowed untyped schema if type is not specified | ||
- 14th July 2014: | ||
- improved error reporting | ||
- updated installation |
{ | ||
"rules":{ | ||
".write":"true&&true&&false&&false", | ||
".read":"false", | ||
"users": { | ||
".write":"true&&false&&false", | ||
".read":"false", | ||
"$userid": { | ||
".write":"true&&true&&false&&true&&false&&(false||false)", | ||
".read":"false||$userid===auth.username", | ||
"inbox": { | ||
".write":"true&&false&&(false||newData.exists()&&!data.exists()&&auth.username!==null||data.exists()&&!newData.exists()&&$userid===auth.username||false)", | ||
".read":"false||false||false||$userid===auth.username", | ||
"$message": { | ||
".write":"true&&true&&(!newData.child('from').parent().parent().parent().parent().parent().exists()||!(newData.child('from').parent().parent().parent().parent().parent().isString()||newData.child('from').parent().parent().parent().parent().parent().isNumber()||newData.child('from').parent().parent().parent().parent().parent().isBoolean()))&&(newData.child('from').parent().parent().parent().parent().parent().val()==null||true)&&true&&(!newData.child('from').parent().parent().parent().parent().exists()||!(newData.child('from').parent().parent().parent().parent().isString()||newData.child('from').parent().parent().parent().parent().isNumber()||newData.child('from').parent().parent().parent().parent().isBoolean()))&&(newData.child('from').parent().parent().parent().parent().val()==null||true)&&true&&(!newData.child('from').parent().parent().parent().exists()||!(newData.child('from').parent().parent().parent().isString()||newData.child('from').parent().parent().parent().isNumber()||newData.child('from').parent().parent().parent().isBoolean()))&&(newData.child('from').parent().parent().parent().val()==null||true)&&true&&(!newData.child('from').parent().parent().exists()||!(newData.child('from').parent().parent().isString()||newData.child('from').parent().parent().isNumber()||newData.child('from').parent().parent().isBoolean()))&&(newData.child('from').parent().parent().val()==null||true)&&true&&(!newData.child('from').parent().exists()||!(newData.child('from').parent().isString()||newData.child('from').parent().isNumber()||newData.child('from').parent().isBoolean()))&&(newData.child('from').parent().val()==null||true&&newData.child('from').parent().child('from').exists()&&newData.child('from').parent().child('to').exists()&&newData.child('from').parent().child('message').exists())&&(auth.username==newData.child('from').val()&&newData.exists()&&!data.exists()||$userid===auth.username&&data.exists()&&!newData.exists())&&(!newData.child('from').exists()||newData.child('from').isString())&&true&&(!newData.child('to').parent().parent().parent().parent().parent().exists()||!(newData.child('to').parent().parent().parent().parent().parent().isString()||newData.child('to').parent().parent().parent().parent().parent().isNumber()||newData.child('to').parent().parent().parent().parent().parent().isBoolean()))&&(newData.child('to').parent().parent().parent().parent().parent().val()==null||true)&&true&&(!newData.child('to').parent().parent().parent().parent().exists()||!(newData.child('to').parent().parent().parent().parent().isString()||newData.child('to').parent().parent().parent().parent().isNumber()||newData.child('to').parent().parent().parent().parent().isBoolean()))&&(newData.child('to').parent().parent().parent().parent().val()==null||true)&&true&&(!newData.child('to').parent().parent().parent().exists()||!(newData.child('to').parent().parent().parent().isString()||newData.child('to').parent().parent().parent().isNumber()||newData.child('to').parent().parent().parent().isBoolean()))&&(newData.child('to').parent().parent().parent().val()==null||true)&&true&&(!newData.child('to').parent().parent().exists()||!(newData.child('to').parent().parent().isString()||newData.child('to').parent().parent().isNumber()||newData.child('to').parent().parent().isBoolean()))&&(newData.child('to').parent().parent().val()==null||true)&&true&&(!newData.child('to').parent().exists()||!(newData.child('to').parent().isString()||newData.child('to').parent().isNumber()||newData.child('to').parent().isBoolean()))&&(newData.child('to').parent().val()==null||true&&newData.child('to').parent().child('from').exists()&&newData.child('to').parent().child('to').exists()&&newData.child('to').parent().child('message').exists())&&(newData.exists()&&!data.exists()||data.exists()&&!newData.exists())&&(!newData.child('to').exists()||newData.child('to').isString())&&true&&(!newData.child('message').parent().parent().parent().parent().parent().exists()||!(newData.child('message').parent().parent().parent().parent().parent().isString()||newData.child('message').parent().parent().parent().parent().parent().isNumber()||newData.child('message').parent().parent().parent().parent().parent().isBoolean()))&&(newData.child('message').parent().parent().parent().parent().parent().val()==null||true)&&true&&(!newData.child('message').parent().parent().parent().parent().exists()||!(newData.child('message').parent().parent().parent().parent().isString()||newData.child('message').parent().parent().parent().parent().isNumber()||newData.child('message').parent().parent().parent().parent().isBoolean()))&&(newData.child('message').parent().parent().parent().parent().val()==null||true)&&true&&(!newData.child('message').parent().parent().parent().exists()||!(newData.child('message').parent().parent().parent().isString()||newData.child('message').parent().parent().parent().isNumber()||newData.child('message').parent().parent().parent().isBoolean()))&&(newData.child('message').parent().parent().parent().val()==null||true)&&true&&(!newData.child('message').parent().parent().exists()||!(newData.child('message').parent().parent().isString()||newData.child('message').parent().parent().isNumber()||newData.child('message').parent().parent().isBoolean()))&&(newData.child('message').parent().parent().val()==null||true)&&true&&(!newData.child('message').parent().exists()||!(newData.child('message').parent().isString()||newData.child('message').parent().isNumber()||newData.child('message').parent().isBoolean()))&&(newData.child('message').parent().val()==null||true&&newData.child('message').parent().child('from').exists()&&newData.child('message').parent().child('to').exists()&&newData.child('message').parent().child('message').exists())&&(newData.exists()&&!data.exists()||data.exists()&&!newData.exists())&&(!newData.child('message').exists()||newData.child('message').isString())&&(false||newData.exists()&&!data.exists()&&auth.username!==null||data.exists()&&!newData.exists()&&$userid===auth.username||false)", | ||
".read":"false||false||false||$userid===auth.username", | ||
"from": { | ||
".write":"true&&(!newData.parent().parent().parent().parent().parent().exists()||!(newData.parent().parent().parent().parent().parent().isString()||newData.parent().parent().parent().parent().parent().isNumber()||newData.parent().parent().parent().parent().parent().isBoolean()))&&(newData.parent().parent().parent().parent().parent().val()==null||true)&&true&&(!newData.parent().parent().parent().parent().exists()||!(newData.parent().parent().parent().parent().isString()||newData.parent().parent().parent().parent().isNumber()||newData.parent().parent().parent().parent().isBoolean()))&&(newData.parent().parent().parent().parent().val()==null||true)&&true&&(!newData.parent().parent().parent().exists()||!(newData.parent().parent().parent().isString()||newData.parent().parent().parent().isNumber()||newData.parent().parent().parent().isBoolean()))&&(newData.parent().parent().parent().val()==null||true)&&true&&(!newData.parent().parent().exists()||!(newData.parent().parent().isString()||newData.parent().parent().isNumber()||newData.parent().parent().isBoolean()))&&(newData.parent().parent().val()==null||true)&&true&&(!newData.parent().exists()||!(newData.parent().isString()||newData.parent().isNumber()||newData.parent().isBoolean()))&&(newData.parent().val()==null||true&&newData.parent().child('from').exists()&&newData.parent().child('to').exists()&&newData.parent().child('message').exists())&&(auth.username==newData.val()&&newData.exists()&&!data.exists()||$userid===auth.username&&data.exists()&&!newData.exists())&&(!newData.exists()||newData.isString())&&(false||newData.exists()&&!data.exists()&&auth.username!==null||data.exists()&&!newData.exists()&&$userid===auth.username||false)", | ||
".read":"false||false||false||$userid===auth.username" | ||
}, | ||
"to": { | ||
".write":"true&&(!newData.parent().parent().parent().parent().parent().exists()||!(newData.parent().parent().parent().parent().parent().isString()||newData.parent().parent().parent().parent().parent().isNumber()||newData.parent().parent().parent().parent().parent().isBoolean()))&&(newData.parent().parent().parent().parent().parent().val()==null||true)&&true&&(!newData.parent().parent().parent().parent().exists()||!(newData.parent().parent().parent().parent().isString()||newData.parent().parent().parent().parent().isNumber()||newData.parent().parent().parent().parent().isBoolean()))&&(newData.parent().parent().parent().parent().val()==null||true)&&true&&(!newData.parent().parent().parent().exists()||!(newData.parent().parent().parent().isString()||newData.parent().parent().parent().isNumber()||newData.parent().parent().parent().isBoolean()))&&(newData.parent().parent().parent().val()==null||true)&&true&&(!newData.parent().parent().exists()||!(newData.parent().parent().isString()||newData.parent().parent().isNumber()||newData.parent().parent().isBoolean()))&&(newData.parent().parent().val()==null||true)&&true&&(!newData.parent().exists()||!(newData.parent().isString()||newData.parent().isNumber()||newData.parent().isBoolean()))&&(newData.parent().val()==null||true&&newData.parent().child('from').exists()&&newData.parent().child('to').exists()&&newData.parent().child('message').exists())&&(newData.exists()&&!data.exists()||data.exists()&&!newData.exists())&&(!newData.exists()||newData.isString())&&(false||newData.exists()&&!data.exists()&&auth.username!==null||data.exists()&&!newData.exists()&&$userid===auth.username||false)", | ||
".read":"false||false||false||$userid===auth.username" | ||
}, | ||
"message": { | ||
".write":"true&&(!newData.parent().parent().parent().parent().parent().exists()||!(newData.parent().parent().parent().parent().parent().isString()||newData.parent().parent().parent().parent().parent().isNumber()||newData.parent().parent().parent().parent().parent().isBoolean()))&&(newData.parent().parent().parent().parent().parent().val()==null||true)&&true&&(!newData.parent().parent().parent().parent().exists()||!(newData.parent().parent().parent().parent().isString()||newData.parent().parent().parent().parent().isNumber()||newData.parent().parent().parent().parent().isBoolean()))&&(newData.parent().parent().parent().parent().val()==null||true)&&true&&(!newData.parent().parent().parent().exists()||!(newData.parent().parent().parent().isString()||newData.parent().parent().parent().isNumber()||newData.parent().parent().parent().isBoolean()))&&(newData.parent().parent().parent().val()==null||true)&&true&&(!newData.parent().parent().exists()||!(newData.parent().parent().isString()||newData.parent().parent().isNumber()||newData.parent().parent().isBoolean()))&&(newData.parent().parent().val()==null||true)&&true&&(!newData.parent().exists()||!(newData.parent().isString()||newData.parent().isNumber()||newData.parent().isBoolean()))&&(newData.parent().val()==null||true&&newData.parent().child('from').exists()&&newData.parent().child('to').exists()&&newData.parent().child('message').exists())&&(newData.exists()&&!data.exists()||data.exists()&&!newData.exists())&&(!newData.exists()||newData.isString())&&(false||newData.exists()&&!data.exists()&&auth.username!==null||data.exists()&&!newData.exists()&&$userid===auth.username||false)", | ||
".read":"false||false||false||$userid===auth.username" | ||
}, | ||
"$other":{".validate":"false"} | ||
} | ||
}, | ||
"outbox": { | ||
".write":"true&&false&&(false||true||false)", | ||
".read":"false||false||$userid===auth.username", | ||
"$message": { | ||
".write":"true&&true&&(!newData.child('from').parent().parent().parent().parent().parent().exists()||!(newData.child('from').parent().parent().parent().parent().parent().isString()||newData.child('from').parent().parent().parent().parent().parent().isNumber()||newData.child('from').parent().parent().parent().parent().parent().isBoolean()))&&(newData.child('from').parent().parent().parent().parent().parent().val()==null||true)&&true&&(!newData.child('from').parent().parent().parent().parent().exists()||!(newData.child('from').parent().parent().parent().parent().isString()||newData.child('from').parent().parent().parent().parent().isNumber()||newData.child('from').parent().parent().parent().parent().isBoolean()))&&(newData.child('from').parent().parent().parent().parent().val()==null||true)&&true&&(!newData.child('from').parent().parent().parent().exists()||!(newData.child('from').parent().parent().parent().isString()||newData.child('from').parent().parent().parent().isNumber()||newData.child('from').parent().parent().parent().isBoolean()))&&(newData.child('from').parent().parent().parent().val()==null||true)&&true&&(!newData.child('from').parent().parent().exists()||!(newData.child('from').parent().parent().isString()||newData.child('from').parent().parent().isNumber()||newData.child('from').parent().parent().isBoolean()))&&(newData.child('from').parent().parent().val()==null||true)&&true&&(!newData.child('from').parent().exists()||!(newData.child('from').parent().isString()||newData.child('from').parent().isNumber()||newData.child('from').parent().isBoolean()))&&(newData.child('from').parent().val()==null||true&&newData.child('from').parent().child('from').exists()&&newData.child('from').parent().child('to').exists()&&newData.child('from').parent().child('message').exists())&&(!newData.child('from').parent().exists()||!(newData.child('from').parent().isString()||newData.child('from').parent().isNumber()||newData.child('from').parent().isBoolean()))&&(newData.child('from').parent().val()==null||true&&newData.child('from').parent().child('from').exists()&&newData.child('from').parent().child('to').exists()&&newData.child('from').parent().child('message').exists())&&(auth.username==newData.child('from').val()&&newData.exists()&&!data.exists()||$userid===auth.username&&data.exists()&&!newData.exists())&&(!newData.child('from').exists()||newData.child('from').isString())&&(!newData.child('from').exists()||newData.child('from').isString())&&true&&(!newData.child('to').parent().parent().parent().parent().parent().exists()||!(newData.child('to').parent().parent().parent().parent().parent().isString()||newData.child('to').parent().parent().parent().parent().parent().isNumber()||newData.child('to').parent().parent().parent().parent().parent().isBoolean()))&&(newData.child('to').parent().parent().parent().parent().parent().val()==null||true)&&true&&(!newData.child('to').parent().parent().parent().parent().exists()||!(newData.child('to').parent().parent().parent().parent().isString()||newData.child('to').parent().parent().parent().parent().isNumber()||newData.child('to').parent().parent().parent().parent().isBoolean()))&&(newData.child('to').parent().parent().parent().parent().val()==null||true)&&true&&(!newData.child('to').parent().parent().parent().exists()||!(newData.child('to').parent().parent().parent().isString()||newData.child('to').parent().parent().parent().isNumber()||newData.child('to').parent().parent().parent().isBoolean()))&&(newData.child('to').parent().parent().parent().val()==null||true)&&true&&(!newData.child('to').parent().parent().exists()||!(newData.child('to').parent().parent().isString()||newData.child('to').parent().parent().isNumber()||newData.child('to').parent().parent().isBoolean()))&&(newData.child('to').parent().parent().val()==null||true)&&true&&(!newData.child('to').parent().exists()||!(newData.child('to').parent().isString()||newData.child('to').parent().isNumber()||newData.child('to').parent().isBoolean()))&&(newData.child('to').parent().val()==null||true&&newData.child('to').parent().child('from').exists()&&newData.child('to').parent().child('to').exists()&&newData.child('to').parent().child('message').exists())&&(!newData.child('to').parent().exists()||!(newData.child('to').parent().isString()||newData.child('to').parent().isNumber()||newData.child('to').parent().isBoolean()))&&(newData.child('to').parent().val()==null||true&&newData.child('to').parent().child('from').exists()&&newData.child('to').parent().child('to').exists()&&newData.child('to').parent().child('message').exists())&&(newData.exists()&&!data.exists()||data.exists()&&!newData.exists())&&(!newData.child('to').exists()||newData.child('to').isString())&&(!newData.child('to').exists()||newData.child('to').isString())&&true&&(!newData.child('message').parent().parent().parent().parent().parent().exists()||!(newData.child('message').parent().parent().parent().parent().parent().isString()||newData.child('message').parent().parent().parent().parent().parent().isNumber()||newData.child('message').parent().parent().parent().parent().parent().isBoolean()))&&(newData.child('message').parent().parent().parent().parent().parent().val()==null||true)&&true&&(!newData.child('message').parent().parent().parent().parent().exists()||!(newData.child('message').parent().parent().parent().parent().isString()||newData.child('message').parent().parent().parent().parent().isNumber()||newData.child('message').parent().parent().parent().parent().isBoolean()))&&(newData.child('message').parent().parent().parent().parent().val()==null||true)&&true&&(!newData.child('message').parent().parent().parent().exists()||!(newData.child('message').parent().parent().parent().isString()||newData.child('message').parent().parent().parent().isNumber()||newData.child('message').parent().parent().parent().isBoolean()))&&(newData.child('message').parent().parent().parent().val()==null||true)&&true&&(!newData.child('message').parent().parent().exists()||!(newData.child('message').parent().parent().isString()||newData.child('message').parent().parent().isNumber()||newData.child('message').parent().parent().isBoolean()))&&(newData.child('message').parent().parent().val()==null||true)&&true&&(!newData.child('message').parent().exists()||!(newData.child('message').parent().isString()||newData.child('message').parent().isNumber()||newData.child('message').parent().isBoolean()))&&(newData.child('message').parent().val()==null||true&&newData.child('message').parent().child('from').exists()&&newData.child('message').parent().child('to').exists()&&newData.child('message').parent().child('message').exists())&&(!newData.child('message').parent().exists()||!(newData.child('message').parent().isString()||newData.child('message').parent().isNumber()||newData.child('message').parent().isBoolean()))&&(newData.child('message').parent().val()==null||true&&newData.child('message').parent().child('from').exists()&&newData.child('message').parent().child('to').exists()&&newData.child('message').parent().child('message').exists())&&(newData.exists()&&!data.exists()||data.exists()&&!newData.exists())&&(!newData.child('message').exists()||newData.child('message').isString())&&(!newData.child('message').exists()||newData.child('message').isString())&&(false||true||false)", | ||
".read":"false||false||$userid===auth.username", | ||
"from": { | ||
".write":"true&&(!newData.parent().parent().parent().parent().parent().exists()||!(newData.parent().parent().parent().parent().parent().isString()||newData.parent().parent().parent().parent().parent().isNumber()||newData.parent().parent().parent().parent().parent().isBoolean()))&&(newData.parent().parent().parent().parent().parent().val()==null||true)&&true&&(!newData.parent().parent().parent().parent().exists()||!(newData.parent().parent().parent().parent().isString()||newData.parent().parent().parent().parent().isNumber()||newData.parent().parent().parent().parent().isBoolean()))&&(newData.parent().parent().parent().parent().val()==null||true)&&true&&(!newData.parent().parent().parent().exists()||!(newData.parent().parent().parent().isString()||newData.parent().parent().parent().isNumber()||newData.parent().parent().parent().isBoolean()))&&(newData.parent().parent().parent().val()==null||true)&&true&&(!newData.parent().parent().exists()||!(newData.parent().parent().isString()||newData.parent().parent().isNumber()||newData.parent().parent().isBoolean()))&&(newData.parent().parent().val()==null||true)&&true&&(!newData.parent().exists()||!(newData.parent().isString()||newData.parent().isNumber()||newData.parent().isBoolean()))&&(newData.parent().val()==null||true&&newData.parent().child('from').exists()&&newData.parent().child('to').exists()&&newData.parent().child('message').exists())&&(!newData.parent().exists()||!(newData.parent().isString()||newData.parent().isNumber()||newData.parent().isBoolean()))&&(newData.parent().val()==null||true&&newData.parent().child('from').exists()&&newData.parent().child('to').exists()&&newData.parent().child('message').exists())&&(auth.username==newData.val()&&newData.exists()&&!data.exists()||$userid===auth.username&&data.exists()&&!newData.exists())&&(!newData.exists()||newData.isString())&&(!newData.exists()||newData.isString())&&(false||true||false)", | ||
".read":"false||false||$userid===auth.username" | ||
}, | ||
"to": { | ||
".write":"true&&(!newData.parent().parent().parent().parent().parent().exists()||!(newData.parent().parent().parent().parent().parent().isString()||newData.parent().parent().parent().parent().parent().isNumber()||newData.parent().parent().parent().parent().parent().isBoolean()))&&(newData.parent().parent().parent().parent().parent().val()==null||true)&&true&&(!newData.parent().parent().parent().parent().exists()||!(newData.parent().parent().parent().parent().isString()||newData.parent().parent().parent().parent().isNumber()||newData.parent().parent().parent().parent().isBoolean()))&&(newData.parent().parent().parent().parent().val()==null||true)&&true&&(!newData.parent().parent().parent().exists()||!(newData.parent().parent().parent().isString()||newData.parent().parent().parent().isNumber()||newData.parent().parent().parent().isBoolean()))&&(newData.parent().parent().parent().val()==null||true)&&true&&(!newData.parent().parent().exists()||!(newData.parent().parent().isString()||newData.parent().parent().isNumber()||newData.parent().parent().isBoolean()))&&(newData.parent().parent().val()==null||true)&&true&&(!newData.parent().exists()||!(newData.parent().isString()||newData.parent().isNumber()||newData.parent().isBoolean()))&&(newData.parent().val()==null||true&&newData.parent().child('from').exists()&&newData.parent().child('to').exists()&&newData.parent().child('message').exists())&&(!newData.parent().exists()||!(newData.parent().isString()||newData.parent().isNumber()||newData.parent().isBoolean()))&&(newData.parent().val()==null||true&&newData.parent().child('from').exists()&&newData.parent().child('to').exists()&&newData.parent().child('message').exists())&&(newData.exists()&&!data.exists()||data.exists()&&!newData.exists())&&(!newData.exists()||newData.isString())&&(!newData.exists()||newData.isString())&&(false||true||false)", | ||
".read":"false||false||$userid===auth.username" | ||
}, | ||
"message": { | ||
".write":"true&&(!newData.parent().parent().parent().parent().parent().exists()||!(newData.parent().parent().parent().parent().parent().isString()||newData.parent().parent().parent().parent().parent().isNumber()||newData.parent().parent().parent().parent().parent().isBoolean()))&&(newData.parent().parent().parent().parent().parent().val()==null||true)&&true&&(!newData.parent().parent().parent().parent().exists()||!(newData.parent().parent().parent().parent().isString()||newData.parent().parent().parent().parent().isNumber()||newData.parent().parent().parent().parent().isBoolean()))&&(newData.parent().parent().parent().parent().val()==null||true)&&true&&(!newData.parent().parent().parent().exists()||!(newData.parent().parent().parent().isString()||newData.parent().parent().parent().isNumber()||newData.parent().parent().parent().isBoolean()))&&(newData.parent().parent().parent().val()==null||true)&&true&&(!newData.parent().parent().exists()||!(newData.parent().parent().isString()||newData.parent().parent().isNumber()||newData.parent().parent().isBoolean()))&&(newData.parent().parent().val()==null||true)&&true&&(!newData.parent().exists()||!(newData.parent().isString()||newData.parent().isNumber()||newData.parent().isBoolean()))&&(newData.parent().val()==null||true&&newData.parent().child('from').exists()&&newData.parent().child('to').exists()&&newData.parent().child('message').exists())&&(!newData.parent().exists()||!(newData.parent().isString()||newData.parent().isNumber()||newData.parent().isBoolean()))&&(newData.parent().val()==null||true&&newData.parent().child('from').exists()&&newData.parent().child('to').exists()&&newData.parent().child('message').exists())&&(newData.exists()&&!data.exists()||data.exists()&&!newData.exists())&&(!newData.exists()||newData.isString())&&(!newData.exists()||newData.isString())&&(false||true||false)", | ||
".read":"false||false||$userid===auth.username" | ||
}, | ||
"$other":{".validate":"false"} | ||
} | ||
} | ||
} | ||
".write":"true&&true&&(!newData.child('extra').parent().exists()||!(newData.child('extra').parent().isString()||newData.child('extra').parent().isNumber()||newData.child('extra').parent().isBoolean()))&&(newData.child('extra').parent().val()==null||true)&&true&&(!newData.child('extra').exists()||newData.child('extra').isString())&&false&&(false||true)", | ||
".read":"false||true", | ||
"extra": { | ||
".write":"true&&(!newData.parent().exists()||!(newData.parent().isString()||newData.parent().isNumber()||newData.parent().isBoolean()))&&(newData.parent().val()==null||true)&&true&&(!newData.exists()||newData.isString())&&(false||true)", | ||
".read":"false||true" | ||
}, | ||
"$other":{".validate":"false"} | ||
"$chld": { | ||
".write":"true&&(!newData.parent().exists()||!(newData.parent().isString()||newData.parent().isNumber()||newData.parent().isBoolean()))&&(newData.parent().val()==null||true)&&newData.val().contains('Y')&&(!newData.exists()||newData.isString())&&(false||true)", | ||
".read":"false||true" | ||
} | ||
} | ||
} |
@@ -39,3 +39,3 @@ // greatjson.js | ||
case 'true': | ||
return new Json.JBoolean(true, start_pos, parser.getPosition()); | ||
return new Json.JBoolean(true, start_pos, parser.getPosition());new Json.JBoolean(true, start_pos, parser.getPosition()); | ||
case 'false': | ||
@@ -42,0 +42,0 @@ return new Json.JBoolean(false, start_pos, parser.getPosition()); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
155
762963
12885
347