fix(auth): unverified members cannot exercise roles; single-membership join (D2)
require_approval was silently void: redeeming an admin-role invite into a require_approval space yielded role=admin,status=unverified and requireMemberWithRole never checked status -> instant admin pre-approval. - PRIVILEGE_STATUSES/isPrivilegeEligible (current|late only; excludes unverified/inactive). requireMemberWithRole now rejects non-privilege- eligible status with 'pending approval' before the role check; Member carries status (getAuthMember selects it). requireMember stays permissive so unverified members still see their own /me. - joinSpace rejects a second active membership (single-space model; prevents the .single() self-DoS). Deferred (HANDOFF): SECURITY DEFINER helpers user_has_role_in_space/ user_has_permission still ignore status (RLS defense-in-depth, own careful pass). 524 tests; build clean.
This commit is contained in:
@@ -4,6 +4,8 @@ import {
|
||||
ADMIN_ROLES,
|
||||
TREASURER_ROLES,
|
||||
ACTIVE_STATUSES,
|
||||
PRIVILEGE_STATUSES,
|
||||
isPrivilegeEligible,
|
||||
hasRole,
|
||||
type Role,
|
||||
} from '@/lib/permissions'
|
||||
@@ -50,6 +52,22 @@ describe('ACTIVE_STATUSES', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('isPrivilegeEligible / PRIVILEGE_STATUSES', () => {
|
||||
it('only current + late may exercise a role/permission', () => {
|
||||
expect([...PRIVILEGE_STATUSES].sort()).toEqual(['current', 'late'].sort())
|
||||
expect(isPrivilegeEligible('current')).toBe(true)
|
||||
expect(isPrivilegeEligible('late')).toBe(true)
|
||||
})
|
||||
it('unverified (pending approval) is NOT privilege-eligible', () => {
|
||||
expect(isPrivilegeEligible('unverified')).toBe(false)
|
||||
})
|
||||
it('inactive / null / undefined are NOT privilege-eligible', () => {
|
||||
expect(isPrivilegeEligible('inactive')).toBe(false)
|
||||
expect(isPrivilegeEligible(null)).toBe(false)
|
||||
expect(isPrivilegeEligible(undefined)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('hasRole', () => {
|
||||
it('returns true when role is in the allowed list', () => {
|
||||
expect(hasRole('admin', ADMIN_ROLES)).toBe(true)
|
||||
|
||||
Reference in New Issue
Block a user