immich/server/src/utils/maintenance.ts
renovate[bot] df970da59e
chore(deps): update dependency eslint-plugin-unicorn to v70 - abandoned (#29684)
* chore(deps): update dependency eslint-plugin-unicorn to v70

* fix: linting

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Dietzler <mail@ddietzler.dev>
2026-07-20 23:47:14 -04:00

63 lines
1.9 KiB
TypeScript

import { SignJWT } from 'jose';
import { randomBytes } from 'node:crypto';
import { join } from 'node:path';
import { StorageCore } from 'src/cores/storage.core';
import { MaintenanceAuthDto, MaintenanceDetectInstallResponseDto } from 'src/dtos/maintenance.dto';
import { StorageFolder } from 'src/enum';
import { StorageRepository } from 'src/repositories/storage.repository';
export async function createMaintenanceLoginUrl(
baseUrl: string,
auth: MaintenanceAuthDto,
secret: string,
): Promise<string> {
return `${baseUrl}/maintenance?token=${await signMaintenanceJwt(secret, auth)}`;
}
export async function signMaintenanceJwt(secret: string, data: MaintenanceAuthDto): Promise<string> {
const alg = 'HS256';
return await new SignJWT({ ...data })
.setProtectedHeader({ alg })
.setIssuedAt()
.setExpirationTime('4h')
.sign(new TextEncoder().encode(secret));
}
export function generateMaintenanceSecret(): string {
return randomBytes(64).toString('hex');
}
export async function detectPriorInstall(
storageRepository: StorageRepository,
): Promise<MaintenanceDetectInstallResponseDto> {
return {
storage: await Promise.all(
Object.values(StorageFolder).map(async (folder) => {
const path = StorageCore.getBaseFolder(folder);
const files = await storageRepository.readdir(path);
const filename = join(StorageCore.getBaseFolder(folder), '.immich');
let isReadable = false,
isWritable = false;
try {
await storageRepository.readFile(filename);
isReadable = true;
await storageRepository.overwriteFile(filename, Buffer.from(Date.now().toString()));
isWritable = true;
} catch {
// no-op
}
return {
folder,
readable: isReadable,
writable: isWritable,
files: files.filter((fn) => fn !== '.immich').length,
};
}),
),
};
}