KeyHelp: Panel-Passwort neu vergeben und verschlüsselt hinterlegen (verblurrt wie Lizenzschlüssel)

This commit is contained in:
Kundencenter 2026-09-27 21:35:15 +02:00
parent 3a2864ee76
commit 6fec6277f5
9 changed files with 136 additions and 20 deletions

View file

@ -120,3 +120,39 @@ describe('KeyHelp: Verbindung, Kundenübernahme, neue Tarife, Hosting-Funktionen
fake.opts.failGet503 = 50; const down = await call(app, owner, 'GET', `/resources/${cres.id}/children/domain`); expect(down.statusCode).toBe(502); fake.opts.failGet503 = 0;
});
});
describe('KeyHelp: Panel-Passwort neu vergeben', () => {
it('erzeugt ein neues Passwort, setzt es beim Anbieter, speichert es verschlüsselt und lässt es auf Abruf ansehen', async () => {
const admin = await staff('kh-pw-admin@x.test', 'admin'); const support = await staff('kh-pw-support@x.test', 'support');
await call(app, admin, 'POST', '/admin/connectors', { connector: 'keyhelp', name: 'KeyHelp-PW-Test', values: { baseUrl: 'https://kh.test', apiKey: 'kh-test-key' } });
await drain();
const res = (await call(app, admin, 'GET', '/resources')).json(); const alpha = res.find((r: any) => r.name.includes('alpha'));
// ohne Berechtigung (Support nur lesend)
expect((await call(app, support, 'POST', `/resources/${alpha.id}/panel-credentials/reset`)).statusCode).toBe(403);
const before = (await call(app, admin, 'GET', `/resources/${alpha.id}/panel-credentials`)).json();
expect(before).toEqual({ canReset: true, set: false, setAt: null });
const reset = await call(app, admin, 'POST', `/resources/${alpha.id}/panel-credentials/reset`); expect(reset.statusCode).toBe(202);
await drain();
const fakeClient = fake.state.clients.find((c) => c.username === 'alpha')!;
const after = (await call(app, admin, 'GET', `/resources/${alpha.id}/panel-credentials`)).json();
expect(after.set).toBe(true); expect(after.setAt).toBeTruthy();
const revealed = (await call(app, admin, 'POST', `/resources/${alpha.id}/panel-credentials/reveal`)).json();
expect(revealed.items).toEqual([{ label: 'Panel-Passwort', value: (fakeClient as any).password }]);
expect((revealed.items[0].value as string).length).toBeGreaterThan(15);
expect((await call(app, support, 'POST', `/resources/${alpha.id}/panel-credentials/reveal`)).statusCode).toBe(403);
// in der Datenbank steht das Passwort nur verschlüsselt
const row = await one('SELECT secret_enc FROM panel_credentials WHERE resource_id = ?', [alpha.id]);
expect(row!.secret_enc).toMatch(/^v1:/); expect(row!.secret_enc).not.toContain((fakeClient as any).password);
// erneutes Vergeben ersetzt das alte Passwort (eigener Idempotenzschlüssel, damit es nicht als Doppelklick gilt)
const oldPw = (fakeClient as any).password;
await app.inject({ method: 'POST', url: `/v1/resources/${alpha.id}/panel-credentials/reset`, headers: { cookie: admin.cookie, 'x-csrf-token': admin.csrf, 'idempotency-key': 'zweiter-reset-test' } });
await drain();
const revealed2 = (await call(app, admin, 'POST', `/resources/${alpha.id}/panel-credentials/reveal`)).json();
expect(revealed2.items[0].value).not.toBe(oldPw);
});
});