diff --git a/src/api/methods/auth.zig b/src/api/methods/auth.zig index 757a3b0..ade047e 100644 --- a/src/api/methods/auth.zig +++ b/src/api/methods/auth.zig @@ -4,11 +4,17 @@ const types = @import("../types.zig"); const Uuid = util.Uuid; const DateTime = util.DateTime; -const RegistrationOptions = @import("../lib.zig").RegistrationOptions; const UserResponse = @import("../lib.zig").UserResponse; const Invite = @import("../lib.zig").Invite; pub const Token = types.Token; +pub const RegistrationOptions = struct { + invite_code: ?[]const u8 = null, + email: ?[]const u8 = null, +}; + +pub const AccountCreateOptions = @import("../services/accounts.zig").CreateOptions; + pub fn methods(comptime models: type) type { return struct { fn isInviteValid(invite: Invite) bool { @@ -33,7 +39,7 @@ pub fn methods(comptime models: type) type { if (self.context.community.kind == .admin) @panic("Unimplmented"); - const user_id = try models.auth.register( + const user_id = try createLocalAccount( tx, username, password, @@ -63,6 +69,28 @@ pub fn methods(comptime models: type) type { return user; } + fn createLocalAccount( + db: anytype, + username: []const u8, + password: []const u8, + community_id: Uuid, + opt: AccountCreateOptions, + alloc: std.mem.Allocator, + ) !Uuid { + const tx = try db.beginOrSavepoint(); + errdefer tx.rollback(); + + const hash = try hashPassword(password, alloc); + defer alloc.free(hash); + + const id = try models.actors.create(tx, username, community_id, false, alloc); + try models.accounts.create(tx, id, hash, opt, alloc); + + try tx.commitOrRelease(); + + return id; + } + pub fn login(self: anytype, username: []const u8, password: []const u8) !Token { const community_id = self.context.community.id; const credentials = try models.accounts.getCredentialsByUsername( @@ -137,6 +165,20 @@ fn verifyPassword( }; } +fn hashPassword(password: []const u8, alloc: std.mem.Allocator) ![]const u8 { + const buf = try alloc.alloc(u8, password_hash_len); + errdefer alloc.free(buf); + return scrypt.strHash( + password, + .{ + .allocator = alloc, + .params = scrypt.Params.interactive, + .encoding = .phc, + }, + buf, + ) catch error.HashFailure; +} + /// A raw token is a sequence of N random bytes, base64 encoded. /// When the token is generated: /// - The hash of the token is calculated by: diff --git a/src/main/controllers/web.zig b/src/main/controllers/web.zig index d6e5a39..342ff31 100644 --- a/src/main/controllers/web.zig +++ b/src/main/controllers/web.zig @@ -169,7 +169,7 @@ const signup = struct { error.UsernameEmpty => "Username cannot be empty", error.UsernameContainsInvalidChar => "Username must be composed of alphanumeric characters and underscore", error.UsernameTooLong => "Username too long", - error.PasswordTooShort => "Password too short, must be at least 12 chars", + //error.PasswordTooShort => "Password too short, must be at least 12 chars", error.UsernameTaken => blk: { status = .unprocessable_entity;