From e8ff326f0e5bd61fb0a8c22c48f296fcf0249830 Mon Sep 17 00:00:00 2001 From: Nathan Reiner Date: Sat, 15 Nov 2025 11:54:00 +0100 Subject: backend implement auth-service --- src/storage/root.zig | 9 ++++- src/storage/session-manager/root.zig | 59 +++++++++++++++++++++++++++++++++ src/storage/session-manager/session.zig | 34 +++++++++++++++++++ src/storage/user.zig | 36 +++++++++++++++++--- 4 files changed, 133 insertions(+), 5 deletions(-) create mode 100644 src/storage/session-manager/root.zig create mode 100644 src/storage/session-manager/session.zig (limited to 'src/storage') diff --git a/src/storage/root.zig b/src/storage/root.zig index bf9803e..f1a753c 100644 --- a/src/storage/root.zig +++ b/src/storage/root.zig @@ -3,10 +3,14 @@ const config = @import("../config.zig"); const prompt = @import("../prompt.zig"); pub const User = @import("user.zig"); +pub const SessionManager = @import("session-manager/root.zig"); +pub const Session = SessionManager.Session; const Self = @This(); dir: std.fs.Dir, +sessions: SessionManager = .empty, +allocator: std.mem.Allocator, pub fn init(allocator: std.mem.Allocator) !Self { const dir = std.fs.cwd().openDir(config.storage_path, .{}) catch blk: { @@ -14,7 +18,10 @@ pub fn init(allocator: std.mem.Allocator) !Self { break :blk try std.fs.cwd().openDir(config.storage_path, .{}); }; - var self = Self { .dir = dir }; + var self = Self { + .dir = dir, + .allocator = allocator, + }; dir.access("user", .{}) catch |err| switch (err) { error.FileNotFound => { diff --git a/src/storage/session-manager/root.zig b/src/storage/session-manager/root.zig new file mode 100644 index 0000000..7f44bf0 --- /dev/null +++ b/src/storage/session-manager/root.zig @@ -0,0 +1,59 @@ +const std = @import("std"); +const config = @import("../../config.zig"); +const Storage = @import("../root.zig"); + +pub const Session = @import("session.zig"); + +const Self = @This(); + +pub const empty: Self = .{ + .cache = .empty, +}; + +cache: std.StringHashMapUnmanaged(Session), + +pub fn add(self: *Self, storage: *Storage, info: Storage.User.Info) !*Session { + const session = try Session.init(storage.allocator, info); + errdefer session.deinit(storage.allocator); + try self.cache.put(storage.allocator, session.fingerprint, session); + return self.cache.getPtr(session.fingerprint) orelse unreachable; +} + +pub fn renew(self: *Self, storage: *Storage, fingerprint: []const u8) !*Session { + if (self.cache.get(fingerprint)) |s| { + var session = s; + try session.reset(); + + try self.cache.put(storage.allocator, session.fingerprint, session); + + _ = self.cache.remove(fingerprint); + + return self.cache.getPtr(session.fingerprint) orelse unreachable; + } + return error.SessionNotFound; +} + +pub fn remove(self: *Self, storage: *Storage, fingerprint: []const u8) void { + if (self.cache.getPtr(fingerprint)) |session| { + session.deinit(storage.allocator); + _ = self.cache.remove(fingerprint); + } +} + +pub fn get(self: *Self, storage: *Storage, fingerprint: []const u8) ?*Session { + if (self.cache.getPtr(fingerprint)) |session| { + const now = std.time.Instant.now() catch return null; + const since = now.since(session.age); + + if (since > config.session_expires_after) { + std.debug.print("here\n", .{}); + session.deinit(storage.allocator); + _ = self.cache.remove(fingerprint); + return null; + } + + return session; + } + + return null; +} diff --git a/src/storage/session-manager/session.zig b/src/storage/session-manager/session.zig new file mode 100644 index 0000000..943334b --- /dev/null +++ b/src/storage/session-manager/session.zig @@ -0,0 +1,34 @@ +const std = @import("std"); +const User = @import("../user.zig"); + +const Self = @This(); + +const fingerprint_size = 512; + +age: std.time.Instant, +info: User.Info, +fingerprint: []u8, + +pub fn init(allocator: std.mem.Allocator, info: User.Info) !Self { + var self: Self = undefined; + self.info = try info.clone(allocator); + self.fingerprint = try allocator.alloc(u8, fingerprint_size); + try self.reset(); + + return self; +} + +pub fn reset(self: *Self) !void { + var raw_buffer: [fingerprint_size / 2]u8 = undefined; + std.crypto.random.bytes(&raw_buffer); + + var writer = std.Io.Writer.fixed(self.fingerprint); + writer.print("{x}", .{raw_buffer}) catch unreachable; + + self.age = try std.time.Instant.now(); +} + +pub fn deinit(self: *const Self, allocator: std.mem.Allocator) void { + self.info.deinit(allocator); + allocator.free(self.fingerprint); +} diff --git a/src/storage/user.zig b/src/storage/user.zig index c981661..4170fd1 100644 --- a/src/storage/user.zig +++ b/src/storage/user.zig @@ -3,16 +3,44 @@ const Storage = @import("root.zig"); const Self = @This(); -pub const UserInfo = struct { +pub const Info = struct { name: []const u8, full_name: []const u8, birthday: []const u8, hash: []const u8, is_admin: bool, + + pub fn clone(self: *const @This(), allocator: std.mem.Allocator) !@This() { + var clone_self: @This() = undefined; + var i: usize = 0; + + inline for (std.meta.fields(@This())) |field_info| { + if (field_info.type == []const u8) { + @field(clone_self, field_info.name) = try allocator.dupe( + u8, + @field(self, field_info.name), + ); + errdefer allocator.free(@field(clone_self, field_info.name)); + } else { + @field(clone_self, field_info.name) = @field(self, field_info.name); + } + i += 1; + } + + return clone_self; + } + + pub fn deinit(self: *const @This(), allocator: std.mem.Allocator) void { + inline for (std.meta.fields(@This())) |field_info| { + if (field_info.type == []const u8) { + allocator.free(@field(self, field_info.name)); + } + } + } }; dir: std.fs.Dir, -info: UserInfo, +info: Info, arena: std.heap.ArenaAllocator, pub fn open( @@ -34,7 +62,7 @@ pub fn open( defer file.close(); const content = try file.readToEndAlloc(allocator, std.math.maxInt(usize)); - const info = try std.json.parseFromSliceLeaky(UserInfo, allocator, content, .{}); + const info = try std.json.parseFromSliceLeaky(Info, allocator, content, .{}); return .{ .dir = dir, @@ -79,7 +107,7 @@ pub fn new( hash_buf ); - const info: UserInfo = .{ + const info: Info = .{ .name = name, .full_name = full_name, .birthday = birthday, -- cgit v1.2.3-70-g09d2