diff options
Diffstat (limited to 'backend/src/repos/users_repo.zig')
-rw-r--r-- | backend/src/repos/users_repo.zig | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/backend/src/repos/users_repo.zig b/backend/src/repos/users_repo.zig new file mode 100644 index 0000000..0f4ea82 --- /dev/null +++ b/backend/src/repos/users_repo.zig @@ -0,0 +1,90 @@ +const std = @import("std"); +const zqlite = @import("zqlite"); +const bcrypt = std.crypto.pwhash.bcrypt; +const rand = std.crypto.random; + +const token_length: usize = 20; + +pub const User = struct { + email: []const u8, + name: []const u8, +}; + +pub fn get_user(allocator: std.mem.Allocator, conn: zqlite.Conn, login_token: []const u8) !?User { + const query = + \\SELECT email, name + \\FROM users + \\WHERE login_token = ? + ; + + if (try conn.row(query, .{login_token})) |row| { + defer row.deinit(); + return User{ + .email = try allocator.dupe(u8, row.text(0)), + .name = try allocator.dupe(u8, row.text(1)), + }; + } else { + return null; + } +} + +pub fn check_password(allocator: std.mem.Allocator, conn: zqlite.Conn, email: []const u8, password: []const u8) !?User { + const query = + \\SELECT password_hash, email, name + \\FROM users + \\WHERE email = ? + ; + + if (try conn.row(query, .{email})) |row| { + defer row.deinit(); + const hash = row.text(0); + const verify_options = bcrypt.VerifyOptions{ .silently_truncate_password = false }; + std.time.sleep(100000000 + rand.intRangeAtMost(u32, 0, 100000000)); + bcrypt.strVerify(hash, password, verify_options) catch { + return null; + }; + return User{ + .email = try allocator.dupe(u8, row.text(1)), + .name = try allocator.dupe(u8, row.text(2)), + }; + } else { + std.time.sleep(500000000 + rand.intRangeAtMost(u32, 0, 500000000)); + return null; + } +} + +pub fn generate_login_token(allocator: std.mem.Allocator, conn: zqlite.Conn, email: []const u8) ![]const u8 { + const query = + \\UPDATE users + \\SET login_token = ?, updated_at = datetime() + \\WHERE email = ? + ; + + const token = try random_token(allocator); + try conn.exec(query, .{ token, email }); + return token; +} + +fn random_token(allocator: std.mem.Allocator) ![]const u8 { + // Generate random bytes + var bytes: [token_length]u8 = undefined; + rand.bytes(&bytes); + + // Encode as base64 + const Encoder = std.base64.standard.Encoder; + const encoded_length = Encoder.calcSize(token_length); + const token = try allocator.alloc(u8, encoded_length); + _ = Encoder.encode(token, &bytes); + + return token; +} + +pub fn remove_login_token(conn: zqlite.Conn, email: []const u8) !void { + const query = + \\ UPDATE users + \\ SET login_token = NULL, updated_at = datetime() + \\ WHERE email = ? + ; + + try conn.exec(query, .{email}); +} |