102 lines
5.9 KiB
Markdown
102 lines
5.9 KiB
Markdown
# 15. Backend Router — DarkWatch (Dark Web Monitoring)
|
|
|
|
meta:
|
|
id: kordant-unified-restructure-15
|
|
feature: kordant-unified-restructure
|
|
priority: P1
|
|
depends_on: [kordant-unified-restructure-12, kordant-unified-restructure-13, kordant-unified-restructure-14]
|
|
tags: [backend, trpc, darkwatch, security, api]
|
|
|
|
objective:
|
|
- Build the tRPC router for DarkWatch, the dark web monitoring service. Port all logic from `services/darkwatch/` and `packages/api/src/routes/darkwatch.routes.ts` into a unified `darkwatch` router and service layer.
|
|
|
|
deliverables:
|
|
- `web/src/server/api/routers/darkwatch.ts` — DarkWatch router:
|
|
- `darkwatch.getWatchlist` — `protectedProcedure` returning user's watchlist items
|
|
- `darkwatch.addWatchlistItem` — `protectedProcedure` adding email/phone/SSN/domain to watchlist
|
|
- `darkwatch.removeWatchlistItem` — `protectedProcedure` removing item
|
|
- `darkwatch.getExposures` — `protectedProcedure` returning detected exposures
|
|
- `darkwatch.getExposureDetails` — `protectedProcedure` returning single exposure with metadata
|
|
- `darkwatch.runScan` — `protectedProcedure` triggering manual scan (respects tier limits)
|
|
- `darkwatch.getScanStatus` — `protectedProcedure` checking scan progress
|
|
- `darkwatch.getReports` — `protectedProcedure` returning generated PDF reports
|
|
- `web/src/server/services/darkwatch.service.ts` — Core business logic:
|
|
- `addWatchlistItem(userId, type, value)` — hash value, deduplicate, save to DB
|
|
- `removeWatchlistItem(userId, itemId)` — delete and cascade
|
|
- `getExposures(userId, filters?)` — query exposures with pagination, sorting
|
|
- `runScan(userId)` — orchestrate multi-source scan:
|
|
- HIBP breach check
|
|
- SecurityTrails lookup
|
|
- Censys/Shodan queries
|
|
- Dark web forum scraping (where applicable)
|
|
- `generateReport(userId, periodStart, periodEnd)` — compile exposures into PDF report
|
|
- `checkTierLimits(userId)` — verify scan frequency against subscription tier
|
|
- `web/src/server/services/darkwatch/scan.engine.ts` — Scan orchestration:
|
|
- `scanHIBP(email)` — query Have I Been Pwned API
|
|
- `scanSecurityTrails(identifier)` — query SecurityTrails API
|
|
- `scanCensys(query)` — query Censys API
|
|
- `scanShodan(query)` — query Shodan API
|
|
- `scanForums(identifier)` — placeholder for forum scraping logic
|
|
- `web/src/server/services/darkwatch/alert.pipeline.ts` — Exposure-to-alert pipeline:
|
|
- `processExposure(exposure)` — severity scoring, deduplication, alert creation
|
|
- `severityScore(exposure)` — calculate severity based on source, data type, recurrence
|
|
|
|
steps:
|
|
1. Create `web/src/server/api/routers/darkwatch.ts`.
|
|
2. Define Zod schemas:
|
|
- `addWatchlistItemSchema`: `type: z.enum(['email', 'phoneNumber', 'ssn', 'address', 'domain'])`, `value: z.string()`
|
|
- `exposureFilterSchema`: `severity: z.enum(['info', 'warning', 'critical']).optional()`, `source: z.enum([...]).optional()`, `page: z.number().default(1)`, `limit: z.number().default(20)`
|
|
3. Implement router procedures:
|
|
- Watchlist CRUD with user ownership checks
|
|
- Exposure queries with filtering and pagination
|
|
- Manual scan with tier limit enforcement
|
|
4. Create `web/src/server/services/darkwatch.service.ts`:
|
|
- Port logic from `services/darkwatch/src/watchlist.service.ts`
|
|
- Port logic from `services/darkwatch/src/scan.service.ts`
|
|
- Port logic from `services/darkwatch/src/alert.pipeline.ts`
|
|
5. Create scan engine modules:
|
|
- Each scanner is a function that takes an identifier and returns raw results
|
|
- Use environment variables for API keys (`HIBP_API_KEY`, `SECURITYTRAILS_API_KEY`, etc.)
|
|
- Implement circuit breaker pattern for external APIs (reference `services/spamshield/test/circuit-breaker.test.ts`)
|
|
6. Create alert pipeline:
|
|
- `processExposure` creates or updates `Exposure` record
|
|
- If new or severity increased, create `Alert` record and trigger notification (via task 14 service)
|
|
- Deduplicate based on `identifierHash` and `source`
|
|
7. Implement tier limit checks:
|
|
- Basic: 1 manual scan/month
|
|
- Plus: 1 manual scan/week
|
|
- Premium: unlimited + real-time monitoring
|
|
8. Wire router into `web/src/server/api/root.ts`.
|
|
9. Write unit tests for service functions with mocked external APIs.
|
|
|
|
steps:
|
|
- Unit: `addWatchlistItem` hashes and deduplicates values
|
|
- Unit: `runScan` calls all scan engines and aggregates results
|
|
- Unit: `severityScore` returns correct severity for different exposure types
|
|
- Unit: `checkTierLimits` enforces scan frequency correctly
|
|
- Unit: Alert pipeline creates alert only for new/high-severity exposures
|
|
- Integration: tRPC procedures enforce user ownership
|
|
|
|
acceptance_criteria:
|
|
- [ ] Watchlist items can be added, listed, and removed per user
|
|
- [ ] Exposures are queryable with filtering and pagination
|
|
- [ ] Manual scan orchestrates all data sources and creates exposure records
|
|
- [ ] Tier limits prevent excessive scanning based on subscription level
|
|
- [ ] Alert pipeline creates notifications for new/high-severity exposures
|
|
- [ ] External API failures are handled gracefully (circuit breaker, retries)
|
|
- [ ] All user data is properly scoped (users cannot see other users' exposures)
|
|
|
|
validation:
|
|
- Add a test watchlist item, run manual scan, verify exposure records created
|
|
- Check that exceeding tier limit returns appropriate error
|
|
- Simulate HIBP API failure and verify circuit breaker opens
|
|
- Run `cd web && pnpm test` for DarkWatch unit tests
|
|
|
|
notes:
|
|
- Reference legacy: `services/darkwatch/src/`, `packages/api/src/routes/darkwatch.routes.ts`
|
|
- The HIBP API requires an API key for breach lookups. Store in `HIBP_API_KEY`.
|
|
- SecurityTrails, Censys, and Shodan also require API keys. Document all required env vars.
|
|
- SSN values should be hashed before storage (already in schema). Never log raw SSNs.
|
|
- The scan engine should be designed to run both synchronously (manual scan) and asynchronously (scheduled scans via task 22).
|
|
- Consider rate-limiting the `runScan` endpoint independently to prevent abuse.
|