aboutsummaryrefslogtreecommitdiff
path: root/backend/src/repos/users_repo.zig
diff options
context:
space:
mode:
Diffstat (limited to 'backend/src/repos/users_repo.zig')
-rw-r--r--backend/src/repos/users_repo.zig90
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});
+}