new accounts use argon2

This commit is contained in:
Huskydog9988
2025-03-22 17:09:10 -04:00
parent 2027c69c0e
commit 2c9fdebf25
6 changed files with 102 additions and 27 deletions

View File

@ -18,6 +18,7 @@
"@nuxtjs/tailwindcss": "^6.12.2",
"@prisma/client": "^6.1.0",
"@tailwindcss/vite": "^4.0.6",
"argon2": "^0.41.1",
"axios": "^1.7.7",
"bcryptjs": "^2.4.3",
"cookie-es": "^1.2.2",

View File

@ -7,7 +7,8 @@ model LinkedAuthMec {
mec AuthMec
enabled Boolean @default(true)
credentials Json
credentials Json // TODO: remove this, automate via migration
password String?
user User @relation(fields: [userId], references: [id])

View File

@ -1,7 +1,10 @@
import { AuthMec } from "@prisma/client";
import { JsonArray } from "@prisma/client/runtime/library";
import prisma from "~/server/internal/db/database";
import { checkHash } from "~/server/internal/security/simple";
import {
checkHashArgon2,
checkHashBcrypt,
} from "~/server/internal/security/simple";
import sessionHandler from "~/server/internal/session";
export default defineEventHandler(async (h3) => {
@ -19,10 +22,20 @@ export default defineEventHandler(async (h3) => {
const authMek = await prisma.linkedAuthMec.findFirst({
where: {
mec: AuthMec.Simple,
enabled: true,
OR: [
{
// TODO: check if this is even needed with below condition
credentials: {
array_starts_with: username,
},
enabled: true,
},
{
user: {
username,
},
},
],
},
include: {
user: {
@ -38,18 +51,43 @@ export default defineEventHandler(async (h3) => {
statusCode: 401,
statusMessage: "Invalid username or password.",
});
const credentials = authMek.credentials as JsonArray;
const hash = credentials.at(1);
if (!hash || !authMek.user.enabled)
else if (!authMek.user.enabled)
throw createError({
statusCode: 403,
statusMessage:
"Invalid or disabled account. Please contact the server administrator.",
});
if (!(await checkHash(password, hash.toString())))
// if using old auth schema
if (Array.isArray(authMek.credentials)) {
const hash = authMek.credentials.at(1);
if (!hash)
throw createError({
statusCode: 403,
statusMessage:
"Invalid password state. Please contact the server administrator.",
});
if (!(await checkHashBcrypt(password, hash.toString())))
throw createError({
statusCode: 401,
statusMessage: "Invalid username or password.",
});
// TODO: send user to forgot password screen or something to force them to change their password to new system
await sessionHandler.setUserId(h3, authMek.userId, rememberMe);
return { result: true, userId: authMek.userId };
} else {
// using new (modern) login flow
if (authMek.password === null)
throw createError({
statusCode: 500,
statusMessage:
"Invalid password state. Please contact the server administrator.",
});
else if (!(await checkHashArgon2(password, authMek.password)))
throw createError({
statusCode: 401,
statusMessage: "Invalid username or password.",
@ -58,4 +96,5 @@ export default defineEventHandler(async (h3) => {
await sessionHandler.setUserId(h3, authMek.userId, rememberMe);
return { result: true, userId: authMek.userId };
}
});

View File

@ -1,6 +1,6 @@
import { AuthMec, Invitation } from "@prisma/client";
import prisma from "~/server/internal/db/database";
import { createHash } from "~/server/internal/security/simple";
import { createHashArgon2 } from "~/server/internal/security/simple";
import { v4 as uuidv4 } from "uuid";
import * as jdenticon from "jdenticon";
import objectHandler from "~/server/internal/objects";
@ -97,6 +97,7 @@ export default defineEventHandler(async (h3) => {
);
const user = await prisma.user.create({
data: {
id: userId,
username,
displayName,
email,
@ -105,12 +106,13 @@ export default defineEventHandler(async (h3) => {
},
});
const hash = await createHash(password);
const hash = await createHashArgon2(password);
await prisma.linkedAuthMec.create({
data: {
mec: AuthMec.Simple,
credentials: [username, hash],
credentials: {},
userId: user.id,
password: hash,
},
});

View File

@ -1,11 +1,19 @@
import bcrypt from 'bcryptjs';
import bcrypt from "bcryptjs";
import * as argon2 from "argon2";
const rounds = 10;
// const bcryptRounds = 10;
// export async function createHashBcrypt(password: string) {
// return await bcrypt.hash(password, bcryptRounds);
// }
export async function createHash(password: string) {
return bcrypt.hashSync(password, rounds);
export async function checkHashBcrypt(password: string, hash: string) {
return await bcrypt.compare(password, hash);
}
export async function checkHash(password: string, hash: string) {
return bcrypt.compareSync(password, hash);
export async function createHashArgon2(password: string) {
return await argon2.hash(password);
}
export async function checkHashArgon2(password: string, hash: string) {
return await argon2.verify(hash, password);
}

View File

@ -1266,6 +1266,11 @@
"@parcel/watcher-win32-ia32" "2.5.0"
"@parcel/watcher-win32-x64" "2.5.0"
"@phc/format@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@phc/format/-/format-1.0.0.tgz#b5627003b3216dc4362125b13f48a4daa76680e4"
integrity sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==
"@pkgjs/parseargs@^0.11.0":
version "0.11.0"
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
@ -2087,6 +2092,15 @@ arg@^5.0.2:
resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==
argon2@^0.41.1:
version "0.41.1"
resolved "https://registry.yarnpkg.com/argon2/-/argon2-0.41.1.tgz#30ce6b013e273bc7e92c558d40e66d35e5e8c63b"
integrity sha512-dqCW8kJXke8Ik+McUcMDltrbuAWETPyU6iq+4AhxqKphWi7pChB/Zgd/Tp/o8xRLbg8ksMj46F/vph9wnxpTzQ==
dependencies:
"@phc/format" "^1.0.0"
node-addon-api "^8.1.0"
node-gyp-build "^4.8.1"
argparse@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
@ -4958,6 +4972,11 @@ node-addon-api@^7.0.0:
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558"
integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==
node-addon-api@^8.1.0:
version "8.3.1"
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-8.3.1.tgz#53bc8a4f8dbde3de787b9828059da94ba9fd4eed"
integrity sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA==
node-fetch-native@^1.6.3, node-fetch-native@^1.6.4:
version "1.6.4"
resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.4.tgz#679fc8fd8111266d47d7e72c379f1bed9acff06e"
@ -4985,6 +5004,11 @@ node-gyp-build@^4.2.2:
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.2.tgz#4f802b71c1ab2ca16af830e6c1ea7dd1ad9496fa"
integrity sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==
node-gyp-build@^4.8.1:
version "4.8.4"
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.4.tgz#8a70ee85464ae52327772a90d66c6077a900cfc8"
integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==
node-mock-http@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/node-mock-http/-/node-mock-http-1.0.0.tgz#4b32cd509c7f46d844e68ea93fb8be405a18a42a"