Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

parser fixes and API usability changes #94

Merged
merged 11 commits into from
May 1, 2024
5 changes: 5 additions & 0 deletions src/main/java/org/biscuitsec/biscuit/datalog/SymbolTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,11 @@ public SymbolTable(SymbolTable s) {
publicKeys.addAll(s.publicKeys);
}

public SymbolTable(List<String> symbols) {
this.symbols = new ArrayList<>(symbols);
this.publicKeys = new ArrayList<>();
}

public SymbolTable(List<String> symbols, List<PublicKey> publicKeys) {
this.symbols = new ArrayList<>();
this.symbols.addAll(symbols);
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/org/biscuitsec/biscuit/token/Block.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,12 @@ public String print(SymbolTable symbol_table) {
s.append("\n\t\texternal key: ");
s.append(this.externalKey.get().toString());
}
s.append("\n\t\tfacts: [");
s.append("\n\t\tscopes: [");
for (Scope scope : this.scopes) {
s.append("\n\t\t\t");
s.append(symbol_table.print_scope(scope));
}
s.append("\n\t\t]\n\t\tfacts: [");
for (Fact f : this.facts) {
s.append("\n\t\t\t");
s.append(symbol_table.print_fact(f));
Expand Down
31 changes: 30 additions & 1 deletion src/main/java/org/biscuitsec/biscuit/token/builder/Block.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public class Block {
List<Rule> rules;
List<Check> checks;
List<Scope> scopes;
List<PublicKey> publicKeys;
Option<PublicKey> externalKey;

public Block(long index, SymbolTable base_symbols) {
this.index = index;
Expand All @@ -43,6 +45,33 @@ public Block(long index, SymbolTable base_symbols) {
this.rules = new ArrayList<>();
this.checks = new ArrayList<>();
this.scopes = new ArrayList<>();
this.publicKeys = new ArrayList<>();
this.externalKey = Option.none();
}

public Block setExternalKey(Option<PublicKey> externalKey) {
this.externalKey = externalKey;
return this;
}

public Block addPublicKey(PublicKey publicKey) {
this.publicKeys.add(publicKey);
return this;
}

public Block addPublicKeys(List<PublicKey> publicKeys) {
this.publicKeys.addAll(publicKeys);
return this;
}

public Block setPublicKeys(List<PublicKey> publicKeys) {
this.publicKeys = publicKeys;
return this;
}

public Block addSymbol(String symbol) {
this.symbols.add(symbol);
return this;
}

public Block add_fact(org.biscuitsec.biscuit.token.builder.Fact f) {
Expand Down Expand Up @@ -124,7 +153,7 @@ public org.biscuitsec.biscuit.token.Block build() {
SchemaVersion schemaVersion = new SchemaVersion(this.facts, this.rules, this.checks, this.scopes);

return new org.biscuitsec.biscuit.token.Block(symbols, this.context, this.facts, this.rules, this.checks,
this.scopes, publicKeys, Option.none(), schemaVersion.version());
this.scopes, publicKeys, this.externalKey, schemaVersion.version());
}

public Block check_right(String right) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,43 +306,57 @@ public static Either<Error, Tuple2<String, Expression>> expr7(String s) {
return Either.left(res1.getLeft());
}
Tuple2<String, Expression> t1 = res1.get();
s = space(t1._1);
Expression e1 = t1._2;

if(!s.startsWith(".")) {
return Either.right(new Tuple2<>(s, e1));
}
s = s.substring(1);

Either<Error, Tuple2<String, Expression.Op>> res2 = binary_op7(s);
if (res2.isLeft()) {
return Either.left(res2.getLeft());
}
Tuple2<String, Expression.Op> t2 = res2.get();
s = space(t2._1);
Expression.Op op = t2._2;

if(!s.startsWith("(")) {
return Either.left(new Error(s, "missing ("));
}

s = space(s.substring(1));
s = t1._1;
Expression e = t1._2;

Either<Error, Tuple2<String, Expression>> res3 = expr(s);
if (res3.isLeft()) {
return Either.left(res3.getLeft());
}
while(true) {
s = space(s);
if(s.isEmpty()) {
break;
}

Tuple2<String, Expression> t3 = res3.get();
if (!s.startsWith(".")) {
return Either.right(new Tuple2<>(s, e));
}

s = space(t3._1);
if(!s.startsWith(")")) {
return Either.left(new Error(s, "missing )"));
s = s.substring(1);
Either<Error, Tuple2<String, Expression.Op>> res2 = binary_op7(s);
if (!res2.isLeft()) {
Tuple2<String, Expression.Op> t2 = res2.get();
s = space(t2._1);
Expression.Op op = t2._2;

if (!s.startsWith("(")) {
return Either.left(new Error(s, "missing ("));
}

s = space(s.substring(1));

Either<Error, Tuple2<String, Expression>> res3 = expr_term(s);
if (res3.isLeft()) {
return Either.left(res3.getLeft());
}

Tuple2<String, Expression> t3 = res3.get();

s = space(t3._1);
if (!s.startsWith(")")) {
return Either.left(new Error(s, "missing )"));
}
s = space(s.substring(1));
Expression e2 = t3._2;

e = new Expression.Binary(op, e, e2);
} else {
if (s.startsWith("length()")) {
e = new Expression.Unary(Expression.Op.Length, e);
s = s.substring(9);
}
}
}
s = space(s.substring(1));
Expression e2 = t3._2;

return Either.right(new Tuple2<>(s, new Expression.Binary(op, e1, e2)));
return Either.right(new Tuple2<>(s, e));
}

public static Either<Error, Tuple2<String, Expression>> expr_term(String s) {
Expand Down Expand Up @@ -517,6 +531,12 @@ public static Either<Error, Tuple2<String, Expression.Op>> binary_op6(String s)
}

public static Either<Error, Tuple2<String, Expression.Op>> binary_op7(String s) {
if(s.startsWith("intersection")) {
return Either.right(new Tuple2<>(s.substring(12), Expression.Op.Intersection));
}
if(s.startsWith("union")) {
return Either.right(new Tuple2<>(s.substring(5), Expression.Op.Union));
}
if(s.startsWith("contains")) {
return Either.right(new Tuple2<>(s.substring(8), Expression.Op.Contains));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package org.biscuitsec.biscuit.token.builder.parser;

import biscuit.format.schema.Schema;
import io.vavr.collection.Stream;
import org.biscuitsec.biscuit.crypto.PublicKey;
import org.biscuitsec.biscuit.datalog.SymbolTable;
import org.biscuitsec.biscuit.token.Policy;
import io.vavr.Tuple2;
import io.vavr.Tuple4;
Expand All @@ -10,9 +12,7 @@

import java.time.OffsetDateTime;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.HashSet;
import java.util.*;
import java.util.function.Function;

public class Parser {
Expand Down Expand Up @@ -524,14 +524,14 @@ public static Either<Error, Tuple2<String, Term.Integer>> integer(String s) {
return Either.left(new Error(s, "not an integer"));
}

Integer i = Integer.parseInt(s.substring(0, index2));
long i = Long.parseLong(s.substring(0, index2));
String remaining = s.substring(index2);

return Either.right(new Tuple2<String, Term.Integer>(remaining, (Term.Integer) Utils.integer(i.intValue())));
return Either.right(new Tuple2<String, Term.Integer>(remaining, (Term.Integer) Utils.integer(i)));
}

public static Either<Error, Tuple2<String, Term.Date>> date(String s) {
Tuple2<String, String> t = take_while(s, (c) -> c != ' ' && c != ',' && c != ')');
Tuple2<String, String> t = take_while(s, (c) -> c != ' ' && c != ',' && c != ')' && c != ']');

try {
OffsetDateTime d = OffsetDateTime.parse(t._1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.biscuitsec.biscuit.datalog.SymbolTable;
import org.biscuitsec.biscuit.datalog.TemporarySymbolTable;
import org.biscuitsec.biscuit.datalog.expressions.Op;
import org.biscuitsec.biscuit.token.Biscuit;
import org.biscuitsec.biscuit.token.builder.parser.Error;
import org.biscuitsec.biscuit.token.builder.parser.Parser;
import io.vavr.Tuple2;
Expand All @@ -15,7 +16,7 @@
import org.junit.jupiter.api.Test;

import static org.biscuitsec.biscuit.datalog.Check.Kind.One;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.*;

import java.util.*;

Expand Down Expand Up @@ -132,6 +133,43 @@ void testRuleWithExpressionOrdering() {
res);
}

@Test
void expressionIntersectionAndContainsTest() {
Either<Error, Tuple2<String, Expression>> res =
Parser.expression("[1, 2, 3].intersection([1, 2]).contains(1)");

assertEquals(Either.right(new Tuple2<>("",
new Expression.Binary(
Expression.Op.Contains,
new Expression.Binary(
Expression.Op.Intersection,
new Expression.Value(Utils.set(new HashSet<>(Arrays.asList(Utils.integer(1), Utils.integer(2), Utils.integer(3))))),
new Expression.Value(Utils.set(new HashSet<>(Arrays.asList(Utils.integer(1), Utils.integer(2)))))
),
new Expression.Value(Utils.integer(1))
))), res);
}

@Test
void expressionIntersectionAndContainsAndLengthEqualsTest() {
Either<Error, Tuple2<String, Expression>> res =
Parser.expression("[1, 2, 3].intersection([1, 2]).length() == 2");

assertEquals(Either.right(new Tuple2<>("",
new Expression.Binary(
Expression.Op.Equal,
new Expression.Unary(
Expression.Op.Length,
new Expression.Binary(
Expression.Op.Intersection,
new Expression.Value(Utils.set(new HashSet<>(Arrays.asList(Utils.integer(1), Utils.integer(2), Utils.integer(3))))),
new Expression.Value(Utils.set(new HashSet<>(Arrays.asList(Utils.integer(1), Utils.integer(2)))))
)
),
new Expression.Value(Utils.integer(2))
))), res);
}

@Test
void ruleWithFreeExpressionVariables() {
Either<Error, Tuple2<String, Rule>> res =
Expand Down
24 changes: 24 additions & 0 deletions src/test/java/org/biscuitsec/biscuit/datalog/ExpressionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;

public class ExpressionTest {

Expand Down Expand Up @@ -114,4 +115,27 @@ public void testNegativeContainsStr() throws Error.Execution {
e.evaluate(new HashMap<>(), new TemporarySymbolTable(symbols))
);
}

@Test
public void testIntersectionAndContains() throws Error.Execution {
SymbolTable symbols = new SymbolTable();

Expression e = new Expression(new ArrayList<Op>(Arrays.asList(
new Op.Value(new Term.Set(new HashSet<>(Arrays.asList(new Term.Integer(1), new Term.Integer(2), new Term.Integer(3))))),
new Op.Value(new Term.Set(new HashSet<>(Arrays.asList(new Term.Integer(1), new Term.Integer(2))))),
new Op.Binary(Op.BinaryOp.Intersection),
new Op.Value(new Term.Integer(1)),
new Op.Binary(Op.BinaryOp.Contains)
)));

assertEquals(
"[1, 2, 3].intersection([1, 2]).contains(1)",
e.print(symbols).get()
);

assertEquals(
new Term.Bool(true),
e.evaluate(new HashMap<>(), new TemporarySymbolTable(symbols))
);
}
}
Loading
Loading