Allow registration with invite
This commit is contained in:
parent
01ef4427f5
commit
76f2b818ab
3 changed files with 21 additions and 5 deletions
|
@ -77,6 +77,7 @@ pub const RegistrationInfo = struct {
|
||||||
username: []const u8,
|
username: []const u8,
|
||||||
password: []const u8,
|
password: []const u8,
|
||||||
email: ?[]const u8,
|
email: ?[]const u8,
|
||||||
|
invite_code: ?[]const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const LoginResult = struct {
|
pub const LoginResult = struct {
|
||||||
|
@ -211,7 +212,7 @@ fn ApiConn(comptime DbConn: type) type {
|
||||||
pub fn register(self: *Self, info: RegistrationInfo) !models.Actor {
|
pub fn register(self: *Self, info: RegistrationInfo) !models.Actor {
|
||||||
const actor_id = Uuid.randV4(prng.random());
|
const actor_id = Uuid.randV4(prng.random());
|
||||||
const user_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)) {
|
if (try self.db.existsWhereEq(models.LocalUser, .username, info.username)) {
|
||||||
return error.UsernameUnavailable;
|
return error.UsernameUnavailable;
|
||||||
|
@ -221,10 +222,20 @@ fn ApiConn(comptime DbConn: type) type {
|
||||||
return error.InconsistentDb;
|
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*
|
// use internal alloc because necessary buffer is *big*
|
||||||
var buf: [pw_hash_buf_size]u8 = undefined;
|
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 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{
|
const actor = models.Actor{
|
||||||
.id = actor_id,
|
.id = actor_id,
|
||||||
|
@ -236,6 +247,7 @@ fn ApiConn(comptime DbConn: type) type {
|
||||||
.actor_id = actor_id,
|
.actor_id = actor_id,
|
||||||
.username = info.username,
|
.username = info.username,
|
||||||
.email = info.email,
|
.email = info.email,
|
||||||
|
.invite_id = invite_id,
|
||||||
.hashed_password = hash,
|
.hashed_password = hash,
|
||||||
.password_changed_at = now,
|
.password_changed_at = now,
|
||||||
.created_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.Actor, actor);
|
||||||
try self.db.insert(models.LocalUser, user);
|
try self.db.insert(models.LocalUser, user);
|
||||||
|
|
||||||
// TODO: return token instead
|
|
||||||
return actor;
|
return actor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -151,14 +151,16 @@ pub const Database = struct {
|
||||||
\\CREATE TABLE IF NOT EXISTS
|
\\CREATE TABLE IF NOT EXISTS
|
||||||
\\local_user(
|
\\local_user(
|
||||||
\\ id TEXT NOT NULL,
|
\\ id TEXT NOT NULL,
|
||||||
|
\\ actor_id TEXT,
|
||||||
\\
|
\\
|
||||||
\\ username TEXT NOT NULL,
|
\\ username TEXT NOT NULL,
|
||||||
\\ actor_id TEXT,
|
|
||||||
\\ email TEXT,
|
\\ email TEXT,
|
||||||
|
\\ invite_id TEXT,
|
||||||
|
\\
|
||||||
\\ hashed_password TEXT NOT NULL,
|
\\ hashed_password TEXT NOT NULL,
|
||||||
|
\\ password_changed_at INTEGER NOT NULL,
|
||||||
\\
|
\\
|
||||||
\\ created_at INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
\\ created_at INTEGER NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
\\ password_changed_at INTEGER NOT NULL,
|
|
||||||
\\
|
\\
|
||||||
\\ UNIQUE(actor_id),
|
\\ UNIQUE(actor_id),
|
||||||
\\ FOREIGN KEY(actor_id) REFERENCES actor(id),
|
\\ FOREIGN KEY(actor_id) REFERENCES actor(id),
|
||||||
|
@ -219,6 +221,8 @@ pub const Database = struct {
|
||||||
\\ created_at INTEGER NOT NULL,
|
\\ created_at INTEGER NOT NULL,
|
||||||
\\ expires_at INTEGER
|
\\ expires_at INTEGER
|
||||||
\\) STRICT;
|
\\) STRICT;
|
||||||
|
,
|
||||||
|
\\ALTER TABLE local_user ADD COLUMN invite_id TEXT REFERENCES invite(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init() !Database {
|
pub fn init() !Database {
|
||||||
|
|
|
@ -77,6 +77,7 @@ pub const LocalUser = struct {
|
||||||
|
|
||||||
username: []const u8,
|
username: []const u8,
|
||||||
email: ?[]const u8,
|
email: ?[]const u8,
|
||||||
|
invite_id: ?Ref(Invite),
|
||||||
|
|
||||||
hashed_password: []const u8, // encoded in PHC format, with salt
|
hashed_password: []const u8, // encoded in PHC format, with salt
|
||||||
password_changed_at: DateTime,
|
password_changed_at: DateTime,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue