Skip to content

Commit

Permalink
WIP parser
Browse files Browse the repository at this point in the history
  • Loading branch information
malcolmstill committed Mar 23, 2024
1 parent d876d4c commit 10432f2
Show file tree
Hide file tree
Showing 12 changed files with 89 additions and 25 deletions.
2 changes: 2 additions & 0 deletions biscuit-builder/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ pub fn build(b: *std.Build) void {

const schema = b.dependency("biscuit-schema", .{ .target = target, .optimize = optimize });
const format = b.dependency("biscuit-format", .{ .target = target, .optimize = optimize });
const datalog = b.dependency("biscuit-datalog", .{ .target = target, .optimize = optimize });

_ = b.addModule("biscuit-builder", .{
.root_source_file = .{ .path = "src/root.zig" },
.imports = &.{
.{ .name = "biscuit-schema", .module = schema.module("biscuit-schema") },
.{ .name = "biscuit-format", .module = format.module("biscuit-format") },
.{ .name = "biscuit-datalog", .module = datalog.module("biscuit-datalog") },
},
});

Expand Down
1 change: 1 addition & 0 deletions biscuit-builder/build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
//},
.@"biscuit-schema" = .{ .path = "../biscuit-schema" },
.@"biscuit-format" = .{ .path = "../biscuit-format" },
.@"biscuit-datalog" = .{ .path = "../biscuit-datalog" },
},

// Specifies the set of files and directories that are included in this package.
Expand Down
10 changes: 10 additions & 0 deletions biscuit-builder/src/check.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const std = @import("std");
const datalog = @import("biscuit-datalog");
const Predicate = @import("predicate.zig").Predicate;
const Term = @import("term.zig").Term;

pub const Check = struct {
pub fn deinit(_: Check) void {
//
}
};
8 changes: 6 additions & 2 deletions biscuit-builder/src/fact.zig
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ pub const Fact = struct {
}

/// convert to datalog fact
pub fn convert(_: Fact) datalog.Fact {
unreachable;
pub fn convert(fact: Fact) datalog.Fact {
return .{ .predicate = fact.predicate.convert() };
}

pub fn format(fact: Fact, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
return writer.print("{any}", .{fact.predicate});
}
};
9 changes: 9 additions & 0 deletions biscuit-builder/src/predicate.zig
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,13 @@ pub const Predicate = struct {
pub fn convert(_: Predicate) datalog.Predicate {
unreachable;
}

pub fn format(predicate: Predicate, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
try writer.print("{s}(", .{predicate.name});
for (predicate.terms.items, 0..) |*term, i| {
try writer.print("{any}", .{term.*});
if (i < predicate.terms.items.len - 1) try writer.print(", ", .{});
}
return writer.print(")", .{});
}
};
1 change: 1 addition & 0 deletions biscuit-builder/src/root.zig
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub const Fact = @import("fact.zig").Fact;
pub const Predicate = @import("predicate.zig").Predicate;
pub const Term = @import("term.zig").Term;
pub const Check = @import("check.zig").Check;
2 changes: 2 additions & 0 deletions biscuit-datalog/src/main.zig
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
pub const fact = @import("fact.zig");
pub const Fact = @import("fact.zig").Fact;
pub const predicate = @import("predicate.zig");
pub const Predicate = @import("predicate.zig").Predicate;
pub const rule = @import("rule.zig");
pub const check = @import("check.zig");
pub const symbol_table = @import("symbol_table.zig");
Expand Down
16 changes: 2 additions & 14 deletions biscuit-parser/src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,11 @@ pub const Parser = struct {
return .{ .input = input };
}

