diff --git a/server/.vscode/settings.json b/server/.vscode/settings.json index 87ca8efb..e426a5e1 100644 --- a/server/.vscode/settings.json +++ b/server/.vscode/settings.json @@ -1,18 +1,21 @@ { - "spellchecker.ignoreWordsList": [ - "mTLS", - "Wireguard" - ], - "sqltools.connections": [ - { - "previewLimit": 50, - "server": "localhost", - "port": 5432, - "driver": "PostgreSQL", - "name": "drop", - "database": "drop", - "username": "drop", - "password": "drop" - } - ] + "spellchecker.ignoreWordsList": ["mTLS", "Wireguard"], + "sqltools.connections": [ + { + "previewLimit": 50, + "server": "localhost", + "port": 5432, + "driver": "PostgreSQL", + "name": "drop", + "database": "drop", + "username": "drop", + "password": "drop" + } + ], + // allow autocomplete for ArkType expressions like "string | num" + "editor.quickSuggestions": { + "strings": "on" + }, + // prioritize ArkType's "type" for autoimports + "typescript.preferences.autoImportSpecifierExcludeRegexes": ["^(node:)?os$"] } diff --git a/server/README.md b/server/README.md index d23a0e2d..55bedacd 100644 --- a/server/README.md +++ b/server/README.md @@ -32,16 +32,18 @@ To just deploy Drop, we've set up a simple docker compose file in deploy-templat 3. Edit the compose.yml file (`nano compose.yml`) and copy your GiamtBomb API Key into the GIANT_BOMB_API_KEY environment variable 4. Run `docker compose up -d` -Your drop server should now be running. To register the admin user, navigate to http://your.drop.server.ip:3000/register?id=admin +Your drop server should now be running. To register the admin user, navigate to http://your.drop.server.ip:3000/register?id=admin and fill in the required forms ### Adding a game + To add a game to the drop library, do as follows: + 1. Ensure that the current user owns the library folder with `sudo chown -R $(id -u $(whoami)) library` 2. `cd library` 3. `mkdir ` with the name of the game which you would like to register 4. `cd ` -5. `mkdir ` Upload files for the specific game version to this folder +5. `mkdir ` Upload files for the specific game version to this folder 6. Navigate to http://your.drop.server.ip:3000/ 7. Import game metadata (uses GiantBomb API Key) by selecting the game and specifying which entry to import 8. Navigate to http://your.drop.server.ip:3000/admin/library @@ -73,7 +75,7 @@ Steps: As part of the first-time bootstrap, Drop creates an invitation with the fixed id of 'admin'. So, to create an admin account, go to: -http://localhost:3000/register?id=admin +http://localhost:3000/auth/register?id=admin ## Contributing diff --git a/server/components/UserHeader/UserWidget.vue b/server/components/UserHeader/UserWidget.vue index 9513045d..3e8d29b4 100644 --- a/server/components/UserHeader/UserWidget.vue +++ b/server/components/UserHeader/UserWidget.vue @@ -85,7 +85,7 @@ const navigation: NavigationItem[] = [ }, { label: "Sign out", - route: "/signout", + route: "/auth/signout", prefix: "", }, ].filter((e) => e !== undefined); diff --git a/server/error.vue b/server/error.vue index 24ecfda1..d75c957f 100644 --- a/server/error.vue +++ b/server/error.vue @@ -16,7 +16,7 @@ const showSignIn = statusCode ? statusCode == 403 || statusCode == 401 : false; async function signIn() { clearError({ - redirect: `/signin?redirect=${encodeURIComponent(route.fullPath)}`, + redirect: `/auth/signin?redirect=${encodeURIComponent(route.fullPath)}`, }); } diff --git a/server/middleware/require-user.global.ts b/server/middleware/require-user.global.ts index 8ec3fa33..dbe218cc 100644 --- a/server/middleware/require-user.global.ts +++ b/server/middleware/require-user.global.ts @@ -1,4 +1,4 @@ -const whitelistedPrefixes = ["/signin", "/register", "/api", "/setup"]; +const whitelistedPrefixes = ["/auth/signin", "/register", "/api", "/setup"]; const requireAdmin = ["/admin"]; export default defineNuxtRouteMiddleware(async (to, from) => { @@ -13,7 +13,10 @@ export default defineNuxtRouteMiddleware(async (to, from) => { await updateUser(); } if (!user.value) { - return navigateTo({ path: "/signin", query: { redirect: to.fullPath } }); + return navigateTo({ + path: "/auth/signin", + query: { redirect: to.fullPath }, + }); } if ( requireAdmin.findIndex((e) => to.fullPath.startsWith(e)) != -1 && diff --git a/server/package.json b/server/package.json index 5a1a2d0f..e3064592 100644 --- a/server/package.json +++ b/server/package.json @@ -19,6 +19,8 @@ "@nuxtjs/tailwindcss": "^6.12.2", "@prisma/client": "^6.1.0", "@tailwindcss/vite": "^4.0.6", + "argon2": "^0.41.1", + "arktype": "^2.1.10", "axios": "^1.7.7", "bcryptjs": "^2.4.3", "cookie-es": "^1.2.2", @@ -31,6 +33,7 @@ "nuxt-security": "2.2.0", "prisma": "^6.1.0", "sanitize-filename": "^1.6.3", + "sharp": "^0.33.5", "stream": "^0.0.3", "stream-mime-type": "^2.0.0", "turndown": "^7.2.0", diff --git a/server/pages/register.vue b/server/pages/auth/register.vue similarity index 94% rename from server/pages/register.vue rename to server/pages/auth/register.vue index c16390f3..5574ab44 100644 --- a/server/pages/register.vue +++ b/server/pages/auth/register.vue @@ -188,6 +188,7 @@ diff --git a/server/server/api/v1/auth/signin/simple.post.ts b/server/server/api/v1/auth/signin/simple.post.ts index db0ad358..481c2809 100644 --- a/server/server/api/v1/auth/signin/simple.post.ts +++ b/server/server/api/v1/auth/signin/simple.post.ts @@ -1,7 +1,12 @@ import { AuthMec } from "@prisma/client"; import { JsonArray } from "@prisma/client/runtime/library"; +import { type } from "arktype"; import prisma from "~/server/internal/db/database"; -import { checkHash } from "~/server/internal/security/simple"; +import { + checkHashArgon2, + checkHashBcrypt, + simpleAuth, +} from "~/server/internal/security/simple"; import sessionHandler from "~/server/internal/session"; export default defineEventHandler(async (h3) => { @@ -19,10 +24,10 @@ export default defineEventHandler(async (h3) => { const authMek = await prisma.linkedAuthMec.findFirst({ where: { mec: AuthMec.Simple, - credentials: { - array_starts_with: username, - }, enabled: true, + user: { + username, + }, }, include: { user: { @@ -38,24 +43,56 @@ 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()))) - throw createError({ - statusCode: 401, - statusMessage: "Invalid username or password.", - }); + // if using old auth schema + if (Array.isArray(authMek.credentials)) { + const hash = authMek.credentials.at(1)?.toString(); - 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))) + 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 + + const creds = simpleAuth(authMek.credentials); + if (creds instanceof type.errors) { + // hover out.summary to see validation errors + console.error(creds.summary); + + throw createError({ + statusCode: 403, + statusMessage: + "Invalid password state. Please contact the server administrator.", + }); + } + + if (!(await checkHashArgon2(password, creds.password))) + throw createError({ + statusCode: 401, + statusMessage: "Invalid username or password.", + }); + + await sessionHandler.setUserId(h3, authMek.userId, rememberMe); + + return { result: true, userId: authMek.userId }; + } }); diff --git a/server/server/api/v1/auth/signup/simple.post.ts b/server/server/api/v1/auth/signup/simple.post.ts index 895ec514..b854f0d5 100644 --- a/server/server/api/v1/auth/signup/simple.post.ts +++ b/server/server/api/v1/auth/signup/simple.post.ts @@ -1,12 +1,22 @@ import { AuthMec, Invitation } from "@prisma/client"; import prisma from "~/server/internal/db/database"; -import { createHash } 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"; +import { type } from "arktype"; +import { writeNonLiteralDefaultMessage } from "arktype/internal/parser/shift/operator/default.ts"; -// Only really a simple test, in case people mistype their emails -const mailRegex = /^\S+@\S+\.\S+$/; +const userValidator = type({ + username: "string >= 5", + email: "string.email", + password: "string >= 14", + "displayName?": "string | undefined", +}); export default defineEventHandler(async (h3) => { const body = await readBody(h3); @@ -27,59 +37,24 @@ export default defineEventHandler(async (h3) => { statusMessage: "Invalid or expired invitation.", }); - const useInvitationOrBodyRequirement = ( - field: keyof Invitation, - check: (v: string) => boolean - ) => { - if (invitation[field]) { - return invitation[field].toString(); - } + const user = userValidator(body); + if (user instanceof type.errors) { + // hover out.summary to see validation errors + console.error(user.summary); - const v: string = body[field]?.toString(); - const valid = check(v); - return valid ? v : undefined; - }; - - const username = useInvitationOrBodyRequirement( - "username", - (e) => e.length >= 5 - ); - const email = useInvitationOrBodyRequirement("email", (e) => - mailRegex.test(e) - ); - const password = body.password; - const displayName = body.displayName || username; - - if (username === undefined) throw createError({ statusCode: 400, - statusMessage: "Username is invalid. Must be more than 5 characters.", - }); - if (username.toLowerCase() != username) - throw createError({ - statusCode: 400, - statusMessage: "Username must be all lowercase", + statusMessage: user.summary, }); + } - if (email === undefined) - throw createError({ - statusCode: 400, - statusMessage: "Invalid email. Must follow the format you@example.com", - }); + // reuse items from invite + if (invitation.username !== null) user.username = invitation.username; + if (invitation.email !== null) user.email = invitation.email; - if (!password) - throw createError({ - statusCode: 400, - statusMessage: "Password empty or missing.", - }); - - if (password.length < 14) - throw createError({ - statusCode: 400, - statusMessage: "Password must be 14 or more characters.", - }); - - const existing = await prisma.user.count({ where: { username: username } }); + const existing = await prisma.user.count({ + where: { username: user.username }, + }); if (existing > 0) throw createError({ statusCode: 400, @@ -91,30 +66,38 @@ export default defineEventHandler(async (h3) => { const profilePictureId = uuidv4(); await objectHandler.createFromSource( profilePictureId, - async () => jdenticon.toPng(username, 256), + async () => jdenticon.toPng(user.username, 256), {}, [`internal:read`, `${userId}:write`] ); - const user = await prisma.user.create({ - data: { - username, - displayName, - email, - profilePicture: profilePictureId, - admin: invitation.isAdmin, - }, - }); - const hash = await createHash(password); - await prisma.linkedAuthMec.create({ - data: { - mec: AuthMec.Simple, - credentials: [username, hash], - userId: user.id, - }, - }); + const creds: SimpleAuthType = { + version: "v1.0.0", + password: await createHashArgon2(user.password), + }; - await prisma.invitation.delete({ where: { id: invitationId } }); + const [linkMec] = await prisma.$transaction([ + prisma.linkedAuthMec.create({ + data: { + mec: AuthMec.Simple, + credentials: creds, + user: { + create: { + id: userId, + username: user.username, + displayName: user.displayName ?? user.username, + email: user.email, + profilePicture: profilePictureId, + admin: invitation.isAdmin, + }, + }, + }, + select: { + user: true, + }, + }), + prisma.invitation.delete({ where: { id: invitationId } }), + ]); - return user; + return linkMec.user; }); diff --git a/server/server/internal/security/simple.ts b/server/server/internal/security/simple.ts index 9494d7ff..5d5f7db1 100644 --- a/server/server/internal/security/simple.ts +++ b/server/server/internal/security/simple.ts @@ -1,11 +1,22 @@ -import bcrypt from 'bcryptjs'; +import bcrypt from "bcryptjs"; +import * as argon2 from "argon2"; +import { type } from "arktype"; -const rounds = 10; +export const simpleAuth = type({ + version: "string.semver", + password: "string", +}); -export async function createHash(password: string) { - return bcrypt.hashSync(password, rounds); +export type SimpleAuthType = typeof simpleAuth.infer; + +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); -} \ No newline at end of file +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); +} diff --git a/server/server/plugins/redirect.ts b/server/server/plugins/redirect.ts index 9ef78e30..a8751535 100644 --- a/server/server/plugins/redirect.ts +++ b/server/server/plugins/redirect.ts @@ -18,7 +18,7 @@ export default defineNitroPlugin((nitro) => { if (userId) break; return sendRedirect( event, - `/signin?redirect=${encodeURIComponent(event.path)}` + `/auth/signin?redirect=${encodeURIComponent(event.path)}` ); } }); diff --git a/server/server/routes/signout.get.ts b/server/server/routes/signout.get.ts index 9706df9c..b1158df4 100644 --- a/server/server/routes/signout.get.ts +++ b/server/server/routes/signout.get.ts @@ -3,5 +3,5 @@ import sessionHandler from "../internal/session"; export default defineEventHandler(async (h3) => { await sessionHandler.clearSession(h3); - return sendRedirect(h3, "/signin"); + return sendRedirect(h3, "/auth/signin"); }); diff --git a/server/server/tsconfig.json b/server/server/tsconfig.json index b9ed69c1..ca5c731e 100644 --- a/server/server/tsconfig.json +++ b/server/server/tsconfig.json @@ -1,3 +1,6 @@ { - "extends": "../.nuxt/tsconfig.server.json" + "extends": "../.nuxt/tsconfig.server.json", + "compilerOptions": { + "exactOptionalPropertyTypes": true + } } diff --git a/server/tsconfig.json b/server/tsconfig.json index a746f2a7..5510f189 100644 --- a/server/tsconfig.json +++ b/server/tsconfig.json @@ -1,4 +1,7 @@ { // https://nuxt.com/docs/guide/concepts/typescript - "extends": "./.nuxt/tsconfig.json" + "extends": "./.nuxt/tsconfig.json", + "compilerOptions": { + "exactOptionalPropertyTypes": true + } } diff --git a/server/yarn.lock b/server/yarn.lock index e720dd83..cd0b82ad 100644 --- a/server/yarn.lock +++ b/server/yarn.lock @@ -20,6 +20,18 @@ resolved "https://registry.yarnpkg.com/@antfu/utils/-/utils-0.7.10.tgz#ae829f170158e297a9b6a28f161a8e487d00814d" integrity sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww== +"@ark/schema@0.45.0": + version "0.45.0" + resolved "https://registry.yarnpkg.com/@ark/schema/-/schema-0.45.0.tgz#5d5da5dfe94ca45d36d54513fe0c53566483a1e7" + integrity sha512-3XlMWkZbEjh0YsF92vnnRNCWNRNhRKDTf6XhugyCXH0YRFuM+w1vFLDbB2JLfZloEd7i5cbqsLaDLzyBZbPrSg== + dependencies: + "@ark/util" "0.45.0" + +"@ark/util@0.45.0": + version "0.45.0" + resolved "https://registry.yarnpkg.com/@ark/util/-/util-0.45.0.tgz#2c55394a6af7865aeeb22924f301e28084aea4c0" + integrity sha512-Z1gHEGbpPzLtPmYb932t2B++6YonlUi1Fa14IQ4vhsGMWhd81Mi1miUmdZXW4fNI/wg1saT7H2/5cAuONgTXhg== + "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.24.7", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0", "@babel/code-frame@^7.26.2": version "7.26.2" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85" @@ -423,6 +435,13 @@ "@drop/droplet-linux-x64-gnu" "0.7.0" "@drop/droplet-win32-x64-msvc" "0.7.0" +"@emnapi/runtime@^1.2.0": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.3.1.tgz#0fcaa575afc31f455fd33534c19381cfce6c6f60" + integrity sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw== + dependencies: + tslib "^2.4.0" + "@esbuild/aix-ppc64@0.21.5": version "0.21.5" resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" @@ -800,6 +819,119 @@ resolved "https://registry.yarnpkg.com/@heroicons/vue/-/vue-2.1.5.tgz#efbf090d11acebbcefa4badcf3bed42d7ceee219" integrity sha512-IpqR72sFqFs55kyKfFS7tN+Ww6odFNeH/7UxycIOrlVYfj4WUGAdzQtLBnJspucSeqWFQsKM0g0YrgU655BEfA== +"@img/sharp-darwin-arm64@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz#ef5b5a07862805f1e8145a377c8ba6e98813ca08" + integrity sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ== + optionalDependencies: + "@img/sharp-libvips-darwin-arm64" "1.0.4" + +"@img/sharp-darwin-x64@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz#e03d3451cd9e664faa72948cc70a403ea4063d61" + integrity sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q== + optionalDependencies: + "@img/sharp-libvips-darwin-x64" "1.0.4" + +"@img/sharp-libvips-darwin-arm64@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz#447c5026700c01a993c7804eb8af5f6e9868c07f" + integrity sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg== + +"@img/sharp-libvips-darwin-x64@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz#e0456f8f7c623f9dbfbdc77383caa72281d86062" + integrity sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ== + +"@img/sharp-libvips-linux-arm64@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz#979b1c66c9a91f7ff2893556ef267f90ebe51704" + integrity sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA== + +"@img/sharp-libvips-linux-arm@1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz#99f922d4e15216ec205dcb6891b721bfd2884197" + integrity sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g== + +"@img/sharp-libvips-linux-s390x@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz#f8a5eb1f374a082f72b3f45e2fb25b8118a8a5ce" + integrity sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA== + +"@img/sharp-libvips-linux-x64@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz#d4c4619cdd157774906e15770ee119931c7ef5e0" + integrity sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw== + +"@img/sharp-libvips-linuxmusl-arm64@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz#166778da0f48dd2bded1fa3033cee6b588f0d5d5" + integrity sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA== + +"@img/sharp-libvips-linuxmusl-x64@1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz#93794e4d7720b077fcad3e02982f2f1c246751ff" + integrity sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw== + +"@img/sharp-linux-arm64@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz#edb0697e7a8279c9fc829a60fc35644c4839bb22" + integrity sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA== + optionalDependencies: + "@img/sharp-libvips-linux-arm64" "1.0.4" + +"@img/sharp-linux-arm@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz#422c1a352e7b5832842577dc51602bcd5b6f5eff" + integrity sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ== + optionalDependencies: + "@img/sharp-libvips-linux-arm" "1.0.5" + +"@img/sharp-linux-s390x@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz#f5c077926b48e97e4a04d004dfaf175972059667" + integrity sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q== + optionalDependencies: + "@img/sharp-libvips-linux-s390x" "1.0.4" + +"@img/sharp-linux-x64@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz#d806e0afd71ae6775cc87f0da8f2d03a7c2209cb" + integrity sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA== + optionalDependencies: + "@img/sharp-libvips-linux-x64" "1.0.4" + +"@img/sharp-linuxmusl-arm64@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz#252975b915894fb315af5deea174651e208d3d6b" + integrity sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64" "1.0.4" + +"@img/sharp-linuxmusl-x64@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz#3f4609ac5d8ef8ec7dadee80b560961a60fd4f48" + integrity sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64" "1.0.4" + +"@img/sharp-wasm32@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz#6f44f3283069d935bb5ca5813153572f3e6f61a1" + integrity sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg== + dependencies: + "@emnapi/runtime" "^1.2.0" + +"@img/sharp-win32-ia32@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz#1a0c839a40c5351e9885628c85f2e5dfd02b52a9" + integrity sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ== + +"@img/sharp-win32-x64@0.33.5": + version "0.33.5" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz#56f00962ff0c4e0eb93d34a047d29fa995e3e342" + integrity sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg== + "@ioredis/commands@^1.1.1": version "1.2.0" resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11" @@ -1365,6 +1497,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" @@ -2416,11 +2553,28 @@ 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" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +arktype@^2.1.10: + version "2.1.10" + resolved "https://registry.yarnpkg.com/arktype/-/arktype-2.1.10.tgz#7a2fb85d1e8fbb22077134993a12e9b12d34ef6e" + integrity sha512-KqbrzI9qIGrQUClifyS1HpUp/oTSRtGDvnMKzwg2TAvxRpynY1mn/ubXaxAAdGPOM8V3pBqwb01Z6TcXqhBxzQ== + dependencies: + "@ark/schema" "0.45.0" + "@ark/util" "0.45.0" + ast-kit@^1.0.1, ast-kit@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/ast-kit/-/ast-kit-1.3.0.tgz#37c8b7418b6c59b1e593d7790dc6c2b1c0814761" @@ -3343,7 +3497,7 @@ detect-libc@^1.0.3: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== -detect-libc@^2.0.0, detect-libc@^2.0.2: +detect-libc@^2.0.0, detect-libc@^2.0.2, detect-libc@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== @@ -5619,6 +5773,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" @@ -5646,6 +5805,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" @@ -6892,6 +7056,35 @@ sharp@^0.32.6: tar-fs "^3.0.4" tunnel-agent "^0.6.0" +sharp@^0.33.5: + version "0.33.5" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.33.5.tgz#13e0e4130cc309d6a9497596715240b2ec0c594e" + integrity sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw== + dependencies: + color "^4.2.3" + detect-libc "^2.0.3" + semver "^7.6.3" + optionalDependencies: + "@img/sharp-darwin-arm64" "0.33.5" + "@img/sharp-darwin-x64" "0.33.5" + "@img/sharp-libvips-darwin-arm64" "1.0.4" + "@img/sharp-libvips-darwin-x64" "1.0.4" + "@img/sharp-libvips-linux-arm" "1.0.5" + "@img/sharp-libvips-linux-arm64" "1.0.4" + "@img/sharp-libvips-linux-s390x" "1.0.4" + "@img/sharp-libvips-linux-x64" "1.0.4" + "@img/sharp-libvips-linuxmusl-arm64" "1.0.4" + "@img/sharp-libvips-linuxmusl-x64" "1.0.4" + "@img/sharp-linux-arm" "0.33.5" + "@img/sharp-linux-arm64" "0.33.5" + "@img/sharp-linux-s390x" "0.33.5" + "@img/sharp-linux-x64" "0.33.5" + "@img/sharp-linuxmusl-arm64" "0.33.5" + "@img/sharp-linuxmusl-x64" "0.33.5" + "@img/sharp-wasm32" "0.33.5" + "@img/sharp-win32-ia32" "0.33.5" + "@img/sharp-win32-x64" "0.33.5" + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -7487,7 +7680,7 @@ ts-interface-checker@^0.1.9: resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699" integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== -tslib@^2.8.0: +tslib@^2.4.0, tslib@^2.8.0: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==