fix(shared/auth/icon): Fixed lots of small things
Icons: Fixed docker-compose to force JWT_SECRET for now Auth: Fixed Guest Login to actually work Auth: Added `Login as Guest` in the login_demo page Shared: Fixed db/user + uuid modules
This commit is contained in:
parent
5306ccfc60
commit
2074f8d8f1
6 changed files with 51 additions and 11 deletions
|
|
@ -41,6 +41,7 @@ services:
|
|||
- images-volume:/volumes/store
|
||||
- sqlite-volume:/volumes/database
|
||||
environment:
|
||||
- JWT_SECRET=KRUGKIDROVUWG2ZAMJZG653OEBTG66BANJ2W24DTEBXXMZLSEB2GQZJANRQXU6JA
|
||||
- USER_ICONS_STORE=/volumes/store
|
||||
- DATABASE_DIR=/volumes/database
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { Database, SqliteReturn } from './_base';
|
|||
import { Otp } from '@shared/auth';
|
||||
import { isNullish } from '@shared/utils';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import { UUID } from 'uuidv7';
|
||||
import { UUID, newUUID } from '@shared/utils/uuid';
|
||||
|
||||
// never use this directly
|
||||
|
||||
|
|
@ -56,12 +56,13 @@ export const UserImpl: Omit<IUserDb, keyof Database> = {
|
|||
*
|
||||
* @returns The user struct
|
||||
*/
|
||||
async createUser(this: IUserDb, name: string, password: string | undefined): Promise<User | undefined> {
|
||||
async createUser(this: IUserDb, name: string, password: string | undefined, guest: boolean = false): Promise<User | undefined> {
|
||||
password = await hashPassword(password);
|
||||
const id = newUUID();
|
||||
return userFromRow(
|
||||
this.prepare(
|
||||
'INSERT OR FAIL INTO user (name, password) VALUES (@name, @password) RETURNING *',
|
||||
).get({ name, password }) as (Partial<User> | undefined),
|
||||
'INSERT OR FAIL INTO user (id, name, password, guest) VALUES (@id, @name, @password, @guest) RETURNING *',
|
||||
).get({ id, name, password, guest: guest ? 1 : 0 }) as (Partial<User> | undefined),
|
||||
);
|
||||
},
|
||||
|
||||
|
|
@ -110,6 +111,7 @@ export type User = {
|
|||
readonly name: string;
|
||||
readonly password?: string;
|
||||
readonly otp?: string;
|
||||
readonly guest: boolean;
|
||||
};
|
||||
|
||||
export async function verifyUserPassword(
|
||||
|
|
@ -148,10 +150,12 @@ function userFromRow(row?: Partial<User>): User | undefined {
|
|||
if (isNullish(row)) return undefined;
|
||||
if (isNullish(row.id)) return undefined;
|
||||
if (isNullish(row.name)) return undefined;
|
||||
if (isNullish(row.guest)) return undefined;
|
||||
return {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
password: row.password ?? undefined,
|
||||
otp: row.otp ?? undefined,
|
||||
guest: !!(row.guest ?? true),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
22
src/@shared/src/utils/uuid.ts
Normal file
22
src/@shared/src/utils/uuid.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import * as uuidv7 from 'uuidv7';
|
||||
|
||||
export type UUID = `${string}-${string}-${string}-${string}-${string}` & { readonly __brand: unique symbol };
|
||||
export default UUID;
|
||||
|
||||
export function newUUID(): UUID {
|
||||
return uuidv7.uuidv7() as UUID;
|
||||
}
|
||||
|
||||
export function isUUID(s: string): s is UUID {
|
||||
try {
|
||||
uuidv7.UUID.parse(s);
|
||||
return true;
|
||||
}
|
||||
catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function parseUUID(s: string): UUID {
|
||||
return uuidv7.UUID.parse(s).toString() as UUID;
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
<br />
|
||||
<br />
|
||||
<button id="b-login">Login</button>
|
||||
<button id="b-login-guest">Login as Guest</button>
|
||||
<br />
|
||||
<button id="b-logout">Logout</button>
|
||||
<br />
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ const iOtp = document.querySelector('#i-otp');
|
|||
|
||||
const bOtpSend = document.querySelector('#b-otpSend');
|
||||
const bLogin = document.querySelector('#b-login');
|
||||
const bLoginGuest = document.querySelector('#b-login-guest');
|
||||
const bLogout = document.querySelector('#b-logout');
|
||||
const bSignin = document.querySelector('#b-signin');
|
||||
const bWhoami = document.querySelector('#b-whoami');
|
||||
|
|
@ -27,6 +28,16 @@ function setResponse(obj) {
|
|||
}
|
||||
let otpToken = null;
|
||||
|
||||
bLoginGuest.addEventListener('click', async () => {
|
||||
const res = await fetch('/api/auth/guest', { method: 'POST' });
|
||||
const json = await res.json();
|
||||
|
||||
setResponse(json);
|
||||
if (json.kind === 'success') {
|
||||
if (json?.payload?.token) {document.cookie = `token=${json?.payload?.token}`;}
|
||||
}
|
||||
});
|
||||
|
||||
bOtpSend.addEventListener('click', async () => {
|
||||
const res = await fetch('/api/auth/otp', { method: 'POST', body: JSON.stringify({ code: iOtp.value, token: otpToken }), headers });
|
||||
const json = await res.json();
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ import { Static, Type } from '@sinclair/typebox';
|
|||
import { typeResponse, makeResponse, isNullish } from '@shared/utils';
|
||||
|
||||
export const GuestLoginRes = Type.Union([
|
||||
typeResponse('failed', 'login.failed.generic'),
|
||||
typeResponse('success', 'login.success', {
|
||||
typeResponse('failed', ['guestLogin.failed.generic.unknown', 'guestLogin.failed.generic.error']),
|
||||
typeResponse('success', 'guestLogin.success', {
|
||||
token: Type.String({
|
||||
description: 'JWT that represent a logged in user',
|
||||
}),
|
||||
|
|
@ -38,14 +38,15 @@ const route: FastifyPluginAsync = async (fastify, _opts): Promise<void> => {
|
|||
true,
|
||||
);
|
||||
if (isNullish(user)) {
|
||||
return makeResponse('failed', 'login.failed.generic');
|
||||
return makeResponse('failed', 'guestLogin.failed.generic.unknown');
|
||||
}
|
||||
return makeResponse('success', 'login.success', {
|
||||
token: this.signJwt('auth', user.id),
|
||||
return makeResponse('success', 'guestLogin.success', {
|
||||
token: this.signJwt('auth', user.id.toString()),
|
||||
});
|
||||
}
|
||||
catch {
|
||||
return makeResponse('failed', 'login.failed.generic');
|
||||
catch (e: unknown) {
|
||||
fastify.log.error(e);
|
||||
return makeResponse('failed', 'guestLogin.failed.generic.error');
|
||||
}
|
||||
},
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue