mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
Updating mfa totp.
This commit is contained in:
parent
df582f1534
commit
16f00607b1
18 changed files with 4077 additions and 314 deletions
12
package.json
12
package.json
|
|
@ -29,12 +29,12 @@
|
||||||
"@melt-ui/svelte": "^0.83.0",
|
"@melt-ui/svelte": "^0.83.0",
|
||||||
"@playwright/test": "^1.46.1",
|
"@playwright/test": "^1.46.1",
|
||||||
"@sveltejs/adapter-auto": "^3.2.4",
|
"@sveltejs/adapter-auto": "^3.2.4",
|
||||||
"@sveltejs/enhanced-img": "^0.3.3",
|
"@sveltejs/enhanced-img": "^0.3.4",
|
||||||
"@sveltejs/kit": "^2.5.24",
|
"@sveltejs/kit": "^2.5.25",
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.1.2",
|
"@sveltejs/vite-plugin-svelte": "^3.1.2",
|
||||||
"@types/cookie": "^0.6.0",
|
"@types/cookie": "^0.6.0",
|
||||||
"@types/node": "^20.16.1",
|
"@types/node": "^20.16.2",
|
||||||
"@types/pg": "^8.11.6",
|
"@types/pg": "^8.11.8",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||||
"@typescript-eslint/parser": "^7.18.0",
|
"@typescript-eslint/parser": "^7.18.0",
|
||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
|
|
@ -95,7 +95,7 @@
|
||||||
"arctic": "^1.9.2",
|
"arctic": "^1.9.2",
|
||||||
"bits-ui": "^0.21.13",
|
"bits-ui": "^0.21.13",
|
||||||
"boardgamegeekclient": "^1.9.1",
|
"boardgamegeekclient": "^1.9.1",
|
||||||
"bullmq": "^5.12.10",
|
"bullmq": "^5.12.12",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cookie": "^0.6.0",
|
"cookie": "^0.6.0",
|
||||||
|
|
@ -114,7 +114,7 @@
|
||||||
"just-capitalize": "^3.2.0",
|
"just-capitalize": "^3.2.0",
|
||||||
"just-kebab-case": "^4.2.0",
|
"just-kebab-case": "^4.2.0",
|
||||||
"loader": "^2.1.1",
|
"loader": "^2.1.1",
|
||||||
"open-props": "^1.7.5",
|
"open-props": "^1.7.6",
|
||||||
"oslo": "^1.2.1",
|
"oslo": "^1.2.1",
|
||||||
"pg": "^8.12.0",
|
"pg": "^8.12.0",
|
||||||
"postgres": "^3.4.4",
|
"postgres": "^3.4.4",
|
||||||
|
|
|
||||||
209
pnpm-lock.yaml
209
pnpm-lock.yaml
|
|
@ -31,7 +31,7 @@ importers:
|
||||||
version: 3.5.5
|
version: 3.5.5
|
||||||
'@lucia-auth/adapter-drizzle':
|
'@lucia-auth/adapter-drizzle':
|
||||||
specifier: ^1.1.0
|
specifier: ^1.1.0
|
||||||
version: 1.1.0(drizzle-orm@0.32.2(@neondatabase/serverless@0.9.4)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4))(lucia@3.2.0)
|
version: 1.1.0(drizzle-orm@0.32.2(@neondatabase/serverless@0.9.4)(@types/pg@8.11.8)(pg@8.12.0)(postgres@3.4.4))(lucia@3.2.0)
|
||||||
'@lukeed/uuid':
|
'@lukeed/uuid':
|
||||||
specifier: ^2.0.1
|
specifier: ^2.0.1
|
||||||
version: 2.0.1
|
version: 2.0.1
|
||||||
|
|
@ -46,10 +46,10 @@ importers:
|
||||||
version: 2.6.2
|
version: 2.6.2
|
||||||
'@sveltejs/adapter-node':
|
'@sveltejs/adapter-node':
|
||||||
specifier: ^5.2.2
|
specifier: ^5.2.2
|
||||||
version: 5.2.2(@sveltejs/kit@2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))
|
version: 5.2.2(@sveltejs/kit@2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))
|
||||||
'@sveltejs/adapter-vercel':
|
'@sveltejs/adapter-vercel':
|
||||||
specifier: ^5.4.3
|
specifier: ^5.4.3
|
||||||
version: 5.4.3(@sveltejs/kit@2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))
|
version: 5.4.3(@sveltejs/kit@2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))
|
||||||
'@types/feather-icons':
|
'@types/feather-icons':
|
||||||
specifier: ^4.29.4
|
specifier: ^4.29.4
|
||||||
version: 4.29.4
|
version: 4.29.4
|
||||||
|
|
@ -66,8 +66,8 @@ importers:
|
||||||
specifier: ^1.9.1
|
specifier: ^1.9.1
|
||||||
version: 1.9.1
|
version: 1.9.1
|
||||||
bullmq:
|
bullmq:
|
||||||
specifier: ^5.12.10
|
specifier: ^5.12.12
|
||||||
version: 5.12.10
|
version: 5.12.12
|
||||||
class-variance-authority:
|
class-variance-authority:
|
||||||
specifier: ^0.7.0
|
specifier: ^0.7.0
|
||||||
version: 0.7.0
|
version: 0.7.0
|
||||||
|
|
@ -85,16 +85,16 @@ importers:
|
||||||
version: 11.0.6
|
version: 11.0.6
|
||||||
drizzle-orm:
|
drizzle-orm:
|
||||||
specifier: ^0.32.2
|
specifier: ^0.32.2
|
||||||
version: 0.32.2(@neondatabase/serverless@0.9.4)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4)
|
version: 0.32.2(@neondatabase/serverless@0.9.4)(@types/pg@8.11.8)(pg@8.12.0)(postgres@3.4.4)
|
||||||
drizzle-zod:
|
drizzle-zod:
|
||||||
specifier: ^0.5.1
|
specifier: ^0.5.1
|
||||||
version: 0.5.1(drizzle-orm@0.32.2(@neondatabase/serverless@0.9.4)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4))(zod@3.23.8)
|
version: 0.5.1(drizzle-orm@0.32.2(@neondatabase/serverless@0.9.4)(@types/pg@8.11.8)(pg@8.12.0)(postgres@3.4.4))(zod@3.23.8)
|
||||||
feather-icons:
|
feather-icons:
|
||||||
specifier: ^4.29.2
|
specifier: ^4.29.2
|
||||||
version: 4.29.2
|
version: 4.29.2
|
||||||
formsnap:
|
formsnap:
|
||||||
specifier: ^1.0.1
|
specifier: ^1.0.1
|
||||||
version: 1.0.1(svelte@5.0.0-next.175)(sveltekit-superforms@2.17.0(@sveltejs/kit@2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175))
|
version: 1.0.1(svelte@5.0.0-next.175)(sveltekit-superforms@2.17.0(@sveltejs/kit@2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175))
|
||||||
handlebars:
|
handlebars:
|
||||||
specifier: ^4.7.8
|
specifier: ^4.7.8
|
||||||
version: 4.7.8
|
version: 4.7.8
|
||||||
|
|
@ -123,8 +123,8 @@ importers:
|
||||||
specifier: ^2.1.1
|
specifier: ^2.1.1
|
||||||
version: 2.1.1
|
version: 2.1.1
|
||||||
open-props:
|
open-props:
|
||||||
specifier: ^1.7.5
|
specifier: ^1.7.6
|
||||||
version: 1.7.5
|
version: 1.7.6
|
||||||
oslo:
|
oslo:
|
||||||
specifier: ^1.2.1
|
specifier: ^1.2.1
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
|
|
@ -157,10 +157,10 @@ importers:
|
||||||
version: 2.5.2
|
version: 2.5.2
|
||||||
tailwind-variants:
|
tailwind-variants:
|
||||||
specifier: ^0.2.1
|
specifier: ^0.2.1
|
||||||
version: 0.2.1(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)))
|
version: 0.2.1(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.16.2)(typescript@5.5.4)))
|
||||||
tailwindcss-animate:
|
tailwindcss-animate:
|
||||||
specifier: ^1.0.7
|
specifier: ^1.0.7
|
||||||
version: 1.0.7(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)))
|
version: 1.0.7(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.16.2)(typescript@5.5.4)))
|
||||||
tsyringe:
|
tsyringe:
|
||||||
specifier: ^4.8.0
|
specifier: ^4.8.0
|
||||||
version: 4.8.0
|
version: 4.8.0
|
||||||
|
|
@ -185,25 +185,25 @@ importers:
|
||||||
version: 1.46.1
|
version: 1.46.1
|
||||||
'@sveltejs/adapter-auto':
|
'@sveltejs/adapter-auto':
|
||||||
specifier: ^3.2.4
|
specifier: ^3.2.4
|
||||||
version: 3.2.4(@sveltejs/kit@2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))
|
version: 3.2.4(@sveltejs/kit@2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))
|
||||||
'@sveltejs/enhanced-img':
|
'@sveltejs/enhanced-img':
|
||||||
specifier: ^0.3.3
|
specifier: ^0.3.4
|
||||||
version: 0.3.3(rollup@4.18.1)(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8))
|
version: 0.3.4(rollup@4.18.1)(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8))
|
||||||
'@sveltejs/kit':
|
'@sveltejs/kit':
|
||||||
specifier: ^2.5.24
|
specifier: ^2.5.25
|
||||||
version: 2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8))
|
version: 2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8))
|
||||||
'@sveltejs/vite-plugin-svelte':
|
'@sveltejs/vite-plugin-svelte':
|
||||||
specifier: ^3.1.2
|
specifier: ^3.1.2
|
||||||
version: 3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8))
|
version: 3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8))
|
||||||
'@types/cookie':
|
'@types/cookie':
|
||||||
specifier: ^0.6.0
|
specifier: ^0.6.0
|
||||||
version: 0.6.0
|
version: 0.6.0
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^20.16.1
|
specifier: ^20.16.2
|
||||||
version: 20.16.1
|
version: 20.16.2
|
||||||
'@types/pg':
|
'@types/pg':
|
||||||
specifier: ^8.11.6
|
specifier: ^8.11.8
|
||||||
version: 8.11.6
|
version: 8.11.8
|
||||||
'@typescript-eslint/eslint-plugin':
|
'@typescript-eslint/eslint-plugin':
|
||||||
specifier: ^7.18.0
|
specifier: ^7.18.0
|
||||||
version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4)
|
version: 7.18.0(@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4)
|
||||||
|
|
@ -224,7 +224,7 @@ importers:
|
||||||
version: 9.1.0(eslint@8.57.0)
|
version: 9.1.0(eslint@8.57.0)
|
||||||
eslint-plugin-svelte:
|
eslint-plugin-svelte:
|
||||||
specifier: ^2.43.0
|
specifier: ^2.43.0
|
||||||
version: 2.43.0(eslint@8.57.0)(svelte@5.0.0-next.175)(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4))
|
version: 2.43.0(eslint@8.57.0)(svelte@5.0.0-next.175)(ts-node@10.9.2(@types/node@20.16.2)(typescript@5.5.4))
|
||||||
just-clone:
|
just-clone:
|
||||||
specifier: ^6.2.0
|
specifier: ^6.2.0
|
||||||
version: 6.2.0
|
version: 6.2.0
|
||||||
|
|
@ -287,19 +287,19 @@ importers:
|
||||||
version: 2.0.1
|
version: 2.0.1
|
||||||
sveltekit-flash-message:
|
sveltekit-flash-message:
|
||||||
specifier: ^2.4.4
|
specifier: ^2.4.4
|
||||||
version: 2.4.4(@sveltejs/kit@2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)
|
version: 2.4.4(@sveltejs/kit@2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)
|
||||||
sveltekit-rate-limiter:
|
sveltekit-rate-limiter:
|
||||||
specifier: ^0.5.2
|
specifier: ^0.5.2
|
||||||
version: 0.5.2(@sveltejs/kit@2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))
|
version: 0.5.2(@sveltejs/kit@2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))
|
||||||
sveltekit-superforms:
|
sveltekit-superforms:
|
||||||
specifier: ^2.17.0
|
specifier: ^2.17.0
|
||||||
version: 2.17.0(@sveltejs/kit@2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)
|
version: 2.17.0(@sveltejs/kit@2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)
|
||||||
tailwindcss:
|
tailwindcss:
|
||||||
specifier: ^3.4.10
|
specifier: ^3.4.10
|
||||||
version: 3.4.10(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4))
|
version: 3.4.10(ts-node@10.9.2(@types/node@20.16.2)(typescript@5.5.4))
|
||||||
ts-node:
|
ts-node:
|
||||||
specifier: ^10.9.2
|
specifier: ^10.9.2
|
||||||
version: 10.9.2(@types/node@20.16.1)(typescript@5.5.4)
|
version: 10.9.2(@types/node@20.16.2)(typescript@5.5.4)
|
||||||
tslib:
|
tslib:
|
||||||
specifier: ^2.7.0
|
specifier: ^2.7.0
|
||||||
version: 2.7.0
|
version: 2.7.0
|
||||||
|
|
@ -311,10 +311,10 @@ importers:
|
||||||
version: 5.5.4
|
version: 5.5.4
|
||||||
vite:
|
vite:
|
||||||
specifier: ^5.4.2
|
specifier: ^5.4.2
|
||||||
version: 5.4.2(@types/node@20.16.1)(sass@1.77.8)
|
version: 5.4.2(@types/node@20.16.2)(sass@1.77.8)
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^1.6.0
|
specifier: ^1.6.0
|
||||||
version: 1.6.0(@types/node@20.16.1)(sass@1.77.8)
|
version: 1.6.0(@types/node@20.16.2)(sass@1.77.8)
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.23.8
|
specifier: ^3.23.8
|
||||||
version: 3.23.8
|
version: 3.23.8
|
||||||
|
|
@ -2054,14 +2054,14 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@sveltejs/kit': ^2.4.0
|
'@sveltejs/kit': ^2.4.0
|
||||||
|
|
||||||
'@sveltejs/enhanced-img@0.3.3':
|
'@sveltejs/enhanced-img@0.3.4':
|
||||||
resolution: {integrity: sha512-nsqJkVuYLUXARDLjMoGKAt4oLzwtY8X2E8rIl/TJl7ueLjpTISxrAhVRN3r8yMO+R+so4G6Taiix2mpiPpqZeg==}
|
resolution: {integrity: sha512-eX+ob5uWr0bTLMKeG9nhhM84aR88hqiLiyEfWZPX7ijhk/wlmYSUX9nOiaVHh2ct1U+Ju9Hhb90Copw+ZNOB8w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
svelte: ^4.0.0 || ^5.0.0-next.0
|
svelte: ^4.0.0 || ^5.0.0-next.0
|
||||||
vite: '>= 5.0.0'
|
vite: '>= 5.0.0'
|
||||||
|
|
||||||
'@sveltejs/kit@2.5.24':
|
'@sveltejs/kit@2.5.25':
|
||||||
resolution: {integrity: sha512-Nr2oxsCsDfEkdS/zzQQQbsPYTbu692Qs3/iE3L7VHzCVjG2+WujF9oMUozWI7GuX98KxYSoPMlAsfmDLSg44hQ==}
|
resolution: {integrity: sha512-5hBSEN8XEjDZ5+2bHkFh8Z0QyOk0C187cyb12aANe1c8aeKbfu5ZD5XaC2vEH4h0alJFDXPdUkXQBmeeXeMr1A==}
|
||||||
engines: {node: '>=18.13'}
|
engines: {node: '>=18.13'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|
@ -2114,12 +2114,15 @@ packages:
|
||||||
'@types/json-schema@7.0.15':
|
'@types/json-schema@7.0.15':
|
||||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||||
|
|
||||||
'@types/node@20.16.1':
|
'@types/node@20.16.2':
|
||||||
resolution: {integrity: sha512-zJDo7wEadFtSyNz5QITDfRcrhqDvQI1xQNQ0VoizPjM/dVAODqqIUWbJPkvsxmTI0MYRGRikcdjMPhOssnPejQ==}
|
resolution: {integrity: sha512-91s/n4qUPV/wg8eE9KHYW1kouTfDk2FPGjXbBMfRWP/2vg1rCXNQL1OCabwGs0XSdukuK+MwCDXE30QpSeMUhQ==}
|
||||||
|
|
||||||
'@types/pg@8.11.6':
|
'@types/pg@8.11.6':
|
||||||
resolution: {integrity: sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ==}
|
resolution: {integrity: sha512-/2WmmBXHLsfRqzfHW7BNZ8SbYzE8OSk7i3WjFYvfgRHj7S1xj+16Je5fUKv3lVdVzk/zn9TXOqf+avFCFIE0yQ==}
|
||||||
|
|
||||||
|
'@types/pg@8.11.8':
|
||||||
|
resolution: {integrity: sha512-IqpCf8/569txXN/HoP5i1LjXfKZWL76Yr2R77xgeIICUbAYHeoaEZFhYHo2uDftecLWrTJUq63JvQu8q3lnDyA==}
|
||||||
|
|
||||||
'@types/pug@2.0.10':
|
'@types/pug@2.0.10':
|
||||||
resolution: {integrity: sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==}
|
resolution: {integrity: sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==}
|
||||||
|
|
||||||
|
|
@ -2402,8 +2405,8 @@ packages:
|
||||||
resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
|
resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
||||||
bullmq@5.12.10:
|
bullmq@5.12.12:
|
||||||
resolution: {integrity: sha512-lXH8Caj+FvYHiBS0QBEpQOq57RcVuEPziBC5cBlWguCVNfn1UMSri22bRrynDKuof8o9XB43ctmYASUpoa0DeQ==}
|
resolution: {integrity: sha512-xrWKDj1ZwnGKmrlmFqF6Vmub3WqDFfdBcIRLCooIs5+jeVzbHK7/1usgYSFg2pZiwK6h6eMivTb9WvcKkNW/+w==}
|
||||||
|
|
||||||
bytes@3.1.2:
|
bytes@3.1.2:
|
||||||
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
|
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
|
||||||
|
|
@ -3667,8 +3670,8 @@ packages:
|
||||||
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
|
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
open-props@1.7.5:
|
open-props@1.7.6:
|
||||||
resolution: {integrity: sha512-DajjLQDJgIa0i+QdB2q5M8lNLo2ICk+DbDh4TsqNsT1tAO8Zm8F7dndSkLMQkobT98lbvDMMpJWO8NT0ibjrjA==}
|
resolution: {integrity: sha512-fE3E22x8lCf6gJrPO3L54NKrPaqQGxeKoXLz4JIXrhALD3Ua1kkE2kMw8HmlTKYF9BSLLMfoVfsT3UC1PJcaww==}
|
||||||
|
|
||||||
openapi3-ts@4.3.3:
|
openapi3-ts@4.3.3:
|
||||||
resolution: {integrity: sha512-LKkzBGJcZ6wdvkKGMoSvpK+0cbN5Xc3XuYkJskO+vjEQWJgs1kgtyUk0pjf8KwPuysv323Er62F5P17XQl96Qg==}
|
resolution: {integrity: sha512-LKkzBGJcZ6wdvkKGMoSvpK+0cbN5Xc3XuYkJskO+vjEQWJgs1kgtyUk0pjf8KwPuysv323Er62F5P17XQl96Qg==}
|
||||||
|
|
@ -5851,9 +5854,9 @@ snapshots:
|
||||||
'@jridgewell/resolve-uri': 3.1.2
|
'@jridgewell/resolve-uri': 3.1.2
|
||||||
'@jridgewell/sourcemap-codec': 1.4.15
|
'@jridgewell/sourcemap-codec': 1.4.15
|
||||||
|
|
||||||
'@lucia-auth/adapter-drizzle@1.1.0(drizzle-orm@0.32.2(@neondatabase/serverless@0.9.4)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4))(lucia@3.2.0)':
|
'@lucia-auth/adapter-drizzle@1.1.0(drizzle-orm@0.32.2(@neondatabase/serverless@0.9.4)(@types/pg@8.11.8)(pg@8.12.0)(postgres@3.4.4))(lucia@3.2.0)':
|
||||||
dependencies:
|
dependencies:
|
||||||
drizzle-orm: 0.32.2(@neondatabase/serverless@0.9.4)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4)
|
drizzle-orm: 0.32.2(@neondatabase/serverless@0.9.4)(@types/pg@8.11.8)(pg@8.12.0)(postgres@3.4.4)
|
||||||
lucia: 3.2.0
|
lucia: 3.2.0
|
||||||
|
|
||||||
'@lukeed/csprng@1.1.0': {}
|
'@lukeed/csprng@1.1.0': {}
|
||||||
|
|
@ -6298,41 +6301,41 @@ snapshots:
|
||||||
'@sodaru/yup-to-json-schema@2.0.1':
|
'@sodaru/yup-to-json-schema@2.0.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@sveltejs/adapter-auto@3.2.4(@sveltejs/kit@2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))':
|
'@sveltejs/adapter-auto@3.2.4(@sveltejs/kit@2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/kit': 2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8))
|
'@sveltejs/kit': 2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8))
|
||||||
import-meta-resolve: 4.1.0
|
import-meta-resolve: 4.1.0
|
||||||
|
|
||||||
'@sveltejs/adapter-node@5.2.2(@sveltejs/kit@2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))':
|
'@sveltejs/adapter-node@5.2.2(@sveltejs/kit@2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@rollup/plugin-commonjs': 26.0.1(rollup@4.18.1)
|
'@rollup/plugin-commonjs': 26.0.1(rollup@4.18.1)
|
||||||
'@rollup/plugin-json': 6.1.0(rollup@4.18.1)
|
'@rollup/plugin-json': 6.1.0(rollup@4.18.1)
|
||||||
'@rollup/plugin-node-resolve': 15.2.3(rollup@4.18.1)
|
'@rollup/plugin-node-resolve': 15.2.3(rollup@4.18.1)
|
||||||
'@sveltejs/kit': 2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8))
|
'@sveltejs/kit': 2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8))
|
||||||
rollup: 4.18.1
|
rollup: 4.18.1
|
||||||
|
|
||||||
'@sveltejs/adapter-vercel@5.4.3(@sveltejs/kit@2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))':
|
'@sveltejs/adapter-vercel@5.4.3(@sveltejs/kit@2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/kit': 2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8))
|
'@sveltejs/kit': 2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8))
|
||||||
'@vercel/nft': 0.27.2
|
'@vercel/nft': 0.27.2
|
||||||
esbuild: 0.21.5
|
esbuild: 0.21.5
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- encoding
|
- encoding
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@sveltejs/enhanced-img@0.3.3(rollup@4.18.1)(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8))':
|
'@sveltejs/enhanced-img@0.3.4(rollup@4.18.1)(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8))':
|
||||||
dependencies:
|
dependencies:
|
||||||
magic-string: 0.30.10
|
magic-string: 0.30.10
|
||||||
svelte: 5.0.0-next.175
|
svelte: 5.0.0-next.175
|
||||||
svelte-parse-markup: 0.1.5(svelte@5.0.0-next.175)
|
svelte-parse-markup: 0.1.5(svelte@5.0.0-next.175)
|
||||||
vite: 5.4.2(@types/node@20.16.1)(sass@1.77.8)
|
vite: 5.4.2(@types/node@20.16.2)(sass@1.77.8)
|
||||||
vite-imagetools: 7.0.2(rollup@4.18.1)
|
vite-imagetools: 7.0.2(rollup@4.18.1)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- rollup
|
- rollup
|
||||||
|
|
||||||
'@sveltejs/kit@2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8))':
|
'@sveltejs/kit@2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/vite-plugin-svelte': 3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8))
|
'@sveltejs/vite-plugin-svelte': 3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8))
|
||||||
'@types/cookie': 0.6.0
|
'@types/cookie': 0.6.0
|
||||||
cookie: 0.6.0
|
cookie: 0.6.0
|
||||||
devalue: 5.0.0
|
devalue: 5.0.0
|
||||||
|
|
@ -6346,28 +6349,28 @@ snapshots:
|
||||||
sirv: 2.0.4
|
sirv: 2.0.4
|
||||||
svelte: 5.0.0-next.175
|
svelte: 5.0.0-next.175
|
||||||
tiny-glob: 0.2.9
|
tiny-glob: 0.2.9
|
||||||
vite: 5.4.2(@types/node@20.16.1)(sass@1.77.8)
|
vite: 5.4.2(@types/node@20.16.2)(sass@1.77.8)
|
||||||
|
|
||||||
'@sveltejs/vite-plugin-svelte-inspector@2.1.0(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8))':
|
'@sveltejs/vite-plugin-svelte-inspector@2.1.0(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/vite-plugin-svelte': 3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8))
|
'@sveltejs/vite-plugin-svelte': 3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8))
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
svelte: 5.0.0-next.175
|
svelte: 5.0.0-next.175
|
||||||
vite: 5.4.2(@types/node@20.16.1)(sass@1.77.8)
|
vite: 5.4.2(@types/node@20.16.2)(sass@1.77.8)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
'@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8))':
|
'@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8))':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/vite-plugin-svelte-inspector': 2.1.0(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8))
|
'@sveltejs/vite-plugin-svelte-inspector': 2.1.0(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8))
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
deepmerge: 4.3.1
|
deepmerge: 4.3.1
|
||||||
kleur: 4.1.5
|
kleur: 4.1.5
|
||||||
magic-string: 0.30.10
|
magic-string: 0.30.10
|
||||||
svelte: 5.0.0-next.175
|
svelte: 5.0.0-next.175
|
||||||
svelte-hmr: 0.16.0(svelte@5.0.0-next.175)
|
svelte-hmr: 0.16.0(svelte@5.0.0-next.175)
|
||||||
vite: 5.4.2(@types/node@20.16.1)(sass@1.77.8)
|
vite: 5.4.2(@types/node@20.16.2)(sass@1.77.8)
|
||||||
vitefu: 0.2.5(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8))
|
vitefu: 0.2.5(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8))
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
|
|
@ -6397,13 +6400,19 @@ snapshots:
|
||||||
'@types/json-schema@7.0.15':
|
'@types/json-schema@7.0.15':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@types/node@20.16.1':
|
'@types/node@20.16.2':
|
||||||
dependencies:
|
dependencies:
|
||||||
undici-types: 6.19.6
|
undici-types: 6.19.6
|
||||||
|
|
||||||
'@types/pg@8.11.6':
|
'@types/pg@8.11.6':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 20.16.1
|
'@types/node': 20.16.2
|
||||||
|
pg-protocol: 1.6.1
|
||||||
|
pg-types: 4.0.2
|
||||||
|
|
||||||
|
'@types/pg@8.11.8':
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 20.16.2
|
||||||
pg-protocol: 1.6.1
|
pg-protocol: 1.6.1
|
||||||
pg-types: 4.0.2
|
pg-types: 4.0.2
|
||||||
|
|
||||||
|
|
@ -6750,7 +6759,7 @@ snapshots:
|
||||||
|
|
||||||
builtin-modules@3.3.0: {}
|
builtin-modules@3.3.0: {}
|
||||||
|
|
||||||
bullmq@5.12.10:
|
bullmq@5.12.12:
|
||||||
dependencies:
|
dependencies:
|
||||||
cron-parser: 4.9.0
|
cron-parser: 4.9.0
|
||||||
ioredis: 5.4.1
|
ioredis: 5.4.1
|
||||||
|
|
@ -7021,16 +7030,16 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
|
|
||||||
drizzle-orm@0.32.2(@neondatabase/serverless@0.9.4)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4):
|
drizzle-orm@0.32.2(@neondatabase/serverless@0.9.4)(@types/pg@8.11.8)(pg@8.12.0)(postgres@3.4.4):
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@neondatabase/serverless': 0.9.4
|
'@neondatabase/serverless': 0.9.4
|
||||||
'@types/pg': 8.11.6
|
'@types/pg': 8.11.8
|
||||||
pg: 8.12.0
|
pg: 8.12.0
|
||||||
postgres: 3.4.4
|
postgres: 3.4.4
|
||||||
|
|
||||||
drizzle-zod@0.5.1(drizzle-orm@0.32.2(@neondatabase/serverless@0.9.4)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4))(zod@3.23.8):
|
drizzle-zod@0.5.1(drizzle-orm@0.32.2(@neondatabase/serverless@0.9.4)(@types/pg@8.11.8)(pg@8.12.0)(postgres@3.4.4))(zod@3.23.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
drizzle-orm: 0.32.2(@neondatabase/serverless@0.9.4)(@types/pg@8.11.6)(pg@8.12.0)(postgres@3.4.4)
|
drizzle-orm: 0.32.2(@neondatabase/serverless@0.9.4)(@types/pg@8.11.8)(pg@8.12.0)(postgres@3.4.4)
|
||||||
zod: 3.23.8
|
zod: 3.23.8
|
||||||
|
|
||||||
eastasianwidth@0.2.0: {}
|
eastasianwidth@0.2.0: {}
|
||||||
|
|
@ -7190,7 +7199,7 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint: 8.57.0
|
eslint: 8.57.0
|
||||||
|
|
||||||
eslint-plugin-svelte@2.43.0(eslint@8.57.0)(svelte@5.0.0-next.175)(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)):
|
eslint-plugin-svelte@2.43.0(eslint@8.57.0)(svelte@5.0.0-next.175)(ts-node@10.9.2(@types/node@20.16.2)(typescript@5.5.4)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
|
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
|
||||||
'@jridgewell/sourcemap-codec': 1.4.15
|
'@jridgewell/sourcemap-codec': 1.4.15
|
||||||
|
|
@ -7199,7 +7208,7 @@ snapshots:
|
||||||
esutils: 2.0.3
|
esutils: 2.0.3
|
||||||
known-css-properties: 0.34.0
|
known-css-properties: 0.34.0
|
||||||
postcss: 8.4.41
|
postcss: 8.4.41
|
||||||
postcss-load-config: 3.1.4(postcss@8.4.41)(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4))
|
postcss-load-config: 3.1.4(postcss@8.4.41)(ts-node@10.9.2(@types/node@20.16.2)(typescript@5.5.4))
|
||||||
postcss-safe-parser: 6.0.0(postcss@8.4.41)
|
postcss-safe-parser: 6.0.0(postcss@8.4.41)
|
||||||
postcss-selector-parser: 6.1.0
|
postcss-selector-parser: 6.1.0
|
||||||
semver: 7.6.2
|
semver: 7.6.2
|
||||||
|
|
@ -7426,11 +7435,11 @@ snapshots:
|
||||||
cross-spawn: 7.0.3
|
cross-spawn: 7.0.3
|
||||||
signal-exit: 4.1.0
|
signal-exit: 4.1.0
|
||||||
|
|
||||||
formsnap@1.0.1(svelte@5.0.0-next.175)(sveltekit-superforms@2.17.0(@sveltejs/kit@2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)):
|
formsnap@1.0.1(svelte@5.0.0-next.175)(sveltekit-superforms@2.17.0(@sveltejs/kit@2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)):
|
||||||
dependencies:
|
dependencies:
|
||||||
nanoid: 5.0.7
|
nanoid: 5.0.7
|
||||||
svelte: 5.0.0-next.175
|
svelte: 5.0.0-next.175
|
||||||
sveltekit-superforms: 2.17.0(@sveltejs/kit@2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)
|
sveltekit-superforms: 2.17.0(@sveltejs/kit@2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)
|
||||||
|
|
||||||
forwarded@0.2.0: {}
|
forwarded@0.2.0: {}
|
||||||
|
|
||||||
|
|
@ -8003,7 +8012,7 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
mimic-fn: 4.0.0
|
mimic-fn: 4.0.0
|
||||||
|
|
||||||
open-props@1.7.5: {}
|
open-props@1.7.6: {}
|
||||||
|
|
||||||
openapi3-ts@4.3.3:
|
openapi3-ts@4.3.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -8285,21 +8294,21 @@ snapshots:
|
||||||
'@csstools/utilities': 1.0.0(postcss@8.4.41)
|
'@csstools/utilities': 1.0.0(postcss@8.4.41)
|
||||||
postcss: 8.4.41
|
postcss: 8.4.41
|
||||||
|
|
||||||
postcss-load-config@3.1.4(postcss@8.4.41)(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)):
|
postcss-load-config@3.1.4(postcss@8.4.41)(ts-node@10.9.2(@types/node@20.16.2)(typescript@5.5.4)):
|
||||||
dependencies:
|
dependencies:
|
||||||
lilconfig: 2.1.0
|
lilconfig: 2.1.0
|
||||||
yaml: 1.10.2
|
yaml: 1.10.2
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
postcss: 8.4.41
|
postcss: 8.4.41
|
||||||
ts-node: 10.9.2(@types/node@20.16.1)(typescript@5.5.4)
|
ts-node: 10.9.2(@types/node@20.16.2)(typescript@5.5.4)
|
||||||
|
|
||||||
postcss-load-config@4.0.2(postcss@8.4.41)(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)):
|
postcss-load-config@4.0.2(postcss@8.4.41)(ts-node@10.9.2(@types/node@20.16.2)(typescript@5.5.4)):
|
||||||
dependencies:
|
dependencies:
|
||||||
lilconfig: 3.1.1
|
lilconfig: 3.1.1
|
||||||
yaml: 2.4.3
|
yaml: 2.4.3
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
postcss: 8.4.41
|
postcss: 8.4.41
|
||||||
ts-node: 10.9.2(@types/node@20.16.1)(typescript@5.5.4)
|
ts-node: 10.9.2(@types/node@20.16.2)(typescript@5.5.4)
|
||||||
|
|
||||||
postcss-load-config@5.1.0(jiti@1.21.6)(postcss@8.4.41)(tsx@4.19.0):
|
postcss-load-config@5.1.0(jiti@1.21.6)(postcss@8.4.41)(tsx@4.19.0):
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
@ -9015,19 +9024,19 @@ snapshots:
|
||||||
magic-string: 0.30.10
|
magic-string: 0.30.10
|
||||||
zimmerframe: 1.1.2
|
zimmerframe: 1.1.2
|
||||||
|
|
||||||
sveltekit-flash-message@2.4.4(@sveltejs/kit@2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175):
|
sveltekit-flash-message@2.4.4(@sveltejs/kit@2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/kit': 2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8))
|
'@sveltejs/kit': 2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8))
|
||||||
svelte: 5.0.0-next.175
|
svelte: 5.0.0-next.175
|
||||||
|
|
||||||
sveltekit-rate-limiter@0.5.2(@sveltejs/kit@2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8))):
|
sveltekit-rate-limiter@0.5.2(@sveltejs/kit@2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8))):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@isaacs/ttlcache': 1.4.1
|
'@isaacs/ttlcache': 1.4.1
|
||||||
'@sveltejs/kit': 2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8))
|
'@sveltejs/kit': 2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8))
|
||||||
|
|
||||||
sveltekit-superforms@2.17.0(@sveltejs/kit@2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175):
|
sveltekit-superforms@2.17.0(@sveltejs/kit@2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sveltejs/kit': 2.5.24(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8))
|
'@sveltejs/kit': 2.5.25(@sveltejs/vite-plugin-svelte@3.1.2(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8))
|
||||||
devalue: 5.0.0
|
devalue: 5.0.0
|
||||||
just-clone: 6.2.0
|
just-clone: 6.2.0
|
||||||
memoize-weak: 1.0.2
|
memoize-weak: 1.0.2
|
||||||
|
|
@ -9052,16 +9061,16 @@ snapshots:
|
||||||
|
|
||||||
tailwind-merge@2.5.2: {}
|
tailwind-merge@2.5.2: {}
|
||||||
|
|
||||||
tailwind-variants@0.2.1(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4))):
|
tailwind-variants@0.2.1(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.16.2)(typescript@5.5.4))):
|
||||||
dependencies:
|
dependencies:
|
||||||
tailwind-merge: 2.5.2
|
tailwind-merge: 2.5.2
|
||||||
tailwindcss: 3.4.10(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4))
|
tailwindcss: 3.4.10(ts-node@10.9.2(@types/node@20.16.2)(typescript@5.5.4))
|
||||||
|
|
||||||
tailwindcss-animate@1.0.7(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4))):
|
tailwindcss-animate@1.0.7(tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.16.2)(typescript@5.5.4))):
|
||||||
dependencies:
|
dependencies:
|
||||||
tailwindcss: 3.4.10(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4))
|
tailwindcss: 3.4.10(ts-node@10.9.2(@types/node@20.16.2)(typescript@5.5.4))
|
||||||
|
|
||||||
tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4)):
|
tailwindcss@3.4.10(ts-node@10.9.2(@types/node@20.16.2)(typescript@5.5.4)):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@alloc/quick-lru': 5.2.0
|
'@alloc/quick-lru': 5.2.0
|
||||||
arg: 5.0.2
|
arg: 5.0.2
|
||||||
|
|
@ -9080,7 +9089,7 @@ snapshots:
|
||||||
postcss: 8.4.41
|
postcss: 8.4.41
|
||||||
postcss-import: 15.1.0(postcss@8.4.41)
|
postcss-import: 15.1.0(postcss@8.4.41)
|
||||||
postcss-js: 4.0.1(postcss@8.4.41)
|
postcss-js: 4.0.1(postcss@8.4.41)
|
||||||
postcss-load-config: 4.0.2(postcss@8.4.41)(ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4))
|
postcss-load-config: 4.0.2(postcss@8.4.41)(ts-node@10.9.2(@types/node@20.16.2)(typescript@5.5.4))
|
||||||
postcss-nested: 6.0.1(postcss@8.4.41)
|
postcss-nested: 6.0.1(postcss@8.4.41)
|
||||||
postcss-selector-parser: 6.1.0
|
postcss-selector-parser: 6.1.0
|
||||||
resolve: 1.22.8
|
resolve: 1.22.8
|
||||||
|
|
@ -9147,14 +9156,14 @@ snapshots:
|
||||||
|
|
||||||
ts-interface-checker@0.1.13: {}
|
ts-interface-checker@0.1.13: {}
|
||||||
|
|
||||||
ts-node@10.9.2(@types/node@20.16.1)(typescript@5.5.4):
|
ts-node@10.9.2(@types/node@20.16.2)(typescript@5.5.4):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@cspotcode/source-map-support': 0.8.1
|
'@cspotcode/source-map-support': 0.8.1
|
||||||
'@tsconfig/node10': 1.0.11
|
'@tsconfig/node10': 1.0.11
|
||||||
'@tsconfig/node12': 1.0.11
|
'@tsconfig/node12': 1.0.11
|
||||||
'@tsconfig/node14': 1.0.3
|
'@tsconfig/node14': 1.0.3
|
||||||
'@tsconfig/node16': 1.0.4
|
'@tsconfig/node16': 1.0.4
|
||||||
'@types/node': 20.16.1
|
'@types/node': 20.16.2
|
||||||
acorn: 8.11.3
|
acorn: 8.11.3
|
||||||
acorn-walk: 8.3.2
|
acorn-walk: 8.3.2
|
||||||
arg: 4.1.3
|
arg: 4.1.3
|
||||||
|
|
@ -9263,13 +9272,13 @@ snapshots:
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- rollup
|
- rollup
|
||||||
|
|
||||||
vite-node@1.6.0(@types/node@20.16.1)(sass@1.77.8):
|
vite-node@1.6.0(@types/node@20.16.2)(sass@1.77.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
cac: 6.7.14
|
cac: 6.7.14
|
||||||
debug: 4.3.4
|
debug: 4.3.4
|
||||||
pathe: 1.1.2
|
pathe: 1.1.2
|
||||||
picocolors: 1.0.0
|
picocolors: 1.0.0
|
||||||
vite: 5.4.2(@types/node@20.16.1)(sass@1.77.8)
|
vite: 5.4.2(@types/node@20.16.2)(sass@1.77.8)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- '@types/node'
|
- '@types/node'
|
||||||
- less
|
- less
|
||||||
|
|
@ -9281,21 +9290,21 @@ snapshots:
|
||||||
- supports-color
|
- supports-color
|
||||||
- terser
|
- terser
|
||||||
|
|
||||||
vite@5.4.2(@types/node@20.16.1)(sass@1.77.8):
|
vite@5.4.2(@types/node@20.16.2)(sass@1.77.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
esbuild: 0.21.5
|
esbuild: 0.21.5
|
||||||
postcss: 8.4.41
|
postcss: 8.4.41
|
||||||
rollup: 4.21.0
|
rollup: 4.21.0
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/node': 20.16.1
|
'@types/node': 20.16.2
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
sass: 1.77.8
|
sass: 1.77.8
|
||||||
|
|
||||||
vitefu@0.2.5(vite@5.4.2(@types/node@20.16.1)(sass@1.77.8)):
|
vitefu@0.2.5(vite@5.4.2(@types/node@20.16.2)(sass@1.77.8)):
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
vite: 5.4.2(@types/node@20.16.1)(sass@1.77.8)
|
vite: 5.4.2(@types/node@20.16.2)(sass@1.77.8)
|
||||||
|
|
||||||
vitest@1.6.0(@types/node@20.16.1)(sass@1.77.8):
|
vitest@1.6.0(@types/node@20.16.2)(sass@1.77.8):
|
||||||
dependencies:
|
dependencies:
|
||||||
'@vitest/expect': 1.6.0
|
'@vitest/expect': 1.6.0
|
||||||
'@vitest/runner': 1.6.0
|
'@vitest/runner': 1.6.0
|
||||||
|
|
@ -9314,11 +9323,11 @@ snapshots:
|
||||||
strip-literal: 2.1.0
|
strip-literal: 2.1.0
|
||||||
tinybench: 2.8.0
|
tinybench: 2.8.0
|
||||||
tinypool: 0.8.4
|
tinypool: 0.8.4
|
||||||
vite: 5.4.2(@types/node@20.16.1)(sass@1.77.8)
|
vite: 5.4.2(@types/node@20.16.2)(sass@1.77.8)
|
||||||
vite-node: 1.6.0(@types/node@20.16.1)(sass@1.77.8)
|
vite-node: 1.6.0(@types/node@20.16.2)(sass@1.77.8)
|
||||||
why-is-node-running: 2.2.2
|
why-is-node-running: 2.2.2
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@types/node': 20.16.1
|
'@types/node': 20.16.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- less
|
- less
|
||||||
- lightningcss
|
- lightningcss
|
||||||
|
|
|
||||||
11
src/lib/dtos/verify-totp.dto.ts
Normal file
11
src/lib/dtos/verify-totp.dto.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export const verifyTotpDto = z.object({
|
||||||
|
code: z
|
||||||
|
.string()
|
||||||
|
.trim()
|
||||||
|
.min(6, { message: 'Must be at least 6 characters' })
|
||||||
|
.max(6, { message: 'Must be less than 6 characters' }),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type VerifyTotpDto = z.infer<typeof verifyTotpDto>;
|
||||||
|
|
@ -33,7 +33,7 @@ export class IamController implements Controller {
|
||||||
const { firstName, lastName, username } = c.req.valid('json')
|
const { firstName, lastName, username } = c.req.valid('json')
|
||||||
const updatedUser = await this.iamService.updateProfile(user.id, { firstName, lastName, username })
|
const updatedUser = await this.iamService.updateProfile(user.id, { firstName, lastName, username })
|
||||||
if (!updatedUser) {
|
if (!updatedUser) {
|
||||||
return c.json("Username already in use", StatusCodes.BAD_REQUEST);
|
return c.json('Username already in use', StatusCodes.BAD_REQUEST)
|
||||||
}
|
}
|
||||||
return c.json({ user: updatedUser }, StatusCodes.OK)
|
return c.json({ user: updatedUser }, StatusCodes.OK)
|
||||||
})
|
})
|
||||||
|
|
@ -42,16 +42,17 @@ export class IamController implements Controller {
|
||||||
const { password } = c.req.valid('json')
|
const { password } = c.req.valid('json')
|
||||||
const passwordVerified = await this.iamService.verifyPassword(user.id, { password })
|
const passwordVerified = await this.iamService.verifyPassword(user.id, { password })
|
||||||
if (!passwordVerified) {
|
if (!passwordVerified) {
|
||||||
|
console.log('Incorrect password')
|
||||||
return c.json('Incorrect password', StatusCodes.BAD_REQUEST)
|
return c.json('Incorrect password', StatusCodes.BAD_REQUEST)
|
||||||
}
|
}
|
||||||
return c.json({ }, StatusCodes.OK)
|
return c.json({}, StatusCodes.OK)
|
||||||
})
|
})
|
||||||
.post('/update/email', requireAuth, zValidator('json', updateEmailDto), limiter({ limit: 10, minutes: 60 }), async (c) => {
|
.post('/update/email', requireAuth, zValidator('json', updateEmailDto), limiter({ limit: 10, minutes: 60 }), async (c) => {
|
||||||
const user = c.var.user
|
const user = c.var.user
|
||||||
const { email } = c.req.valid('json')
|
const { email } = c.req.valid('json')
|
||||||
const updatedUser = await this.iamService.updateEmail(user.id, { email })
|
const updatedUser = await this.iamService.updateEmail(user.id, { email })
|
||||||
if (!updatedUser) {
|
if (!updatedUser) {
|
||||||
return c.json("Email already in use", StatusCodes.BAD_REQUEST);
|
return c.json('Email already in use', StatusCodes.BAD_REQUEST)
|
||||||
}
|
}
|
||||||
return c.json({ user: updatedUser }, StatusCodes.OK)
|
return c.json({ user: updatedUser }, StatusCodes.OK)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,62 @@
|
||||||
import 'reflect-metadata';
|
import 'reflect-metadata'
|
||||||
import { Hono } from 'hono';
|
import { inject, injectable } from 'tsyringe'
|
||||||
import { inject, injectable } from 'tsyringe';
|
import { Hono } from 'hono'
|
||||||
import { requireAuth } from "../middleware/auth.middleware";
|
import { zValidator } from '@hono/zod-validator'
|
||||||
import type { HonoTypes } from '../types';
|
import { requireAuth } from '../middleware/auth.middleware'
|
||||||
import type { Controller } from '$lib/server/api/interfaces/controller.interface';
|
import type { HonoTypes } from '../types'
|
||||||
import { TotpService } from '$lib/server/api/services/totp.service';
|
import type { Controller } from '$lib/server/api/interfaces/controller.interface'
|
||||||
import {StatusCodes} from "$lib/constants/status-codes";
|
import { TotpService } from '$lib/server/api/services/totp.service'
|
||||||
|
import { StatusCodes } from '$lib/constants/status-codes'
|
||||||
|
import { verifyTotpDto } from '$lib/dtos/verify-totp.dto'
|
||||||
|
import { UsersService } from '../services/users.service'
|
||||||
|
import { CredentialsType } from '$db/tables'
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class MfaController implements Controller {
|
export class MfaController implements Controller {
|
||||||
controller = new Hono<HonoTypes>();
|
controller = new Hono<HonoTypes>()
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@inject(TotpService) private readonly totpService: TotpService
|
@inject(TotpService) private readonly totpService: TotpService,
|
||||||
) {
|
@inject(UsersService) private readonly usersService: UsersService,
|
||||||
}
|
) {}
|
||||||
|
|
||||||
|
|
||||||
routes() {
|
routes() {
|
||||||
return this.controller
|
return this.controller
|
||||||
.get('/totp', requireAuth, async (c) => {
|
.get('/totp', requireAuth, async (c) => {
|
||||||
const user = c.var.user;
|
const user = c.var.user
|
||||||
const totpCredential = await this.totpService.findOneByUserId(user.id);
|
const totpCredential = await this.totpService.findOneByUserId(user.id)
|
||||||
return c.json({ totpCredential });
|
return c.json({ totpCredential })
|
||||||
})
|
})
|
||||||
.post('/totp', requireAuth, async (c) => {
|
.post('/totp', requireAuth, async (c) => {
|
||||||
const user = c.var.user;
|
const user = c.var.user
|
||||||
const totpCredential = await this.totpService.create(user.id);
|
const totpCredential = await this.totpService.create(user.id)
|
||||||
return c.json({ totpCredential })
|
return c.json({ totpCredential })
|
||||||
})
|
})
|
||||||
.delete('/totp', requireAuth, async (c) => {
|
.delete('/totp', requireAuth, async (c) => {
|
||||||
const user = c.var.user;
|
const user = c.var.user
|
||||||
await this.totpService.deleteOneByUserId(user.id);
|
try {
|
||||||
return c.status(StatusCodes.NO_CONTENT);
|
await this.totpService.deleteOneByUserIdAndType(user.id, CredentialsType.TOTP)
|
||||||
});
|
console.log('TOTP deleted')
|
||||||
|
return c.body(null, StatusCodes.NO_CONTENT)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
return c.status(StatusCodes.INTERNAL_SERVER_ERROR)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.post('/totp/verify', requireAuth, zValidator('json', verifyTotpDto), async (c) => {
|
||||||
|
try {
|
||||||
|
const user = c.var.user
|
||||||
|
const { code } = c.req.valid('json')
|
||||||
|
const verified = await this.totpService.verify(user.id, code)
|
||||||
|
if (verified) {
|
||||||
|
this.usersService.updateUser(user.id, { mfa_enabled: true })
|
||||||
|
return c.json({}, StatusCodes.OK)
|
||||||
|
}
|
||||||
|
return c.json({}, StatusCodes.BAD_REQUEST)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
return c.status(StatusCodes.INTERNAL_SERVER_ERROR)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -23,6 +23,7 @@ export const lucia = new Lucia(adapter, {
|
||||||
email: attributes.email,
|
email: attributes.email,
|
||||||
firstName: attributes.first_name,
|
firstName: attributes.first_name,
|
||||||
lastName: attributes.last_name,
|
lastName: attributes.last_name,
|
||||||
|
mfa_enabled: attributes.mfa_enabled,
|
||||||
theme: attributes.theme,
|
theme: attributes.theme,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
@ -56,6 +57,7 @@ declare module 'lucia' {
|
||||||
email: string;
|
email: string;
|
||||||
first_name: string;
|
first_name: string;
|
||||||
last_name: string;
|
last_name: string;
|
||||||
|
mfa_enabled: boolean;
|
||||||
theme: string;
|
theme: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE "users" ADD COLUMN "enabled" boolean DEFAULT false NOT NULL;
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE "users" RENAME COLUMN "enabled" TO "mfa_enabled";
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -29,6 +29,20 @@
|
||||||
"when": 1723593488634,
|
"when": 1723593488634,
|
||||||
"tag": "0003_worried_taskmaster",
|
"tag": "0003_worried_taskmaster",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 4,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1725055403926,
|
||||||
|
"tag": "0004_heavy_sphinx",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 5,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1725055643756,
|
||||||
|
"tag": "0005_true_mathemanic",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { boolean, pgTable, text, uuid } from 'drizzle-orm/pg-core';
|
import { boolean, pgTable, text, uuid } from 'drizzle-orm/pg-core'
|
||||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
import { type InferSelectModel, relations } from 'drizzle-orm'
|
||||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
import { createId as cuid2 } from '@paralleldrive/cuid2'
|
||||||
import { timestamps } from '../utils';
|
import { timestamps } from '../utils'
|
||||||
import {user_roles} from './userRoles';
|
import { user_roles } from './userRoles'
|
||||||
|
|
||||||
export const usersTable = pgTable('users', {
|
export const usersTable = pgTable('users', {
|
||||||
id: uuid('id').primaryKey().defaultRandom(),
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
|
@ -15,12 +15,13 @@ export const usersTable = pgTable('users', {
|
||||||
last_name: text('last_name'),
|
last_name: text('last_name'),
|
||||||
verified: boolean('verified').default(false),
|
verified: boolean('verified').default(false),
|
||||||
receive_email: boolean('receive_email').default(false),
|
receive_email: boolean('receive_email').default(false),
|
||||||
|
mfa_enabled: boolean('mfa_enabled').notNull().default(false),
|
||||||
theme: text('theme').default('system'),
|
theme: text('theme').default('system'),
|
||||||
...timestamps,
|
...timestamps,
|
||||||
});
|
})
|
||||||
|
|
||||||
export const userRelations = relations(usersTable, ({ many }) => ({
|
export const userRelations = relations(usersTable, ({ many }) => ({
|
||||||
user_roles: many(user_roles),
|
user_roles: many(user_roles),
|
||||||
}));
|
}))
|
||||||
|
|
||||||
export type Users = InferSelectModel<typeof usersTable>;
|
export type Users = InferSelectModel<typeof usersTable>
|
||||||
|
|
|
||||||
|
|
@ -1,50 +1,50 @@
|
||||||
import type { MiddlewareHandler } from 'hono';
|
import type { MiddlewareHandler } from 'hono'
|
||||||
import { createMiddleware } from 'hono/factory';
|
import { createMiddleware } from 'hono/factory'
|
||||||
import type { HonoTypes } from '../types';
|
import type { HonoTypes } from '../types'
|
||||||
import { lucia } from '../infrastructure/auth/lucia';
|
import { lucia } from '../infrastructure/auth/lucia'
|
||||||
import { verifyRequestOrigin } from 'lucia';
|
import { verifyRequestOrigin } from 'oslo/request'
|
||||||
import type { Session, User } from 'lucia';
|
import type { Session, User } from 'lucia'
|
||||||
import { Unauthorized } from '../common/errors';
|
import { Unauthorized } from '../common/errors'
|
||||||
|
|
||||||
export const verifyOrigin: MiddlewareHandler<HonoTypes> = createMiddleware(async (c, next) => {
|
export const verifyOrigin: MiddlewareHandler<HonoTypes> = createMiddleware(async (c, next) => {
|
||||||
if (c.req.method === "GET") {
|
if (c.req.method === 'GET') {
|
||||||
return next();
|
return next()
|
||||||
}
|
}
|
||||||
const originHeader = c.req.header("Origin") ?? null;
|
const originHeader = c.req.header('Origin') ?? null
|
||||||
const hostHeader = c.req.header("Host") ?? null;
|
const hostHeader = c.req.header('Host') ?? null
|
||||||
if (!originHeader || !hostHeader || !verifyRequestOrigin(originHeader, [hostHeader])) {
|
if (!originHeader || !hostHeader || !verifyRequestOrigin(originHeader, [hostHeader])) {
|
||||||
return c.body(null, 403);
|
return c.body(null, 403)
|
||||||
}
|
}
|
||||||
return next();
|
return next()
|
||||||
})
|
})
|
||||||
|
|
||||||
export const validateAuthSession: MiddlewareHandler<HonoTypes> = createMiddleware(async (c, next) => {
|
export const validateAuthSession: MiddlewareHandler<HonoTypes> = createMiddleware(async (c, next) => {
|
||||||
const sessionId = lucia.readSessionCookie(c.req.header("Cookie") ?? "");
|
const sessionId = lucia.readSessionCookie(c.req.header('Cookie') ?? '')
|
||||||
if (!sessionId) {
|
if (!sessionId) {
|
||||||
c.set("user", null);
|
c.set('user', null)
|
||||||
c.set("session", null);
|
c.set('session', null)
|
||||||
return next();
|
return next()
|
||||||
}
|
}
|
||||||
|
|
||||||
const { session, user } = await lucia.validateSession(sessionId);
|
const { session, user } = await lucia.validateSession(sessionId)
|
||||||
if (session && session.fresh) {
|
if (session && session.fresh) {
|
||||||
c.header("Set-Cookie", lucia.createSessionCookie(session.id).serialize(), { append: true });
|
c.header('Set-Cookie', lucia.createSessionCookie(session.id).serialize(), { append: true })
|
||||||
}
|
}
|
||||||
if (!session) {
|
if (!session) {
|
||||||
c.header("Set-Cookie", lucia.createBlankSessionCookie().serialize(), { append: true });
|
c.header('Set-Cookie', lucia.createBlankSessionCookie().serialize(), { append: true })
|
||||||
}
|
}
|
||||||
c.set("session", session);
|
c.set('session', session)
|
||||||
c.set("user", user);
|
c.set('user', user)
|
||||||
return next();
|
return next()
|
||||||
})
|
})
|
||||||
|
|
||||||
export const requireAuth: MiddlewareHandler<{
|
export const requireAuth: MiddlewareHandler<{
|
||||||
Variables: {
|
Variables: {
|
||||||
session: Session;
|
session: Session
|
||||||
user: User;
|
user: User
|
||||||
};
|
}
|
||||||
}> = createMiddleware(async (c, next) => {
|
}> = createMiddleware(async (c, next) => {
|
||||||
const user = c.var.user;
|
const user = c.var.user
|
||||||
if (!user) throw Unauthorized('You must be logged in to access this resource');
|
if (!user) throw Unauthorized('You must be logged in to access this resource')
|
||||||
return next();
|
return next()
|
||||||
});
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,83 +1,69 @@
|
||||||
import { and, eq, type InferInsertModel } from "drizzle-orm";
|
import { and, eq, type InferInsertModel } from 'drizzle-orm'
|
||||||
import { credentialsTable, CredentialsType } from "../infrastructure/database/tables/credentials.table";
|
import { credentialsTable, CredentialsType } from '../infrastructure/database/tables/credentials.table'
|
||||||
import { takeFirstOrThrow } from "../infrastructure/database/utils";
|
import { takeFirstOrThrow } from '../infrastructure/database/utils'
|
||||||
import {inject, injectable} from "tsyringe";
|
import { inject, injectable } from 'tsyringe'
|
||||||
import {DatabaseProvider} from "$lib/server/api/providers";
|
import { DatabaseProvider } from '$lib/server/api/providers'
|
||||||
|
|
||||||
export type CreateCredentials = InferInsertModel<typeof credentialsTable>;
|
export type CreateCredentials = InferInsertModel<typeof credentialsTable>
|
||||||
export type UpdateCredentials = Partial<CreateCredentials>;
|
export type UpdateCredentials = Partial<CreateCredentials>
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class CredentialsRepository {
|
export class CredentialsRepository {
|
||||||
constructor(@inject(DatabaseProvider) private readonly db: DatabaseProvider) { }
|
constructor(@inject(DatabaseProvider) private readonly db: DatabaseProvider) {}
|
||||||
|
|
||||||
async findOneByUserId(userId: string) {
|
async findOneByUserId(userId: string) {
|
||||||
return this.db.query.credentialsTable.findFirst({
|
return this.db.query.credentialsTable.findFirst({
|
||||||
where: eq(credentialsTable.user_id, userId)
|
where: eq(credentialsTable.user_id, userId),
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async findOneByUserIdAndType(userId: string, type: CredentialsType) {
|
async findOneByUserIdAndType(userId: string, type: CredentialsType) {
|
||||||
return this.db.query.credentialsTable.findFirst({
|
return this.db.query.credentialsTable.findFirst({
|
||||||
where: and(
|
where: and(eq(credentialsTable.user_id, userId), eq(credentialsTable.type, type)),
|
||||||
eq(credentialsTable.user_id, userId),
|
})
|
||||||
eq(credentialsTable.type, type)
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async findPasswordCredentialsByUserId(userId: string) {
|
async findPasswordCredentialsByUserId(userId: string) {
|
||||||
return this.db.query.credentialsTable.findFirst({
|
return this.db.query.credentialsTable.findFirst({
|
||||||
where: and(
|
where: and(eq(credentialsTable.user_id, userId), eq(credentialsTable.type, CredentialsType.PASSWORD)),
|
||||||
eq(credentialsTable.user_id, userId),
|
})
|
||||||
eq(credentialsTable.type, CredentialsType.PASSWORD)
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async findTOTPCredentialsByUserId(userId: string) {
|
async findTOTPCredentialsByUserId(userId: string) {
|
||||||
return this.db.query.credentialsTable.findFirst({
|
return this.db.query.credentialsTable.findFirst({
|
||||||
where: and(
|
where: and(eq(credentialsTable.user_id, userId), eq(credentialsTable.type, CredentialsType.TOTP)),
|
||||||
eq(credentialsTable.user_id, userId),
|
})
|
||||||
eq(credentialsTable.type, CredentialsType.TOTP)
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async findOneById(id: string) {
|
async findOneById(id: string) {
|
||||||
return this.db.query.credentialsTable.findFirst({
|
return this.db.query.credentialsTable.findFirst({
|
||||||
where: eq(credentialsTable.id, id)
|
where: eq(credentialsTable.id, id),
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async findOneByIdOrThrow(id: string) {
|
async findOneByIdOrThrow(id: string) {
|
||||||
const credentials = await this.findOneById(id);
|
const credentials = await this.findOneById(id)
|
||||||
if (!credentials) throw Error('Credentials not found');
|
if (!credentials) throw Error('Credentials not found')
|
||||||
return credentials;
|
return credentials
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(data: CreateCredentials) {
|
async create(data: CreateCredentials) {
|
||||||
return this.db.insert(credentialsTable).values(data).returning().then(takeFirstOrThrow);
|
return this.db.insert(credentialsTable).values(data).returning().then(takeFirstOrThrow)
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(id: string, data: UpdateCredentials) {
|
async update(id: string, data: UpdateCredentials) {
|
||||||
return this.db
|
return this.db.update(credentialsTable).set(data).where(eq(credentialsTable.id, id)).returning().then(takeFirstOrThrow)
|
||||||
.update(credentialsTable)
|
|
||||||
.set(data)
|
|
||||||
.where(eq(credentialsTable.id, id))
|
|
||||||
.returning()
|
|
||||||
.then(takeFirstOrThrow);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete(id: string) {
|
async delete(id: string) {
|
||||||
return this.db
|
return this.db.delete(credentialsTable).where(eq(credentialsTable.id, id))
|
||||||
.delete(credentialsTable)
|
|
||||||
.where(eq(credentialsTable.id, id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteByUserId(userId: string) {
|
async deleteByUserId(userId: string) {
|
||||||
return this.db
|
return this.db.delete(credentialsTable).where(eq(credentialsTable.user_id, userId))
|
||||||
.delete(credentialsTable)
|
}
|
||||||
.where(eq(credentialsTable.user_id, userId));
|
|
||||||
|
async deleteByUserIdAndType(userId: string, type: CredentialsType) {
|
||||||
|
return this.db.delete(credentialsTable).where(and(eq(credentialsTable.user_id, userId), eq(credentialsTable.type, type)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import { inject, injectable } from "tsyringe";
|
import { inject, injectable } from "tsyringe";
|
||||||
import { HMAC } from 'oslo/crypto';
|
import { HMAC } from 'oslo/crypto';
|
||||||
import { encodeHex } from 'oslo/encoding';
|
import { decodeHex, encodeHex } from 'oslo/encoding';
|
||||||
import {CredentialsRepository} from "$lib/server/api/repositories/credentials.repository";
|
import {CredentialsRepository} from "$lib/server/api/repositories/credentials.repository";
|
||||||
|
import { TOTPController } from "oslo/otp";
|
||||||
|
import type { CredentialsType } from "$db/tables";
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class TotpService {
|
export class TotpService {
|
||||||
|
|
@ -15,6 +17,14 @@ export class TotpService {
|
||||||
return this.credentialsRepository.findTOTPCredentialsByUserId(userId);
|
return this.credentialsRepository.findTOTPCredentialsByUserId(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findOneByUserIdOrThrow(userId: string) {
|
||||||
|
const credential = await this.findOneByUserId(userId);
|
||||||
|
if (!credential) {
|
||||||
|
throw new Error('TOTP credential not found');
|
||||||
|
}
|
||||||
|
return credential;
|
||||||
|
}
|
||||||
|
|
||||||
async create(userId: string) {
|
async create(userId: string) {
|
||||||
const twoFactorSecret = await new HMAC('SHA-1').generateKey();
|
const twoFactorSecret = await new HMAC('SHA-1').generateKey();
|
||||||
|
|
||||||
|
|
@ -33,4 +43,16 @@ export class TotpService {
|
||||||
async deleteOneByUserId(userId: string) {
|
async deleteOneByUserId(userId: string) {
|
||||||
return this.credentialsRepository.deleteByUserId(userId);
|
return this.credentialsRepository.deleteByUserId(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteOneByUserIdAndType(userId: string, type: CredentialsType) {
|
||||||
|
return this.credentialsRepository.deleteByUserIdAndType(userId, type)
|
||||||
|
}
|
||||||
|
|
||||||
|
async verify(userId: string, code: string) {
|
||||||
|
const credential = await this.credentialsRepository.findTOTPCredentialsByUserId(userId);
|
||||||
|
if (!credential) {
|
||||||
|
throw new Error('TOTP credential not found');
|
||||||
|
}
|
||||||
|
return await new TOTPController().verify(code, decodeHex(credential.secret_data))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -10,7 +10,7 @@ export async function parseApiResponse<T>(response: ClientResponse<T>) {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
const data = await response.json() as T;
|
const data = await response.json() as T;
|
||||||
|
|
||||||
return { data, error: null, status: response.status };
|
return { data, error: null, response }
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle errors
|
// handle errors
|
||||||
|
|
|
||||||
|
|
@ -1,43 +1,43 @@
|
||||||
import { type Actions, fail, error } from '@sveltejs/kit';
|
import { type Actions, fail, error } from '@sveltejs/kit'
|
||||||
import { eq } from 'drizzle-orm';
|
import { eq } from 'drizzle-orm'
|
||||||
import { encodeHex, decodeHex } from 'oslo/encoding';
|
import { encodeHex, decodeHex } from 'oslo/encoding'
|
||||||
import { Argon2id } from 'oslo/password';
|
import { Argon2id } from 'oslo/password'
|
||||||
import { createTOTPKeyURI, TOTPController } from 'oslo/otp';
|
import { createTOTPKeyURI, TOTPController } from 'oslo/otp'
|
||||||
import { HMAC } from 'oslo/crypto';
|
import { HMAC } from 'oslo/crypto'
|
||||||
import kebabCase from 'just-kebab-case';
|
import kebabCase from 'just-kebab-case'
|
||||||
import QRCode from 'qrcode';
|
import QRCode from 'qrcode'
|
||||||
import { zod } from 'sveltekit-superforms/adapters';
|
import { zod } from 'sveltekit-superforms/adapters'
|
||||||
import { setError, superValidate } from 'sveltekit-superforms/server';
|
import { setError, superValidate } from 'sveltekit-superforms/server'
|
||||||
import { redirect, setFlash } from 'sveltekit-flash-message/server';
|
import { redirect, setFlash } from 'sveltekit-flash-message/server'
|
||||||
import type { PageServerLoad } from '../../$types';
|
import type { PageServerLoad } from '../../$types'
|
||||||
import { addTwoFactorSchema, removeTwoFactorSchema } from '$lib/validations/account';
|
import { addTwoFactorSchema, removeTwoFactorSchema } from '$lib/validations/account'
|
||||||
import { notSignedInMessage } from '$lib/flashMessages';
|
import { notSignedInMessage } from '$lib/flashMessages'
|
||||||
import { db } from '$lib/server/api/infrastructure/database';
|
import { db } from '$lib/server/api/infrastructure/database'
|
||||||
import { recoveryCodesTable, credentialsTable, usersTable, type Credentials } from '$lib/server/api/infrastructure/database/tables';
|
import { recoveryCodesTable, credentialsTable, usersTable, type Credentials } from '$lib/server/api/infrastructure/database/tables'
|
||||||
import { userNotAuthenticated } from '$lib/server/auth-utils';
|
import { userNotAuthenticated } from '$lib/server/auth-utils'
|
||||||
import env from '$src/env';
|
import env from '$src/env'
|
||||||
|
import { StatusCodes } from '$lib/constants/status-codes'
|
||||||
|
|
||||||
export const load: PageServerLoad = async (event) => {
|
export const load: PageServerLoad = async (event) => {
|
||||||
const { locals } = event;
|
const { locals } = event
|
||||||
|
|
||||||
const authedUser = await locals.getAuthedUser();
|
const authedUser = await locals.getAuthedUser()
|
||||||
if (!authedUser) {
|
if (!authedUser) {
|
||||||
throw redirect(302, '/login', notSignedInMessage, event);
|
throw redirect(302, '/login', notSignedInMessage, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
const addTwoFactorForm = await superValidate(event, zod(addTwoFactorSchema));
|
const addTwoFactorForm = await superValidate(event, zod(addTwoFactorSchema))
|
||||||
const removeTwoFactorForm = await superValidate(event, zod(removeTwoFactorSchema));
|
const removeTwoFactorForm = await superValidate(event, zod(removeTwoFactorSchema))
|
||||||
// const addAuthNFactorForm = await superValidate(event, zod(addAuthNFactorSchema));
|
// const addAuthNFactorForm = await superValidate(event, zod(addAuthNFactorSchema));
|
||||||
|
|
||||||
const { data, error } = await locals.api.mfa.totp.$get().then(locals.parseApiResponse);
|
const { data, error } = await locals.api.mfa.totp.$get().then(locals.parseApiResponse)
|
||||||
if (error || !data) {
|
if (error || !data) {
|
||||||
return fail(500, {
|
return fail(500, {
|
||||||
addTwoFactorForm,
|
addTwoFactorForm,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
const { totpCredential } = data
|
const { totpCredential } = data
|
||||||
|
if (totpCredential && authedUser.mfa_enabled) {
|
||||||
if (totpCredential) {
|
|
||||||
return {
|
return {
|
||||||
addTwoFactorForm,
|
addTwoFactorForm,
|
||||||
removeTwoFactorForm,
|
removeTwoFactorForm,
|
||||||
|
|
@ -48,9 +48,13 @@ export const load: PageServerLoad = async (event) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const issuer = kebabCase(env.PUBLIC_SITE_NAME);
|
if (totpCredential && !authedUser.mfa_enabled) {
|
||||||
const accountName = authedUser.email || authedUser.username;
|
await locals.api.mfa.totp.$delete().then(locals.parseApiResponse)
|
||||||
const { data: createdTotpData, error: createdTotpError } = await locals.api.mfa.totp.$post().then(locals.parseApiResponse);
|
}
|
||||||
|
|
||||||
|
const issuer = kebabCase(env.PUBLIC_SITE_NAME)
|
||||||
|
const accountName = authedUser.email || authedUser.username
|
||||||
|
const { data: createdTotpData, error: createdTotpError } = await locals.api.mfa.totp.$post().then(locals.parseApiResponse)
|
||||||
|
|
||||||
if (createdTotpError || !createdTotpData) {
|
if (createdTotpError || !createdTotpData) {
|
||||||
return fail(500, {
|
return fail(500, {
|
||||||
|
|
@ -58,19 +62,19 @@ export const load: PageServerLoad = async (event) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const { totpCredential: createdTotpCredentials } = createdTotpData;
|
const { totpCredential: createdTotpCredentials } = createdTotpData
|
||||||
// pass the website's name and the user identifier (e.g. email, username)
|
// pass the website's name and the user identifier (e.g. email, username)
|
||||||
if (!createdTotpCredentials?.secret_data) {
|
if (!createdTotpCredentials?.secret_data) {
|
||||||
return fail(500, {
|
return fail(500, {
|
||||||
addTwoFactorForm,
|
addTwoFactorForm,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
const totpUri = createTOTPKeyURI(issuer, accountName, createdTotpCredentials.secret_data);
|
const totpUri = createTOTPKeyURI(issuer, accountName, decodeHex(createdTotpCredentials.secret_data))
|
||||||
|
|
||||||
addTwoFactorForm.data = {
|
addTwoFactorForm.data = {
|
||||||
current_password: '',
|
current_password: '',
|
||||||
two_factor_code: '',
|
two_factor_code: '',
|
||||||
};
|
}
|
||||||
return {
|
return {
|
||||||
addTwoFactorForm,
|
addTwoFactorForm,
|
||||||
removeTwoFactorForm,
|
removeTwoFactorForm,
|
||||||
|
|
@ -78,8 +82,8 @@ export const load: PageServerLoad = async (event) => {
|
||||||
recoveryCodes: [],
|
recoveryCodes: [],
|
||||||
totpUri,
|
totpUri,
|
||||||
qrCode: await QRCode.toDataURL(totpUri),
|
qrCode: await QRCode.toDataURL(totpUri),
|
||||||
};
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export const actions: Actions = {
|
export const actions: Actions = {
|
||||||
enableTotp: async (event) => {
|
enableTotp: async (event) => {
|
||||||
|
|
@ -98,31 +102,12 @@ export const actions: Actions = {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data, error } = await locals.api.mfa.totp.$get().then(locals.parseApiResponse)
|
const { error: verifyPasswordError } = await locals.api.me.verify.password.$post({
|
||||||
if (error || !data) {
|
|
||||||
return fail(500, {
|
|
||||||
addTwoFactorForm,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const { totpCredential } = data
|
|
||||||
|
|
||||||
if (!totpCredential) {
|
|
||||||
addTwoFactorForm.data.current_password = ''
|
|
||||||
addTwoFactorForm.data.two_factor_code = ''
|
|
||||||
return setError(addTwoFactorForm, 'Error occurred. Please try again or contact support if you need further help.')
|
|
||||||
}
|
|
||||||
|
|
||||||
if (totpCredential.secret_data === '' || totpCredential.secret_data === null) {
|
|
||||||
addTwoFactorForm.data.current_password = ''
|
|
||||||
addTwoFactorForm.data.two_factor_code = ''
|
|
||||||
return setError(addTwoFactorForm, 'Error occurred. Please try again or contact support if you need further help.')
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentPasswordVerified = await locals.api.me.verify.password.$post({
|
|
||||||
json: { password: addTwoFactorForm.data.current_password },
|
json: { password: addTwoFactorForm.data.current_password },
|
||||||
});
|
}).then(locals.parseApiResponse)
|
||||||
|
|
||||||
if (!currentPasswordVerified) {
|
if (verifyPasswordError) {
|
||||||
|
console.log(verifyPasswordError)
|
||||||
return setError(addTwoFactorForm, 'current_password', 'Your password is incorrect')
|
return setError(addTwoFactorForm, 'current_password', 'Your password is incorrect')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,14 +116,16 @@ export const actions: Actions = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const twoFactorCode = addTwoFactorForm.data.two_factor_code
|
const twoFactorCode = addTwoFactorForm.data.two_factor_code
|
||||||
const validOTP = await new TOTPController().verify(twoFactorCode, decodeHex(twoFactorDetails.secret))
|
const { error: verifyTotpError } = locals.api.mfa.totp.verify
|
||||||
|
.$post({
|
||||||
|
json: { code: twoFactorCode },
|
||||||
|
})
|
||||||
|
.then(locals.parseApiResponse)
|
||||||
|
|
||||||
if (!validOTP) {
|
if (verifyTotpError) {
|
||||||
return setError(addTwoFactorForm, 'two_factor_code', 'Invalid code')
|
return setError(addTwoFactorForm, 'two_factor_code', 'Invalid code')
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.update(twoFactor).set({ enabled: true }).where(eq(twoFactor.userId, user!.id!))
|
|
||||||
|
|
||||||
redirect(302, '/profile/security/two-factor/recovery-codes')
|
redirect(302, '/profile/security/two-factor/recovery-codes')
|
||||||
},
|
},
|
||||||
disableTotp: async (event) => {
|
disableTotp: async (event) => {
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,7 @@ import { redirect } from 'sveltekit-flash-message/server';
|
||||||
import { db } from '$lib/server/api/infrastructure/database';
|
import { db } from '$lib/server/api/infrastructure/database';
|
||||||
import { notSignedInMessage } from '$lib/flashMessages';
|
import { notSignedInMessage } from '$lib/flashMessages';
|
||||||
import type { PageServerLoad } from '../../../$types';
|
import type { PageServerLoad } from '../../../$types';
|
||||||
import { recoveryCodesTable, twoFactorTable, usersTable} from '$lib/server/api/infrastructure/database/tables';
|
import { recoveryCodesTable } from '$lib/server/api/infrastructure/database/tables';
|
||||||
import { userNotAuthenticated } from '$lib/server/auth-utils';
|
|
||||||
|
|
||||||
export const load: PageServerLoad = async (event) => {
|
export const load: PageServerLoad = async (event) => {
|
||||||
const { locals } = event;
|
const { locals } = event;
|
||||||
|
|
@ -16,51 +15,31 @@ export const load: PageServerLoad = async (event) => {
|
||||||
throw redirect(302, '/login', notSignedInMessage, event);
|
throw redirect(302, '/login', notSignedInMessage, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dbUser = await db.query.usersTable.findFirst({
|
if (authedUser.mfa_enabled) {
|
||||||
where: eq(usersTable.id, authedUser.id),
|
const dbRecoveryCodes = await db.query.recoveryCodesTable.findMany({
|
||||||
});
|
where: eq(recoveryCodesTable.userId, authedUser.id),
|
||||||
|
})
|
||||||
if (!dbUser) {
|
|
||||||
throw redirect(302, '/login', notSignedInMessage, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
const twoFactorDetails = await db.query.twoFactor.findFirst({
|
|
||||||
where: eq(twoFactor.userId, dbUser.id),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (twoFactorDetails?.enabled) {
|
|
||||||
const dbRecoveryCodes = await db.query.recoveryCodes.findMany({
|
|
||||||
where: eq(recoveryCodes.userId, authedUser.id),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (dbRecoveryCodes.length === 0) {
|
if (dbRecoveryCodes.length === 0) {
|
||||||
const createdRecoveryCodes = Array.from({ length: 5 }, () =>
|
const createdRecoveryCodes = Array.from({ length: 5 }, () => generateRandomString(10, alphabet('A-Z', '0-9')))
|
||||||
generateRandomString(10, alphabet('A-Z', '0-9')),
|
|
||||||
);
|
|
||||||
if (createdRecoveryCodes) {
|
if (createdRecoveryCodes) {
|
||||||
for (const code of createdRecoveryCodes) {
|
for (const code of createdRecoveryCodes) {
|
||||||
const hashedCode = await new Argon2id().hash(code);
|
const hashedCode = await new Argon2id().hash(code)
|
||||||
console.log('Inserting recovery code', code, hashedCode);
|
console.log('Inserting recovery code', code, hashedCode)
|
||||||
await db.insert(recoveryCodes).values({
|
await db.insert(recoveryCodesTable).values({
|
||||||
userId: authedUser.id,
|
userId: authedUser.id,
|
||||||
code: hashedCode,
|
code: hashedCode,
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
recoveryCodes: createdRecoveryCodes,
|
recoveryCodes: createdRecoveryCodes,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
recoveryCodes: [],
|
recoveryCodes: [],
|
||||||
};
|
|
||||||
} else {
|
|
||||||
console.error('2FA not enabled');
|
|
||||||
redirect(
|
|
||||||
302,
|
|
||||||
'/profile',
|
|
||||||
{ message: 'Two-Factor Authentication is not enabled', type: 'error' },
|
|
||||||
event,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
console.error('2FA not enabled')
|
||||||
|
redirect(302, '/profile', { message: 'Two-Factor Authentication is not enabled', type: 'error' }, event)
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue