Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/app/api/auth/key-backup/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,10 @@ export async function PUT(request) {

// Validate that encrypted_keys is valid JSON (it should be the export format)
try {
JSON.parse(encrypted_keys);
const backupExport = JSON.parse(encrypted_keys);
if (!backupExport || typeof backupExport !== 'object' || Array.isArray(backupExport)) {
return NextResponse.json({ error: 'encrypted_keys must be a JSON object string' }, { status: 400 });
}
} catch {
return NextResponse.json({ error: 'encrypted_keys must be a valid JSON string' }, { status: 400 });
}
Expand Down
44 changes: 44 additions & 0 deletions src/app/api/auth/key-backup/route.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,24 @@ function createBackupQuery() {
return query;
}

function createUpsertQuery() {
const query = {
upsert: vi.fn(() => query),
select: vi.fn(() => query),
single: vi.fn(() =>
Promise.resolve({
data: {
id: 'backup-id',
created_at: '2026-07-11T00:00:00.000Z',
updated_at: '2026-07-11T00:00:00.000Z'
},
error: null
})
)
};
return query;
}

describe('key backup cookie authentication', () => {
beforeEach(() => {
vi.resetModules();
Expand Down Expand Up @@ -108,4 +126,30 @@ describe('key backup cookie authentication', () => {
expect(response.status).toBe(200);
expect(mocks.authGetUser).toHaveBeenCalledWith('cookie-token');
});

it('rejects encrypted_keys JSON that is not an object export', async () => {
const { PUT } = await import('./route.js');
mocks.serviceFrom.mockImplementation((table) => {
if (table === 'key_backups') return createUpsertQuery();
throw new Error(`Unexpected table: ${table}`);
});

const response = await PUT(
new Request('https://qrypt.chat/api/auth/key-backup', {
method: 'PUT',
headers: {
authorization: 'Bearer access-token',
'content-type': 'application/json'
},
body: JSON.stringify({
encrypted_keys: '"not-a-backup-export"'
})
})
);
const body = await response.json();

expect(response.status).toBe(400);
expect(body).toEqual({ error: 'encrypted_keys must be a JSON object string' });
expect(mocks.serviceFrom).not.toHaveBeenCalled();
});
});
Loading