Sifa professional network API (Fastify, AT Protocol, Jetstream) sifa.id/
at main 100 lines 4.0 kB view raw
1import { describe, it, expect } from 'vitest'; 2import type { FastifyRequest, FastifyReply } from 'fastify'; 3import type { NodeOAuthClient } from '@atproto/oauth-client-node'; 4import { 5 TokenInvalidError, 6 TokenRefreshError, 7 TokenRevokedError, 8} from '@atproto/oauth-client-node'; 9import type { Database } from '../../src/db/index.js'; 10import { createAuthMiddleware } from '../../src/middleware/auth.js'; 11import { isPermanentSessionError } from '../../src/oauth/errors.js'; 12 13describe('Auth middleware', () => { 14 it('returns 401 when no session cookie', async () => { 15 const middleware = createAuthMiddleware( 16 {} as unknown as NodeOAuthClient, 17 {} as unknown as Database, 18 ); 19 const request = { cookies: {} } as unknown as FastifyRequest; 20 const reply = { 21 status: (code: number) => ({ 22 send: (body: Record<string, unknown>) => ({ statusCode: code, body }), 23 }), 24 } as unknown as FastifyReply; 25 26 const result = await middleware(request, reply); 27 expect((result as { statusCode: number }).statusCode).toBe(401); 28 }); 29 30 it('returns 503 when oauthClient is null', async () => { 31 const middleware = createAuthMiddleware(null, {} as unknown as Database); 32 const request = { cookies: { session: 'some-session-id' } } as unknown as FastifyRequest; 33 const reply = { 34 status: (code: number) => ({ 35 send: (body: Record<string, unknown>) => ({ statusCode: code, body }), 36 }), 37 } as unknown as FastifyReply; 38 39 const result = await middleware(request, reply); 40 expect((result as { statusCode: number }).statusCode).toBe(503); 41 }); 42}); 43 44describe('isPermanentSessionError', () => { 45 const testDid = 'did:plc:test123'; 46 47 it('returns true for TokenInvalidError', () => { 48 expect(isPermanentSessionError(new TokenInvalidError(testDid))).toBe(true); 49 expect(isPermanentSessionError(new TokenInvalidError(testDid, 'invalid_grant'))).toBe(true); 50 }); 51 52 it('returns true for TokenRevokedError', () => { 53 expect(isPermanentSessionError(new TokenRevokedError(testDid))).toBe(true); 54 }); 55 56 it('returns true for TokenRefreshError caused by a permanent error', () => { 57 const cause = new TokenInvalidError(testDid); 58 const err = new TokenRefreshError(testDid, 'Refresh failed', { cause }); 59 expect(isPermanentSessionError(err)).toBe(true); 60 }); 61 62 it('returns true for TokenRefreshError caused by a revoked token', () => { 63 const cause = new TokenRevokedError(testDid); 64 const err = new TokenRefreshError(testDid, 'Refresh failed', { cause }); 65 expect(isPermanentSessionError(err)).toBe(true); 66 }); 67 68 it('returns false for TokenRefreshError with a transient cause', () => { 69 const cause = new Error('fetch failed'); 70 const err = new TokenRefreshError(testDid, 'Refresh failed', { cause }); 71 expect(isPermanentSessionError(err)).toBe(false); 72 }); 73 74 it('returns false for TokenRefreshError with no cause', () => { 75 const err = new TokenRefreshError(testDid, 'Refresh failed'); 76 expect(isPermanentSessionError(err)).toBe(false); 77 }); 78 79 it('returns false for network errors (transient)', () => { 80 expect(isPermanentSessionError(new Error('fetch failed'))).toBe(false); 81 expect(isPermanentSessionError(new Error('connect ECONNREFUSED'))).toBe(false); 82 expect(isPermanentSessionError(new Error('ETIMEDOUT'))).toBe(false); 83 }); 84 85 it('returns false for rate limiting errors (transient)', () => { 86 const err = new Error('Failed to resolve identity: did:plc:abc'); 87 err.cause = new Error('Too Many Requests'); 88 expect(isPermanentSessionError(err)).toBe(false); 89 }); 90 91 it('returns false for unknown errors (safe default: transient)', () => { 92 expect(isPermanentSessionError(new Error('Something unexpected happened'))).toBe(false); 93 expect(isPermanentSessionError(new Error('New error type from library v2'))).toBe(false); 94 }); 95 96 it('returns false for non-Error values', () => { 97 expect(isPermanentSessionError('string error')).toBe(false); 98 expect(isPermanentSessionError(null)).toBe(false); 99 }); 100});