mirror of
https://github.com/immich-app/immich
synced 2026-08-15 13:03:57 +00:00
fix(server): do not throw on unparsable DB_URL when building backup arguments
`buildPostgresLaunchArguments` already guarded URL parsing with `URL.canParse`, but the returned password was read from a second, unguarded `new URL(databaseConfig.url)` call. A `DB_URL` that `new URL` cannot parse, such as a unix domain socket URL like `socket://user:password@/path/to/socket?db=immich`, made the database backup job fail immediately with `TypeError: Invalid URL`. The password is now collected alongside the username inside the guarded branch and falls back to an empty string, matching the existing username fallback. Closes #30331
This commit is contained in:
parent
af33a78d18
commit
a67d572f93
2 changed files with 47 additions and 1 deletions
|
|
@ -565,6 +565,48 @@ describe(DatabaseBackupService.name, () => {
|
|||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('using an unparsable URL', () => {
|
||||
beforeEach(() => {
|
||||
// unix domain socket URLs cannot be parsed by `new URL`
|
||||
const dbUrl = 'socket://mypg:mypwd@/var/run/postgresql?db=myimmich';
|
||||
const configMock = {
|
||||
getEnv: () => ({ database: { config: { connectionType: 'url', url: dbUrl }, skipMigrations: false } }),
|
||||
getWorker: () => ImmichWorker.Api,
|
||||
isDev: () => false,
|
||||
} as unknown as any;
|
||||
|
||||
sut = new DatabaseBackupService(
|
||||
mocks.logger as never,
|
||||
mocks.storage as never,
|
||||
configMock as never,
|
||||
mocks.systemMetadata as never,
|
||||
mocks.process,
|
||||
mocks.database as never,
|
||||
mocks.user as never,
|
||||
mocks.cron as never,
|
||||
mocks.job as never,
|
||||
void 0 as never,
|
||||
);
|
||||
});
|
||||
|
||||
it('should fallback to reasonable defaults', async () => {
|
||||
await expect(sut.buildPostgresLaunchArguments('pg_dump')).resolves.toMatchInlineSnapshot(`
|
||||
{
|
||||
"args": [
|
||||
"socket://mypg:mypwd@/var/run/postgresql?db=myimmich",
|
||||
"--clean",
|
||||
"--if-exists",
|
||||
],
|
||||
"bin": "/usr/lib/postgresql/14/bin/pg_dump",
|
||||
"databaseMajorVersion": 14,
|
||||
"databasePassword": "",
|
||||
"databaseUsername": "postgres",
|
||||
"databaseVersion": "14.10 (Debian 14.10-1.pgdg120+1)",
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('uploadBackup', () => {
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ export class DatabaseBackupService {
|
|||
|
||||
const args: string[] = [];
|
||||
let databaseUsername;
|
||||
let databasePassword;
|
||||
|
||||
if (isUrlConnection) {
|
||||
if (bin !== 'pg_dump') {
|
||||
|
|
@ -142,16 +143,19 @@ export class DatabaseBackupService {
|
|||
parsedUrl.searchParams.delete('uselibpqcompat');
|
||||
|
||||
databaseUsername = parsedUrl.username || parsedUrl.searchParams.get('user');
|
||||
databasePassword = parsedUrl.password;
|
||||
|
||||
url = parsedUrl.href;
|
||||
}
|
||||
|
||||
// assume typical values if we can't parse URL or not present
|
||||
databaseUsername ??= 'postgres';
|
||||
databasePassword ??= '';
|
||||
|
||||
args.push(url);
|
||||
} else {
|
||||
databaseUsername = databaseConfig.username;
|
||||
databasePassword = databaseConfig.password;
|
||||
|
||||
args.push(
|
||||
'--username',
|
||||
|
|
@ -214,7 +218,7 @@ export class DatabaseBackupService {
|
|||
bin: `/usr/lib/postgresql/${databaseMajorVersion}/bin/${bin}`,
|
||||
args,
|
||||
databaseUsername,
|
||||
databasePassword: isUrlConnection ? new URL(databaseConfig.url).password : databaseConfig.password,
|
||||
databasePassword,
|
||||
databaseVersion,
|
||||
databaseMajorVersion,
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue