srctree

Gregory Mullen parent 7228c78f a85c7cd8
remove AnyAuth and promote Provider to cannon type

src/auth.zig added: 114, removed: 111, total 3
@@ -1,8 +1,9 @@
provider: Provider,
current_user: ?User = null,
 
pub const Auth = @This();
pub const User = @import("auth/user.zig");
 
provider: AnyAuth,
current_user: ?User = null,
pub const Provider = @import("auth/provider.zig");
 
pub const Error = error{
UnknownUser,
@@ -22,76 +23,50 @@ pub fn requireValid(a: Auth) error{Unauthenticated}!void {
if (a.current_user == null or !a.valid()) return error.Unauthenticated;
}
 
pub fn Provider(T: type) type {
return struct {
const Self = @This();
ctx: T,
pub const MTLS = struct {
pub fn provider(mtls: *MTLS) Provider {
return Provider{
.ctx = mtls,
.vtable = .{
.valid = validPtr,
.lookup_user = lookupUserPtr,
},
};
}
 
pub fn init(ctx: T) Self {
return .{
.ctx = ctx,
};
}
pub fn valid(mtls: *MTLS) bool {
_ = mtls;
return false;
}
 
/// TODO document the implications of non consttime function
pub fn lookupUser(self: *const Self, user_id: []const u8) Error!User {
return try self.ctx.lookupUser(user_id);
}
fn validPtr(ptr: *anyopaque) bool {
const self: *MTLS = @ptrCast(ptr);
return self.valid();
}
 
pub fn any(self: *const Self) AnyAuth {
return .{
.ctx = self,
.vtable = .{
.valid = null,
.lookup_user = lookupUserUntyped,
},
};
}
pub fn lookupUser(mtls: *MTLS, user_id: []const u8) Error!User {
_ = mtls;
_ = user_id;
return error.UnknownUser;
}
 
pub fn lookupUserPtr(ptr: *anyopaque, user_id: []const u8) Error!User {
const self: *MTLS = @ptrCast(ptr);
return self.lookupUser(user_id);
}
};
 
test MTLS {
//const a = std.testing.allocator;
 
fn lookupUserUntyped(self: *const anyopaque, user_id: []const u8) Error!User {
const typed: *const T = @ptrCast(self);
return typed.lookupUser(user_id);
}
};
}
 
/// Auth VTable
pub const VTable = struct {
lookup_user: ?LookupUserFn,
valid: ?ValidFn,
 
pub const LookupUserFn = *const fn (*const anyopaque, []const u8) Error!User;
pub const ValidFn = *const fn (*const anyopaque) Error!bool;
pub const DefaultEmpty = .{
.lookup_user = null,
.valid = null,
};
};
 
/// Type Erased Version of an auth provider
pub const AnyAuth = struct {
ctx: *const anyopaque,
vtable: VTable,
 
pub fn valid(self: AnyAuth) Error!bool {
if (self.vtable.valid) |v| {
return try v(self.ctx);
} else return error.NotProvided;
}
 
pub fn lookupUser(self: AnyAuth, user_id: []const u8) Error!User {
if (self.vtable.lookup_user) |lookup_fn| {
return try lookup_fn(self.ctx, user_id);
} else return error.NotProvided;
}
};
 
pub const MTLSAuth = struct {};
 
pub const InvalidProvider = struct {
pub fn empty() AnyAuth {
const P = Provider(@This());
return P.init(@This(){}).any();
pub const InvalidAuth = struct {
pub fn provider() Provider {
return Provider{
.ctx = undefined,
.vtable = Provider.VTable.DefaultEmpty,
};
}
 
fn lookupUser(_: @This(), _: []const u8) Error!User {
@@ -118,7 +93,7 @@ const TestingAuth = struct {
return typed.lookupUser(user_id);
}
 
pub fn any(self: *const TestingAuth) AnyAuth {
pub fn provider(self: *TestingAuth) Provider {
return .{
.ctx = self,
.vtable = .{
@@ -130,28 +105,15 @@ const TestingAuth = struct {
};
 
test Provider {
const expected_user = User{
const expected_user = Auth.User{
.username = "testing",
};
 
const ProvidedAuth = Provider(TestingAuth);
const p = ProvidedAuth.init(TestingAuth{});
const user = p.lookupUser("12345");
var t = TestingAuth{};
const provider = t.provider();
const user = provider.lookupUser("12345");
try std.testing.expectEqualDeep(expected_user, user);
const erruser = p.lookupUser("123456");
try std.testing.expectError(error.UnknownUser, erruser);
}
 
test AnyAuth {
const expected_user = User{
.username = "testing",
};
 
var provided = TestingAuth.init().any();
 
const user = provided.lookupUser("12345");
try std.testing.expectEqualDeep(expected_user, user);
const erruser = provided.lookupUser("123456");
const erruser = provider.lookupUser("123456");
try std.testing.expectError(error.UnknownUser, erruser);
}
 
 
filename was Deleted added: 114, removed: 111, total 3
@@ -0,0 +1,38 @@
//! Verse Authentication Provider
//! TODO document!
ctx: *anyopaque,
vtable: VTable,
 
const Provider = @This();
 
pub const VTable = struct {
lookup_user: ?LookupUserFn,
valid: ?ValidFn,
 
pub const LookupUserFn = *const fn (*const anyopaque, []const u8) Auth.Error!Auth.User;
pub const ValidFn = *const fn (*const anyopaque) Auth.Error!bool;
 
pub const DefaultEmpty = .{
.lookup_user = null,
.valid = null,
};
};
 
/// TODO document the implications of non consttime function
pub fn lookupUser(self: *const Provider, user_id: []const u8) Auth.Error!Auth.User {
if (self.vtable.lookup_user) |lookup_fn| {
return try lookup_fn(self.ctx, user_id);
} else return error.NotProvided;
}
 
//pub fn any(self: *const ) AnyAuth {
// return .{
// .ctx = self,
// .vtable = .{
// .valid = null,
// .lookup_user = lookupUserUntyped,
// },
// };
//}
 
const Auth = @import("../auth.zig");
 
src/endpoint.zig added: 114, removed: 111, total 3
@@ -7,8 +7,8 @@ pub const Target = struct {
};
 
pub const Options = struct {
mode: Verse.Server.RunMode = .{ .http = .{} },
auth: Verse.Auth.AnyAuth = .{ .ctx = undefined, .vtable = Verse.Auth.VTable.DefaultEmpty },
mode: Server.RunMode = .{ .http = .{} },
auth: Auth.Provider = Auth.InvalidAuth.provider(),
};
 
pub fn Endpoints(endpoints: anytype) type {
@@ -34,8 +34,8 @@ pub fn Endpoints(endpoints: anytype) type {
try server.serve();
}
 
pub fn route(v: *Verse) !Verse.Router.BuildFn {
return Verse.Router.router(v, &routes);
pub fn route(v: *Verse) !Router.BuildFn {
return Router.router(v, &routes);
}
};
}
@@ -53,12 +53,12 @@ fn routeCount(EP: type) usize {
return count;
}
 
fn buildRoutes(EP: anytype) [routeCount(EP)]Verse.Router.Match {
var match: [routeCount(EP)]Verse.Router.Match = undefined;
fn buildRoutes(EP: anytype) [routeCount(EP)]Router.Match {
var match: [routeCount(EP)]Router.Match = undefined;
var idx: usize = 0;
for (@typeInfo(EP).Struct.decls) |decl| {
if (std.mem.eql(u8, "index", decl.name)) {
match[idx] = Verse.Router.ANY("", EP.index);
match[idx] = Router.ANY("", EP.index);
idx += 1;
}
}
@@ -69,3 +69,6 @@ fn buildRoutes(EP: anytype) [routeCount(EP)]Verse.Router.Match {
const std = @import("std");
const Allocator = std.mem.Allocator;
const Verse = @import("verse.zig");
const Auth = @import("auth.zig");
const Server = @import("server.zig");
const Router = @import("router.zig");
 
src/server.zig added: 114, removed: 111, total 3
@@ -1,18 +1,9 @@
const std = @import("std");
const Allocator = std.mem.Allocator;
 
const Verse = @import("verse.zig");
const Router = @import("router.zig");
 
pub const Server = @This();
 
pub const zWSGI = @import("zwsgi.zig");
pub const Http = @import("http.zig");
 
alloc: Allocator,
router: Router,
interface: Interface,
 
pub const Server = @This();
 
pub const RunModes = enum {
zwsgi,
http,
@@ -34,7 +25,7 @@ pub const Interface = union(RunModes) {
pub const Options = struct {
mode: RunMode = .{ .http = .{} },
router: Router,
auth: Verse.Auth.AnyAuth = .{ .ctx = undefined, .vtable = Verse.Auth.VTable.DefaultEmpty },
auth: Auth.Provider = Auth.InvalidAuth.provider(),
};
 
pub fn init(a: Allocator, opts: Options) !Server {
@@ -60,3 +51,12 @@ pub fn serve(srv: *Server) !void {
test Server {
std.testing.refAllDecls(@This());
}
 
const std = @import("std");
const Allocator = std.mem.Allocator;
 
const Verse = @import("verse.zig");
const Auth = @import("auth.zig");
const Router = @import("router.zig");
pub const zWSGI = @import("zwsgi.zig");
pub const Http = @import("http.zig");
 
src/verse.zig added: 114, removed: 111, total 3
@@ -91,7 +91,7 @@ pub fn init(a: Allocator, req: *const Request) !Verse {
},
.uri = splitScalar(u8, req.uri[1..], '/'),
.auth = Auth{
.provider = Auth.InvalidProvider.empty(),
.provider = Auth.InvalidAuth.provider(),
},
.headers = Headers.init(a),
.cookie_jar = try Cookies.Jar.init(a),