| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232 |
- import { safeSql } from '@supabase/pg-meta'
- import { describe, expect, it } from 'vitest'
- import type { RoleImpersonationState } from './role-impersonation'
- import {
- getExp1HourFromNow,
- getPostgrestClaims,
- wrapWithRoleImpersonation,
- } from './role-impersonation'
- const createBaseUser = (overrides = {}) => ({
- id: 'user123',
- email: 'test@example.com',
- phone: undefined,
- role: 'authenticated',
- is_anonymous: false,
- raw_app_meta_data: { provider: 'email' },
- raw_user_meta_data: { name: 'Tester' },
- ...overrides,
- })
- const createTestClaims = (overrides = {}) => ({
- ref: 'test-project',
- exp: getExp1HourFromNow(),
- iat: Math.floor(Date.now() / 1000),
- iss: 'https://test-project.supabase.co/auth/v1',
- role: 'authenticated' as const,
- ...overrides,
- })
- describe('getExp1HourFromNow', () => {
- it('returns a timestamp 1 hour in the future', () => {
- const now = Math.floor(Date.now() / 1000)
- const exp = getExp1HourFromNow()
- expect(exp).toBeGreaterThan(now)
- expect(exp).toBeLessThanOrEqual(now + 3600)
- })
- })
- describe('getPostgrestClaims', () => {
- describe('native user claims', () => {
- it('returns basic user claims', () => {
- const claims = getPostgrestClaims('test-project', {
- type: 'postgrest',
- role: 'authenticated',
- userType: 'native',
- user: createBaseUser() as any,
- })
- expect(claims.aud).toBe('authenticated')
- expect(claims.email).toBe('test@example.com')
- expect(claims.sub).toBe('user123')
- })
- it('handles missing user data gracefully', () => {
- const claims = getPostgrestClaims('test-project', {
- type: 'postgrest',
- role: 'authenticated',
- userType: 'native',
- } as any)
- expect(claims.role).toBe('authenticated')
- expect(claims.ref).toBe('test-project')
- })
- })
- describe('external user claims', () => {
- it('returns claims with additional data', () => {
- const claims = getPostgrestClaims('test-project', {
- type: 'postgrest',
- role: 'authenticated',
- userType: 'external',
- externalAuth: {
- sub: 'ext123',
- additionalClaims: { foo: 'bar', custom: 'value' },
- },
- })
- expect(claims.sub).toBe('ext123')
- expect((claims as any).foo).toBe('bar')
- expect((claims as any).custom).toBe('value')
- })
- it('handles missing additional claims', () => {
- const claims = getPostgrestClaims('test-project', {
- type: 'postgrest',
- role: 'authenticated',
- userType: 'external',
- externalAuth: {
- sub: 'ext123',
- },
- })
- expect(claims.sub).toBe('ext123')
- expect((claims as any).foo).toBeUndefined()
- })
- })
- describe('system roles', () => {
- it('returns basic claims for anon role', () => {
- const claims = getPostgrestClaims('test-project', {
- type: 'postgrest',
- role: 'anon',
- })
- expect(claims.role).toBe('anon')
- expect(claims.ref).toBe('test-project')
- })
- it('returns basic claims for service_role', () => {
- const claims = getPostgrestClaims('test-project', {
- type: 'postgrest',
- role: 'service_role',
- })
- expect(claims.role).toBe('service_role')
- expect(claims.ref).toBe('test-project')
- })
- })
- })
- describe('wrapWithRoleImpersonation', () => {
- const sql = safeSql`select * from colors;`
- const ref = 'default'
- describe('postgres role (undefined)', () => {
- it('returns SQL as is when no role is selected', () => {
- const roleImpersonationState: RoleImpersonationState = {
- role: undefined,
- claims: undefined,
- }
- const result = wrapWithRoleImpersonation(sql, roleImpersonationState)
- expect(result).toBe(sql)
- })
- })
- describe('anon role', () => {
- it('wraps SQL with anon user configuration', () => {
- const claims = createTestClaims({
- iss: 'briven',
- ref,
- role: 'anon' as const,
- })
- const roleImpersonationState: RoleImpersonationState = {
- role: { type: 'postgrest', role: 'anon' },
- claims,
- }
- const result = wrapWithRoleImpersonation(sql, roleImpersonationState)
- expect(result).toContain("set_config('role', 'anon', true)")
- expect(result).toContain('request.jwt.claims')
- expect(result).toContain('ROLE_IMPERSONATION_NO_RESULTS')
- expect(result).toContain(sql)
- })
- })
- describe('authenticated user', () => {
- it('wraps SQL with native user configuration', () => {
- const claims = createTestClaims({
- iss: `https://${ref}.supabase.co/auth/v1`,
- role: 'authenticated' as const,
- })
- const roleImpersonationState: RoleImpersonationState = {
- role: {
- type: 'postgrest',
- role: 'authenticated',
- aal: 'aal1',
- userType: 'native',
- user: {
- email: 'test@email.com',
- id: 'abc',
- providers: [],
- },
- },
- claims,
- }
- const result = wrapWithRoleImpersonation(sql, roleImpersonationState)
- expect(result).toContain("set_config('role', 'authenticated', true)")
- expect(result).toContain('request.jwt.claims')
- expect(result).toContain('ROLE_IMPERSONATION_NO_RESULTS')
- expect(result).toContain(sql)
- })
- it('wraps SQL with external user configuration', () => {
- const claims = createTestClaims({
- aal: 'aal1' as const,
- aud: 'authenticated',
- role: 'authenticated' as const,
- session_id: 'ecab6bfd-3707-4e63-9b3b-d37af69449d9',
- sub: 'user123',
- })
- const roleImpersonationState: RoleImpersonationState = {
- role: {
- type: 'postgrest',
- role: 'authenticated',
- userType: 'external',
- externalAuth: {
- sub: 'user123',
- additionalClaims: {},
- },
- aal: 'aal1',
- },
- claims,
- }
- const result = wrapWithRoleImpersonation(sql, roleImpersonationState)
- expect(result).toContain("set_config('role', 'authenticated', true)")
- expect(result).toContain('request.jwt.claims')
- expect(result).toContain('ROLE_IMPERSONATION_NO_RESULTS')
- expect(result).toContain(sql)
- })
- })
- describe('custom role', () => {
- it('wraps SQL with custom role configuration', () => {
- const customRole = 'test'
- const roleImpersonationState: RoleImpersonationState = {
- role: { type: 'custom', role: customRole },
- claims: undefined,
- }
- const result = wrapWithRoleImpersonation(sql, roleImpersonationState)
- expect(result).toContain(`set local role '${customRole}'`)
- expect(result).toContain('ROLE_IMPERSONATION_NO_RESULTS')
- expect(result).toContain(sql)
- })
- })
- })
|