diff --git a/prisma/schema/auth.prisma b/prisma/schema/auth.prisma index 8e003d2..bf862dd 100644 --- a/prisma/schema/auth.prisma +++ b/prisma/schema/auth.prisma @@ -7,8 +7,7 @@ model LinkedAuthMec { mec AuthMec enabled Boolean @default(true) - credentials Json // TODO: remove this, automate via migration - password String? + credentials Json user User @relation(fields: [userId], references: [id]) diff --git a/server/api/v1/auth/signin/simple.post.ts b/server/api/v1/auth/signin/simple.post.ts index 281e7b5..68ed174 100644 --- a/server/api/v1/auth/signin/simple.post.ts +++ b/server/api/v1/auth/signin/simple.post.ts @@ -1,9 +1,11 @@ import { AuthMec } from "@prisma/client"; import { JsonArray } from "@prisma/client/runtime/library"; +import { type } from "arktype"; import prisma from "~/server/internal/db/database"; import { checkHashArgon2, checkHashBcrypt, + simpleAuth, } from "~/server/internal/security/simple"; import sessionHandler from "~/server/internal/session"; @@ -23,19 +25,9 @@ export default defineEventHandler(async (h3) => { where: { mec: AuthMec.Simple, enabled: true, - OR: [ - { - // TODO: check if this is even needed with below condition - credentials: { - array_starts_with: username, - }, - }, - { - user: { - username, - }, - }, - ], + user: { + username, + }, }, include: { user: { @@ -81,13 +73,18 @@ export default defineEventHandler(async (h3) => { } else { // using new (modern) login flow - if (authMek.password === null) + const creds = simpleAuth(authMek.credentials); + if (creds instanceof type.errors) { + // hover out.summary to see validation errors + console.error(creds.summary); + throw createError({ - statusCode: 500, - statusMessage: - "Invalid password state. Please contact the server administrator.", + statusCode: 400, + statusMessage: creds.summary, }); - else if (!(await checkHashArgon2(password, authMek.password))) + } + + if (!(await checkHashArgon2(password, creds.password))) throw createError({ statusCode: 401, statusMessage: "Invalid username or password.", diff --git a/server/api/v1/auth/signup/simple.post.ts b/server/api/v1/auth/signup/simple.post.ts index 4d31cf7..b854f0d 100644 --- a/server/api/v1/auth/signup/simple.post.ts +++ b/server/api/v1/auth/signup/simple.post.ts @@ -1,6 +1,10 @@ import { AuthMec, Invitation } from "@prisma/client"; import prisma from "~/server/internal/db/database"; -import { createHashArgon2 } from "~/server/internal/security/simple"; +import { + createHashArgon2, + simpleAuth, + SimpleAuthType, +} from "~/server/internal/security/simple"; import { v4 as uuidv4 } from "uuid"; import * as jdenticon from "jdenticon"; import objectHandler from "~/server/internal/objects"; @@ -67,13 +71,16 @@ export default defineEventHandler(async (h3) => { [`internal:read`, `${userId}:write`] ); - const hash = await createHashArgon2(user.password); + const creds: SimpleAuthType = { + version: "v1.0.0", + password: await createHashArgon2(user.password), + }; + const [linkMec] = await prisma.$transaction([ prisma.linkedAuthMec.create({ data: { mec: AuthMec.Simple, - credentials: {}, - password: hash, + credentials: creds, user: { create: { id: userId, diff --git a/server/internal/security/simple.ts b/server/internal/security/simple.ts index 6482299..5d5f7db 100644 --- a/server/internal/security/simple.ts +++ b/server/internal/security/simple.ts @@ -1,10 +1,13 @@ import bcrypt from "bcryptjs"; import * as argon2 from "argon2"; +import { type } from "arktype"; -// const bcryptRounds = 10; -// export async function createHashBcrypt(password: string) { -// return await bcrypt.hash(password, bcryptRounds); -// } +export const simpleAuth = type({ + version: "string.semver", + password: "string", +}); + +export type SimpleAuthType = typeof simpleAuth.infer; export async function checkHashBcrypt(password: string, hash: string) { return await bcrypt.compare(password, hash);