diff --git a/SPECIFICATIONS.md b/SPECIFICATIONS.md index 857fec4..909f790 100644 --- a/SPECIFICATIONS.md +++ b/SPECIFICATIONS.md @@ -75,7 +75,10 @@ _predicates_ over the following types: - _byte array_ - _date_ - _boolean_ +- _null_ - _set_ a deduplicated list of values of any type, except _variable_ or _set_ +- _array_ an array of values of any type, expect _variable_ (nested arrays are allowed) +- _map_ a map of key/value pairs. keys must be either strings or integers, values can be of any type, except _variable_ (nested maps are allowed) While a Biscuit token does not use a textual representation for storage, we use one for parsing and pretty printing of Datalog elements. @@ -117,7 +120,10 @@ We will represent the various types as follows: - byte array: `hex:01A2` - date in RFC 3339 format: `1985-04-12T23:20:50.52Z` - boolean: `true` or `false` -- set: `[ "a", "b", "c"]` +- null: `null`, supported since v3.3 +- set: `{ "a", "b", "c"}` +- array: `[ "a", true, null]`, supported since v3.3 +- map: `{ "a": true, 12: "a" }`, supported since v3.3 As an example, assuming we have the following facts: `parent("a", "b")`, `parent("b", "c")`, `parent("c", "d")`. If we apply the rule @@ -136,27 +142,33 @@ rules application does not generate any new facts, we can stop. #### Data types An _integer_ is a signed 64 bits integer. It supports the following operations: -lower than, greater than, lower than or equal, greater than or equal, equal, -not equal, set inclusion, addition, subtraction, mutiplication, division, -bitwise and, bitwise or, bitwise xor. +lower than, greater than, lower than or equal, greater than or equal, strict equal, +strict not equal, set inclusion, addition, subtraction, mutiplication, division, +bitwise and, bitwise or, bitwise xor, lenient equal, lenient not equal, typeof. A _string_ is a suite of UTF-8 characters. It supports the following -operations: prefix, suffix, equal, not equal, set inclusion, regular -expression, concatenation (with `+`), substring test (with `.contains()`). +operations: prefix, suffix, strict equal, strict not equal, set inclusion, regular +expression, concatenation (with `+`), substring test (with `.contains()`), lenient equal, lenient not equal, typeof. A _byte array_ is a suite of bytes. It supports the following -operations: equal, not equal, set inclusion. +operations: strict equal, strict not equal, set inclusion, lenient equal, lenient not equal, typeof. A _date_ is a 64 bit unsigned integer representing a UTC unix timestamp (number of seconds since 1970-01-01T00:00:00Z). It supports -the following operations: `<`, `<=` (before), `>`, `>=` (after), equal, -not equal, set inclusion. +the following operations: `<`, `<=` (before), `>`, `>=` (after), strict equal, +strict not equal, set inclusion, lenient equal, lenient not equal, typeof. A _boolean_ is `true` or `false`. It supports the following operations: -`==`, `!=`, `||`, `&&`, set inclusion. +`===` (strict equal), `!==` (strict not equal), eager or, eager and, set inclusion, `==` (lenient equal), `!=` (lenient not equal), typeof, short-circuiting or, short-circuiting and. + +A _null_ is a default type indicating the absence of value. It supports `===` (strict equal), `!==` (strict not equal), `==` (lenient equal) and `!=` (lenient not equal), typeof. `null` is always equal to itself. A _set_ is a deduplicated list of terms of the same type. It cannot contain -variables or other sets. It supports equal, not equal, , intersection, union, -set inclusion. +variables or other sets. It supports strict equal, strict not equal, intersection, union, +set inclusion, lenient equal, lenient not equal, any, all, typeof. + +An _array_ is an ordered list of terms, not necessarily of the same type. It supports `===` (strict equal), `!==` (strict not equal), `==` (lenient equal) and `!=` (lenient not equal), contains, prefix, suffix, get, typeof. + +A _map_ is an unordered collection of key/value pairs, with unique keys. Keys are either strings or integers, values can be any term. It supports `===` (strict equal), `!==` (strict not equal), `==` (lenient equal) and `!=` (lenient not equal), contains, get, typeof. #### Grammar @@ -165,7 +177,7 @@ The logic language is described by the following EBNF grammar: ``` ::= ? "trusting " ? ("," ? ?)* ::= "authority" | "previous" | "/" - ::= "ed25519" + ::= "ed25519" | "secp256r1" ::= ( ";" ?)? ( | )* ::= ? ( | | ) ? ";" ? @@ -184,24 +196,28 @@ The logic language is described by the following EBNF grammar: ::= "(" ? (? "," ? )* ? ")" ::= | - ::= | | | ("hex:" ) | | - ::= | | | | + ::= | | | ("hex:" ) | | | + ::= | | | | | ::= "-"? [0-9]+ ::= ([a-z] | [0-9])+ ::= "true" | "false" + ::= "null" ::= [0-9]* "-" [0-9] [0-9] "-" [0-9] [0-9] "T" [0-9] [0-9] ":" [0-9] [0-9] ":" [0-9] [0-9] ( "Z" | ( ("+" | "-") [0-9] [0-9] ":" [0-9] [0-9] )) - ::= "[" ? ( ( ? "," ? )* ? )? "]" + ::= "{" ? ( ( ? "," ? )* ? )? "}" + ::= "[" ? ( ( ? "," ? )* ? )? "]" + ::= ( | ) ? ":" ? + ::= "{" ? ( ( ? "," ? )* ? )? "}" ::= (? ? )* ::= | ( ? ) ::= "!" ? ::= "." "(" ? ( ( ? "," ? )* )? ? ")" - ::= ([a-z] | [A-Z] ) ([a-z] | [A-Z] | [0-9] | "_" )* + ::= (extern::)?([a-z] | [A-Z] ) ([a-z] | [A-Z] | [0-9] | "_" )* ::= | ("(" ? ? ")") - ::= "<" | ">" | "<=" | ">=" | "==" | "!=" | "&&" | "||" | "+" | "-" | "*" | "/" | "&" | "|" | "^" + ::= "<" | ">" | "<=" | ">=" | "===" | "!==" | "&&" | "||" | "+" | "-" | "*" | "/" | "&" | "|" | "^" | "==" | "!==" ::= (" " | "\t" | "\n")+ ``` @@ -291,23 +307,27 @@ To validate an operation, all of a token's checks must succeed. One block can contain one or more checks. -Their text representation is `check if` or `check all` followed by the body of the query. +Their text representation is `check if`, `check all` or `reject if` followed by the body of the query. There can be multiple queries inside of a check, it will succeed if any of them -succeeds. They are separated by a `or` token. +succeeds (in the case of `reject if`, the check will fail if any query matches). They are separated by a `or` token. - a `check if` query succeeds if it finds one set of facts that matches the body and expressions - a `check all` query succeeds if all the sets of facts that match the body also succeed the expression. -`check all` can only be used starting from block version 4 +- a `reject if` query succeeds if no set of facts matches the body and expressions + +`check all` can only be used starting from `v3.1`. +`reject if` can only be used starting from `v3.3`. Here are some examples of writing checks: #### Basic token This first token defines a list of authority facts giving `read` and `write` -rights on `file1`, `read` on `file2`. The first caveat checks that the operation +rights on `file1`, `read` on `file2`. The first check ensures that the operation is `read` (and will not allow any other `operation` fact), and then that we have -the `read` right over the resource. -The second caveat checks that the resource is `file1`. +the `read` right over the resource. +The second check ensures that the resource is either `file1` or `file2`. +The third check ensures that the resource is not `file1`. ``` authority: @@ -323,20 +343,24 @@ check if ---------- Block 2: check if - resource("file1") // restrict to file1 resource + resource("file1") + or resource("file2") // restrict to file1 or file2 +---------- +Block 3: +reject if + resource("file1") // forbid using the token on file1 ``` The verifier side provides the `resource` and `operation` facts with information from the request. -If the verifier provided the facts `resource("file2")` and +If the verifier provided the facts `resource("file1")` and `operation("read")`, the rule application of the first check would see -`resource("file2"), operation("read"), right("file2", "read")` -with `X = "file2"`, so it would succeed, but the second check would fail -because it expects `resource("file1")`. +`resource("file1"), operation("read"), right("file1", "read")` +with `X = "file1"`, so it would succeed, the second check would also succeed because it expects `resource("file1")` or `resource("file2")`. The third check would then fail because it would match on `resource("file1")`. -If the verifier provided the facts `resource("file1")` and -`operation("read")`, both checks would succeed. +If the verifier provided the facts `resource("file2")` and +`operation("read")`, all checks would succeed. #### Broad authority rules @@ -416,7 +440,7 @@ rule. #### Execution Expressions are internally represented as a series of opcodes for a stack based -virtual machine. There are three kinds of opcodes: +virtual machine. There are four kinds of opcodes: - _value_: a raw value of any type. If it is a variable, the variable must also appear in a predicate, so the variable gets a real value for execution. When @@ -425,15 +449,37 @@ virtual machine. There are three kinds of opcodes: it pops a value from the stack, applies the operation, then pushes the result - _binary operation_: an operation that applies on two arguments. When executed, it pops two values from the stack, applies the operation, then pushes the result +- _closure_: a function definition containing the name of parameters and the body of the function expressed as a list of opcodes. Closures can be nested. After executing, the stack must contain only one value, of the boolean type. +##### Closures + +Closures are evaluated recursively. When executing a closure, a new empty stack is created, and the closure opcodes are evaluated. After evaluation, the stack must contain only one value, of any type, which is then pushed on the parent stack. + +The closure arguments are treated the same way as datalog variables and are replaced by their value when the corresponding opcode is evaluated. + +Shadowing (defining a parameter with the same name as a variable already in scope) is not allowed and should be rejected before starting the evaluation. + +Short-circuiting boolean operators (`&&` and `||`) are implemented using closures: the right-hand side is defined in a closure (taking zero arguments) and is only evaluated as needed. + +##### Operations + Here are the currently defined unary operations: - _negate_: boolean negation - _parens_: returns its argument without modification (this is used when printing the expression, to avoid precedence errors) - _length_: defined on strings, byte arrays and sets (for strings, _length_ is defined as the number of bytes in the UTF-8 encoded string; the alternative of counting grapheme clusters would be inconsistent between languages) +- _type_, defined on all types, returns a string (v3.3+) + - `integer` + - `string` + - `date` + - `bytes` + - `bool` + - `set` + - `null` +- *external* call: implementation-defined, allows the datalog engine to call out to a function provided by the host language. The external call name is an interned string, stored in the symbol table (v3.3+) Here are the currently defined binary operations: @@ -441,8 +487,8 @@ Here are the currently defined binary operations: - _greater than_, defined on integers and dates, returns a boolean - _less or equal_, defined on integers and dates, returns a boolean - _greater or equal_, defined on integers and dates, returns a boolean -- _equal_, defined on integers, strings, byte arrays, dates, set, returns a boolean -- _not equal_, defined on integers, strings, byte arrays, dates, set, returns a boolean (v4 only) +- _strict equal_, defined on integers, strings, byte arrays, dates, set, null, returns a boolean +- _strict not equal_, defined on integers, strings, byte arrays, dates, set, null, returns a boolean (v3.1+) - _contains_ takes a set and another value as argument, returns a boolean. Between two sets, indicates if the first set is a superset of the second one. between two strings, indicates a substring test. - _prefix_, defined on strings, returns a boolean @@ -452,27 +498,44 @@ Here are the currently defined binary operations: - _sub_, defined on integers, returns an integer - _mul_, defined on integers, returns an integer - _div_, defined on integers, returns an integer -- _and_, defined on booleans, returns a boolean -- _or_, defined on booleans, returns a boolean +- _eager and_, defined on booleans, returns a boolean +- _eager or_, defined on booleans, returns a boolean - _intersection_, defined on sets, return a set that is the intersection of both arguments - _union_, defined on sets, return a set that is the union of both arguments -- _bitwiseAnd_, defined on integers, returns an integer (v4 only) -- _bitwiseOr_, defined on integers, returns an integer (v4 only) -- _bitwiseXor_, defined on integers, returns an integer (v4 only) +- _bitwiseAnd_, defined on integers, returns an integer (v3.1+) +- _bitwiseOr_, defined on integers, returns an integer (v3.1+) +- _bitwiseXor_, defined on integers, returns an integer (v3.1+) +- _lenient equal_, defined on all types, returns a boolean (v3.3+) +- _lenient not equal_, defined on all types, returns a boolean (v3.3+) +- _any_, defined on sets, takes a closure term -> boolean, returns a boolean (v3.3+) +- _all_, defined on sets, takes a closure term -> boolean, returns a boolean (v3.3+) +- _short circuiting and_, defined on booleans, takes a closure () -> boolean, returns a boolean (v3.3+) +- _short circuiting or_, defined on booleans, takes a closure () -> boolean, returns a boolean (v3.3+) +- _get_, defined on arrays and maps (v3.3+) + on arrays, takes an integer and returns the corresponding element (or `null`, if out of bounds) + on maps, takes either an integer or a string and returns the corresponding element (or `null`, if out of bounds) +- *external* call: implementation-defined, allows the datalog engine to call out to a function provided by the host language. The external call name is an interned string, stored in the symbol table (v3.3+) Integer operations must have overflow checks. If it overflows, the expression fails. +Strict equality fails with a type error when trying to compare different types. + +Lenient equality returns false when trying to compare different types. + +External calls are implementation defined. External calls carry a function name, which can be used to call a user-defined function provided to the biscuit library. The function name is an interned string, stored in the symbol table. + #### Example -The expression `1 + 2 < 4` will translate to the following opcodes: 1, 2, +, 4, < +The expression `$a + 2 < 4` will translate to the following opcodes: $a, 2, +, 4, < -Here is how it would be executed: +Here is how it would be executed, given $a is bound to the value 1: ``` +Context: a ~> 1 Op | stack | [ ] -1 | [ 1 ] +$a | [ 1 ] 2 | [ 2, 1 ] + | [ 3 ] 4 | [ 4, 3 ] @@ -481,6 +544,48 @@ Op | stack The stack contains only one value, and it is `true`: the expression succeeds. +##### Closures + +The expression `[1,2].any($x -> $x == $a)` will translate to the following opcodes: [1,2], x->[$x, $a, ==], any. + +Here is how it would be executed, given $a is bound to the value 2: + +``` +Context: a ~> 2 +Op | stack + | [ ] +[1,2] | [ [1,2] ] +x->[$x,$a,==] | [ x->[$x,$a,==],[1,2] ] +any | … starting recursive evaluation … + + +Beginning new evaluation +Context: a ~> 2, x ~> 1 +Op | stack + | [] +$x | [ 1 ] +$a | [ 2, 1 ] +== | [ false ] + +The stack contains one value, false. So the evaluation must continue with the next set element. + +Beggining new evaluation +Context: a ~> 2, x ~> 2 +Op | stack + | [] +$x | [ 2 ] +$a | [ 2, 2 ] +== | [ true ] + +The stack contains one value, true. The evaluation can stop here, the evaluation of any can return true. + +Resuming parent stack +Context: a ~> 2 +Op | stack +any | true +``` +The stack contains only one value, and it is `true`: the expression succeeds. + ### Datalog fact generation Datalog fact generation works by repeatedly extending a Datalog _world_ until no new facts are generated. @@ -594,6 +699,7 @@ message SignedBlock { required PublicKey nextKey = 2; required bytes signature = 3; optional ExternalSignature externalSignature = 4; + optional uint32 version = 5; } message ExternalSignature { @@ -606,6 +712,7 @@ message PublicKey { enum Algorithm { Ed25519 = 0; + SECP256R1 = 1; } required bytes key = 2; @@ -624,7 +731,8 @@ for signature verification. Each block contains a serialized byte array of the Datalog data (`block`), the next public key (`nextKey`) and the signature of that block and key -by the previous key. +by the previous key. The `version` field indicates the version of the signature +payload format. The `proof` field contains either the private key corresponding to the public key in the last block (attenuable tokens) or a signature of the last @@ -646,7 +754,7 @@ message Block { } ``` -Each block contains a `version` field, indicating at which format version it +Each block contains a `version` field, indicating at which datalog version it was generated. Since a Biscuit implementation at version N can receive a valid token generated at version N-1, new implementations must be able to recognize older formats. Moreover, when appending a new block, they cannot convert the @@ -658,12 +766,19 @@ each block must carry its own version. - An implementation may generate blocks with older formats to help with backwards compatibility, when possible, especially for biscuit versions that are only additive in terms of features. -- The lowest supported biscuit version is `3`; -- The highest supported biscuit version is `4`; +The format version is encoded as a single integer: -# Version 2 +- `v3.0` is encoded as `3` +- `v3.1` is encoded as `4` +- `v3.2` is encoded as `5` +- `v3.3` is encoded as `6` -This is the format for the 2.0 version of Biscuit. +- The lowest supported datalog version is `v3.0`; +- The highest supported datalog version is `v3.3`; + +# Format + +This is the format for the 3.x version of Biscuit. It transport expressions as an array of opcodes. @@ -675,20 +790,139 @@ is a Biscuit token, that base 64 string should be prefixed with `biscuit:`. ### Cryptography -Biscuit tokens are based on public key cryptography, with a chain of Ed25519 +Biscuit tokens are based on public key cryptography, with a chain of signatures. Each block contains the serialized Datalog, the next public key, and the signature by the previous key. The token also contains the private key corresponding to the last public key, to sign a new block and attenuate the token, or a signature of the last block by the last private key, to seal the token. +#### Algorithms + +Biscuit supports multiple signature algorithms for its blocks, that can change +between blocks in one token. The algorithm kind is defined in the `Algorithm` +enum of the protobuf serialization of the public key. The `nextSecret` field +in the proof section of the token uses the same algorithm as the `nextKey` +of the last block. + +The following algorithms are supported: + +##### Ed25519 + +The default signature algorithm is Ed25519 as introduced in [Bernstein, Daniel J.; +Duif, Niels; Lange, Tanja; Schwabe, Peter; Bo-Yin Yang (2012). "High-speed +high-security signatures" (PDF). Journal of Cryptographic Engineering](https://ed25519.cr.yp.to/ed25519-20110926.pdf) +and specified in [RFC 8032](https://www.rfc-editor.org/rfc/rfc8032). + +The protobuf encoding is defined as follows: +- `key` field of the `Publickey` message: [compressed Edwards Y format](https://www.rfc-editor.org/rfc/rfc8032#section-5.1.2) +- `nextSecret` in the `Proof` message: [32 bytes of cryptographically secure random data in little-endian](https://www.rfc-editor.org/rfc/rfc8032#section-5.1.5) +- `signature` field in `Signature` and `ExternalSignature` messages: [concatenation of R and S values](https://www.rfc-editor.org/rfc/rfc8032#section-5.1.6) + +##### ECDSA + +Biscuit supports the ECDSA algorithm over the secp256r1 curve as defined in +[SEC2v1](https://www.secg.org/sec1-v2.pdf), using the SHA-256 hashing +algorithm. It is recommended to use a deterministic signature algorithm +version like the one defined in [RFC 6979](https://datatracker.ietf.org/doc/html/rfc6979). + + +The protobuf encoding is defined as follows: +- `key` field of the `Publickey` message: [compressed SEC1 format, defined in section 2.3.3](https://www.secg.org/sec1-v2.pdf). Allowed prefixes: `02`, `03` +- `nextSecret` in the `Proof` message: big endian representation of the secret scalar +- `signature` field in `Signature` and `ExternalSignature` messages: [SEC1 ASN.1 format, defined in section C5](https://www.secg.org/sec1-v2.pdf), only using the `r` and `s` parameters + +``` +ECDSA-Sig-Value ::= SEQUENCE { + r INTEGER, + s INTEGER +} +``` + +#### Signed payload generation + +The data covered by the signature algorithm depends on the `version` field of +the `SignedBlock` message. If the field is absent, it defaults to version 0. + +Signature version 1 *must* be used for third-party blocks. + +##### Version 0 (deprecated) + +This defines the block signature payload v0. + +The authority block signature payload v0 is the concatenation of: +- `data_0`: the serialized Datalog +- `pk_1`: the next public key +- `alg_1`: the little endian representation of the signature algorithm for `pk_1` + +To sign the block at index `n+1`, the signed payload format is the concatenation of: +- `data_n+1`: the serialized Datalog +- `pk_n+2`: the next public key +- `alg_n+2`: the little endian representation of the signature algorithm for `pk_n+2` + +if `external_sig_n+1` is present, the signed payload format is instead the concatenation of: +- `data_n+1`: the serialized Datalog +- `external_sig_n+1`: the optional external signature of the block +- `pk_n+2`: the next public key +- `alg_n+2`: the little endian representation of the signature algorithm for `pk_n+2` + +This format is deprecated and will be gradually replaced by version 1. + +The signed payload format for external signatures, thereafter referred as "external signature payload v0", is the concatenation of: +- `data_n+1`: the serialized Datalog +- `pk_n+1`: the public key for the next block +- `alg_n+1`: the little endian representation of the signature algorithm for `pk_n+1` + +This format is not supported anymore and should be replaced by version 1. + +##### Version 1 + +This defines the block signature payload v1. + +The authority block signature payload v1 is the concatenation of: +- the binary representation of the ASCII string "\0BLOCK\0" +- the binary representation of the ASCII string "\0VERSION\0" +- the little endian representation of the version of the signature payload format +- the binary representation of the ASCII string "\0PAYLOAD\0" +- `data_0`: the serialized Datalog +- the binary representation of the ASCII string "\0ALGORITHM\0" +- `alg_1`: the little endian representation of the signature algorithm for `pk_1` +- the binary representation of the ASCII string "\0NEXTKEY\0" +- `pk_1`: the next public key + +To sign the block at index `n+1`, the signed payload format is the concatenation of: +- the binary representation of the ASCII string "\0BLOCK\0" +- the binary representation of the ASCII string "\0VERSION\0" +- the little endian representation of the version of the signature payload format +- the binary representation of the ASCII string "\0PAYLOAD\0" +- `data_n+1`: the serialized Datalog +- the binary representation of the ASCII string "\0ALGORITHM\0" +- `alg_n+2`: the little endian representation of the signature algorithm for `pk_n+2` +- the binary representation of the ASCII string "\0NEXTKEY\0" +- `pk_n+2`: the next public key +- the binary representation of the ASCII string "\0PREVSIG\0" +- `sig_n`: the signature of the previous block +- if `external_sig_n+1` is present: + - the binary representation of the ASCII string "\0EXTERNALSIG\0" + - `external_sig_n+1`: the optional external signature of the block + +the signed payload format for external signatures, thereafter referred as "external signature payload v1", is the concatenation of: +- the binary representation of the ASCII string "\0EXTERNAL\0" +- the binary representation of the ASCII string "\0VERSION\0" +- the little endian representation of the version of the signature payload format +- the binary representation of the ASCII string "\0PAYLOAD\0" +- `data_n+1`: the serialized Datalog +- the binary representation of the ASCII string "\0PREVSIG\0" +- `sig_n`: the signature of the previous block + #### Signature (one block) -- `(pk_0, sk_0)` the root public and private Ed25519 keys +- `(pk_0, sk_0)` the root public and private keys - `data_0` the serialized Datalog - `(pk_1, sk_1)` the next key pair, generated at random - `alg_1` the little endian representation of the signature algorithm fr `pk1, sk1` (see protobuf schema) -- `sig_0 = sign(sk_0, data_0 + alg_1 + pk_1)` +- the signed block version indicates the version of the signature payload format, either "block signature payload v0" or "block signature payload v1" +- `sig_0` is the signature of the payload by `sk_0` The token will contain: @@ -721,7 +955,9 @@ The token also contains `sk_n+1`. The new block can optionally be signed by an external keypair `(epk, esk)` and carry an external signature `esig`. -We generate at random `(pk_n+2, sk_n+2)` and the signature `sig_n+1 = sign(sk_n+1, data_n+1 + esig? + alg_n+2 + pk_n+2)`. If the block is not signed by an external keypair, then `esig` is not part of the signed payload. +the signed block version indicates the version of the signature payload format, either "block signature payload v0" or "block signature payload v1". + +We generate at random `(pk_n+2, sk_n+2)` and the signature `sig_n+1` is the signature of the payload by `sk_n+1`. The token will contain: @@ -745,14 +981,10 @@ Token { ##### Optional external signature Blocks generated by a trusted third party can carry an *extra* signature to provide a proof of their -origin. Same as regular signatures, they rely on Ed25519. - -The external signature for block `n+1`, with `(external_pk, external_sk)` is `external_sig_n+1 = sign(external_sk, data_n+1 + alg_n+1 + pk_n+1)`. -It's quite similar to the regular signature, with a crucial difference: the public key appended to the block payload is the one _carried_ by block `n` (and which is used to verify block `n+1`). -This means that the authority block can't carry an external signature (that would be useless, since -the root key is not ephemeral and can be trusted directly). +origin. Same as regular signatures, they rely on public key cryptography. -This is necessary to make sure an external signature can't be used for any other token. +The external signature for block `n+1`, with `(external_pk, external_sk)` is `external_sig_n+1`, the signature of the payload in format "external signature payload v1" by `external_sk`. +The authority block can't carry an external signature. This is necessary to make sure an external signature can't be used for any other token. The presence of an external signature affects the regular signature: the external signature is part of the payload signed by the regular signature. @@ -776,12 +1008,11 @@ Token { } ``` - #### Verifying For each block i from 0 to n: - -- verify(pk_i, sig_i, data_i + alg_i+1 + pk_i+1) +- `payload_i`: the signature payload for block i +- `verify(pk_i, sig_i, payload_i)` If all signatures are verified, extract pk_n+1 from the last block and sk_n+1 from the proof field, and check that they are from the same @@ -790,8 +1021,8 @@ key pair. ##### Verifying external signatures For each block i from 1 to n, _where an external signature is present_: - -- verify(external_pk_i, external_sig_i, data_i + alg_i + pk_i) +- `external_payload_i`: the external signature payload for block i +- `verify(external_pk_i, external_sig_i, external_payload_i)` #### Signature (sealing) @@ -911,7 +1142,7 @@ block in order, the block's symbols. It is important to verify that different blocks do not contain the same symbol in their list. -##### 3rd party blocks (with an external signature) +##### third party blocks (with an external signature) Blocks that are signed by an external key don't use the token symbol table and start from the default symbol table. Following blocks ignore the symbols @@ -926,7 +1157,7 @@ Public keys carried in `SignedBlock`s are stored as is, as they are required for Public keys carried in datalog scope annotations are stored in a table, to reduce token size. -Public keys are interned the same way for first-party and third-party tokens, unlike symbols. +Third-party blocks use an isolated public keys table, same as for symbols. #### Reading @@ -949,14 +1180,15 @@ that were not present in the table yet. Third party blocks are special blocks, that are meant to be signed by a trusted party, to either expand a token or fulfill special checks with dedicated public key constraints. -Unlike first-party blocks, the party signing the token should not have access to the token itself. The third party needs however some context in order to be able to properly serialize and sign block contents. Additionally, the third party needs to return both the serialized block and the external signature. +Unlike first-party blocks, the party signing the token should not have access to the token itself. The third party needs however some context in order to be able to properly sign block contents. Additionally, the third party needs to return both the serialized block and the external signature. To support this use-case, the protobuf schema defines two message types: `ThirdPartyBlockRequest` and `ThirdPartyBlockContents`: ``` message ThirdPartyBlockRequest { - required PublicKey previousKey = 1; - repeated PublicKey publicKeys = 2; + optional PublicKey legacyPreviousKey = 1; + repeated PublicKey legacyPublicKeys = 2; + required bytes previousSignature = 3; } message ThirdPartyBlockContents { @@ -967,8 +1199,9 @@ message ThirdPartyBlockContents { `ThirdPartyBlockRequest` contains the necessary context for serializing and signing a datalog block: -- `previousKey` is needed for the signature (it makes sure that a third-party block can only be used for a specific biscuit token -- `publicKeys` is the list of public keys already present in the token table; they are used for serialization +- `legacyPreviousKey` was needed for the signature. It is not needed anymore with `v1` signatures and must be empty. +- `legacyPublicKeys` was needed for serialization but is not used anymore, it must be empty. +- `previousSignature` is needed for the signature (to make sure that a third-party block can only be used for a specific biscuit token) `ThirdPartyBlockContents` contains both the serialized `Block` and the external signature. @@ -988,6 +1221,10 @@ An implementation must be able to: Same as biscuit tokens, the `ThirdPartyBlockRequest` and `ThirdPartyBlockContents` values can be transfered in text format by encoding them with base64url. +### Third-party block datalog version + +Third-party blocks must at least have datalog version `3.2` (implementations not supporting at least version `3.2` have different symbol tables mechanisms and may interpret third-party blocks incorrectly). + ## Test cases We provide sample tokens and the expected result of their verification at diff --git a/samples/current/README.md b/samples/current/README.md index e123c7c..78838b6 100644 --- a/samples/current/README.md +++ b/samples/current/README.md @@ -45,7 +45,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -53,7 +53,7 @@ World { "resource(\"file1\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -68,7 +68,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -141,7 +141,7 @@ check if resource($0), operation("read"), right($0, "read"); ### validation -result: `Err(Format(InvalidSignatureSize(16)))` +result: `Err(Format(BlockSignatureDeserializationError("block signature deserialization error: [117, 149, 161, 18, 161, 235, 91, 129, 166, 227, 152, 133, 46, 97, 24, 183]")))` ------------------------------ @@ -296,7 +296,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -305,7 +305,7 @@ World { "resource(\"file2\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -316,7 +316,7 @@ World { "user_id(\"alice\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 2, @@ -328,7 +328,7 @@ World { }, ] rules: [ - AuthorizerRuleSet { + Rules { origin: Some( 1, ), @@ -338,7 +338,7 @@ World { }, ] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -407,7 +407,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -416,7 +416,7 @@ World { "resource(\"file2\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -426,7 +426,7 @@ World { "right(\"file1\", \"read\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 2, @@ -439,7 +439,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -499,7 +499,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -512,7 +512,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -574,7 +574,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -583,7 +583,7 @@ World { "resource(\"file2\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -593,7 +593,7 @@ World { "right(\"file1\", \"read\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -606,7 +606,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -657,7 +657,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -666,7 +666,7 @@ World { "resource(\"file2\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -679,7 +679,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -728,7 +728,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -740,7 +740,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -773,7 +773,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -785,7 +785,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -825,7 +825,7 @@ public keys: [] ``` valid_date("file1") <- time($0), resource("file1"), $0 <= 2030-12-31T12:59:59Z; -valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, !["file1"].contains($1); +valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, !{"file1"}.contains($1); check if valid_date($0), resource($0); ``` @@ -847,7 +847,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -856,7 +856,7 @@ World { "time(2020-12-21T09:23:12Z)", ], }, - AuthorizerFactSet { + Facts { origin: { None, Some( @@ -867,7 +867,7 @@ World { "valid_date(\"file1\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -880,18 +880,18 @@ World { }, ] rules: [ - AuthorizerRuleSet { + Rules { origin: Some( 1, ), rules: [ "valid_date(\"file1\") <- time($0), resource(\"file1\"), $0 <= 2030-12-31T12:59:59Z", - "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, ![\"file1\"].contains($1)", + "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, !{\"file1\"}.contains($1)", ], }, ] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -925,7 +925,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -934,7 +934,7 @@ World { "time(2020-12-21T09:23:12Z)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -947,18 +947,18 @@ World { }, ] rules: [ - AuthorizerRuleSet { + Rules { origin: Some( 1, ), rules: [ "valid_date(\"file1\") <- time($0), resource(\"file1\"), $0 <= 2030-12-31T12:59:59Z", - "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, ![\"file1\"].contains($1)", + "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, !{\"file1\"}.contains($1)", ], }, ] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -1006,7 +1006,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1017,7 +1017,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1049,7 +1049,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1060,7 +1060,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1108,7 +1108,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1121,7 +1121,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -1177,7 +1177,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -1190,7 +1190,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1214,50 +1214,49 @@ result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedB ### token authority: -symbols: ["hello world", "hello", "world", "aaabde", "a*c?.e", "abd", "aaa", "b", "de", "abcD12", "abc", "def"] +symbols: ["hello world", "hello", "world", "aaabde", "a*c?.e", "abd", "aaa", "b", "de", "abcD12", "é", "abc", "def"] public keys: [] ``` check if true; check if !false; -check if !false && true; -check if false || true; -check if (true || false) && true; -check if true == true; -check if false == false; +check if true === true; +check if false === false; check if 1 < 2; check if 2 > 1; check if 1 <= 2; check if 1 <= 1; check if 2 >= 1; check if 2 >= 2; -check if 3 == 3; -check if 1 + 2 * 3 - 4 / 2 == 5; -check if "hello world".starts_with("hello") && "hello world".ends_with("world"); +check if 3 === 3; +check if 1 + 2 * 3 - 4 / 2 === 5; +check if "hello world".starts_with("hello"), "hello world".ends_with("world"); check if "aaabde".matches("a*c?.e"); check if "aaabde".contains("abd"); -check if "aaabde" == "aaa" + "b" + "de"; -check if "abcD12" == "abcD12"; +check if "aaabde" === "aaa" + "b" + "de"; +check if "abcD12" === "abcD12"; +check if "abcD12".length() === 6; +check if "é".length() === 2; check if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z; check if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z; check if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z; check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z; check if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z; check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z; -check if 2020-12-04T09:46:41Z == 2020-12-04T09:46:41Z; -check if hex:12ab == hex:12ab; -check if [1, 2].contains(2); -check if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z); -check if [false, true].contains(true); -check if ["abc", "def"].contains("abc"); -check if [hex:12ab, hex:34de].contains(hex:34de); -check if [1, 2].contains([2]); -check if [1, 2] == [1, 2]; -check if [1, 2].intersection([2, 3]) == [2]; -check if [1, 2].union([2, 3]) == [1, 2, 3]; -check if [1, 2, 3].intersection([1, 2]).contains(1); -check if [1, 2, 3].intersection([1, 2]).length() == 2; +check if 2020-12-04T09:46:41Z === 2020-12-04T09:46:41Z; +check if hex:12ab === hex:12ab; +check if {1, 2}.contains(2); +check if {2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z}.contains(2020-12-04T09:46:41Z); +check if {false, true}.contains(true); +check if {"abc", "def"}.contains("abc"); +check if {hex:12ab, hex:34de}.contains(hex:34de); +check if {1, 2}.contains({2}); +check if {1, 2} === {1, 2}; +check if {1, 2}.intersection({2, 3}) === {2}; +check if {1, 2}.union({2, 3}) === {1, 2, 3}; +check if {1, 2, 3}.intersection({1, 2}).contains(1); +check if {1, 2, 3}.intersection({1, 2}).length() === 2; ``` ### validation @@ -1268,7 +1267,7 @@ allow if true; ``` revocation ids: -- `f61b4cb4fc58777fec6c8d39fe62259dc3c78511868236c391e9f67ffd03a3a8b8e3042d4bacce0d5756d053f5afccd4c5e4df0597af44b36bdfab492e5fe50e` +- `d0420227266e3583a42dfaa0e38550d99f681d150dd18856f3af9a697bc9c5c8bf06b4b0fe5b9df0377d1b963574e2fd210a0a76a8b0756a65f640c602bebd07` authorizer world: ``` @@ -1276,20 +1275,20 @@ World { facts: [] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), checks: [ "check if !false", - "check if !false && true", - "check if \"aaabde\" == \"aaa\" + \"b\" + \"de\"", + "check if \"aaabde\" === \"aaa\" + \"b\" + \"de\"", "check if \"aaabde\".contains(\"abd\")", "check if \"aaabde\".matches(\"a*c?.e\")", - "check if \"abcD12\" == \"abcD12\"", - "check if \"hello world\".starts_with(\"hello\") && \"hello world\".ends_with(\"world\")", - "check if (true || false) && true", - "check if 1 + 2 * 3 - 4 / 2 == 5", + "check if \"abcD12\" === \"abcD12\"", + "check if \"abcD12\".length() === 6", + "check if \"hello world\".starts_with(\"hello\"), \"hello world\".ends_with(\"world\")", + "check if \"é\".length() === 2", + "check if 1 + 2 * 3 - 4 / 2 === 5", "check if 1 < 2", "check if 1 <= 1", "check if 1 <= 2", @@ -1298,28 +1297,27 @@ World { "check if 2 >= 2", "check if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z", "check if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z", - "check if 2020-12-04T09:46:41Z == 2020-12-04T09:46:41Z", + "check if 2020-12-04T09:46:41Z === 2020-12-04T09:46:41Z", "check if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z", "check if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z", "check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z", "check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z", - "check if 3 == 3", - "check if [\"abc\", \"def\"].contains(\"abc\")", - "check if [1, 2, 3].intersection([1, 2]).contains(1)", - "check if [1, 2, 3].intersection([1, 2]).length() == 2", - "check if [1, 2] == [1, 2]", - "check if [1, 2].contains(2)", - "check if [1, 2].contains([2])", - "check if [1, 2].intersection([2, 3]) == [2]", - "check if [1, 2].union([2, 3]) == [1, 2, 3]", - "check if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z)", - "check if [false, true].contains(true)", - "check if [hex:12ab, hex:34de].contains(hex:34de)", - "check if false == false", - "check if false || true", - "check if hex:12ab == hex:12ab", + "check if 3 === 3", + "check if false === false", + "check if hex:12ab === hex:12ab", "check if true", - "check if true == true", + "check if true === true", + "check if {\"abc\", \"def\"}.contains(\"abc\")", + "check if {1, 2, 3}.intersection({1, 2}).contains(1)", + "check if {1, 2, 3}.intersection({1, 2}).length() === 2", + "check if {1, 2} === {1, 2}", + "check if {1, 2}.contains(2)", + "check if {1, 2}.contains({2})", + "check if {1, 2}.intersection({2, 3}) === {2}", + "check if {1, 2}.union({2, 3}) === {1, 2, 3}", + "check if {2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z}.contains(2020-12-04T09:46:41Z)", + "check if {false, true}.contains(true)", + "check if {hex:12ab, hex:34de}.contains(hex:34de)", ], }, ] @@ -1400,7 +1398,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1408,7 +1406,7 @@ World { "operation(\"write\")", ], }, - AuthorizerFactSet { + Facts { origin: { None, Some( @@ -1421,7 +1419,7 @@ World { }, ] rules: [ - AuthorizerRuleSet { + Rules { origin: Some( 1, ), @@ -1431,7 +1429,7 @@ World { }, ] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1492,7 +1490,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1501,7 +1499,7 @@ World { "resource(\"file1\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1516,7 +1514,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -1564,7 +1562,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1577,7 +1575,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -1652,7 +1650,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1692,7 +1690,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -1759,7 +1757,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1769,7 +1767,7 @@ World { "authority_fact(1)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -1782,7 +1780,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 2, ), @@ -1837,13 +1835,13 @@ allow if true; revocation ids: - `470e4bf7aa2a01ab39c98150bd06aa15b4aa5d86509044a8809a8634cd8cf2b42269a51a774b65d10bac9369d013070b00187925196a8e680108473f11cf8f03` -- `93a7315ab1272da9eeef015f6fecbc9ac96fe4660e6204bf64ea2105ebe309e9c9cadc0a26c5604f13910fae3f2cd0800756afb6b6b208bf77adeb1ab2f42405` +- `901b2af4dacf33458d2d91ac484b60bad948e8d10faa9695b096054d5b46e832a977b60b17464cacf545ad0801f549ea454675f0ac88c413406925e2af83ff08` authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -1853,7 +1851,7 @@ World { "right(\"read\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -1866,7 +1864,7 @@ World { ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1874,7 +1872,7 @@ World { "check if group(\"admin\") trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -1903,7 +1901,7 @@ symbols: ["allowed_operations", "A", "B", "op", "allowed"] public keys: [] ``` -allowed_operations(["A", "B"]); +allowed_operations({"A", "B"}); check all operation($op), allowed_operations($allowed), $allowed.contains($op); ``` @@ -1924,7 +1922,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1933,20 +1931,20 @@ World { "operation(\"B\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, ), }, facts: [ - "allowed_operations([\"A\", \"B\"])", + "allowed_operations({\"A\", \"B\"})", ], }, ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -1979,7 +1977,7 @@ authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { None, }, @@ -1988,20 +1986,20 @@ World { "operation(\"invalid\")", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 0, ), }, facts: [ - "allowed_operations([\"A\", \"B\"])", + "allowed_operations({\"A\", \"B\"})", ], }, ] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -2037,7 +2035,7 @@ check if true trusting previous, ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755 1: symbols: [] -public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463"] +public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189"] external signature by: "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189" @@ -2051,7 +2049,7 @@ check if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5 2: symbols: [] -public keys: [] +public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189"] external signature by: "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463" @@ -2064,7 +2062,7 @@ check if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5 3: symbols: [] -public keys: [] +public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189"] external signature by: "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463" @@ -2077,7 +2075,7 @@ check if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5 4: symbols: [] -public keys: ["ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136"] +public keys: ["ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136"] ``` query(4); @@ -2099,16 +2097,16 @@ allow if true; revocation ids: - `3771cefe71beb21ead35a59c8116ee82627a5717c0295f35980662abccb159fe1b37848cb1818e548656bd4fd882d0094a2daab631c76b2b72e3a093914bfe04` -- `45133b90f228a81fe4d3042a79f6c6b7608e656e903d6b1f4db32cd774b09b8315af360879a5f210ad7be37ff55e3eb34f237bcc9711407b6329ac6018bfb400` -- `179f054f3c572646aba5013159ae192ac42f5666dbdd984129955f4652b6829e59f54aa251e451f96329d42a2524ce569c3e1ec52e708b642dd8994af51dd703` -- `edab54789d6656936fcd28200b9c61643434842d531f09f209fad555e11ff53174db174dafba126e6de448983a56f78d2042bc5782d71a45799c022fe69fb30d` -- `6a62306831e9dbe83e7b33db96b758c77dd690930f2d2d87e239b210b1944c5582bf6d7e1bfea8e7f928c27f2fff0e2ee2e0adc41e11e0c3abe8d7b96b9ede07` +- `7113d4dbb3b688b80e941f365a2c6342d480c77ed03937bccf85dc5cc3554c7517887b1b0c9021388a71e6ca9047aabaaad5ae5b511a2880902568444a98e50b` +- `d0e3fc4bbd1b7320022800af909585aa906f677c4ca79c275a10b6779f669384c464ee84a1b04f13877a25761a874748362c065f4d15a8cab5c5e16c34074403` +- `29b7e0a1f118a6185814a552660c516c43482044e280e7a8de85b8e7e54947e0ae82eb39d7b524d4b72cb9812a7a4b8871964f8f825b1c1ed85d344c05281d0d` +- `3f675d6c364e06405d4868c904e40f3d81c32b083d91586db814d4cb4bf536b4ba209d82f11b4cb6da293b60b20d6122fc3e0e08e80c381dee83edd848211900` authorizer world: ``` World { facts: [ - AuthorizerFactSet { + Facts { origin: { Some( 0, @@ -2118,7 +2116,7 @@ World { "query(0)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -2128,7 +2126,7 @@ World { "query(1)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 1, @@ -2141,7 +2139,7 @@ World { "query(1, 2)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 2, @@ -2151,7 +2149,7 @@ World { "query(2)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 3, @@ -2161,7 +2159,7 @@ World { "query(3)", ], }, - AuthorizerFactSet { + Facts { origin: { Some( 4, @@ -2173,7 +2171,7 @@ World { }, ] rules: [ - AuthorizerRuleSet { + Rules { origin: Some( 1, ), @@ -2183,7 +2181,7 @@ World { }, ] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), @@ -2191,7 +2189,7 @@ World { "check if true trusting previous, ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 1, ), @@ -2200,7 +2198,7 @@ World { "check if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 2, ), @@ -2209,7 +2207,7 @@ World { "check if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 3, ), @@ -2218,7 +2216,7 @@ World { "check if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 4, ), @@ -2227,7 +2225,7 @@ World { "check if query(4) trusting ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136", ], }, - AuthorizerCheckSet { + Checks { origin: Some( 18446744073709551615, ), @@ -2259,9 +2257,9 @@ symbols: [] public keys: [] ``` -check if true || 10000000000 * 10000000000 != 0; -check if true || 9223372036854775807 + 1 != 0; -check if true || -9223372036854775808 - 1 != 0; +check if 10000000000 * 10000000000 != 0; +check if 9223372036854775807 + 1 != 0; +check if -9223372036854775808 - 1 != 0; ``` ### validation @@ -2272,7 +2270,7 @@ allow if true; ``` revocation ids: -- `3346a22aae0abfc1ffa526f02f7650e90af909e5e519989026441e78cdc245b7fd126503cfdc8831325fc04307edc65238db319724477915f7040a2f6a719a05` +- `31f01031b8d9cc312c346674625a2218b19a126e931318dc02d8d53aec2775faecd3f848f60c1446573c37ea0664fefc768f35ba5ce4365b83ff06f0c0409b0e` authorizer world: ``` @@ -2280,14 +2278,14 @@ World { facts: [] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), checks: [ - "check if true || -9223372036854775808 - 1 != 0", - "check if true || 10000000000 * 10000000000 != 0", - "check if true || 9223372036854775807 + 1 != 0", + "check if -9223372036854775808 - 1 != 0", + "check if 10000000000 * 10000000000 != 0", + "check if 9223372036854775807 + 1 != 0", ], }, ] @@ -2311,12 +2309,12 @@ symbols: ["abcD12x", "abcD12"] public keys: [] ``` -check if 1 != 3; -check if 1 | 2 ^ 3 == 0; -check if "abcD12x" != "abcD12"; -check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z; -check if hex:12abcd != hex:12ab; -check if [1, 4] != [1, 2]; +check if 1 !== 3; +check if 1 | 2 ^ 3 === 0; +check if "abcD12x" !== "abcD12"; +check if 2022-12-04T09:46:41Z !== 2020-12-04T09:46:41Z; +check if hex:12abcd !== hex:12ab; +check if {1, 4} !== {1, 2}; ``` ### validation @@ -2335,17 +2333,934 @@ World { facts: [] rules: [] checks: [ - AuthorizerCheckSet { + Checks { origin: Some( 0, ), checks: [ - "check if \"abcD12x\" != \"abcD12\"", - "check if 1 != 3", - "check if 1 | 2 ^ 3 == 0", - "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z", - "check if [1, 4] != [1, 2]", - "check if hex:12abcd != hex:12ab", + "check if \"abcD12x\" !== \"abcD12\"", + "check if 1 !== 3", + "check if 1 | 2 ^ 3 === 0", + "check if 2022-12-04T09:46:41Z !== 2020-12-04T09:46:41Z", + "check if hex:12abcd !== hex:12ab", + "check if {1, 4} !== {1, 2}", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Ok(0)` + + +------------------------------ + +## test reject if: test029_reject_if.bc +### token + +authority: +symbols: ["test"] + +public keys: [] + +``` +reject if test($test), $test; +``` + +### validation + +authorizer code: +``` +test(false); + +allow if true; +``` + +revocation ids: +- `2e6dcafe4061dd86f61ad038a0a1bea816b85898bb86a14b16177e78ee249fcfb2455e2eed52ccfe8eafc679b1f34f9ef98e92e3719981dd4098b901b6cb040b` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "test(false)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "reject if test($test), $test", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Ok(0)` +### validation for "rejection" + +authorizer code: +``` +test(true); + +allow if true; +``` + +revocation ids: +- `2e6dcafe4061dd86f61ad038a0a1bea816b85898bb86a14b16177e78ee249fcfb2455e2eed52ccfe8eafc679b1f34f9ef98e92e3719981dd4098b901b6cb040b` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "test(true)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "reject if test($test), $test", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "reject if test($test), $test" })] }))` + + +------------------------------ + +## test null: test030_null.bc +### token + +authority: +symbols: ["fact", "value"] + +public keys: [] + +``` +check if fact(null, $value), $value == null; +reject if fact(null, $value), $value != null; +``` + +### validation + +authorizer code: +``` +fact(null, null); + +allow if true; +``` + +revocation ids: +- `c6c60ff84938908ca2bfcc7d674a400857c3349bdb373646c825e946ad0d08d76fd4734cd40f09884db0a41aee0c078897750e27706959d785750ef24acf100f` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "fact(null, null)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Ok(0)` +### validation for "rejection1" + +authorizer code: +``` +fact(null, 1); + +allow if true; +``` + +revocation ids: +- `c6c60ff84938908ca2bfcc7d674a400857c3349bdb373646c825e946ad0d08d76fd4734cd40f09884db0a41aee0c078897750e27706959d785750ef24acf100f` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "fact(null, 1)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "check if fact(null, $value), $value == null" }), Block(FailedBlockCheck { block_id: 0, check_id: 1, rule: "reject if fact(null, $value), $value != null" })] }))` +### validation for "rejection2" + +authorizer code: +``` +fact(null, true); + +allow if true; +``` + +revocation ids: +- `c6c60ff84938908ca2bfcc7d674a400857c3349bdb373646c825e946ad0d08d76fd4734cd40f09884db0a41aee0c078897750e27706959d785750ef24acf100f` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "fact(null, true)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "check if fact(null, $value), $value == null" }), Block(FailedBlockCheck { block_id: 0, check_id: 1, rule: "reject if fact(null, $value), $value != null" })] }))` +### validation for "rejection3" + +authorizer code: +``` +fact(null, "abcd"); + +allow if true; +``` + +revocation ids: +- `c6c60ff84938908ca2bfcc7d674a400857c3349bdb373646c825e946ad0d08d76fd4734cd40f09884db0a41aee0c078897750e27706959d785750ef24acf100f` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "fact(null, \"abcd\")", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Block(FailedBlockCheck { block_id: 0, check_id: 0, rule: "check if fact(null, $value), $value == null" }), Block(FailedBlockCheck { block_id: 0, check_id: 1, rule: "reject if fact(null, $value), $value != null" })] }))` + + +------------------------------ + +## test heterogeneous equal: test031_heterogeneous_equal.bc +### token + +authority: +symbols: ["abcD12", "abcD12x", "fact", "value", "fact2"] + +public keys: [] + +``` +check if true == true; +check if false == false; +check if false != true; +check if 1 != true; +check if 1 == 1; +check if 1 != 3; +check if 1 != true; +check if "abcD12" == "abcD12"; +check if "abcD12x" != "abcD12"; +check if "abcD12x" != true; +check if 2022-12-04T09:46:41Z == 2022-12-04T09:46:41Z; +check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z; +check if 2022-12-04T09:46:41Z != true; +check if hex:12abcd == hex:12abcd; +check if hex:12abcd != hex:12ab; +check if hex:12abcd != true; +check if {1, 2} == {1, 2}; +check if {1, 4} != {1, 2}; +check if {1, 4} != true; +check if fact(1, $value), 1 == $value; +check if fact2(1, $value), 1 != $value; +``` + +### validation + +authorizer code: +``` +fact(1, 1); +fact2(1, 2); + +allow if true; +``` + +revocation ids: +- `899521bb50786bd40a21bf22c9362b021a9300e20cbf1b8b2f70bd1f5a9b01c420efeab85092f081db71ce7b7cebfc01b4a4f8f2294c478ce4c7f8813ffa5c0f` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "fact(1, 1)", + "fact2(1, 2)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if \"abcD12\" == \"abcD12\"", + "check if \"abcD12x\" != \"abcD12\"", + "check if \"abcD12x\" != true", + "check if 1 != 3", + "check if 1 != true", + "check if 1 != true", + "check if 1 == 1", + "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z", + "check if 2022-12-04T09:46:41Z != true", + "check if 2022-12-04T09:46:41Z == 2022-12-04T09:46:41Z", + "check if fact(1, $value), 1 == $value", + "check if fact2(1, $value), 1 != $value", + "check if false != true", + "check if false == false", + "check if hex:12abcd != hex:12ab", + "check if hex:12abcd != true", + "check if hex:12abcd == hex:12abcd", + "check if true == true", + "check if {1, 2} == {1, 2}", + "check if {1, 4} != true", + "check if {1, 4} != {1, 2}", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Ok(0)` +### validation for "evaluate to false" + +authorizer code: +``` +fact(1, 2); +fact2(1, 1); + +check if false != false; + +allow if true; +``` + +revocation ids: +- `899521bb50786bd40a21bf22c9362b021a9300e20cbf1b8b2f70bd1f5a9b01c420efeab85092f081db71ce7b7cebfc01b4a4f8f2294c478ce4c7f8813ffa5c0f` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "fact(1, 2)", + "fact2(1, 1)", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if \"abcD12\" == \"abcD12\"", + "check if \"abcD12x\" != \"abcD12\"", + "check if \"abcD12x\" != true", + "check if 1 != 3", + "check if 1 != true", + "check if 1 != true", + "check if 1 == 1", + "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z", + "check if 2022-12-04T09:46:41Z != true", + "check if 2022-12-04T09:46:41Z == 2022-12-04T09:46:41Z", + "check if fact(1, $value), 1 == $value", + "check if fact2(1, $value), 1 != $value", + "check if false != true", + "check if false == false", + "check if hex:12abcd != hex:12ab", + "check if hex:12abcd != true", + "check if hex:12abcd == hex:12abcd", + "check if true == true", + "check if {1, 2} == {1, 2}", + "check if {1, 4} != true", + "check if {1, 4} != {1, 2}", + ], + }, + Checks { + origin: Some( + 18446744073709551615, + ), + checks: [ + "check if false != false", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Err(FailedLogic(Unauthorized { policy: Allow(0), checks: [Authorizer(FailedAuthorizerCheck { check_id: 0, rule: "check if false != false" }), Block(FailedBlockCheck { block_id: 0, check_id: 19, rule: "check if fact(1, $value), 1 == $value" }), Block(FailedBlockCheck { block_id: 0, check_id: 20, rule: "check if fact2(1, $value), 1 != $value" })] }))` + + +------------------------------ + +## test laziness and closures: test032_laziness_closures.bc +### token + +authority: +symbols: ["x", "p", "q"] + +public keys: [] + +``` +check if !false && true; +check if false || true; +check if (true || false) && true; +check if !(false && "x".intersection("x")); +check if true || "x".intersection("x"); +check if {1, 2, 3}.all($p -> $p > 0); +check if !{1, 2, 3}.all($p -> $p == 2); +check if {1, 2, 3}.any($p -> $p > 2); +check if !{1, 2, 3}.any($p -> $p > 3); +check if {1, 2, 3}.any($p -> $p > 1 && {3, 4, 5}.any($q -> $p == $q)); +``` + +### validation + +authorizer code: +``` +allow if true; +``` + +revocation ids: +- `ef75002a071b56293152a4c9eb69ba0793614993e667736a6a92275ddd5aa35a287de5b13acaec72b5af6ba2ee8a3629b1a33cfa51597ae5afbebd8aa35dbe08` + +authorizer world: +``` +World { + facts: [] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if !(false && \"x\".intersection(\"x\"))", + "check if !false && true", + "check if !{1, 2, 3}.all($p -> $p == 2)", + "check if !{1, 2, 3}.any($p -> $p > 3)", + "check if (true || false) && true", + "check if false || true", + "check if true || \"x\".intersection(\"x\")", + "check if {1, 2, 3}.all($p -> $p > 0)", + "check if {1, 2, 3}.any($p -> $p > 1 && {3, 4, 5}.any($q -> $p == $q))", + "check if {1, 2, 3}.any($p -> $p > 2)", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Ok(0)` +### validation for "shadowing" + +authorizer code: +``` +allow if [true].any($p -> [true].all($p -> $p)); +``` + +revocation ids: +- `ef75002a071b56293152a4c9eb69ba0793614993e667736a6a92275ddd5aa35a287de5b13acaec72b5af6ba2ee8a3629b1a33cfa51597ae5afbebd8aa35dbe08` + +authorizer world: +``` +World { + facts: [] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if !(false && \"x\".intersection(\"x\"))", + "check if !false && true", + "check if !{1, 2, 3}.all($p -> $p == 2)", + "check if !{1, 2, 3}.any($p -> $p > 3)", + "check if (true || false) && true", + "check if false || true", + "check if true || \"x\".intersection(\"x\")", + "check if {1, 2, 3}.all($p -> $p > 0)", + "check if {1, 2, 3}.any($p -> $p > 1 && {3, 4, 5}.any($q -> $p == $q))", + "check if {1, 2, 3}.any($p -> $p > 2)", + ], + }, +] + policies: [ + "allow if [true].any($p -> [true].all($p -> $p))", +] +} +``` + +result: `Err(Execution(ShadowedVariable))` + + +------------------------------ + +## test .type(): test033_typeof.bc +### token + +authority: +symbols: ["integer", "string", "test", "date", "bytes", "bool", "set", "null", "array", "map", "a", "t"] + +public keys: [] + +``` +integer(1); +string("test"); +date(2023-12-28T00:00:00Z); +bytes(hex:aa); +bool(true); +set({false, true}); +null(null); +array([1, 2, 3]); +map({"a": true}); +check if 1.type() == "integer"; +check if integer($t), $t.type() == "integer"; +check if "test".type() == "string"; +check if string($t), $t.type() == "string"; +check if (2023-12-28T00:00:00Z).type() == "date"; +check if date($t), $t.type() == "date"; +check if hex:aa.type() == "bytes"; +check if bytes($t), $t.type() == "bytes"; +check if true.type() == "bool"; +check if bool($t), $t.type() == "bool"; +check if {false, true}.type() == "set"; +check if set($t), $t.type() == "set"; +check if null.type() == "null"; +check if null($t), $t.type() == "null"; +check if array($t), $t.type() == "array"; +check if map($t), $t.type() == "map"; +``` + +### validation + +authorizer code: +``` +allow if true; +``` + +revocation ids: +- `c8f7ff152b40a3e8f3ab19a435ccd16c41288762864022895b99d2abb6330c794b3f1378a4651b31d249f4c35b69246d88124d40e05e634a0eb9ca9e54b1ca0a` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + Some( + 0, + ), + }, + facts: [ + "array([1, 2, 3])", + "bool(true)", + "bytes(hex:aa)", + "date(2023-12-28T00:00:00Z)", + "integer(1)", + "map({\"a\": true})", + "null(null)", + "set({false, true})", + "string(\"test\")", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if \"test\".type() == \"string\"", + "check if (2023-12-28T00:00:00Z).type() == \"date\"", + "check if 1.type() == \"integer\"", + "check if array($t), $t.type() == \"array\"", + "check if bool($t), $t.type() == \"bool\"", + "check if bytes($t), $t.type() == \"bytes\"", + "check if date($t), $t.type() == \"date\"", + "check if hex:aa.type() == \"bytes\"", + "check if integer($t), $t.type() == \"integer\"", + "check if map($t), $t.type() == \"map\"", + "check if null($t), $t.type() == \"null\"", + "check if null.type() == \"null\"", + "check if set($t), $t.type() == \"set\"", + "check if string($t), $t.type() == \"string\"", + "check if true.type() == \"bool\"", + "check if {false, true}.type() == \"set\"", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Ok(0)` + + +------------------------------ + +## test array and map operations: test034_array_map.bc +### token + +authority: +symbols: ["a", "b", "c", "p", "d", "A", "kv", "id", "roles"] + +public keys: [] + +``` +check if [1, 2, 1].length() == 3; +check if ["a", "b"] != true; +check if ["a", "b"] != [1, 2, 3]; +check if ["a", "b"] == ["a", "b"]; +check if ["a", "b"] === ["a", "b"]; +check if ["a", "b"] !== ["a", "c"]; +check if ["a", "b", "c"].contains("c"); +check if [1, 2, 3].starts_with([1, 2]); +check if [4, 5, 6].ends_with([6]); +check if [1, 2, "a"].get(2) == "a"; +check if [1, 2].get(3) == null; +check if [1, 2, 3].all($p -> $p > 0); +check if [1, 2, 3].any($p -> $p > 2); +check if {"a": 1, "b": 2, "c": 3, "d": 4}.length() == 4; +check if {1: "a", 2: "b"} != true; +check if {1: "a", 2: "b"} != {"a": 1, "b": 2}; +check if {1: "a", 2: "b"} == {1: "a", 2: "b"}; +check if {1: "a", 2: "b"} !== {"a": 1, "b": 2}; +check if {1: "a", 2: "b"} === {1: "a", 2: "b"}; +check if {"a": 1, "b": 2, "c": 3, "d": 4}.contains("d"); +check if {1: "A", "a": 1, "b": 2}.get("a") == 1; +check if {1: "A", "a": 1, "b": 2}.get(1) == "A"; +check if {1: "A", "a": 1, "b": 2}.get("c") == null; +check if {1: "A", "a": 1, "b": 2}.get(2) == null; +check if {"a": 1, "b": 2}.all($kv -> $kv.get(0) != "c" && $kv.get(1) < 3); +check if {1: "A", "a": 1, "b": 2}.any($kv -> $kv.get(0) == 1 && $kv.get(1) == "A"); +check if {"user": {"id": 1, "roles": ["admin"]}}.get("user").get("roles").contains("admin"); +``` + +### validation + +authorizer code: +``` +allow if true; +``` + +revocation ids: +- `8041144f92616477f1cd00b81e8be79581202a3853b08b3d477797b0d91f30c02fd7c01ca91a00f8a222d6be4794cc287baa361a1a00d5941518c1917967ec03` + +authorizer world: +``` +World { + facts: [] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if [\"a\", \"b\", \"c\"].contains(\"c\")", + "check if [\"a\", \"b\"] != [1, 2, 3]", + "check if [\"a\", \"b\"] != true", + "check if [\"a\", \"b\"] !== [\"a\", \"c\"]", + "check if [\"a\", \"b\"] == [\"a\", \"b\"]", + "check if [\"a\", \"b\"] === [\"a\", \"b\"]", + "check if [1, 2, \"a\"].get(2) == \"a\"", + "check if [1, 2, 1].length() == 3", + "check if [1, 2, 3].all($p -> $p > 0)", + "check if [1, 2, 3].any($p -> $p > 2)", + "check if [1, 2, 3].starts_with([1, 2])", + "check if [1, 2].get(3) == null", + "check if [4, 5, 6].ends_with([6])", + "check if {\"a\": 1, \"b\": 2, \"c\": 3, \"d\": 4}.contains(\"d\")", + "check if {\"a\": 1, \"b\": 2, \"c\": 3, \"d\": 4}.length() == 4", + "check if {\"a\": 1, \"b\": 2}.all($kv -> $kv.get(0) != \"c\" && $kv.get(1) < 3)", + "check if {\"user\": {\"id\": 1, \"roles\": [\"admin\"]}}.get(\"user\").get(\"roles\").contains(\"admin\")", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.any($kv -> $kv.get(0) == 1 && $kv.get(1) == \"A\")", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.get(\"a\") == 1", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.get(\"c\") == null", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.get(1) == \"A\"", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.get(2) == null", + "check if {1: \"a\", 2: \"b\"} != true", + "check if {1: \"a\", 2: \"b\"} != {\"a\": 1, \"b\": 2}", + "check if {1: \"a\", 2: \"b\"} !== {\"a\": 1, \"b\": 2}", + "check if {1: \"a\", 2: \"b\"} == {1: \"a\", 2: \"b\"}", + "check if {1: \"a\", 2: \"b\"} === {1: \"a\", 2: \"b\"}", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Ok(0)` + + +------------------------------ + +## test ffi calls (v6 blocks): test035_ffi.bc +### token + +authority: +symbols: ["test", "a", "equal strings"] + +public keys: [] + +``` +check if true.extern::test(), "a".extern::test("a") == "equal strings"; +``` + +### validation + +authorizer code: +``` +allow if true; +``` + +revocation ids: +- `faf26fe6f5dfa08c114a0a29321405b6fb7be79b0d80694d27925f7deb01effe5707600e42fd74f9a1d2920466446d51949155f4548f0fd68f3e9326c7e12404` + +authorizer world: +``` +World { + facts: [] + rules: [] + checks: [ + Checks { + origin: Some( + 0, + ), + checks: [ + "check if true.extern::test(), \"a\".extern::test(\"a\") == \"equal strings\"", + ], + }, +] + policies: [ + "allow if true", +] +} +``` + +result: `Ok(0)` + + +------------------------------ + +## ECDSA secp256r1 signatures: test036_secp256r1.bc +### token + +authority: +symbols: ["file1", "file2"] + +public keys: [] + +``` +right("file1", "read"); +right("file2", "read"); +right("file1", "write"); +``` + +1: +symbols: ["0"] + +public keys: [] + +``` +check if resource($0), operation("read"), right($0, "read"); +``` + +### validation + +authorizer code: +``` +resource("file1"); +operation("read"); + +allow if true; +``` + +revocation ids: +- `760785de30d7348e9c847aab8b3bdad6a0d463f4f50ed9667aade563e9112ee6d2f589630dd7553c2eced2a57edf3636d5c874b35df15120c62fddcbdbd2de09` +- `30440220039667c7a4d964e4b449289dc8fd206d7aa0e77eb701a9253b3307d32c177fa8022023f7523c143c5fb55ee4cafe49804702ef05a70883ebf42185b54bd36a7e7cd4` + +authorizer world: +``` +World { + facts: [ + Facts { + origin: { + None, + }, + facts: [ + "operation(\"read\")", + "resource(\"file1\")", + ], + }, + Facts { + origin: { + Some( + 0, + ), + }, + facts: [ + "right(\"file1\", \"read\")", + "right(\"file1\", \"write\")", + "right(\"file2\", \"read\")", + ], + }, +] + rules: [] + checks: [ + Checks { + origin: Some( + 1, + ), + checks: [ + "check if resource($0), operation(\"read\"), right($0, \"read\")", ], }, ] diff --git a/samples/current/samples.json b/samples/current/samples.json index 432c45d..fbb9462 100644 --- a/samples/current/samples.json +++ b/samples/current/samples.json @@ -154,7 +154,7 @@ "result": { "Err": { "Format": { - "InvalidSignatureSize": 16 + "BlockSignatureDeserializationError": "block signature deserialization error: [117, 149, 161, 18, 161, 235, 91, 129, 166, 227, 152, 133, 46, 97, 24, 183]" } } }, @@ -862,7 +862,7 @@ ], "public_keys": [], "external_key": null, - "code": "valid_date(\"file1\") <- time($0), resource(\"file1\"), $0 <= 2030-12-31T12:59:59Z;\nvalid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, ![\"file1\"].contains($1);\ncheck if valid_date($0), resource($0);\n" + "code": "valid_date(\"file1\") <- time($0), resource(\"file1\"), $0 <= 2030-12-31T12:59:59Z;\nvalid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, !{\"file1\"}.contains($1);\ncheck if valid_date($0), resource($0);\n" } ], "validations": { @@ -902,7 +902,7 @@ "origin": 1, "rules": [ "valid_date(\"file1\") <- time($0), resource(\"file1\"), $0 <= 2030-12-31T12:59:59Z", - "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, ![\"file1\"].contains($1)" + "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, !{\"file1\"}.contains($1)" ] } ], @@ -954,7 +954,7 @@ "origin": 1, "rules": [ "valid_date(\"file1\") <- time($0), resource(\"file1\"), $0 <= 2030-12-31T12:59:59Z", - "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, ![\"file1\"].contains($1)" + "valid_date($1) <- time($0), resource($1), $0 <= 1999-12-31T12:59:59Z, !{\"file1\"}.contains($1)" ] } ], @@ -1239,12 +1239,13 @@ "b", "de", "abcD12", + "é", "abc", "def" ], "public_keys": [], "external_key": null, - "code": "check if true;\ncheck if !false;\ncheck if !false && true;\ncheck if false || true;\ncheck if (true || false) && true;\ncheck if true == true;\ncheck if false == false;\ncheck if 1 < 2;\ncheck if 2 > 1;\ncheck if 1 <= 2;\ncheck if 1 <= 1;\ncheck if 2 >= 1;\ncheck if 2 >= 2;\ncheck if 3 == 3;\ncheck if 1 + 2 * 3 - 4 / 2 == 5;\ncheck if \"hello world\".starts_with(\"hello\") && \"hello world\".ends_with(\"world\");\ncheck if \"aaabde\".matches(\"a*c?.e\");\ncheck if \"aaabde\".contains(\"abd\");\ncheck if \"aaabde\" == \"aaa\" + \"b\" + \"de\";\ncheck if \"abcD12\" == \"abcD12\";\ncheck if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z;\ncheck if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z == 2020-12-04T09:46:41Z;\ncheck if hex:12ab == hex:12ab;\ncheck if [1, 2].contains(2);\ncheck if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z);\ncheck if [false, true].contains(true);\ncheck if [\"abc\", \"def\"].contains(\"abc\");\ncheck if [hex:12ab, hex:34de].contains(hex:34de);\ncheck if [1, 2].contains([2]);\ncheck if [1, 2] == [1, 2];\ncheck if [1, 2].intersection([2, 3]) == [2];\ncheck if [1, 2].union([2, 3]) == [1, 2, 3];\ncheck if [1, 2, 3].intersection([1, 2]).contains(1);\ncheck if [1, 2, 3].intersection([1, 2]).length() == 2;\n" + "code": "check if true;\ncheck if !false;\ncheck if true === true;\ncheck if false === false;\ncheck if 1 < 2;\ncheck if 2 > 1;\ncheck if 1 <= 2;\ncheck if 1 <= 1;\ncheck if 2 >= 1;\ncheck if 2 >= 2;\ncheck if 3 === 3;\ncheck if 1 + 2 * 3 - 4 / 2 === 5;\ncheck if \"hello world\".starts_with(\"hello\"), \"hello world\".ends_with(\"world\");\ncheck if \"aaabde\".matches(\"a*c?.e\");\ncheck if \"aaabde\".contains(\"abd\");\ncheck if \"aaabde\" === \"aaa\" + \"b\" + \"de\";\ncheck if \"abcD12\" === \"abcD12\";\ncheck if \"abcD12\".length() === 6;\ncheck if \"é\".length() === 2;\ncheck if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z;\ncheck if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z;\ncheck if 2020-12-04T09:46:41Z === 2020-12-04T09:46:41Z;\ncheck if hex:12ab === hex:12ab;\ncheck if {1, 2}.contains(2);\ncheck if {2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z}.contains(2020-12-04T09:46:41Z);\ncheck if {false, true}.contains(true);\ncheck if {\"abc\", \"def\"}.contains(\"abc\");\ncheck if {hex:12ab, hex:34de}.contains(hex:34de);\ncheck if {1, 2}.contains({2});\ncheck if {1, 2} === {1, 2};\ncheck if {1, 2}.intersection({2, 3}) === {2};\ncheck if {1, 2}.union({2, 3}) === {1, 2, 3};\ncheck if {1, 2, 3}.intersection({1, 2}).contains(1);\ncheck if {1, 2, 3}.intersection({1, 2}).length() === 2;\n" } ], "validations": { @@ -1257,14 +1258,14 @@ "origin": 0, "checks": [ "check if !false", - "check if !false && true", - "check if \"aaabde\" == \"aaa\" + \"b\" + \"de\"", + "check if \"aaabde\" === \"aaa\" + \"b\" + \"de\"", "check if \"aaabde\".contains(\"abd\")", "check if \"aaabde\".matches(\"a*c?.e\")", - "check if \"abcD12\" == \"abcD12\"", - "check if \"hello world\".starts_with(\"hello\") && \"hello world\".ends_with(\"world\")", - "check if (true || false) && true", - "check if 1 + 2 * 3 - 4 / 2 == 5", + "check if \"abcD12\" === \"abcD12\"", + "check if \"abcD12\".length() === 6", + "check if \"hello world\".starts_with(\"hello\"), \"hello world\".ends_with(\"world\")", + "check if \"é\".length() === 2", + "check if 1 + 2 * 3 - 4 / 2 === 5", "check if 1 < 2", "check if 1 <= 1", "check if 1 <= 2", @@ -1273,28 +1274,27 @@ "check if 2 >= 2", "check if 2019-12-04T09:46:41Z < 2020-12-04T09:46:41Z", "check if 2019-12-04T09:46:41Z <= 2020-12-04T09:46:41Z", - "check if 2020-12-04T09:46:41Z == 2020-12-04T09:46:41Z", + "check if 2020-12-04T09:46:41Z === 2020-12-04T09:46:41Z", "check if 2020-12-04T09:46:41Z > 2019-12-04T09:46:41Z", "check if 2020-12-04T09:46:41Z >= 2019-12-04T09:46:41Z", "check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z", "check if 2020-12-04T09:46:41Z >= 2020-12-04T09:46:41Z", - "check if 3 == 3", - "check if [\"abc\", \"def\"].contains(\"abc\")", - "check if [1, 2, 3].intersection([1, 2]).contains(1)", - "check if [1, 2, 3].intersection([1, 2]).length() == 2", - "check if [1, 2] == [1, 2]", - "check if [1, 2].contains(2)", - "check if [1, 2].contains([2])", - "check if [1, 2].intersection([2, 3]) == [2]", - "check if [1, 2].union([2, 3]) == [1, 2, 3]", - "check if [2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z].contains(2020-12-04T09:46:41Z)", - "check if [false, true].contains(true)", - "check if [hex:12ab, hex:34de].contains(hex:34de)", - "check if false == false", - "check if false || true", - "check if hex:12ab == hex:12ab", + "check if 3 === 3", + "check if false === false", + "check if hex:12ab === hex:12ab", "check if true", - "check if true == true" + "check if true === true", + "check if {\"abc\", \"def\"}.contains(\"abc\")", + "check if {1, 2, 3}.intersection({1, 2}).contains(1)", + "check if {1, 2, 3}.intersection({1, 2}).length() === 2", + "check if {1, 2} === {1, 2}", + "check if {1, 2}.contains(2)", + "check if {1, 2}.contains({2})", + "check if {1, 2}.intersection({2, 3}) === {2}", + "check if {1, 2}.union({2, 3}) === {1, 2, 3}", + "check if {2019-12-04T09:46:41Z, 2020-12-04T09:46:41Z}.contains(2020-12-04T09:46:41Z)", + "check if {false, true}.contains(true)", + "check if {hex:12ab, hex:34de}.contains(hex:34de)" ] } ], @@ -1307,7 +1307,7 @@ }, "authorizer_code": "allow if true;\n", "revocation_ids": [ - "f61b4cb4fc58777fec6c8d39fe62259dc3c78511868236c391e9f67ffd03a3a8b8e3042d4bacce0d5756d053f5afccd4c5e4df0597af44b36bdfab492e5fe50e" + "d0420227266e3583a42dfaa0e38550d99f681d150dd18856f3af9a697bc9c5c8bf06b4b0fe5b9df0377d1b963574e2fd210a0a76a8b0756a65f640c602bebd07" ] } } @@ -1795,7 +1795,7 @@ "authorizer_code": "allow if true;\n", "revocation_ids": [ "470e4bf7aa2a01ab39c98150bd06aa15b4aa5d86509044a8809a8634cd8cf2b42269a51a774b65d10bac9369d013070b00187925196a8e680108473f11cf8f03", - "93a7315ab1272da9eeef015f6fecbc9ac96fe4660e6204bf64ea2105ebe309e9c9cadc0a26c5604f13910fae3f2cd0800756afb6b6b208bf77adeb1ab2f42405" + "901b2af4dacf33458d2d91ac484b60bad948e8d10faa9695b096054d5b46e832a977b60b17464cacf545ad0801f549ea454675f0ac88c413406925e2af83ff08" ] } } @@ -1814,7 +1814,7 @@ ], "public_keys": [], "external_key": null, - "code": "allowed_operations([\"A\", \"B\"]);\ncheck all operation($op), allowed_operations($allowed), $allowed.contains($op);\n" + "code": "allowed_operations({\"A\", \"B\"});\ncheck all operation($op), allowed_operations($allowed), $allowed.contains($op);\n" } ], "validations": { @@ -1835,7 +1835,7 @@ 0 ], "facts": [ - "allowed_operations([\"A\", \"B\"])" + "allowed_operations({\"A\", \"B\"})" ] } ], @@ -1877,7 +1877,7 @@ 0 ], "facts": [ - "allowed_operations([\"A\", \"B\"])" + "allowed_operations({\"A\", \"B\"})" ] } ], @@ -1936,26 +1936,34 @@ { "symbols": [], "public_keys": [ - "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463" + "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", + "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189" ], "external_key": "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189", "code": "query(1);\nquery(1, 2) <- query(1), query(2) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n" }, { "symbols": [], - "public_keys": [], + "public_keys": [ + "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", + "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189" + ], "external_key": "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "code": "query(2);\ncheck if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n" }, { "symbols": [], - "public_keys": [], + "public_keys": [ + "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", + "ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189" + ], "external_key": "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "code": "query(3);\ncheck if query(2), query(3) trusting ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\ncheck if query(1) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\n" }, { "symbols": [], "public_keys": [ + "ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463", "ed25519/f98da8c1cf907856431bfc3dc87531e0eaadba90f919edc232405b85877ef136" ], "external_key": null, @@ -2079,10 +2087,10 @@ "authorizer_code": "check if query(1, 2) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189, ed25519/a060270db7e9c9f06e8f9cc33a64e99f6596af12cb01c4b638df8afc7b642463;\n\ndeny if query(3);\ndeny if query(1, 2);\ndeny if query(0) trusting ed25519/acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189;\nallow if true;\n", "revocation_ids": [ "3771cefe71beb21ead35a59c8116ee82627a5717c0295f35980662abccb159fe1b37848cb1818e548656bd4fd882d0094a2daab631c76b2b72e3a093914bfe04", - "45133b90f228a81fe4d3042a79f6c6b7608e656e903d6b1f4db32cd774b09b8315af360879a5f210ad7be37ff55e3eb34f237bcc9711407b6329ac6018bfb400", - "179f054f3c572646aba5013159ae192ac42f5666dbdd984129955f4652b6829e59f54aa251e451f96329d42a2524ce569c3e1ec52e708b642dd8994af51dd703", - "edab54789d6656936fcd28200b9c61643434842d531f09f209fad555e11ff53174db174dafba126e6de448983a56f78d2042bc5782d71a45799c022fe69fb30d", - "6a62306831e9dbe83e7b33db96b758c77dd690930f2d2d87e239b210b1944c5582bf6d7e1bfea8e7f928c27f2fff0e2ee2e0adc41e11e0c3abe8d7b96b9ede07" + "7113d4dbb3b688b80e941f365a2c6342d480c77ed03937bccf85dc5cc3554c7517887b1b0c9021388a71e6ca9047aabaaad5ae5b511a2880902568444a98e50b", + "d0e3fc4bbd1b7320022800af909585aa906f677c4ca79c275a10b6779f669384c464ee84a1b04f13877a25761a874748362c065f4d15a8cab5c5e16c34074403", + "29b7e0a1f118a6185814a552660c516c43482044e280e7a8de85b8e7e54947e0ae82eb39d7b524d4b72cb9812a7a4b8871964f8f825b1c1ed85d344c05281d0d", + "3f675d6c364e06405d4868c904e40f3d81c32b083d91586db814d4cb4bf536b4ba209d82f11b4cb6da293b60b20d6122fc3e0e08e80c381dee83edd848211900" ] } } @@ -2095,7 +2103,7 @@ "symbols": [], "public_keys": [], "external_key": null, - "code": "check if true || 10000000000 * 10000000000 != 0;\ncheck if true || 9223372036854775807 + 1 != 0;\ncheck if true || -9223372036854775808 - 1 != 0;\n" + "code": "check if 10000000000 * 10000000000 != 0;\ncheck if 9223372036854775807 + 1 != 0;\ncheck if -9223372036854775808 - 1 != 0;\n" } ], "validations": { @@ -2107,9 +2115,9 @@ { "origin": 0, "checks": [ - "check if true || -9223372036854775808 - 1 != 0", - "check if true || 10000000000 * 10000000000 != 0", - "check if true || 9223372036854775807 + 1 != 0" + "check if -9223372036854775808 - 1 != 0", + "check if 10000000000 * 10000000000 != 0", + "check if 9223372036854775807 + 1 != 0" ] } ], @@ -2124,7 +2132,7 @@ }, "authorizer_code": "allow if true;\n", "revocation_ids": [ - "3346a22aae0abfc1ffa526f02f7650e90af909e5e519989026441e78cdc245b7fd126503cfdc8831325fc04307edc65238db319724477915f7040a2f6a719a05" + "31f01031b8d9cc312c346674625a2218b19a126e931318dc02d8d53aec2775faecd3f848f60c1446573c37ea0664fefc768f35ba5ce4365b83ff06f0c0409b0e" ] } } @@ -2140,7 +2148,7 @@ ], "public_keys": [], "external_key": null, - "code": "check if 1 != 3;\ncheck if 1 | 2 ^ 3 == 0;\ncheck if \"abcD12x\" != \"abcD12\";\ncheck if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z;\ncheck if hex:12abcd != hex:12ab;\ncheck if [1, 4] != [1, 2];\n" + "code": "check if 1 !== 3;\ncheck if 1 | 2 ^ 3 === 0;\ncheck if \"abcD12x\" !== \"abcD12\";\ncheck if 2022-12-04T09:46:41Z !== 2020-12-04T09:46:41Z;\ncheck if hex:12abcd !== hex:12ab;\ncheck if {1, 4} !== {1, 2};\n" } ], "validations": { @@ -2152,12 +2160,12 @@ { "origin": 0, "checks": [ - "check if \"abcD12x\" != \"abcD12\"", - "check if 1 != 3", - "check if 1 | 2 ^ 3 == 0", - "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z", - "check if [1, 4] != [1, 2]", - "check if hex:12abcd != hex:12ab" + "check if \"abcD12x\" !== \"abcD12\"", + "check if 1 !== 3", + "check if 1 | 2 ^ 3 === 0", + "check if 2022-12-04T09:46:41Z !== 2020-12-04T09:46:41Z", + "check if hex:12abcd !== hex:12ab", + "check if {1, 4} !== {1, 2}" ] } ], @@ -2174,6 +2182,849 @@ ] } } + }, + { + "title": "test reject if", + "filename": "test029_reject_if.bc", + "token": [ + { + "symbols": [ + "test" + ], + "public_keys": [], + "external_key": null, + "code": "reject if test($test), $test;\n" + } + ], + "validations": { + "": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "test(false)" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "reject if test($test), $test" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "test(false);\n\nallow if true;\n", + "revocation_ids": [ + "2e6dcafe4061dd86f61ad038a0a1bea816b85898bb86a14b16177e78ee249fcfb2455e2eed52ccfe8eafc679b1f34f9ef98e92e3719981dd4098b901b6cb040b" + ] + }, + "rejection": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "test(true)" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "reject if test($test), $test" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Err": { + "FailedLogic": { + "Unauthorized": { + "policy": { + "Allow": 0 + }, + "checks": [ + { + "Block": { + "block_id": 0, + "check_id": 0, + "rule": "reject if test($test), $test" + } + } + ] + } + } + } + }, + "authorizer_code": "test(true);\n\nallow if true;\n", + "revocation_ids": [ + "2e6dcafe4061dd86f61ad038a0a1bea816b85898bb86a14b16177e78ee249fcfb2455e2eed52ccfe8eafc679b1f34f9ef98e92e3719981dd4098b901b6cb040b" + ] + } + } + }, + { + "title": "test null", + "filename": "test030_null.bc", + "token": [ + { + "symbols": [ + "fact", + "value" + ], + "public_keys": [], + "external_key": null, + "code": "check if fact(null, $value), $value == null;\nreject if fact(null, $value), $value != null;\n" + } + ], + "validations": { + "": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "fact(null, null)" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "fact(null, null);\n\nallow if true;\n", + "revocation_ids": [ + "c6c60ff84938908ca2bfcc7d674a400857c3349bdb373646c825e946ad0d08d76fd4734cd40f09884db0a41aee0c078897750e27706959d785750ef24acf100f" + ] + }, + "rejection1": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "fact(null, 1)" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Err": { + "FailedLogic": { + "Unauthorized": { + "policy": { + "Allow": 0 + }, + "checks": [ + { + "Block": { + "block_id": 0, + "check_id": 0, + "rule": "check if fact(null, $value), $value == null" + } + }, + { + "Block": { + "block_id": 0, + "check_id": 1, + "rule": "reject if fact(null, $value), $value != null" + } + } + ] + } + } + } + }, + "authorizer_code": "fact(null, 1);\n\nallow if true;\n", + "revocation_ids": [ + "c6c60ff84938908ca2bfcc7d674a400857c3349bdb373646c825e946ad0d08d76fd4734cd40f09884db0a41aee0c078897750e27706959d785750ef24acf100f" + ] + }, + "rejection2": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "fact(null, true)" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Err": { + "FailedLogic": { + "Unauthorized": { + "policy": { + "Allow": 0 + }, + "checks": [ + { + "Block": { + "block_id": 0, + "check_id": 0, + "rule": "check if fact(null, $value), $value == null" + } + }, + { + "Block": { + "block_id": 0, + "check_id": 1, + "rule": "reject if fact(null, $value), $value != null" + } + } + ] + } + } + } + }, + "authorizer_code": "fact(null, true);\n\nallow if true;\n", + "revocation_ids": [ + "c6c60ff84938908ca2bfcc7d674a400857c3349bdb373646c825e946ad0d08d76fd4734cd40f09884db0a41aee0c078897750e27706959d785750ef24acf100f" + ] + }, + "rejection3": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "fact(null, \"abcd\")" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if fact(null, $value), $value == null", + "reject if fact(null, $value), $value != null" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Err": { + "FailedLogic": { + "Unauthorized": { + "policy": { + "Allow": 0 + }, + "checks": [ + { + "Block": { + "block_id": 0, + "check_id": 0, + "rule": "check if fact(null, $value), $value == null" + } + }, + { + "Block": { + "block_id": 0, + "check_id": 1, + "rule": "reject if fact(null, $value), $value != null" + } + } + ] + } + } + } + }, + "authorizer_code": "fact(null, \"abcd\");\n\nallow if true;\n", + "revocation_ids": [ + "c6c60ff84938908ca2bfcc7d674a400857c3349bdb373646c825e946ad0d08d76fd4734cd40f09884db0a41aee0c078897750e27706959d785750ef24acf100f" + ] + } + } + }, + { + "title": "test heterogeneous equal", + "filename": "test031_heterogeneous_equal.bc", + "token": [ + { + "symbols": [ + "abcD12", + "abcD12x", + "fact", + "value", + "fact2" + ], + "public_keys": [], + "external_key": null, + "code": "check if true == true;\ncheck if false == false;\ncheck if false != true;\ncheck if 1 != true;\ncheck if 1 == 1;\ncheck if 1 != 3;\ncheck if 1 != true;\ncheck if \"abcD12\" == \"abcD12\";\ncheck if \"abcD12x\" != \"abcD12\";\ncheck if \"abcD12x\" != true;\ncheck if 2022-12-04T09:46:41Z == 2022-12-04T09:46:41Z;\ncheck if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z;\ncheck if 2022-12-04T09:46:41Z != true;\ncheck if hex:12abcd == hex:12abcd;\ncheck if hex:12abcd != hex:12ab;\ncheck if hex:12abcd != true;\ncheck if {1, 2} == {1, 2};\ncheck if {1, 4} != {1, 2};\ncheck if {1, 4} != true;\ncheck if fact(1, $value), 1 == $value;\ncheck if fact2(1, $value), 1 != $value;\n" + } + ], + "validations": { + "": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "fact(1, 1)", + "fact2(1, 2)" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if \"abcD12\" == \"abcD12\"", + "check if \"abcD12x\" != \"abcD12\"", + "check if \"abcD12x\" != true", + "check if 1 != 3", + "check if 1 != true", + "check if 1 != true", + "check if 1 == 1", + "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z", + "check if 2022-12-04T09:46:41Z != true", + "check if 2022-12-04T09:46:41Z == 2022-12-04T09:46:41Z", + "check if fact(1, $value), 1 == $value", + "check if fact2(1, $value), 1 != $value", + "check if false != true", + "check if false == false", + "check if hex:12abcd != hex:12ab", + "check if hex:12abcd != true", + "check if hex:12abcd == hex:12abcd", + "check if true == true", + "check if {1, 2} == {1, 2}", + "check if {1, 4} != true", + "check if {1, 4} != {1, 2}" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "fact(1, 1);\nfact2(1, 2);\n\nallow if true;\n", + "revocation_ids": [ + "899521bb50786bd40a21bf22c9362b021a9300e20cbf1b8b2f70bd1f5a9b01c420efeab85092f081db71ce7b7cebfc01b4a4f8f2294c478ce4c7f8813ffa5c0f" + ] + }, + "evaluate to false": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "fact(1, 2)", + "fact2(1, 1)" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if \"abcD12\" == \"abcD12\"", + "check if \"abcD12x\" != \"abcD12\"", + "check if \"abcD12x\" != true", + "check if 1 != 3", + "check if 1 != true", + "check if 1 != true", + "check if 1 == 1", + "check if 2022-12-04T09:46:41Z != 2020-12-04T09:46:41Z", + "check if 2022-12-04T09:46:41Z != true", + "check if 2022-12-04T09:46:41Z == 2022-12-04T09:46:41Z", + "check if fact(1, $value), 1 == $value", + "check if fact2(1, $value), 1 != $value", + "check if false != true", + "check if false == false", + "check if hex:12abcd != hex:12ab", + "check if hex:12abcd != true", + "check if hex:12abcd == hex:12abcd", + "check if true == true", + "check if {1, 2} == {1, 2}", + "check if {1, 4} != true", + "check if {1, 4} != {1, 2}" + ] + }, + { + "origin": 18446744073709551615, + "checks": [ + "check if false != false" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Err": { + "FailedLogic": { + "Unauthorized": { + "policy": { + "Allow": 0 + }, + "checks": [ + { + "Authorizer": { + "check_id": 0, + "rule": "check if false != false" + } + }, + { + "Block": { + "block_id": 0, + "check_id": 19, + "rule": "check if fact(1, $value), 1 == $value" + } + }, + { + "Block": { + "block_id": 0, + "check_id": 20, + "rule": "check if fact2(1, $value), 1 != $value" + } + } + ] + } + } + } + }, + "authorizer_code": "fact(1, 2);\nfact2(1, 1);\n\ncheck if false != false;\n\nallow if true;\n", + "revocation_ids": [ + "899521bb50786bd40a21bf22c9362b021a9300e20cbf1b8b2f70bd1f5a9b01c420efeab85092f081db71ce7b7cebfc01b4a4f8f2294c478ce4c7f8813ffa5c0f" + ] + } + } + }, + { + "title": "test laziness and closures", + "filename": "test032_laziness_closures.bc", + "token": [ + { + "symbols": [ + "x", + "p", + "q" + ], + "public_keys": [], + "external_key": null, + "code": "check if !false && true;\ncheck if false || true;\ncheck if (true || false) && true;\ncheck if !(false && \"x\".intersection(\"x\"));\ncheck if true || \"x\".intersection(\"x\");\ncheck if {1, 2, 3}.all($p -> $p > 0);\ncheck if !{1, 2, 3}.all($p -> $p == 2);\ncheck if {1, 2, 3}.any($p -> $p > 2);\ncheck if !{1, 2, 3}.any($p -> $p > 3);\ncheck if {1, 2, 3}.any($p -> $p > 1 && {3, 4, 5}.any($q -> $p == $q));\n" + } + ], + "validations": { + "": { + "world": { + "facts": [], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if !(false && \"x\".intersection(\"x\"))", + "check if !false && true", + "check if !{1, 2, 3}.all($p -> $p == 2)", + "check if !{1, 2, 3}.any($p -> $p > 3)", + "check if (true || false) && true", + "check if false || true", + "check if true || \"x\".intersection(\"x\")", + "check if {1, 2, 3}.all($p -> $p > 0)", + "check if {1, 2, 3}.any($p -> $p > 1 && {3, 4, 5}.any($q -> $p == $q))", + "check if {1, 2, 3}.any($p -> $p > 2)" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "allow if true;\n", + "revocation_ids": [ + "ef75002a071b56293152a4c9eb69ba0793614993e667736a6a92275ddd5aa35a287de5b13acaec72b5af6ba2ee8a3629b1a33cfa51597ae5afbebd8aa35dbe08" + ] + }, + "shadowing": { + "world": { + "facts": [], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if !(false && \"x\".intersection(\"x\"))", + "check if !false && true", + "check if !{1, 2, 3}.all($p -> $p == 2)", + "check if !{1, 2, 3}.any($p -> $p > 3)", + "check if (true || false) && true", + "check if false || true", + "check if true || \"x\".intersection(\"x\")", + "check if {1, 2, 3}.all($p -> $p > 0)", + "check if {1, 2, 3}.any($p -> $p > 1 && {3, 4, 5}.any($q -> $p == $q))", + "check if {1, 2, 3}.any($p -> $p > 2)" + ] + } + ], + "policies": [ + "allow if [true].any($p -> [true].all($p -> $p))" + ] + }, + "result": { + "Err": { + "Execution": "ShadowedVariable" + } + }, + "authorizer_code": "allow if [true].any($p -> [true].all($p -> $p));\n", + "revocation_ids": [ + "ef75002a071b56293152a4c9eb69ba0793614993e667736a6a92275ddd5aa35a287de5b13acaec72b5af6ba2ee8a3629b1a33cfa51597ae5afbebd8aa35dbe08" + ] + } + } + }, + { + "title": "test .type()", + "filename": "test033_typeof.bc", + "token": [ + { + "symbols": [ + "integer", + "string", + "test", + "date", + "bytes", + "bool", + "set", + "null", + "array", + "map", + "a", + "t" + ], + "public_keys": [], + "external_key": null, + "code": "integer(1);\nstring(\"test\");\ndate(2023-12-28T00:00:00Z);\nbytes(hex:aa);\nbool(true);\nset({false, true});\nnull(null);\narray([1, 2, 3]);\nmap({\"a\": true});\ncheck if 1.type() == \"integer\";\ncheck if integer($t), $t.type() == \"integer\";\ncheck if \"test\".type() == \"string\";\ncheck if string($t), $t.type() == \"string\";\ncheck if (2023-12-28T00:00:00Z).type() == \"date\";\ncheck if date($t), $t.type() == \"date\";\ncheck if hex:aa.type() == \"bytes\";\ncheck if bytes($t), $t.type() == \"bytes\";\ncheck if true.type() == \"bool\";\ncheck if bool($t), $t.type() == \"bool\";\ncheck if {false, true}.type() == \"set\";\ncheck if set($t), $t.type() == \"set\";\ncheck if null.type() == \"null\";\ncheck if null($t), $t.type() == \"null\";\ncheck if array($t), $t.type() == \"array\";\ncheck if map($t), $t.type() == \"map\";\n" + } + ], + "validations": { + "": { + "world": { + "facts": [ + { + "origin": [ + 0 + ], + "facts": [ + "array([1, 2, 3])", + "bool(true)", + "bytes(hex:aa)", + "date(2023-12-28T00:00:00Z)", + "integer(1)", + "map({\"a\": true})", + "null(null)", + "set({false, true})", + "string(\"test\")" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if \"test\".type() == \"string\"", + "check if (2023-12-28T00:00:00Z).type() == \"date\"", + "check if 1.type() == \"integer\"", + "check if array($t), $t.type() == \"array\"", + "check if bool($t), $t.type() == \"bool\"", + "check if bytes($t), $t.type() == \"bytes\"", + "check if date($t), $t.type() == \"date\"", + "check if hex:aa.type() == \"bytes\"", + "check if integer($t), $t.type() == \"integer\"", + "check if map($t), $t.type() == \"map\"", + "check if null($t), $t.type() == \"null\"", + "check if null.type() == \"null\"", + "check if set($t), $t.type() == \"set\"", + "check if string($t), $t.type() == \"string\"", + "check if true.type() == \"bool\"", + "check if {false, true}.type() == \"set\"" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "allow if true;\n", + "revocation_ids": [ + "c8f7ff152b40a3e8f3ab19a435ccd16c41288762864022895b99d2abb6330c794b3f1378a4651b31d249f4c35b69246d88124d40e05e634a0eb9ca9e54b1ca0a" + ] + } + } + }, + { + "title": "test array and map operations", + "filename": "test034_array_map.bc", + "token": [ + { + "symbols": [ + "a", + "b", + "c", + "p", + "d", + "A", + "kv", + "id", + "roles" + ], + "public_keys": [], + "external_key": null, + "code": "check if [1, 2, 1].length() == 3;\ncheck if [\"a\", \"b\"] != true;\ncheck if [\"a\", \"b\"] != [1, 2, 3];\ncheck if [\"a\", \"b\"] == [\"a\", \"b\"];\ncheck if [\"a\", \"b\"] === [\"a\", \"b\"];\ncheck if [\"a\", \"b\"] !== [\"a\", \"c\"];\ncheck if [\"a\", \"b\", \"c\"].contains(\"c\");\ncheck if [1, 2, 3].starts_with([1, 2]);\ncheck if [4, 5, 6].ends_with([6]);\ncheck if [1, 2, \"a\"].get(2) == \"a\";\ncheck if [1, 2].get(3) == null;\ncheck if [1, 2, 3].all($p -> $p > 0);\ncheck if [1, 2, 3].any($p -> $p > 2);\ncheck if {\"a\": 1, \"b\": 2, \"c\": 3, \"d\": 4}.length() == 4;\ncheck if {1: \"a\", 2: \"b\"} != true;\ncheck if {1: \"a\", 2: \"b\"} != {\"a\": 1, \"b\": 2};\ncheck if {1: \"a\", 2: \"b\"} == {1: \"a\", 2: \"b\"};\ncheck if {1: \"a\", 2: \"b\"} !== {\"a\": 1, \"b\": 2};\ncheck if {1: \"a\", 2: \"b\"} === {1: \"a\", 2: \"b\"};\ncheck if {\"a\": 1, \"b\": 2, \"c\": 3, \"d\": 4}.contains(\"d\");\ncheck if {1: \"A\", \"a\": 1, \"b\": 2}.get(\"a\") == 1;\ncheck if {1: \"A\", \"a\": 1, \"b\": 2}.get(1) == \"A\";\ncheck if {1: \"A\", \"a\": 1, \"b\": 2}.get(\"c\") == null;\ncheck if {1: \"A\", \"a\": 1, \"b\": 2}.get(2) == null;\ncheck if {\"a\": 1, \"b\": 2}.all($kv -> $kv.get(0) != \"c\" && $kv.get(1) < 3);\ncheck if {1: \"A\", \"a\": 1, \"b\": 2}.any($kv -> $kv.get(0) == 1 && $kv.get(1) == \"A\");\ncheck if {\"user\": {\"id\": 1, \"roles\": [\"admin\"]}}.get(\"user\").get(\"roles\").contains(\"admin\");\n" + } + ], + "validations": { + "": { + "world": { + "facts": [], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if [\"a\", \"b\", \"c\"].contains(\"c\")", + "check if [\"a\", \"b\"] != [1, 2, 3]", + "check if [\"a\", \"b\"] != true", + "check if [\"a\", \"b\"] !== [\"a\", \"c\"]", + "check if [\"a\", \"b\"] == [\"a\", \"b\"]", + "check if [\"a\", \"b\"] === [\"a\", \"b\"]", + "check if [1, 2, \"a\"].get(2) == \"a\"", + "check if [1, 2, 1].length() == 3", + "check if [1, 2, 3].all($p -> $p > 0)", + "check if [1, 2, 3].any($p -> $p > 2)", + "check if [1, 2, 3].starts_with([1, 2])", + "check if [1, 2].get(3) == null", + "check if [4, 5, 6].ends_with([6])", + "check if {\"a\": 1, \"b\": 2, \"c\": 3, \"d\": 4}.contains(\"d\")", + "check if {\"a\": 1, \"b\": 2, \"c\": 3, \"d\": 4}.length() == 4", + "check if {\"a\": 1, \"b\": 2}.all($kv -> $kv.get(0) != \"c\" && $kv.get(1) < 3)", + "check if {\"user\": {\"id\": 1, \"roles\": [\"admin\"]}}.get(\"user\").get(\"roles\").contains(\"admin\")", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.any($kv -> $kv.get(0) == 1 && $kv.get(1) == \"A\")", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.get(\"a\") == 1", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.get(\"c\") == null", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.get(1) == \"A\"", + "check if {1: \"A\", \"a\": 1, \"b\": 2}.get(2) == null", + "check if {1: \"a\", 2: \"b\"} != true", + "check if {1: \"a\", 2: \"b\"} != {\"a\": 1, \"b\": 2}", + "check if {1: \"a\", 2: \"b\"} !== {\"a\": 1, \"b\": 2}", + "check if {1: \"a\", 2: \"b\"} == {1: \"a\", 2: \"b\"}", + "check if {1: \"a\", 2: \"b\"} === {1: \"a\", 2: \"b\"}" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "allow if true;\n", + "revocation_ids": [ + "8041144f92616477f1cd00b81e8be79581202a3853b08b3d477797b0d91f30c02fd7c01ca91a00f8a222d6be4794cc287baa361a1a00d5941518c1917967ec03" + ] + } + } + }, + { + "title": "test ffi calls (v6 blocks)", + "filename": "test035_ffi.bc", + "token": [ + { + "symbols": [ + "test", + "a", + "equal strings" + ], + "public_keys": [], + "external_key": null, + "code": "check if true.extern::test(), \"a\".extern::test(\"a\") == \"equal strings\";\n" + } + ], + "validations": { + "": { + "world": { + "facts": [], + "rules": [], + "checks": [ + { + "origin": 0, + "checks": [ + "check if true.extern::test(), \"a\".extern::test(\"a\") == \"equal strings\"" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "allow if true;\n", + "revocation_ids": [ + "faf26fe6f5dfa08c114a0a29321405b6fb7be79b0d80694d27925f7deb01effe5707600e42fd74f9a1d2920466446d51949155f4548f0fd68f3e9326c7e12404" + ] + } + } + }, + { + "title": "ECDSA secp256r1 signatures", + "filename": "test036_secp256r1.bc", + "token": [ + { + "symbols": [ + "file1", + "file2" + ], + "public_keys": [], + "external_key": null, + "code": "right(\"file1\", \"read\");\nright(\"file2\", \"read\");\nright(\"file1\", \"write\");\n" + }, + { + "symbols": [ + "0" + ], + "public_keys": [], + "external_key": null, + "code": "check if resource($0), operation(\"read\"), right($0, \"read\");\n" + } + ], + "validations": { + "": { + "world": { + "facts": [ + { + "origin": [ + null + ], + "facts": [ + "operation(\"read\")", + "resource(\"file1\")" + ] + }, + { + "origin": [ + 0 + ], + "facts": [ + "right(\"file1\", \"read\")", + "right(\"file1\", \"write\")", + "right(\"file2\", \"read\")" + ] + } + ], + "rules": [], + "checks": [ + { + "origin": 1, + "checks": [ + "check if resource($0), operation(\"read\"), right($0, \"read\")" + ] + } + ], + "policies": [ + "allow if true" + ] + }, + "result": { + "Ok": 0 + }, + "authorizer_code": "resource(\"file1\");\noperation(\"read\");\n\nallow if true;\n", + "revocation_ids": [ + "760785de30d7348e9c847aab8b3bdad6a0d463f4f50ed9667aade563e9112ee6d2f589630dd7553c2eced2a57edf3636d5c874b35df15120c62fddcbdbd2de09", + "30440220039667c7a4d964e4b449289dc8fd206d7aa0e77eb701a9253b3307d32c177fa8022023f7523c143c5fb55ee4cafe49804702ef05a70883ebf42185b54bd36a7e7cd4" + ] + } + } } ] } diff --git a/samples/current/test017_expressions.bc b/samples/current/test017_expressions.bc index 10f5024..7be7a4f 100644 Binary files a/samples/current/test017_expressions.bc and b/samples/current/test017_expressions.bc differ diff --git a/samples/current/test024_third_party.bc b/samples/current/test024_third_party.bc index 7bca415..8b7b864 100644 Binary files a/samples/current/test024_third_party.bc and b/samples/current/test024_third_party.bc differ diff --git a/samples/current/test026_public_keys_interning.bc b/samples/current/test026_public_keys_interning.bc index 49e417b..47b139b 100644 Binary files a/samples/current/test026_public_keys_interning.bc and b/samples/current/test026_public_keys_interning.bc differ diff --git a/samples/current/test027_integer_wraparound.bc b/samples/current/test027_integer_wraparound.bc index 50aa63b..a3a2f71 100644 Binary files a/samples/current/test027_integer_wraparound.bc and b/samples/current/test027_integer_wraparound.bc differ diff --git a/samples/current/test029_reject_if.bc b/samples/current/test029_reject_if.bc new file mode 100644 index 0000000..b118bc8 Binary files /dev/null and b/samples/current/test029_reject_if.bc differ diff --git a/samples/current/test030_null.bc b/samples/current/test030_null.bc new file mode 100644 index 0000000..8adc4fa Binary files /dev/null and b/samples/current/test030_null.bc differ diff --git a/samples/current/test031_heterogeneous_equal.bc b/samples/current/test031_heterogeneous_equal.bc new file mode 100644 index 0000000..442623b Binary files /dev/null and b/samples/current/test031_heterogeneous_equal.bc differ diff --git a/samples/current/test032_laziness_closures.bc b/samples/current/test032_laziness_closures.bc new file mode 100644 index 0000000..dfd0c5b Binary files /dev/null and b/samples/current/test032_laziness_closures.bc differ diff --git a/samples/current/test033_typeof.bc b/samples/current/test033_typeof.bc new file mode 100644 index 0000000..649e254 Binary files /dev/null and b/samples/current/test033_typeof.bc differ diff --git a/samples/current/test034_array_map.bc b/samples/current/test034_array_map.bc new file mode 100644 index 0000000..2fb4394 Binary files /dev/null and b/samples/current/test034_array_map.bc differ diff --git a/samples/current/test035_ffi.bc b/samples/current/test035_ffi.bc new file mode 100644 index 0000000..d5bb3a8 Binary files /dev/null and b/samples/current/test035_ffi.bc differ diff --git a/samples/current/test036_secp256r1.bc b/samples/current/test036_secp256r1.bc new file mode 100644 index 0000000..15a8a42 Binary files /dev/null and b/samples/current/test036_secp256r1.bc differ diff --git a/schema.proto b/schema.proto index bc6cb29..02e9eab 100644 --- a/schema.proto +++ b/schema.proto @@ -14,6 +14,7 @@ message SignedBlock { required PublicKey nextKey = 2; required bytes signature = 3; optional ExternalSignature externalSignature = 4; + optional uint32 version = 5; } message ExternalSignature { @@ -26,6 +27,7 @@ message PublicKey { enum Algorithm { Ed25519 = 0; + SECP256R1 = 1; } required bytes key = 2; @@ -80,6 +82,7 @@ message CheckV2 { enum Kind { One = 0; All = 1; + Reject = 2; } } @@ -97,6 +100,9 @@ message TermV2 { bytes bytes = 5; bool bool = 6; TermSet set = 7; + Empty null = 8; + Array array = 9; + Map map = 10; } } @@ -104,6 +110,26 @@ message TermSet { repeated TermV2 set = 1; } +message Array { + repeated TermV2 array = 1; +} + +message Map { + repeated MapEntry entries = 1; +} + +message MapEntry { + required MapKey key = 1; + required TermV2 value = 2; +} + +message MapKey { + oneof Content { + int64 integer = 1; + uint64 string = 2; + } +} + message ExpressionV2 { repeated Op ops = 1; } @@ -113,6 +139,7 @@ message Op { TermV2 value = 1; OpUnary unary = 2; OpBinary Binary = 3; + OpClosure closure = 4; } } @@ -121,9 +148,12 @@ message OpUnary { Negate = 0; Parens = 1; Length = 2; + TypeOf = 3; + Ffi = 4; } required Kind kind = 1; + optional uint64 ffiName = 2; } message OpBinary { @@ -149,9 +179,23 @@ message OpBinary { BitwiseOr = 18; BitwiseXor = 19; NotEqual = 20; + HeterogeneousEqual = 21; + HeterogeneousNotEqual = 22; + LazyAnd = 23; + LazyOr = 24; + All = 25; + Any = 26; + Get = 27; + Ffi = 28; } required Kind kind = 1; + optional uint64 ffiName = 2; +} + +message OpClosure { + repeated uint32 params = 1; + repeated Op ops = 2; } message Policy { @@ -174,8 +218,10 @@ message AuthorizerPolicies { } message ThirdPartyBlockRequest { - required PublicKey previousKey = 1; - repeated PublicKey publicKeys = 2; + optional PublicKey legacyPreviousKey = 1; + repeated PublicKey legacyPublicKeys = 2; + required bytes previousSignature = 3; + } message ThirdPartyBlockContents { @@ -228,4 +274,4 @@ message SnapshotBlock { repeated CheckV2 checks_v2 = 5; repeated Scope scope = 6; optional PublicKey externalKey = 7; -} \ No newline at end of file +}