pub fn fact(parser: *Parser) !Fact {
return try parser.factPredicate();
pub fn fact(parser: *Parser, allocator: std.mem.Allocator) !Fact {
return try parser.factPredicate(allocator);
}

pub fn factPredicate(parser: *Parser, allocator: std.mem.Allocator) !Fact {
std.debug.print("{s}[0] = {s}\n", .{ @src().fn_name, parser.rest() });
defer std.debug.print("{s}[1] = {s}\n", .{ @src().fn_name, parser.rest() });

const name = parser.readName();

parser.skipWhiteSpace();
Expand Down Expand Up @@ -65,9 +62,6 @@ pub const Parser = struct {
}

pub fn factTerm(parser: *Parser) !Term {
std.debug.print("{s}[0] = {s}\n", .{ @src().fn_name, parser.rest() });
defer std.debug.print("{s}[1] = {s}\n", .{ @src().fn_name, parser.rest() });

const rst = parser.rest();

try parser.reject('$'); // Variables are disallowed in a fact term
Expand Down Expand Up @@ -97,18 +91,12 @@ pub const Parser = struct {
}

fn string(parser: *Parser) ![]const u8 {
std.debug.print("{s}[0] = {s}\n", .{ @src().fn_name, parser.rest() });
defer std.debug.print("{s}[1] = {s}\n", .{ @src().fn_name, parser.rest() });

try parser.expect('"');

return error.ExpectedStringTerm;
}

fn boolean(parser: *Parser) !bool {
std.debug.print("{s}[0] = {s}\n", .{ @src().fn_name, parser.rest() });
defer std.debug.print("{s}[1] = {s}\n", .{ @src().fn_name, parser.rest() });

if (std.mem.startsWith(u8, parser.rest(), "true")) {
parser.offset += "term".len;
return true;
Expand Down
34 changes: 25 additions & 9 deletions biscuit-samples/src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -41,26 +41,26 @@ pub fn main() anyerror!void {
const token = try std.fs.cwd().readFileAlloc(alloc, testcase.filename, 0xFFFFFFF);

for (testcase.validations.map.values()) |validation| {
try validate(alloc, token, public_key, validation.result);
try validate(alloc, token, public_key, validation.result, validation.authorizer_code);
}
}
}

pub fn validate(alloc: mem.Allocator, token: []const u8, public_key: std.crypto.sign.Ed25519.PublicKey, result: Result) !void {
pub fn validate(alloc: mem.Allocator, token: []const u8, public_key: std.crypto.sign.Ed25519.PublicKey, result: Result, authorizer_code: []const u8) !void {
var errors = std.ArrayList(AuthorizerError).init(alloc);
defer errors.deinit();

switch (result) {
.Ok => try runValidation(alloc, token, public_key, &errors),
.Ok => try runValidation(alloc, token, public_key, authorizer_code, &errors),
.Err => |e| {
switch (e) {
.Format => |f| switch (f) {
.InvalidSignatureSize => runValidation(alloc, token, public_key, &errors) catch |err| switch (err) {
.InvalidSignatureSize => runValidation(alloc, token, public_key, authorizer_code, &errors) catch |err| switch (err) {
error.IncorrectBlockSignatureLength => return,
else => return err,
},
.Signature => |s| switch (s) {
.InvalidSignature => runValidation(alloc, token, public_key, &errors) catch |err| switch (err) {
.InvalidSignature => runValidation(alloc, token, public_key, authorizer_code, &errors) catch |err| switch (err) {
error.SignatureVerificationFailed,
error.InvalidEncoding,
=> return,
Expand All @@ -69,7 +69,7 @@ pub fn validate(alloc: mem.Allocator, token: []const u8, public_key: std.crypto.
},
},
.FailedLogic => |f| switch (f) {
.Unauthorized => |u| runValidation(alloc, token, public_key, &errors) catch |err| switch (err) {
.Unauthorized => |u| runValidation(alloc, token, public_key, authorizer_code, &errors) catch |err| switch (err) {
error.AuthorizationFailed => {

// Check that we have expected check failures
Expand Down Expand Up @@ -100,11 +100,11 @@ pub fn validate(alloc: mem.Allocator, token: []const u8, public_key: std.crypto.
},
else => return err,
},
.InvalidBlockRule => runValidation(alloc, token, public_key, &errors) catch |err| switch (err) {
.InvalidBlockRule => runValidation(alloc, token, public_key, authorizer_code, &errors) catch |err| switch (err) {
else => return err,
},
},
.Execution => runValidation(alloc, token, public_key, &errors) catch |err| switch (err) {
.Execution => runValidation(alloc, token, public_key, authorizer_code, &errors) catch |err| switch (err) {
else => return err,
},
}
Expand All @@ -114,12 +114,28 @@ pub fn validate(alloc: mem.Allocator, token: []const u8, public_key: std.crypto.
}
}

pub fn runValidation(alloc: mem.Allocator, token: []const u8, public_key: std.crypto.sign.Ed25519.PublicKey, errors: *std.ArrayList(AuthorizerError)) !void {
pub fn runValidation(alloc: mem.Allocator, token: []const u8, public_key: std.crypto.sign.Ed25519.PublicKey, authorizer_code: []const u8, errors: *std.ArrayList(AuthorizerError)) !void {
var b = try Biscuit.initFromBytes(alloc, token, public_key);
defer b.deinit();

var a = b.authorizer(alloc);
defer a.deinit();

var it = std.mem.split(u8, authorizer_code, ";");
while (it.next()) |code| {
const text = std.mem.trim(u8, code, " ");
if (text.len == 0) continue;

if (std.mem.startsWith(u8, text, "check if") or std.mem.startsWith(u8, text, "check all")) {
// try a.addCheck(text);
} else if (std.mem.startsWith(u8, text, "allow if") or std.mem.startsWith(u8, text, "deny if")) {
// try a.addPolicy(text);
} else if (std.mem.startsWith(u8, text, "revocation_id")) {
//
} else {
try a.addFact(text);
}
}

try a.authorize(errors);
}
4 changes: 4 additions & 0 deletions biscuit/build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,17 @@ pub fn build(b: *std.Build) void {

const schema = b.dependency("biscuit_schema", .{ .target = target, .optimize = optimize });
const format = b.dependency("biscuit_format", .{ .target = target, .optimize = optimize });
const builder = b.dependency("biscuit-builder", .{ .target = target, .optimize = optimize });
const parser = b.dependency("biscuit-parser", .{ .target = target, .optimize = optimize });
const datalog = b.dependency("biscuit_datalog", .{ .target = target, .optimize = optimize });

_ = b.addModule("biscuit", .{
.root_source_file = .{ .path = "src/main.zig" },
.imports = &.{
.{ .name = "biscuit-schema", .module = schema.module("biscuit-schema") },
.{ .name = "biscuit-format", .module = format.module("biscuit-format") },
.{ .name = "biscuit-builder", .module = builder.module("biscuit-builder") },
.{ .name = "biscuit-parser", .module = parser.module("biscuit-parser") },
.{ .name = "biscuit-datalog", .module = datalog.module("biscuit-datalog") },
},
});
Expand Down
2 changes: 2 additions & 0 deletions biscuit/build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@

.biscuit_schema = .{ .path = "../biscuit-schema" },
.biscuit_format = .{ .path = "../biscuit-format" },
.@"biscuit-builder" = .{ .path = "../biscuit-builder" },
.@"biscuit-parser" = .{ .path = "../biscuit-parser" },
.biscuit_datalog = .{ .path = "../biscuit-datalog" },
},

Expand Down
25 changes: 25 additions & 0 deletions biscuit/src/authorizer.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@ const Biscuit = @import("biscuit.zig").Biscuit;
const World = @import("biscuit-datalog").world.World;
const Check = @import("biscuit-datalog").check.Check;
const SymbolTable = @import("biscuit-datalog").symbol_table.SymbolTable;
const Parser = @import("biscuit-parser").Parser;
const builder = @import("biscuit-builder");

pub const Authorizer = struct {
allocator: mem.Allocator,
checks: std.ArrayList(builder.Check),
biscuit: ?Biscuit,
world: World,
symbols: SymbolTable,

pub fn init(allocator: std.mem.Allocator, biscuit: Biscuit) Authorizer {
return .{
.allocator = allocator,
.checks = std.ArrayList(builder.Check).init(allocator),
.biscuit = biscuit,
.world = World.init(allocator),
.symbols = SymbolTable.init(allocator),
Expand All @@ -23,6 +27,27 @@ pub const Authorizer = struct {
pub fn deinit(authorizer: *Authorizer) void {
authorizer.world.deinit();
authorizer.symbols.deinit();

for (authorizer.checks.items) |check| {
check.deinit();
}
authorizer.checks.deinit();
}

pub fn addFact(authorizer: *Authorizer, input: []const u8) !void {
var parser = Parser.init(input);

const fact = try parser.fact(authorizer.allocator);

try authorizer.world.addFact(fact.convert());
}

pub fn addCheck(authorizer: *Authorizer, input: []const u8) void {
var parser = Parser.init(input);

const check = try parser.check();

try authorizer.checks.append(check);
}

/// authorize
Expand Down

0 comments on commit 10432f2

Please sign in to comment.