X-Git-Url: https://gitweb.ps.run/chirp/blobdiff_plain/c1543f56be31c2d071db75dd7f146e1b5e0de4fe..8ce4f0b76cab1963cd0a8ad55bf5b30b9eae917f:/src/main.zig diff --git a/src/main.zig b/src/main.zig index eeada2b..b016e1b 100644 --- a/src/main.zig +++ b/src/main.zig @@ -4,19 +4,18 @@ const lmdb = @import("lmdb"); // db {{{ const Prng = struct { - prng: std.Random.DefaultPrng = std.Random.DefaultPrng.init(0), + var prng: std.Random.DefaultPrng = std.Random.DefaultPrng.init(0); - pub fn gen_id(self: *Prng, dbi: anytype) Id { - var id = self.prng.next(); + pub fn gen_id(dbi: anytype) Id { + var id = Prng.prng.next(); while (dbi.has(id)) { - id = self.prng.next(); + id = Prng.prng.next(); } return id; } }; -var prng = Prng{}; // }}} @@ -114,116 +113,125 @@ pub fn verify_password(password: []const u8, hash: PasswordHash) bool { pub fn register_user(env: *lmdb.Env, username: []const u8, password: []const u8) !void { const username_array = try Username.fromSlice(username); - var user_id: Id = undefined; - - if (env.txn()) |*txn| { - defer txn.commit(); - if (txn.dbi("users", Id, User)) |users| { - user_id = prng.gen_id(users); - users.put(user_id, User{ - .username = username_array, - .password_hash = try hash_password(password), - }); - } + const txn = try env.txn(); + defer { + txn.commit(); + env.sync(); } - if (env.txn()) |txn| { - defer txn.commit(); - if (txn.dbi("user_ids", @TypeOf(username_array.buffer), Id)) |user_ids| { - user_ids.put(username_array.buffer, user_id); - } - } + const users = try txn.dbi("users", Id, User); + const user_id = Prng.gen_id(users); + users.put(user_id, User{ + .username = username_array, + .password_hash = try hash_password(password), + }); - env.sync(); + const user_ids = try txn.dbi("user_ids", Username, Id); + user_ids.put(username_array, user_id); } -pub fn login_user(env: *lmdb.Env, username: []const u8, password: []const u8) ?SessionToken { - const username_array = Username.fromSlice(username) catch return null; - - var user_id_maybe: ?Id = null; - var user_maybe: ?User = null; +pub fn login_user(env: *lmdb.Env, username: []const u8, password: []const u8) !SessionToken { + const username_array = try Username.fromSlice(username); - if (env.txn()) |txn| { - defer txn.abort(); - if (txn.dbi("user_ids", @TypeOf(username_array.buffer), Id)) |user_ids| { - user_id_maybe = user_ids.get(username_array.buffer); - std.debug.print("id: {?}\n", .{user_id_maybe}); - } + const txn = try env.txn(); + defer { + txn.commit(); + env.sync(); } - if (user_id_maybe) |user_id| { - if (env.txn()) |txn| { - defer txn.abort(); - if (txn.dbi("users", Id, User)) |users| { - user_maybe = users.get(user_id_maybe.?); - } + const user_ids = try txn.dbi("user_ids", Username, Id); + const user_id = user_ids.get(username_array) orelse return error.UnknownUsername; + std.debug.print("id: {}\n", .{user_id}); + + const users = try txn.dbi("users", Id, User); + if (users.get(user_id)) |user| { + if (verify_password(password, user.password_hash)) { + const sessions = try txn.dbi("sessions", Id, Id); + const session_token = Prng.gen_id(sessions); + sessions.put(session_token, user_id); + return session_token; + } else { + return error.IncorrectPassword; } + } else { + return error.UserNotFound; + } +} - if (user_maybe) |user| { - if (verify_password(password, user.password_hash)) { - if (env.txn()) |txn| { - defer txn.commit(); - if (txn.dbi("sessions", Id, Id)) |sessions| { - const session_token = prng.gen_id(sessions); - sessions.put(session_token, user_id); - return session_token; - } - } - } - } +fn logout_user(env: *lmdb.Env, session_token: SessionToken) !void { + const txn = try env.txn(); + defer { + txn.commit(); + env.sync(); } - return null; + const sessions = try txn.dbi("sessions", Id, Id); + sessions.del(session_token); } -fn logout_user(env: *lmdb.Env, session_token: SessionToken) void { - if (env.txn()) |txn| { - defer txn.commit(); - if (txn.dbi("sessions", Id, Id)) |sessions| { - sessions.del(session_token); - } +fn get_session_user(env: *lmdb.Env, session_token: SessionToken) !User { + const txn = try env.txn(); + defer txn.abort(); + + const sessions = try txn.dbi("sessions", Id, Id); + const users = try txn.dbi("users", Id, User); + + if (sessions.get(session_token)) |user_id| { + return users.get(user_id) orelse error.UnknownUser; + } else { + return error.SessionNotFound; } } -fn get_session_user(env: *lmdb.Env, session_token: SessionToken) ?User { - var user_id_maybe: ?Id = null; +// }}} - if (env.txn()) |txn| { - defer txn.abort(); - if (txn.dbi("sessions", Id, Id)) |sessions| { - user_id_maybe = sessions.get(session_token); - } - } +fn list_users(env: *lmdb.Env) !void { + const txn = try env.txn(); + defer txn.abort(); - if (user_id_maybe) |user_id| { - if (env.txn()) |txn| { - defer txn.abort(); - if (txn.dbi("users", Id, User)) |users| { - return users.get(user_id); - } - } + const users = try txn.dbi("users", Id, User); + var cursor = try users.cursor(); + + var key: Id = undefined; + var user_maybe = cursor.get(&key, .First); + + while (user_maybe) |user| { + std.debug.print("[{}] {s}\n", .{ key, user.username.constSlice() }); + + user_maybe = cursor.get(&key, .Next); } +} +fn list_user_ids(env: *lmdb.Env) !void { + const txn = try env.txn(); + defer txn.abort(); - return null; + const user_ids = try txn.dbi("user_ids", Username, Id); + var cursor = try user_ids.cursor(); + + var key: Username = undefined; + var user_id_maybe = cursor.get(&key, .First); + + while (user_id_maybe) |user_id| { + std.debug.print("[{s}] {}\n", .{ key.constSlice(), user_id }); + + user_id_maybe = cursor.get(&key, .Next); + } } -// }}} +fn list_sessions(env: *lmdb.Env) !void { + const txn = try env.txn(); + defer txn.abort(); -fn list_users(env: *lmdb.Env) void { - if (env.txn()) |txn| { - defer txn.abort(); - if (txn.dbi("users", Id, User)) |users| { - var cursor = users.cursor(); + const sessions = try txn.dbi("sessions", SessionToken, Id); + var cursor = try sessions.cursor(); - var key: Id = undefined; - var user_maybe = cursor.get(&key, .First); + var key: SessionToken = undefined; + var user_id_maybe = cursor.get(&key, .First); - while (user_maybe) |user| { - std.debug.print("[{}] {s}\n", .{ key, user.username.constSlice() }); + while (user_id_maybe) |user_id| { + std.debug.print("[{}] {}\n", .{ key, user_id }); - user_maybe = cursor.get(&key, .Next); - } - } + user_id_maybe = cursor.get(&key, .Next); } } @@ -237,10 +245,15 @@ pub fn main() !void { defer server.deinit(); // lmdb - var env = lmdb.Env.open("db", 1024 * 1024 * 10); + var env = lmdb.Env.open("db", 1024 * 100); defer env.close(); - list_users(&env); + std.debug.print("Users:\n", .{}); + try list_users(&env); + std.debug.print("User IDs:\n", .{}); + try list_user_ids(&env); + std.debug.print("Sessions:\n", .{}); + try list_sessions(&env); accept: while (true) { const conn = try server.accept(); @@ -267,6 +280,8 @@ pub fn main() !void { .user = user, .session_token = session_token, }; + } else |err| { + std.debug.print("get_session_user err: {}\n", .{err}); } // TODO: delete session token // TODO: add changeable headers (set, delete cookies) @@ -339,12 +354,13 @@ pub fn main() !void { .{ .name = "Set-Cookie", .value = cookie_buffer.constSlice() }, }, }); - } else { + } else |err| { + std.debug.print("login_user err: {}\n", .{err}); try redirect(&req, "/login"); } } else if (std.mem.eql(u8, req.head.target, "/logout")) { if (logged_in) |login| { - logout_user(&env, login.session_token); + try logout_user(&env, login.session_token); try req.respond("", .{ .status = .see_other, .extra_headers = &.{