/*
CREATE TABLE user (
id TEXT NOT NULL PRIMARY KEY,
email_address TEXT NOT NULL UNIQUE,
password_hash BLOB NOT NULL,
password_salt BLOB NOT NULL,
password_hash_algorithm_id TEXT NOT NULL,
disabled INTEGER NOT NULL DEFAULT 0,
email_address_counter INTEGER NOT NULL DEFAULT 0,
password_hash_counter INTEGER NOT NULL DEFAULT 0,
disabled_counter INTEGER NOT NULL DEFAULT 0,
sessions_counter INTEGER NOT NULL DEFAULT 0
) STRICT;
*/
import * as faroe_user_server from "@faroe/user-server";
const actions: faroe_user_server.Actions = {
async createUserAction(_actionInvocationId, emailAddress, passwordHash, passwordHashAlgorithmId, passwordSalt) {
const id = generateId(); // TODO
try {
await db.execute(
"INSERT INTO user (id, email_address, password_hash, password_hash_algorithm_id, password_salt) VALUES (?, ?, ?, ?, ?)",
[
id,
emailAddress,
passwordHash,
passwordHashAlgorithmId,
passwordSalt,
]
);
} catch (error: unknown) {
// TODO
if (error is uniqueConstraintFailedError) {
throw new faroe_user_server.ActionError("email_address_already_used");
}
throw new faroe_user_server.ActionError("unexpected_error");
}
const user: faroe_user_server.User = {
id,
emailAddress,
passwordHash,
passwordHashAlgorithmId,
passwordSalt,
disabled: false,
displayName: emailAddress,
emailAddressCounter: 0,
passwordHashCounter: 0,
disabledCounter: 0,
sessionsCounter: 0,
};
return user;
},
async getUserAction(_actionInvocationId, userId) {
let result: QueryResult;
try {
result = await db.execute(
"SELECT email_address, password_hash, password_hash_algorithm_id, password_salt, disabled, email_address_counter, password_hash_counter, disabled_counter, sessions_counter FROM user WHERE id = ?",
[userId]
);
} catch {
throw new faroe_user_server.ActionError("unexpected_error");
}
if (result.rows.length === 0) {
throw new faroe_user_server.ActionError("user_not_found");
}
const row = result.rows[0];
const user: faroe_user_server.User = {
id: userId,
emailAddress: row[0],
passwordHash: row[1],
passwordHashAlgorithmId: row[2],
passwordSalt: row[3],
disabled: row[4],
displayName: "",
emailAddressCounter: row[5],
passwordHashCounter: row[6],
disabledCounter: row[7],
sessionsCounter: row[8],
};
return user;
},
async getUserByEmailAddressAction(_actionInvocationId, emailAddress) {
let result: QueryResult;
try {
result = await db.execute(
"SELECT id, password_hash, password_hash_algorithm_id, password_salt, disabled, email_address_counter, password_hash_counter, disabled_counter, sessions_counter FROM user WHERE email_address = ?",
[emailAddress]
);
} catch {
throw new faroe_user_server.ActionError("unexpected_error");
}
if (result.rows.length === 0) {
throw new faroe_user_server.ActionError("user_not_found");
}
const row = result.rows[0];
const user: faroe_user_server.User = {
id: row[0],
emailAddress: emailAddress,
passwordHash: row[1],
passwordHashAlgorithmId: row[2],
passwordSalt: row[3],
disabled: row[4],
displayName: "",
emailAddressCounter: row[5],
passwordHashCounter: row[6],
disabledCounter: row[7],
sessionsCounter: row[8],
};
return user;
},
async updateUserEmailAddressAction(_actionInvocationId, userId, emailAddress, userEmailAddressCounter) {
let result;
try {
result = await db.execute(
"UPDATE user SET email_address = ?, email_address_counter = email_address_counter + 1 WHERE id = ? AND email_address_counter = ?",
[emailAddress, userId, userEmailAddressCounter]
);
} catch {
throw new faroe_user_server.ActionError("unexpected_error");
}
if (result.changes === 0) {
throw new faroe_user_server.ActionError("user_not_found");
}
},
async updateUserPasswordHashAction(_actionInvocationId, userId, passwordHash, passwordHashAlgorithmId, passwordSalt, userPasswordHashCounter) {
let result;
try {
result = await db.execute(
"UPDATE user SET password_hash = ?, password_hash_algorithm_id = ?, password_salt = ?, password_hash_counter = password_hash_counter + 1 WHERE id = ? AND password_hash_counter = ?",
[
passwordHash,
passwordHashAlgorithmId,
passwordSalt,
userId,
userPasswordHashCounter,
]
);
} catch {
throw new faroe_user_server.ActionError("unexpected_error");
}
if (result.changes === 0) {
throw new faroe_user_server.UserNotFoundError();
}
},
async incrementUserSessionsCounterAction(_actionInvocationId, userId, userSessionsCounter) {
let result;
try {
result = await db.execute(
"UPDATE user SET sessions_counter = sessions_counter + 1 WHERE id = ? AND sessions_counter = ?",
[userId, userSessionsCounter]
);
} catch {
throw new faroe_user_server.ActionError("unexpected_error");
}
if (result.changes === 0) {
throw new faroe_user_server.ActionError("user_not_found");
}
},
async deleteUserAction(_actionInvocationId, userId) {
let result;
try {
result = await db.execute("DELETE FROM user WHERE id = ?", [
userId,
]);
} catch {
throw new faroe_user_server.ActionError("unexpected_error");
}
if (result.changes === 0) {
throw new faroe_user_server.ActionError("user_not_found");
}
},
};