From 8676a042eb6215c43f0575d40fda8e8ee26cb941 Mon Sep 17 00:00:00 2001 From: izzy Date: Thu, 6 Nov 2025 17:58:13 +0000 Subject: [PATCH] refactor: encode at point of usage --- .../maintenance-worker.repository.ts | 8 +++---- .../repositories/maintenance.repository.ts | 24 ++++++++----------- server/src/services/maintenance.service.ts | 2 +- server/src/types.ts | 4 ++-- 4 files changed, 17 insertions(+), 21 deletions(-) diff --git a/server/src/repositories/maintenance-worker.repository.ts b/server/src/repositories/maintenance-worker.repository.ts index a2b1bd9eb4..129c76b495 100644 --- a/server/src/repositories/maintenance-worker.repository.ts +++ b/server/src/repositories/maintenance-worker.repository.ts @@ -49,12 +49,12 @@ export class MaintenanceWorkerRepository implements OnGatewayConnection, OnGatew } async exitMaintenanceMode(): Promise { - const state: MaintenanceModeState = { isMaintenanceMode: false as const }; + const state: MaintenanceModeState = { isMaintenanceMode: false as const }; await this.systemMetadataRepository.set(SystemMetadataKey.MaintenanceMode, state); this.restartApp(state); } - async maintenanceSecret(): Promise { + async maintenanceSecret(): Promise { const result = await this.systemMetadataRepository.get(SystemMetadataKey.MaintenanceMode); if (!result) { throw new Error('Unreachable: Missing metadata for maintenance mode.'); @@ -64,7 +64,7 @@ export class MaintenanceWorkerRepository implements OnGatewayConnection, OnGatew throw new Error('Unreachable: Not in maintenance mode.'); } - return new TextEncoder().encode(result.secret); + return result.secret; } async logSecret(): Promise { @@ -101,7 +101,7 @@ export class MaintenanceWorkerRepository implements OnGatewayConnection, OnGatew try { const secret = await this.maintenanceSecret(); - const result = await jose.jwtVerify(jwtToken, secret); + const result = await jose.jwtVerify(jwtToken, new TextEncoder().encode(secret)); return result.payload; } catch { throw new UnauthorizedException('Invalid JWT Token'); diff --git a/server/src/repositories/maintenance.repository.ts b/server/src/repositories/maintenance.repository.ts index e1b883a830..c113667563 100644 --- a/server/src/repositories/maintenance.repository.ts +++ b/server/src/repositories/maintenance.repository.ts @@ -21,17 +21,13 @@ export class MaintenanceRepository { private systemMetadataRepository: SystemMetadataRepository, ) {} - getMaintenanceMode(): Promise> { + getMaintenanceMode(): Promise { return this.systemMetadataRepository .get(SystemMetadataKey.MaintenanceMode) - .then((state) => - state?.isMaintenanceMode - ? { isMaintenanceMode: true, secret: new TextEncoder().encode(state.secret) } - : { isMaintenanceMode: false as const }, - ); + .then((state) => state ?? { isMaintenanceMode: false as const }); } - async setMaintenanceMode(state: MaintenanceModeState) { + async setMaintenanceMode(state: MaintenanceModeState) { await this.systemMetadataRepository.set(SystemMetadataKey.MaintenanceMode, state); await this.eventRepository.emit('AppRestart', state); } @@ -51,14 +47,14 @@ export class MaintenanceRepository { }); } - async enterMaintenanceMode(): Promise<{ secret: Uint8Array }> { + async enterMaintenanceMode(): Promise<{ secret: string }> { const secret = randomBytes(64).toString('hex'); - const state: MaintenanceModeState = { isMaintenanceMode: true, secret }; + const state: MaintenanceModeState = { isMaintenanceMode: true, secret }; await this.systemMetadataRepository.set(SystemMetadataKey.MaintenanceMode, state); await this.eventRepository.emit('AppRestart', state); - return { secret: new TextEncoder().encode(secret) }; + return { secret }; } exitApp() { @@ -70,7 +66,7 @@ export class MaintenanceRepository { /* eslint-enable unicorn/no-process-exit */ } - async createLoginUrl(baseUrl: string, auth: MaintenanceAuthDto, secret?: Uint8Array) { + async createLoginUrl(baseUrl: string, auth: MaintenanceAuthDto, secret?: string) { secret ??= await this.getMaintenanceMode().then((state) => { if (!state.isMaintenanceMode) { throw new Error('Not in maintenance mode.'); @@ -82,18 +78,18 @@ export class MaintenanceRepository { return await MaintenanceRepository.createLoginUrl(baseUrl, auth, secret!); } - static async createLoginUrl(baseUrl: string, auth: MaintenanceAuthDto, secret: Uint8Array) { + static async createLoginUrl(baseUrl: string, auth: MaintenanceAuthDto, secret: string) { return `${baseUrl}/maintenance?token=${encodeURIComponent(await MaintenanceRepository.createJwt(secret!, auth))}`; } - static async createJwt(secret: Uint8Array, data: MaintenanceAuthDto) { + static async createJwt(secret: string, data: MaintenanceAuthDto) { const alg = 'HS256'; return await new SignJWT({ ...data }) .setProtectedHeader({ alg }) .setIssuedAt() .setExpirationTime('4h') - .sign(secret); + .sign(new TextEncoder().encode(secret)); } setCloseFn(fn: () => Promise) { diff --git a/server/src/services/maintenance.service.ts b/server/src/services/maintenance.service.ts index 5fc8d17a53..b1f4d4c3c5 100644 --- a/server/src/services/maintenance.service.ts +++ b/server/src/services/maintenance.service.ts @@ -7,7 +7,7 @@ import { BaseService } from 'src/services/base.service'; */ @Injectable() export class MaintenanceService extends BaseService { - async startMaintenance(): Promise<{ secret: Uint8Array }> { + async startMaintenance(): Promise<{ secret: string }> { const { isMaintenanceMode } = await this.maintenanceRepository.getMaintenanceMode(); if (isMaintenanceMode) { throw new BadRequestException('Already in maintenance mode'); diff --git a/server/src/types.ts b/server/src/types.ts index 5cf8a10553..049e78cc23 100644 --- a/server/src/types.ts +++ b/server/src/types.ts @@ -469,7 +469,7 @@ export interface MemoryData { export type VersionCheckMetadata = { checkedAt: string; releaseVersion: string }; export type SystemFlags = { mountChecks: Record }; -export type MaintenanceModeState = { isMaintenanceMode: true; secret: S } | { isMaintenanceMode: false }; +export type MaintenanceModeState = { isMaintenanceMode: true; secret: string } | { isMaintenanceMode: false }; export type MemoriesState = { /** memories have already been created through this date */ lastOnThisDayDate: string; @@ -480,7 +480,7 @@ export interface SystemMetadata extends Record; + [SystemMetadataKey.MaintenanceMode]: MaintenanceModeState; [SystemMetadataKey.MediaLocation]: MediaLocation; [SystemMetadataKey.ReverseGeocodingState]: { lastUpdate?: string; lastImportFileName?: string }; [SystemMetadataKey.SystemConfig]: DeepPartial;