feat(control-panel): web admin UI for the zero-touch tunnel
Loopback Fastify auth-broker + esbuild SPA. Operator password login (constant-time, signed HttpOnly session cookie, per-forwarded-IP rate-limit) → session-gated proxy that mints a fresh 60s manage capability token per call to the control-plane admin API: list hosts, mint pairing codes (with QR + pair command), revoke hosts. Security headers + CSP, CP_URL pinned loopback (anti-SSRF), hostId dot-segment guard. 55 tests pass; security-reviewed. Deployed behind nginx panel.terminal.yaojia.wang.
This commit is contained in:
31
control-panel/test/compare.test.ts
Normal file
31
control-panel/test/compare.test.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { constantTimeEqual, constantTimeEqualBytes } from '../src/security/compare.js'
|
||||
|
||||
describe('constantTimeEqual', () => {
|
||||
it('returns true for identical strings', () => {
|
||||
expect(constantTimeEqual('correct-horse', 'correct-horse')).toBe(true)
|
||||
})
|
||||
|
||||
it('returns false for different strings', () => {
|
||||
expect(constantTimeEqual('correct-horse', 'battery-staple')).toBe(false)
|
||||
})
|
||||
|
||||
it('returns false for different-length strings (no length oracle)', () => {
|
||||
expect(constantTimeEqual('abc', 'abcdef')).toBe(false)
|
||||
})
|
||||
|
||||
it('returns false when either side is empty or undefined', () => {
|
||||
expect(constantTimeEqual('', 'x')).toBe(false)
|
||||
expect(constantTimeEqual('x', '')).toBe(false)
|
||||
expect(constantTimeEqual(undefined, 'x')).toBe(false)
|
||||
expect(constantTimeEqual('x', undefined)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('constantTimeEqualBytes', () => {
|
||||
it('true for equal buffers, false for differing or mismatched length', () => {
|
||||
expect(constantTimeEqualBytes(Buffer.from('aa'), Buffer.from('aa'))).toBe(true)
|
||||
expect(constantTimeEqualBytes(Buffer.from('aa'), Buffer.from('ab'))).toBe(false)
|
||||
expect(constantTimeEqualBytes(Buffer.from('aa'), Buffer.from('aaa'))).toBe(false)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user