feat(quick-260907-let): Verbindungstest fuer Postfach-Endpunkt im API
- TenderEmailConfigService.testConnection(userId, dto) mit Rueckfall auf
gespeicherte, entschluesselte Zugangsdaten bei leeren Feldern
- TendersController: POST email-config/test, userId aus Auth-Kontext,
deklariert vor @Get(':id')
- Beide Provider (ImapProvider/ExchangeInboxProvider) optional angehaengt,
bestehende 2-Arg-Konstruktoraufrufe bleiben typkorrekt
- Reihenfolge-Waechter und IDOR-Testfall ergaenzt
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FYZcd3SSmo14QTqWx2KKzU
This commit is contained in:
@@ -136,6 +136,7 @@ function makeFakeEmailConfigService() {
|
||||
id: 'ec-1',
|
||||
...dto,
|
||||
})),
|
||||
testConnection: vi.fn(async (_userId: string, _dto: any) => ({ success: true }) as any),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -408,17 +409,20 @@ describe('TendersController — route declaration order (static route before :id
|
||||
expect(removeIdx).toBeLessThan(idIdx);
|
||||
});
|
||||
|
||||
it('declares getEmailConfig/saveEmailConfig before getTender so GET /:id cannot shadow "email-config" (Plan 14-03, Pitfall 5)', () => {
|
||||
it('declares getEmailConfig/saveEmailConfig/testEmailConnection before getTender so GET /:id cannot shadow "email-config" (Plan 14-03, Pitfall 5; testEmailConnection added Quick 260907-let)', () => {
|
||||
const methods = Object.getOwnPropertyNames(TendersController.prototype);
|
||||
const getIdx = methods.indexOf('getEmailConfig');
|
||||
const saveIdx = methods.indexOf('saveEmailConfig');
|
||||
const testIdx = methods.indexOf('testEmailConnection');
|
||||
const idIdx = methods.indexOf('getTender');
|
||||
|
||||
expect(getIdx).toBeGreaterThanOrEqual(0);
|
||||
expect(saveIdx).toBeGreaterThanOrEqual(0);
|
||||
expect(testIdx).toBeGreaterThanOrEqual(0);
|
||||
expect(idIdx).toBeGreaterThanOrEqual(0);
|
||||
expect(getIdx).toBeLessThan(idIdx);
|
||||
expect(saveIdx).toBeLessThan(idIdx);
|
||||
expect(testIdx).toBeLessThan(idIdx);
|
||||
});
|
||||
|
||||
it('declares listTriage and setTriage before getTender so GET /:id cannot shadow "triage" (Plan 11-05, Pitfall 5)', () => {
|
||||
@@ -1129,6 +1133,30 @@ describe('TendersController — email-config (Plan 14-03, per-user since Phase 1
|
||||
expect(emailConfigService.getConfigForApi).toHaveBeenNthCalledWith(1, 'user-a');
|
||||
expect(emailConfigService.getConfigForApi).toHaveBeenNthCalledWith(2, 'user-b');
|
||||
});
|
||||
|
||||
it('POST /email-config/test resolves userId from the auth context, even when the body carries a different identity field (T-QT16-01, IDOR)', async () => {
|
||||
const prisma = makeFakePrisma();
|
||||
const scheduler = { setInterval: vi.fn(), stopJob: vi.fn() } as any;
|
||||
const emailConfigService = makeFakeEmailConfigService();
|
||||
const controller = new TendersController(
|
||||
prisma as any,
|
||||
scheduler,
|
||||
makeFakeTriageService() as any,
|
||||
makeFakeSavedSearchService() as any,
|
||||
makeFakeNotificationPrefService() as any,
|
||||
makeFakeRssFeedService() as any,
|
||||
emailConfigService as any,
|
||||
);
|
||||
|
||||
const dto = {
|
||||
protocol: 'imap',
|
||||
encryption: 'ssl-tls',
|
||||
userId: 'attacker-supplied-id',
|
||||
} as any;
|
||||
await controller.testEmailConnection(dto, makeFakeRequest('u1', 'tenant1'));
|
||||
|
||||
expect(emailConfigService.testConnection).toHaveBeenCalledWith('u1', dto);
|
||||
});
|
||||
});
|
||||
|
||||
describe('TendersController — D-13 private (email-alert) tender visibility (Phase 14, Plan 03)', () => {
|
||||
|
||||
Reference in New Issue
Block a user