mirror of
https://github.com/Drop-OSS/drop.git
synced 2025-11-14 00:31:25 +10:00
new accounts use argon2
This commit is contained in:
@ -18,6 +18,7 @@
|
|||||||
"@nuxtjs/tailwindcss": "^6.12.2",
|
"@nuxtjs/tailwindcss": "^6.12.2",
|
||||||
"@prisma/client": "^6.1.0",
|
"@prisma/client": "^6.1.0",
|
||||||
"@tailwindcss/vite": "^4.0.6",
|
"@tailwindcss/vite": "^4.0.6",
|
||||||
|
"argon2": "^0.41.1",
|
||||||
"axios": "^1.7.7",
|
"axios": "^1.7.7",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"cookie-es": "^1.2.2",
|
"cookie-es": "^1.2.2",
|
||||||
|
|||||||
@ -7,7 +7,8 @@ model LinkedAuthMec {
|
|||||||
mec AuthMec
|
mec AuthMec
|
||||||
enabled Boolean @default(true)
|
enabled Boolean @default(true)
|
||||||
|
|
||||||
credentials Json
|
credentials Json // TODO: remove this, automate via migration
|
||||||
|
password String?
|
||||||
|
|
||||||
user User @relation(fields: [userId], references: [id])
|
user User @relation(fields: [userId], references: [id])
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
import { AuthMec } from "@prisma/client";
|
import { AuthMec } from "@prisma/client";
|
||||||
import { JsonArray } from "@prisma/client/runtime/library";
|
import { JsonArray } from "@prisma/client/runtime/library";
|
||||||
import prisma from "~/server/internal/db/database";
|
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";
|
import sessionHandler from "~/server/internal/session";
|
||||||
|
|
||||||
export default defineEventHandler(async (h3) => {
|
export default defineEventHandler(async (h3) => {
|
||||||
@ -19,10 +22,20 @@ export default defineEventHandler(async (h3) => {
|
|||||||
const authMek = await prisma.linkedAuthMec.findFirst({
|
const authMek = await prisma.linkedAuthMec.findFirst({
|
||||||
where: {
|
where: {
|
||||||
mec: AuthMec.Simple,
|
mec: AuthMec.Simple,
|
||||||
credentials: {
|
|
||||||
array_starts_with: username,
|
|
||||||
},
|
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
OR: [
|
||||||
|
{
|
||||||
|
// TODO: check if this is even needed with below condition
|
||||||
|
credentials: {
|
||||||
|
array_starts_with: username,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
user: {
|
||||||
|
username,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
user: {
|
user: {
|
||||||
@ -38,24 +51,50 @@ export default defineEventHandler(async (h3) => {
|
|||||||
statusCode: 401,
|
statusCode: 401,
|
||||||
statusMessage: "Invalid username or password.",
|
statusMessage: "Invalid username or password.",
|
||||||
});
|
});
|
||||||
|
else if (!authMek.user.enabled)
|
||||||
const credentials = authMek.credentials as JsonArray;
|
|
||||||
const hash = credentials.at(1);
|
|
||||||
|
|
||||||
if (!hash || !authMek.user.enabled)
|
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: 403,
|
statusCode: 403,
|
||||||
statusMessage:
|
statusMessage:
|
||||||
"Invalid or disabled account. Please contact the server administrator.",
|
"Invalid or disabled account. Please contact the server administrator.",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!(await checkHash(password, hash.toString())))
|
// if using old auth schema
|
||||||
throw createError({
|
if (Array.isArray(authMek.credentials)) {
|
||||||
statusCode: 401,
|
const hash = authMek.credentials.at(1);
|
||||||
statusMessage: "Invalid username or password.",
|
|
||||||
});
|
|
||||||
|
|
||||||
await sessionHandler.setUserId(h3, authMek.userId, rememberMe);
|
if (!hash)
|
||||||
|
throw createError({
|
||||||
|
statusCode: 403,
|
||||||
|
statusMessage:
|
||||||
|
"Invalid password state. Please contact the server administrator.",
|
||||||
|
});
|
||||||
|
|
||||||
return { result: true, userId: authMek.userId };
|
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.",
|
||||||
|
});
|
||||||
|
|
||||||
|
await sessionHandler.setUserId(h3, authMek.userId, rememberMe);
|
||||||
|
|
||||||
|
return { result: true, userId: authMek.userId };
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { AuthMec, Invitation } from "@prisma/client";
|
import { AuthMec, Invitation } from "@prisma/client";
|
||||||
import prisma from "~/server/internal/db/database";
|
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 { v4 as uuidv4 } from "uuid";
|
||||||
import * as jdenticon from "jdenticon";
|
import * as jdenticon from "jdenticon";
|
||||||
import objectHandler from "~/server/internal/objects";
|
import objectHandler from "~/server/internal/objects";
|
||||||
@ -97,6 +97,7 @@ export default defineEventHandler(async (h3) => {
|
|||||||
);
|
);
|
||||||
const user = await prisma.user.create({
|
const user = await prisma.user.create({
|
||||||
data: {
|
data: {
|
||||||
|
id: userId,
|
||||||
username,
|
username,
|
||||||
displayName,
|
displayName,
|
||||||
email,
|
email,
|
||||||
@ -105,12 +106,13 @@ export default defineEventHandler(async (h3) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const hash = await createHash(password);
|
const hash = await createHashArgon2(password);
|
||||||
await prisma.linkedAuthMec.create({
|
await prisma.linkedAuthMec.create({
|
||||||
data: {
|
data: {
|
||||||
mec: AuthMec.Simple,
|
mec: AuthMec.Simple,
|
||||||
credentials: [username, hash],
|
credentials: {},
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
|
password: hash,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -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) {
|
export async function checkHashBcrypt(password: string, hash: string) {
|
||||||
return bcrypt.hashSync(password, rounds);
|
return await bcrypt.compare(password, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function checkHash(password: string, hash: string) {
|
export async function createHashArgon2(password: string) {
|
||||||
return bcrypt.compareSync(password, hash);
|
return await argon2.hash(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function checkHashArgon2(password: string, hash: string) {
|
||||||
|
return await argon2.verify(hash, password);
|
||||||
|
}
|
||||||
|
|||||||
24
yarn.lock
24
yarn.lock
@ -1266,6 +1266,11 @@
|
|||||||
"@parcel/watcher-win32-ia32" "2.5.0"
|
"@parcel/watcher-win32-ia32" "2.5.0"
|
||||||
"@parcel/watcher-win32-x64" "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":
|
"@pkgjs/parseargs@^0.11.0":
|
||||||
version "0.11.0"
|
version "0.11.0"
|
||||||
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
|
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"
|
resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
|
||||||
integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==
|
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:
|
argparse@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
|
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"
|
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558"
|
||||||
integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==
|
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:
|
node-fetch-native@^1.6.3, node-fetch-native@^1.6.4:
|
||||||
version "1.6.4"
|
version "1.6.4"
|
||||||
resolved "https://registry.yarnpkg.com/node-fetch-native/-/node-fetch-native-1.6.4.tgz#679fc8fd8111266d47d7e72c379f1bed9acff06e"
|
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"
|
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.2.tgz#4f802b71c1ab2ca16af830e6c1ea7dd1ad9496fa"
|
||||||
integrity sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==
|
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:
|
node-mock-http@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/node-mock-http/-/node-mock-http-1.0.0.tgz#4b32cd509c7f46d844e68ea93fb8be405a18a42a"
|
resolved "https://registry.yarnpkg.com/node-mock-http/-/node-mock-http-1.0.0.tgz#4b32cd509c7f46d844e68ea93fb8be405a18a42a"
|
||||||
|
|||||||
Reference in New Issue
Block a user