Migration 034 adds member_cards (RFID/NFC UID -> member). The card UID is treated as a credential: door.manage-only RLS with no member SELECT policy; the member's own "My access cards" view goes through a service -client action that returns only count + last4 (never the raw UID). New door.manage / door.operate permissions (group Access), seeded to board and backfilled, introduced now for the whole Door epic. Pure door-logic masking is unit-tested. A per-member "Cards" panel on /members is gated to door.manage (independent of admin). No controller calls and no anonymous path in this phase. Mirrored in schema.sql; types and schema docs updated.
23 lines
742 B
TypeScript
23 lines
742 B
TypeScript
import { describe, it, expect } from 'vitest'
|
|
import { last4, maskCardUid } from '@/lib/door-logic'
|
|
|
|
describe('last4', () => {
|
|
it('returns the last 4 chars, or the whole short value', () => {
|
|
expect(last4('0123456789')).toBe('6789')
|
|
expect(last4('ABCD')).toBe('ABCD')
|
|
expect(last4('AB')).toBe('AB')
|
|
})
|
|
})
|
|
|
|
describe('maskCardUid', () => {
|
|
it('reveals only the last 4 characters', () => {
|
|
expect(maskCardUid('0123456789')).toBe('••••••6789')
|
|
expect(maskCardUid('AABBCCDD')).toBe('••••CCDD')
|
|
})
|
|
it('reveals nothing for short UIDs', () => {
|
|
expect(maskCardUid('ABCD')).toBe('••••')
|
|
expect(maskCardUid('AB')).toBe('••')
|
|
expect(maskCardUid('')).toBe('••••')
|
|
})
|
|
})
|