fix: cancelled tier, remove key logging, add billing rate limits
All checks were successful
Build & Deploy to Staging / Build & Deploy to Staging (push) Successful in 10m13s

- Add 'cancelled' tier (0 req/month) for downgraded subscriptions
- Remove full API key from recovery endpoint logs (security)
- Add IP-based rate limiting (10/15min) to billing endpoints
- Bump version to 0.7.0
- 4 new tests (338 total)
This commit is contained in:
Hoid 2026-03-04 09:06:16 +01:00
parent f3a363fb17
commit 9575d312fe
5 changed files with 68 additions and 7 deletions

View file

@ -256,6 +256,34 @@ describe('GET /v1/billing/success', () => {
})
})
describe('GET /v1/billing/recover - security', () => {
beforeEach(() => { vi.clearAllMocks() })
it('should return masked key, not the full key', async () => {
vi.mocked(getKeyByEmail).mockResolvedValue({
key: 'snap_abcdef1234567890abcdef1234567890abcdef12345678',
tier: 'pro',
email: 'user@example.com',
createdAt: '2024-01-01T00:00:00Z',
})
const response = await request(app).get('/v1/billing/recover').query({ email: 'user@example.com' })
expect(response.status).toBe(200)
expect(response.body.maskedKey).toBeDefined()
expect(response.body.maskedKey).toContain('...')
// Must NOT contain the full key
expect(response.body.key).toBeUndefined()
})
})
describe('Billing rate limiting', () => {
it('should return rate limit headers on billing endpoints', async () => {
vi.mocked(getKeyByEmail).mockResolvedValue(undefined)
const response = await request(app).get('/v1/billing/recover').query({ email: 'test@example.com' })
expect(response.headers['ratelimit-limit']).toBeDefined()
})
})
describe('POST /v1/billing/webhook', () => {
beforeEach(() => { vi.clearAllMocks() })