fix: sanitise project data on load

This commit is contained in:
Carlos Valente
2026-03-29 19:00:26 +02:00
committed by Carlos Valente
parent 23298bbe85
commit 5e98fdb2e9
3 changed files with 72 additions and 3 deletions
@@ -7,4 +7,25 @@ describe('parseProjectData()', () => {
expect(result).toBeTypeOf('object');
expect(errorEmitter).toHaveBeenCalledOnce();
});
it('sanitises malformed custom project data', () => {
const errorEmitter = vi.fn();
const result = parseProjectData(
{
project: {
title: 'Demo',
description: '',
url: '',
info: '',
logo: null,
// @ts-expect-error -- checking malformed data
custom: '{"networkInterfaces":[{"name":"localhost","address":"127.0.0.1"}]}',
},
},
errorEmitter,
);
expect(result.custom).toEqual([]);
expect(errorEmitter).toHaveBeenCalledWith('Project custom data is invalid, using defaults');
});
});
@@ -22,6 +22,53 @@ export function parseProjectData(data: Partial<DatabaseModel>, emitError?: Error
url: data.project.url ?? defaultProject.url,
info: data.project.info ?? defaultProject.info,
logo: data.project.logo ?? defaultProject.logo,
custom: data.project.custom ?? defaultProject.custom,
custom: parseCustomProjectData(data.project.custom, defaultProject.custom, emitError),
};
}
function isProjectCustomEntry(entry: unknown): entry is ProjectData['custom'][number] {
if (typeof entry !== 'object' || entry === null || Array.isArray(entry)) {
return false;
}
const { title, value, url } = entry as Record<string, unknown>;
return typeof title === 'string' && typeof value === 'string' && (url === undefined || typeof url === 'string');
}
function parseCustomProjectData(
data: unknown,
defaultCustomData: ProjectData['custom'],
emitError?: ErrorEmitter,
): ProjectData['custom'] {
if (!Array.isArray(data)) {
if (data !== undefined) {
emitError?.('Project custom data is invalid, using defaults');
}
return defaultCustomData;
}
const parsed: ProjectData['custom'] = [];
let skippedInvalidEntry = false;
for (let i = 0; i < data.length; i++) {
const entry = data[i];
if (!isProjectCustomEntry(entry)) {
skippedInvalidEntry = true;
continue;
}
parsed.push({
title: entry.title,
value: entry.value,
url: entry.url ?? '',
});
}
if (skippedInvalidEntry) {
emitError?.('Project custom data contained invalid entries, skipping them');
}
return parsed;
}