mirror of
https://github.com/immich-app/immich
synced 2026-08-22 13:13:05 +00:00
feat: jwt auth for maintenance
This commit is contained in:
parent
5f4a72735c
commit
014669f4a4
9 changed files with 482 additions and 48 deletions
383
pnpm-lock.yaml
generated
383
pnpm-lock.yaml
generated
|
|
@ -310,6 +310,9 @@ importers:
|
|||
'@nestjs/core':
|
||||
specifier: ^11.0.4
|
||||
version: 11.1.7(@nestjs/common@11.1.7(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.7)(@nestjs/websockets@11.1.7)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||
'@nestjs/jwt':
|
||||
specifier: ^11.0.1
|
||||
version: 11.0.1(@nestjs/common@11.1.7(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))
|
||||
'@nestjs/platform-express':
|
||||
specifier: ^11.0.4
|
||||
version: 11.1.7(@nestjs/common@11.1.7(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7)
|
||||
|
|
@ -613,19 +616,19 @@ importers:
|
|||
version: 13.15.3
|
||||
'@vitest/coverage-v8':
|
||||
specifier: ^3.0.0
|
||||
version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.13)(happy-dom@20.0.8)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
version: 3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.13)(happy-dom@20.0.8)(jiti@1.21.7)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
eslint:
|
||||
specifier: ^9.14.0
|
||||
version: 9.38.0(jiti@2.6.1)
|
||||
version: 9.38.0(jiti@1.21.7)
|
||||
eslint-config-prettier:
|
||||
specifier: ^10.1.8
|
||||
version: 10.1.8(eslint@9.38.0(jiti@2.6.1))
|
||||
version: 10.1.8(eslint@9.38.0(jiti@1.21.7))
|
||||
eslint-plugin-prettier:
|
||||
specifier: ^5.1.3
|
||||
version: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.38.0(jiti@2.6.1)))(eslint@9.38.0(jiti@2.6.1))(prettier@3.6.2)
|
||||
version: 5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.38.0(jiti@1.21.7)))(eslint@9.38.0(jiti@1.21.7))(prettier@3.6.2)
|
||||
eslint-plugin-unicorn:
|
||||
specifier: ^60.0.0
|
||||
version: 60.0.0(eslint@9.38.0(jiti@2.6.1))
|
||||
version: 60.0.0(eslint@9.38.0(jiti@1.21.7))
|
||||
globals:
|
||||
specifier: ^16.0.0
|
||||
version: 16.4.0
|
||||
|
|
@ -661,16 +664,16 @@ importers:
|
|||
version: 5.9.3
|
||||
typescript-eslint:
|
||||
specifier: ^8.28.0
|
||||
version: 8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
version: 8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.9.3)
|
||||
unplugin-swc:
|
||||
specifier: ^1.4.5
|
||||
version: 1.5.8(@swc/core@1.13.5(@swc/helpers@0.5.17))(rollup@4.52.5)
|
||||
vite-tsconfig-paths:
|
||||
specifier: ^5.0.0
|
||||
version: 5.1.4(typescript@5.9.3)(vite@7.1.12(@types/node@22.18.13)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
version: 5.1.4(typescript@5.9.3)(vite@7.1.12(@types/node@22.18.13)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
vitest:
|
||||
specifier: ^3.0.0
|
||||
version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.13)(happy-dom@20.0.8)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.13)(happy-dom@20.0.8)(jiti@1.21.7)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
|
||||
web:
|
||||
dependencies:
|
||||
|
|
@ -3209,6 +3212,11 @@ packages:
|
|||
'@nestjs/websockets':
|
||||
optional: true
|
||||
|
||||
'@nestjs/jwt@11.0.1':
|
||||
resolution: {integrity: sha512-HXSsc7SAnCnjA98TsZqrE7trGtHDnYXWp4Ffy6LwSmck1QvbGYdMzBquXofX5l6tIRpeY4Qidl2Ti2CVG77Pdw==}
|
||||
peerDependencies:
|
||||
'@nestjs/common': ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0
|
||||
|
||||
'@nestjs/mapped-types@2.1.0':
|
||||
resolution: {integrity: sha512-W+n+rM69XsFdwORF11UqJahn4J3xi4g/ZEOlJNL6KoW5ygWSmBB2p0S2BZ4FQeS/NDH72e6xIcu35SfJnE8bXw==}
|
||||
peerDependencies:
|
||||
|
|
@ -4590,6 +4598,9 @@ packages:
|
|||
'@types/json-schema@7.0.15':
|
||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||
|
||||
'@types/jsonwebtoken@9.0.10':
|
||||
resolution: {integrity: sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==}
|
||||
|
||||
'@types/justified-layout@4.1.4':
|
||||
resolution: {integrity: sha512-q2ybP0u0NVj87oMnGZOGxY2iUN8ddr48zPOBHBdbOLpsMTA/keGj+93ou+OMCnJk0xewzlNIaVEkxM6VBD3E2w==}
|
||||
|
||||
|
|
@ -5361,6 +5372,9 @@ packages:
|
|||
resolution: {integrity: sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
|
||||
buffer-equal-constant-time@1.0.1:
|
||||
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
|
||||
|
||||
buffer-from@1.1.2:
|
||||
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
||||
|
||||
|
|
@ -6291,6 +6305,9 @@ packages:
|
|||
eastasianwidth@0.2.0:
|
||||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
|
||||
|
||||
ecdsa-sig-formatter@1.0.11:
|
||||
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
|
||||
|
||||
ee-first@1.1.1:
|
||||
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
||||
|
||||
|
|
@ -7714,12 +7731,22 @@ packages:
|
|||
jsonfile@6.2.0:
|
||||
resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==}
|
||||
|
||||
jsonwebtoken@9.0.2:
|
||||
resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==}
|
||||
engines: {node: '>=12', npm: '>=6'}
|
||||
|
||||
just-compare@2.3.0:
|
||||
resolution: {integrity: sha512-6shoR7HDT+fzfL3gBahx1jZG3hWLrhPAf+l7nCwahDdT9XDtosB9kIF0ZrzUp5QY8dJWfQVr5rnsPqsbvflDzg==}
|
||||
|
||||
justified-layout@4.1.0:
|
||||
resolution: {integrity: sha512-M5FimNMXgiOYerVRGsXZ2YK9YNCaTtwtYp7Hb2308U1Q9TXXHx5G0p08mcVR5O53qf8bWY4NJcPBxE6zuayXSg==}
|
||||
|
||||
jwa@1.4.2:
|
||||
resolution: {integrity: sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==}
|
||||
|
||||
jws@3.2.2:
|
||||
resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==}
|
||||
|
||||
kdbush@3.0.0:
|
||||
resolution: {integrity: sha512-hRkd6/XW4HTsA9vjVpY9tuXJYLSlelnkTmVFu4M9/7MIYQtFcHpbugAU7UbOfjOiVSVYl2fqgBuJ32JUmRo5Ew==}
|
||||
|
||||
|
|
@ -7919,15 +7946,36 @@ packages:
|
|||
lodash.defaults@4.2.0:
|
||||
resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
|
||||
|
||||
lodash.includes@4.3.0:
|
||||
resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==}
|
||||
|
||||
lodash.isarguments@3.1.0:
|
||||
resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==}
|
||||
|
||||
lodash.isboolean@3.0.3:
|
||||
resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==}
|
||||
|
||||
lodash.isinteger@4.0.4:
|
||||
resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==}
|
||||
|
||||
lodash.isnumber@3.0.3:
|
||||
resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==}
|
||||
|
||||
lodash.isplainobject@4.0.6:
|
||||
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
|
||||
|
||||
lodash.isstring@4.0.1:
|
||||
resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==}
|
||||
|
||||
lodash.memoize@4.1.2:
|
||||
resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==}
|
||||
|
||||
lodash.merge@4.6.2:
|
||||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||
|
||||
lodash.once@4.1.1:
|
||||
resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==}
|
||||
|
||||
lodash.uniq@4.5.0:
|
||||
resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==}
|
||||
|
||||
|
|
@ -14112,6 +14160,11 @@ snapshots:
|
|||
'@esbuild/win32-x64@0.25.11':
|
||||
optional: true
|
||||
|
||||
'@eslint-community/eslint-utils@4.9.0(eslint@9.38.0(jiti@1.21.7))':
|
||||
dependencies:
|
||||
eslint: 9.38.0(jiti@1.21.7)
|
||||
eslint-visitor-keys: 3.4.3
|
||||
|
||||
'@eslint-community/eslint-utils@4.9.0(eslint@9.38.0(jiti@2.6.1))':
|
||||
dependencies:
|
||||
eslint: 9.38.0(jiti@2.6.1)
|
||||
|
|
@ -14863,6 +14916,12 @@ snapshots:
|
|||
'@nestjs/platform-express': 11.1.7(@nestjs/common@11.1.7(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7)
|
||||
'@nestjs/websockets': 11.1.7(@nestjs/common@11.1.7(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.7)(@nestjs/platform-socket.io@11.1.7)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||
|
||||
'@nestjs/jwt@11.0.1(@nestjs/common@11.1.7(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))':
|
||||
dependencies:
|
||||
'@nestjs/common': 11.1.7(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||
'@types/jsonwebtoken': 9.0.10
|
||||
jsonwebtoken: 9.0.2
|
||||
|
||||
'@nestjs/mapped-types@2.1.0(@nestjs/common@11.1.7(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2))(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)':
|
||||
dependencies:
|
||||
'@nestjs/common': 11.1.7(class-transformer@0.5.1)(class-validator@0.14.2)(reflect-metadata@0.2.2)(rxjs@7.8.2)
|
||||
|
|
@ -16411,6 +16470,11 @@ snapshots:
|
|||
|
||||
'@types/json-schema@7.0.15': {}
|
||||
|
||||
'@types/jsonwebtoken@9.0.10':
|
||||
dependencies:
|
||||
'@types/ms': 2.1.0
|
||||
'@types/node': 22.18.13
|
||||
|
||||
'@types/justified-layout@4.1.4': {}
|
||||
|
||||
'@types/keygrip@1.0.6': {}
|
||||
|
|
@ -16643,6 +16707,23 @@ snapshots:
|
|||
dependencies:
|
||||
'@types/yargs-parser': 21.0.3
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.38.0(jiti@1.21.7))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
'@typescript-eslint/parser': 8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.9.3)
|
||||
'@typescript-eslint/scope-manager': 8.46.2
|
||||
'@typescript-eslint/type-utils': 8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.9.3)
|
||||
'@typescript-eslint/utils': 8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.9.3)
|
||||
'@typescript-eslint/visitor-keys': 8.46.2
|
||||
eslint: 9.38.0(jiti@1.21.7)
|
||||
graphemer: 1.4.0
|
||||
ignore: 7.0.5
|
||||
natural-compare: 1.4.0
|
||||
ts-api-utils: 2.1.0(typescript@5.9.3)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
|
|
@ -16660,6 +16741,18 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 8.46.2
|
||||
'@typescript-eslint/types': 8.46.2
|
||||
'@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3)
|
||||
'@typescript-eslint/visitor-keys': 8.46.2
|
||||
debug: 4.4.3
|
||||
eslint: 9.38.0(jiti@1.21.7)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 8.46.2
|
||||
|
|
@ -16690,6 +16783,18 @@ snapshots:
|
|||
dependencies:
|
||||
typescript: 5.9.3
|
||||
|
||||
'@typescript-eslint/type-utils@8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.46.2
|
||||
'@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3)
|
||||
'@typescript-eslint/utils': 8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.9.3)
|
||||
debug: 4.4.3
|
||||
eslint: 9.38.0(jiti@1.21.7)
|
||||
ts-api-utils: 2.1.0(typescript@5.9.3)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/type-utils@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 8.46.2
|
||||
|
|
@ -16720,6 +16825,17 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/utils@8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@1.21.7))
|
||||
'@typescript-eslint/scope-manager': 8.46.2
|
||||
'@typescript-eslint/types': 8.46.2
|
||||
'@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3)
|
||||
eslint: 9.38.0(jiti@1.21.7)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/utils@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@2.6.1))
|
||||
|
|
@ -16740,6 +16856,25 @@ snapshots:
|
|||
|
||||
'@vercel/oidc@3.0.3': {}
|
||||
|
||||
'@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.13)(happy-dom@20.0.8)(jiti@1.21.7)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))':
|
||||
dependencies:
|
||||
'@ampproject/remapping': 2.3.0
|
||||
'@bcoe/v8-coverage': 1.0.2
|
||||
ast-v8-to-istanbul: 0.3.3
|
||||
debug: 4.4.3
|
||||
istanbul-lib-coverage: 3.2.2
|
||||
istanbul-lib-report: 3.0.1
|
||||
istanbul-lib-source-maps: 5.0.6
|
||||
istanbul-reports: 3.1.7
|
||||
magic-string: 0.30.21
|
||||
magicast: 0.3.5
|
||||
std-env: 3.10.0
|
||||
test-exclude: 7.0.1
|
||||
tinyrainbow: 2.0.0
|
||||
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.13)(happy-dom@20.0.8)(jiti@1.21.7)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@vitest/coverage-v8@3.2.4(vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.13)(happy-dom@20.0.8)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))':
|
||||
dependencies:
|
||||
'@ampproject/remapping': 2.3.0
|
||||
|
|
@ -16786,6 +16921,14 @@ snapshots:
|
|||
chai: 5.2.0
|
||||
tinyrainbow: 2.0.0
|
||||
|
||||
'@vitest/mocker@3.2.4(vite@7.1.12(@types/node@22.18.13)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))':
|
||||
dependencies:
|
||||
'@vitest/spy': 3.2.4
|
||||
estree-walker: 3.0.3
|
||||
magic-string: 0.30.21
|
||||
optionalDependencies:
|
||||
vite: 7.1.12(@types/node@22.18.13)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
|
||||
'@vitest/mocker@3.2.4(vite@7.1.12(@types/node@22.18.13)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))':
|
||||
dependencies:
|
||||
'@vitest/spy': 3.2.4
|
||||
|
|
@ -17377,6 +17520,8 @@ snapshots:
|
|||
|
||||
buffer-crc32@1.0.0: {}
|
||||
|
||||
buffer-equal-constant-time@1.0.1: {}
|
||||
|
||||
buffer-from@1.1.2: {}
|
||||
|
||||
buffer@5.7.1:
|
||||
|
|
@ -18329,6 +18474,10 @@ snapshots:
|
|||
|
||||
eastasianwidth@0.2.0: {}
|
||||
|
||||
ecdsa-sig-formatter@1.0.11:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
ee-first@1.1.1: {}
|
||||
|
||||
electron-to-chromium@1.5.243: {}
|
||||
|
|
@ -18539,6 +18688,10 @@ snapshots:
|
|||
source-map: 0.6.1
|
||||
optional: true
|
||||
|
||||
eslint-config-prettier@10.1.8(eslint@9.38.0(jiti@1.21.7)):
|
||||
dependencies:
|
||||
eslint: 9.38.0(jiti@1.21.7)
|
||||
|
||||
eslint-config-prettier@10.1.8(eslint@9.38.0(jiti@2.6.1)):
|
||||
dependencies:
|
||||
eslint: 9.38.0(jiti@2.6.1)
|
||||
|
|
@ -18555,6 +18708,16 @@ snapshots:
|
|||
lodash.memoize: 4.1.2
|
||||
semver: 7.7.3
|
||||
|
||||
eslint-plugin-prettier@5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.38.0(jiti@1.21.7)))(eslint@9.38.0(jiti@1.21.7))(prettier@3.6.2):
|
||||
dependencies:
|
||||
eslint: 9.38.0(jiti@1.21.7)
|
||||
prettier: 3.6.2
|
||||
prettier-linter-helpers: 1.0.0
|
||||
synckit: 0.11.11
|
||||
optionalDependencies:
|
||||
'@types/eslint': 9.6.1
|
||||
eslint-config-prettier: 10.1.8(eslint@9.38.0(jiti@1.21.7))
|
||||
|
||||
eslint-plugin-prettier@5.5.4(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.38.0(jiti@2.6.1)))(eslint@9.38.0(jiti@2.6.1))(prettier@3.6.2):
|
||||
dependencies:
|
||||
eslint: 9.38.0(jiti@2.6.1)
|
||||
|
|
@ -18583,6 +18746,28 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- ts-node
|
||||
|
||||
eslint-plugin-unicorn@60.0.0(eslint@9.38.0(jiti@1.21.7)):
|
||||
dependencies:
|
||||
'@babel/helper-validator-identifier': 7.28.5
|
||||
'@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@1.21.7))
|
||||
'@eslint/plugin-kit': 0.3.5
|
||||
change-case: 5.4.4
|
||||
ci-info: 4.3.0
|
||||
clean-regexp: 1.0.0
|
||||
core-js-compat: 3.46.0
|
||||
eslint: 9.38.0(jiti@1.21.7)
|
||||
esquery: 1.6.0
|
||||
find-up-simple: 1.0.1
|
||||
globals: 16.4.0
|
||||
indent-string: 5.0.0
|
||||
is-builtin-module: 5.0.0
|
||||
jsesc: 3.1.0
|
||||
pluralize: 8.0.0
|
||||
regexp-tree: 0.1.27
|
||||
regjsparser: 0.12.0
|
||||
semver: 7.7.3
|
||||
strip-indent: 4.0.0
|
||||
|
||||
eslint-plugin-unicorn@60.0.0(eslint@9.38.0(jiti@2.6.1)):
|
||||
dependencies:
|
||||
'@babel/helper-validator-identifier': 7.28.5
|
||||
|
|
@ -18641,6 +18826,47 @@ snapshots:
|
|||
|
||||
eslint-visitor-keys@4.2.1: {}
|
||||
|
||||
eslint@9.38.0(jiti@1.21.7):
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@1.21.7))
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
'@eslint/config-array': 0.21.1
|
||||
'@eslint/config-helpers': 0.4.1
|
||||
'@eslint/core': 0.16.0
|
||||
'@eslint/eslintrc': 3.3.1
|
||||
'@eslint/js': 9.38.0
|
||||
'@eslint/plugin-kit': 0.4.0
|
||||
'@humanfs/node': 0.16.7
|
||||
'@humanwhocodes/module-importer': 1.0.1
|
||||
'@humanwhocodes/retry': 0.4.3
|
||||
'@types/estree': 1.0.8
|
||||
ajv: 6.12.6
|
||||
chalk: 4.1.2
|
||||
cross-spawn: 7.0.6
|
||||
debug: 4.4.3
|
||||
escape-string-regexp: 4.0.0
|
||||
eslint-scope: 8.4.0
|
||||
eslint-visitor-keys: 4.2.1
|
||||
espree: 10.4.0
|
||||
esquery: 1.6.0
|
||||
esutils: 2.0.3
|
||||
fast-deep-equal: 3.1.3
|
||||
file-entry-cache: 8.0.0
|
||||
find-up: 5.0.0
|
||||
glob-parent: 6.0.2
|
||||
ignore: 5.3.2
|
||||
imurmurhash: 0.1.4
|
||||
is-glob: 4.0.3
|
||||
json-stable-stringify-without-jsonify: 1.0.1
|
||||
lodash.merge: 4.6.2
|
||||
minimatch: 3.1.2
|
||||
natural-compare: 1.4.0
|
||||
optionator: 0.9.4
|
||||
optionalDependencies:
|
||||
jiti: 1.21.7
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
eslint@9.38.0(jiti@2.6.1):
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.9.0(eslint@9.38.0(jiti@2.6.1))
|
||||
|
|
@ -20143,10 +20369,34 @@ snapshots:
|
|||
optionalDependencies:
|
||||
graceful-fs: 4.2.11
|
||||
|
||||
jsonwebtoken@9.0.2:
|
||||
dependencies:
|
||||
jws: 3.2.2
|
||||
lodash.includes: 4.3.0
|
||||
lodash.isboolean: 3.0.3
|
||||
lodash.isinteger: 4.0.4
|
||||
lodash.isnumber: 3.0.3
|
||||
lodash.isplainobject: 4.0.6
|
||||
lodash.isstring: 4.0.1
|
||||
lodash.once: 4.1.1
|
||||
ms: 2.1.3
|
||||
semver: 7.7.3
|
||||
|
||||
just-compare@2.3.0: {}
|
||||
|
||||
justified-layout@4.1.0: {}
|
||||
|
||||
jwa@1.4.2:
|
||||
dependencies:
|
||||
buffer-equal-constant-time: 1.0.1
|
||||
ecdsa-sig-formatter: 1.0.11
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
jws@3.2.2:
|
||||
dependencies:
|
||||
jwa: 1.4.2
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
kdbush@3.0.0: {}
|
||||
|
||||
kdbush@4.0.2: {}
|
||||
|
|
@ -20311,12 +20561,26 @@ snapshots:
|
|||
|
||||
lodash.defaults@4.2.0: {}
|
||||
|
||||
lodash.includes@4.3.0: {}
|
||||
|
||||
lodash.isarguments@3.1.0: {}
|
||||
|
||||
lodash.isboolean@3.0.3: {}
|
||||
|
||||
lodash.isinteger@4.0.4: {}
|
||||
|
||||
lodash.isnumber@3.0.3: {}
|
||||
|
||||
lodash.isplainobject@4.0.6: {}
|
||||
|
||||
lodash.isstring@4.0.1: {}
|
||||
|
||||
lodash.memoize@4.1.2: {}
|
||||
|
||||
lodash.merge@4.6.2: {}
|
||||
|
||||
lodash.once@4.1.1: {}
|
||||
|
||||
lodash.uniq@4.5.0: {}
|
||||
|
||||
lodash@4.17.21: {}
|
||||
|
|
@ -23927,6 +24191,17 @@ snapshots:
|
|||
|
||||
typedarray@0.0.6: {}
|
||||
|
||||
typescript-eslint@8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.38.0(jiti@1.21.7))(typescript@5.9.3)
|
||||
'@typescript-eslint/parser': 8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.9.3)
|
||||
'@typescript-eslint/typescript-estree': 8.46.2(typescript@5.9.3)
|
||||
'@typescript-eslint/utils': 8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.9.3)
|
||||
eslint: 9.38.0(jiti@1.21.7)
|
||||
typescript: 5.9.3
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
typescript-eslint@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3):
|
||||
dependencies:
|
||||
'@typescript-eslint/eslint-plugin': 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.38.0(jiti@2.6.1))(typescript@5.9.3)
|
||||
|
|
@ -24205,6 +24480,27 @@ snapshots:
|
|||
- rollup
|
||||
- supports-color
|
||||
|
||||
vite-node@3.2.4(@types/node@22.18.13)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1):
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.4.3
|
||||
es-module-lexer: 1.7.0
|
||||
pathe: 2.0.3
|
||||
vite: 7.1.12(@types/node@22.18.13)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- jiti
|
||||
- less
|
||||
- lightningcss
|
||||
- sass
|
||||
- sass-embedded
|
||||
- stylus
|
||||
- sugarss
|
||||
- supports-color
|
||||
- terser
|
||||
- tsx
|
||||
- yaml
|
||||
|
||||
vite-node@3.2.4(@types/node@22.18.13)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1):
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
|
|
@ -24247,6 +24543,17 @@ snapshots:
|
|||
- tsx
|
||||
- yaml
|
||||
|
||||
vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.1.12(@types/node@22.18.13)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)):
|
||||
dependencies:
|
||||
debug: 4.4.3
|
||||
globrex: 0.1.2
|
||||
tsconfck: 3.1.6(typescript@5.9.3)
|
||||
optionalDependencies:
|
||||
vite: 7.1.12(@types/node@22.18.13)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@7.1.12(@types/node@22.18.13)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)):
|
||||
dependencies:
|
||||
debug: 4.4.3
|
||||
|
|
@ -24258,6 +24565,22 @@ snapshots:
|
|||
- supports-color
|
||||
- typescript
|
||||
|
||||
vite@7.1.12(@types/node@22.18.13)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1):
|
||||
dependencies:
|
||||
esbuild: 0.25.11
|
||||
fdir: 6.5.0(picomatch@4.0.3)
|
||||
picomatch: 4.0.3
|
||||
postcss: 8.5.6
|
||||
rollup: 4.52.5
|
||||
tinyglobby: 0.2.15
|
||||
optionalDependencies:
|
||||
'@types/node': 22.18.13
|
||||
fsevents: 2.3.3
|
||||
jiti: 1.21.7
|
||||
lightningcss: 1.30.2
|
||||
terser: 5.44.0
|
||||
yaml: 2.8.1
|
||||
|
||||
vite@7.1.12(@types/node@22.18.13)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1):
|
||||
dependencies:
|
||||
esbuild: 0.25.11
|
||||
|
|
@ -24298,6 +24621,50 @@ snapshots:
|
|||
dependencies:
|
||||
vitest: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.13)(happy-dom@20.0.8)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
|
||||
vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.13)(happy-dom@20.0.8)(jiti@1.21.7)(jsdom@26.1.0(canvas@2.11.2))(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1):
|
||||
dependencies:
|
||||
'@types/chai': 5.2.2
|
||||
'@vitest/expect': 3.2.4
|
||||
'@vitest/mocker': 3.2.4(vite@7.1.12(@types/node@22.18.13)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1))
|
||||
'@vitest/pretty-format': 3.2.4
|
||||
'@vitest/runner': 3.2.4
|
||||
'@vitest/snapshot': 3.2.4
|
||||
'@vitest/spy': 3.2.4
|
||||
'@vitest/utils': 3.2.4
|
||||
chai: 5.2.0
|
||||
debug: 4.4.3
|
||||
expect-type: 1.2.1
|
||||
magic-string: 0.30.21
|
||||
pathe: 2.0.3
|
||||
picomatch: 4.0.3
|
||||
std-env: 3.10.0
|
||||
tinybench: 2.9.0
|
||||
tinyexec: 0.3.2
|
||||
tinyglobby: 0.2.15
|
||||
tinypool: 1.1.1
|
||||
tinyrainbow: 2.0.0
|
||||
vite: 7.1.12(@types/node@22.18.13)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
vite-node: 3.2.4(@types/node@22.18.13)(jiti@1.21.7)(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@types/debug': 4.1.12
|
||||
'@types/node': 22.18.13
|
||||
happy-dom: 20.0.8
|
||||
jsdom: 26.1.0(canvas@2.11.2)
|
||||
transitivePeerDependencies:
|
||||
- jiti
|
||||
- less
|
||||
- lightningcss
|
||||
- msw
|
||||
- sass
|
||||
- sass-embedded
|
||||
- stylus
|
||||
- sugarss
|
||||
- supports-color
|
||||
- terser
|
||||
- tsx
|
||||
- yaml
|
||||
|
||||
vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.13)(happy-dom@20.0.8)(jiti@2.6.1)(jsdom@26.1.0(canvas@2.11.2(encoding@0.1.13)))(lightningcss@1.30.2)(terser@5.44.0)(yaml@2.8.1):
|
||||
dependencies:
|
||||
'@types/chai': 5.2.2
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
"@nestjs/bullmq": "^11.0.1",
|
||||
"@nestjs/common": "^11.0.4",
|
||||
"@nestjs/core": "^11.0.4",
|
||||
"@nestjs/jwt": "^11.0.1",
|
||||
"@nestjs/platform-express": "^11.0.4",
|
||||
"@nestjs/platform-socket.io": "^11.0.4",
|
||||
"@nestjs/schedule": "^6.0.0",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { BullModule } from '@nestjs/bullmq';
|
||||
import { Inject, Module, OnModuleDestroy, OnModuleInit, ValidationPipe } from '@nestjs/common';
|
||||
import { APP_FILTER, APP_GUARD, APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { ScheduleModule, SchedulerRegistry } from '@nestjs/schedule';
|
||||
import { ClsModule } from 'nestjs-cls';
|
||||
import { KyselyModule } from 'nestjs-kysely';
|
||||
|
|
@ -49,6 +50,13 @@ const commonImports = [
|
|||
ClsModule.forRoot(cls.config),
|
||||
KyselyModule.forRoot(getKyselyConfig(database.config)),
|
||||
OpenTelemetryModule.forRoot(otel),
|
||||
JwtModule.register({
|
||||
// used for maintenance mode JWTs
|
||||
global: true,
|
||||
signOptions: {
|
||||
expiresIn: '1h',
|
||||
},
|
||||
}),
|
||||
];
|
||||
|
||||
const bullImports = [BullModule.forRoot(bull.config), BullModule.registerQueue(...bull.queues)];
|
||||
|
|
|
|||
|
|
@ -1,21 +1,42 @@
|
|||
import { BadRequestException, Controller, Post, Res } from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
import { Response } from 'express';
|
||||
import { MaintenanceModeResponseDto } from 'src/dtos/maintenance.dto';
|
||||
import { AuthDto } from 'src/dtos/auth.dto';
|
||||
import { MaintenanceAuthDto, MaintenanceModeResponseDto } from 'src/dtos/maintenance.dto';
|
||||
import { ImmichCookie, Permission } from 'src/enum';
|
||||
import { Authenticated } from 'src/middleware/auth.guard';
|
||||
import { Auth, Authenticated } from 'src/middleware/auth.guard';
|
||||
import { MaintenanceService } from 'src/services/maintenance.service';
|
||||
|
||||
@ApiTags('Maintenance (admin)')
|
||||
@Controller('admin/maintenance')
|
||||
export class MaintenanceController {
|
||||
constructor(private service: MaintenanceService) {}
|
||||
constructor(
|
||||
private service: MaintenanceService,
|
||||
private jwtService: JwtService,
|
||||
) {}
|
||||
|
||||
@Post('start')
|
||||
@Authenticated({ permission: Permission.Maintenance, admin: true })
|
||||
async startMaintenance(@Res({ passthrough: true }) response: Response): Promise<MaintenanceModeResponseDto> {
|
||||
await this.service.startMaintenance();
|
||||
response.cookie(ImmichCookie.MaintenanceToken, 'my-token');
|
||||
async startMaintenance(
|
||||
@Auth() auth: AuthDto,
|
||||
@Res({ passthrough: true }) response: Response,
|
||||
): Promise<MaintenanceModeResponseDto> {
|
||||
const { token } = await this.service.startMaintenance();
|
||||
|
||||
const jwt = await this.jwtService.signAsync(
|
||||
{
|
||||
data: {
|
||||
username: auth.user.name,
|
||||
} as MaintenanceAuthDto,
|
||||
},
|
||||
{
|
||||
secret: token,
|
||||
},
|
||||
);
|
||||
|
||||
response.cookie(ImmichCookie.MaintenanceToken, jwt);
|
||||
|
||||
return { isMaintenanceMode: true };
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,4 +5,6 @@ export class MaintenanceModeResponseDto {
|
|||
isMaintenanceMode!: boolean;
|
||||
}
|
||||
|
||||
export class MaintenanceAuthDto {}
|
||||
export class MaintenanceAuthDto {
|
||||
username!: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,15 +3,18 @@ import {
|
|||
ExecutionContext,
|
||||
Injectable,
|
||||
SetMetadata,
|
||||
UnauthorizedException,
|
||||
applyDecorators,
|
||||
createParamDecorator,
|
||||
} from '@nestjs/common';
|
||||
import { Reflector } from '@nestjs/core';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { parse } from 'cookie';
|
||||
import { Request } from 'express';
|
||||
import { MaintenanceAuthDto } from 'src/dtos/maintenance.dto';
|
||||
import { MetadataKey } from 'src/enum';
|
||||
import { ImmichCookie, MetadataKey } from 'src/enum';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
import { MaintenanceWorkerService } from 'src/services/maintenance-worker.service';
|
||||
import { MaintenanceWorkerRepository } from 'src/repositories/maintenance-worker.repository';
|
||||
|
||||
export const MaintenanceRoute = (options = {}): MethodDecorator => {
|
||||
const decorators: MethodDecorator[] = [SetMetadata(MetadataKey.AuthRoute, options)];
|
||||
|
|
@ -19,15 +22,15 @@ export const MaintenanceRoute = (options = {}): MethodDecorator => {
|
|||
};
|
||||
|
||||
export interface MaintenanceAuthRequest extends Request {
|
||||
user?: MaintenanceAuthDto;
|
||||
maintenanceAuth?: MaintenanceAuthDto;
|
||||
}
|
||||
|
||||
export interface MaintenanceAuthenticatedRequest extends Request {
|
||||
user: MaintenanceAuthDto;
|
||||
maintenanceAuth: MaintenanceAuthDto;
|
||||
}
|
||||
|
||||
export const MaintenanceAuth = createParamDecorator((data, context: ExecutionContext): MaintenanceAuthDto => {
|
||||
return context.switchToHttp().getRequest<MaintenanceAuthenticatedRequest>().user;
|
||||
return context.switchToHttp().getRequest<MaintenanceAuthenticatedRequest>().maintenanceAuth;
|
||||
});
|
||||
|
||||
@Injectable()
|
||||
|
|
@ -35,7 +38,8 @@ export class MaintenanceAuthGuard implements CanActivate {
|
|||
constructor(
|
||||
private logger: LoggingRepository,
|
||||
private reflector: Reflector,
|
||||
private maintenanceWorkerService: MaintenanceWorkerService,
|
||||
private maintenanceWorkerRepository: MaintenanceWorkerRepository,
|
||||
private jwtService: JwtService,
|
||||
) {
|
||||
this.logger.setContext(MaintenanceAuthGuard.name);
|
||||
}
|
||||
|
|
@ -48,7 +52,23 @@ export class MaintenanceAuthGuard implements CanActivate {
|
|||
}
|
||||
|
||||
const request = context.switchToHttp().getRequest<MaintenanceAuthRequest>();
|
||||
request.user = await this.maintenanceWorkerService.authenticate(request.headers);
|
||||
const token = parse(request.headers.cookie || '')[ImmichCookie.MaintenanceToken];
|
||||
|
||||
if (!token) {
|
||||
throw new UnauthorizedException('Missing JWT Token');
|
||||
}
|
||||
|
||||
try {
|
||||
const payload = await this.jwtService.verifyAsync(token, {
|
||||
secret: await this.maintenanceWorkerRepository.maintenanceToken(),
|
||||
});
|
||||
|
||||
request['maintenanceAuth'] = payload;
|
||||
this.logger.debug(payload);
|
||||
} catch {
|
||||
throw new UnauthorizedException('Invalid JWT Token');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,12 +53,12 @@ export class CliService extends BaseService {
|
|||
|
||||
async disableMaintenanceMode(): Promise<void> {
|
||||
const state = { isMaintenanceMode: false as const };
|
||||
this.maintenanceRepository.setMaintenanceMode(state);
|
||||
await this.maintenanceRepository.setMaintenanceMode(state);
|
||||
this.oneShotServerSend('AppRestart', state);
|
||||
}
|
||||
|
||||
async enableMaintenanceMode(): Promise<void> {
|
||||
this.maintenanceRepository.enterMaintenanceMode();
|
||||
await this.maintenanceRepository.enterMaintenanceMode();
|
||||
this.oneShotServerSend('AppRestart', {
|
||||
isMaintenanceMode: true,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,8 +1,4 @@
|
|||
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
||||
import { parse } from 'cookie';
|
||||
import { IncomingHttpHeaders } from 'node:http';
|
||||
import { MaintenanceAuthDto } from 'src/dtos/maintenance.dto';
|
||||
import { ImmichCookie } from 'src/enum';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||
import { LoggingRepository } from 'src/repositories/logging.repository';
|
||||
import { MaintenanceWorkerRepository } from 'src/repositories/maintenance-worker.repository';
|
||||
|
|
@ -56,17 +52,4 @@ export class MaintenanceWorkerService {
|
|||
async endMaintenance(): Promise<void> {
|
||||
await this.maintenanceRepository.exitMaintenanceMode();
|
||||
}
|
||||
|
||||
private getCookieToken(headers: IncomingHttpHeaders): string | null {
|
||||
const cookies = parse(headers.cookie || '');
|
||||
return cookies[ImmichCookie.MaintenanceToken] || null;
|
||||
}
|
||||
|
||||
async authenticate(headers: IncomingHttpHeaders): Promise<MaintenanceAuthDto> {
|
||||
if (this.getCookieToken(headers) !== 'my-token') {
|
||||
throw new UnauthorizedException('Invalid maintenance key');
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,55 @@
|
|||
<script>
|
||||
<script lang="ts">
|
||||
import AuthPageLayout from '$lib/components/layouts/AuthPageLayout.svelte';
|
||||
import { endMaintenance } from '@immich/sdk';
|
||||
import { Button, Heading } from '@immich/ui';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
function checkAuth() {
|
||||
try {
|
||||
const jwtCookie = document.cookie
|
||||
.split(';')
|
||||
.map((cookie) => cookie.split('=', 2).map((value) => value.trim()))
|
||||
.find(([name]) => name === 'immich_maintenance_token');
|
||||
|
||||
if (jwtCookie) {
|
||||
const [, jwt] = jwtCookie;
|
||||
|
||||
// decode the JWT
|
||||
// https://stackoverflow.com/a/38552302
|
||||
const encodedPayload = decodeURIComponent(
|
||||
// eslint-disable-next-line unicorn/prefer-string-replace-all
|
||||
atob(jwt.split('.')[1].replace(/-/g, '+').replace(/_/g, '/'))
|
||||
.split('')
|
||||
// eslint-disable-next-line unicorn/prefer-code-point
|
||||
.map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
|
||||
.join(''),
|
||||
);
|
||||
|
||||
return JSON.parse(encodedPayload).data as {
|
||||
username: string;
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
void error;
|
||||
}
|
||||
}
|
||||
|
||||
const user = checkAuth();
|
||||
</script>
|
||||
|
||||
<AuthPageLayout>
|
||||
<div class="flex flex-col place-items-center text-center gap-4">
|
||||
<Heading size="large" color="primary" tag="h1">{$t('maintenance_title')}</Heading>
|
||||
<p>{$t('maintenance_description')}</p>
|
||||
<!-- {#if $user && $user.isAdmin}
|
||||
{#if user}
|
||||
<p>
|
||||
{$t('maintenance_logged_in_as', {
|
||||
values: {
|
||||
user: $user.name,
|
||||
user: user.username,
|
||||
},
|
||||
})}
|
||||
</p> -->
|
||||
<Button onclick={() => endMaintenance()}>{$t('maintenance_exit')}</Button>
|
||||
<!-- {/if} -->
|
||||
</p>
|
||||
<Button onclick={() => endMaintenance()}>{$t('maintenance_exit')}</Button>
|
||||
{/if}
|
||||
</div>
|
||||
</AuthPageLayout>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue