Allow registration with invite

This commit is contained in:
jaina heartles 2022-07-26 22:30:52 -07:00
parent 01ef4427f5
commit 76f2b818ab
3 changed files with 21 additions and 5 deletions

View file

@ -77,6 +77,7 @@ pub const RegistrationInfo = struct {
username: []const u8,
password: []const u8,
email: ?[]const u8,
invite_code: ?[]const u8,
};
pub const LoginResult = struct {
@ -211,7 +212,7 @@ fn ApiConn(comptime DbConn: type) type {
pub fn register(self: *Self, info: RegistrationInfo) !models.Actor {
const actor_id = Uuid.randV4(prng.random());
const user_id = Uuid.randV4(prng.random());
// TODO: transaction?
// TODO: lock for transaction
if (try self.db.existsWhereEq(models.LocalUser, .username, info.username)) {
return error.UsernameUnavailable;
@ -221,10 +222,20 @@ fn ApiConn(comptime DbConn: type) type {
return error.InconsistentDb;
}
const now = DateTime.now();
const invite_id = if (info.invite_code) |invite_code| blk: {
const invite = (try self.db.getBy(models.Invite, .invite_code, invite_code, self.arena.allocator())) orelse return error.InvalidInvite;
const uses_left = if (invite.max_uses) |max_uses| invite.uses < max_uses else true;
const expired = if (invite.expires_at) |expires_at| now.seconds_since_epoch > expires_at.seconds_since_epoch else false;
if (!uses_left or expired) return error.InvalidInvite;
// TODO: increment uses
break :blk invite.id;
} else null;
// use internal alloc because necessary buffer is *big*
var buf: [pw_hash_buf_size]u8 = undefined;
const hash = try PwHash.strHash(info.password, .{ .allocator = self.internal_alloc, .params = pw_hash_params, .encoding = pw_hash_encoding }, &buf);
const now = DateTime.now();
const actor = models.Actor{
.id = actor_id,
@ -236,6 +247,7 @@ fn ApiConn(comptime DbConn: type) type {
.actor_id = actor_id,
.username = info.username,
.email = info.email,
.invite_id = invite_id,
.hashed_password = hash,
.password_changed_at = now,
.created_at = now,
@ -243,7 +255,6 @@ fn ApiConn(comptime DbConn: type) type {
try self.db.insert(models.Actor, actor);
try self.db.insert(models.LocalUser, user);
// TODO: return token instead
return actor;
}

View file

@ -151,14 +151,16 @@ pub const Database = struct {
\\CREATE TABLE IF NOT EXISTS
\\local_user(
\\ id TEXT NOT NULL,
\\ actor_id TEXT,
\\
\\ username TEXT NOT NULL,
\\ actor_id TEXT,
\\ email TEXT,
\\ invite_id TEXT,
\\
\\ hashed_password TEXT NOT NULL,
\\ password_changed_at INTEGER NOT NULL,
\\
\\ created_at INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP,
\\ password_changed_at INTEGER NOT NULL,
\\
\\ UNIQUE(actor_id),
\\ FOREIGN KEY(actor_id) REFERENCES actor(id),
@ -219,6 +221,8 @@ pub const Database = struct {
\\ created_at INTEGER NOT NULL,
\\ expires_at INTEGER
\\) STRICT;
,
\\ALTER TABLE local_user ADD COLUMN invite_id TEXT REFERENCES invite(id);
};
pub fn init() !Database {

View file

@ -77,6 +77,7 @@ pub const LocalUser = struct {
username: []const u8,
email: ?[]const u8,
invite_id: ?Ref(Invite),
hashed_password: []const u8, // encoded in PHC format, with salt
password_changed_at: DateTime,