A social knowledge tool for researchers built on ATProto
fork

Configure Feed

Select the types of activity you want to include in your feed.

at development 114 lines 3.2 kB view raw
1import jwt from 'jsonwebtoken'; 2import { v4 as uuidv4 } from 'uuid'; 3import { Result, ok, err } from 'src/shared/core/Result'; 4import { ITokenService } from '../../application/services/ITokenService'; 5import { ITokenRepository } from '../../domain/repositories/ITokenRepository'; 6import { TokenPair } from '../../application/dtos/TokenDTO'; 7 8export class FakeJwtTokenService implements ITokenService { 9 private jwtSecret: string; 10 private accessTokenExpiresIn: number = 3600; // 1 hour 11 private refreshTokenExpiresIn: number = 2592000; // 30 days 12 13 constructor(private tokenRepository: ITokenRepository) { 14 this.jwtSecret = process.env.MOCK_ACCESS_TOKEN || 'mock-access-token-123'; 15 } 16 17 async generateToken(did: string): Promise<Result<TokenPair>> { 18 try { 19 // Generate actual JWT access token 20 const accessToken = jwt.sign( 21 { did, iat: Math.floor(Date.now() / 1000) }, 22 this.jwtSecret, 23 { expiresIn: this.accessTokenExpiresIn }, 24 ); 25 26 // Generate refresh token 27 const refreshToken = uuidv4(); 28 const tokenId = uuidv4(); 29 const now = new Date(); 30 const expiresAt = new Date( 31 now.getTime() + this.refreshTokenExpiresIn * 1000, 32 ); 33 34 // Store refresh token 35 const saveResult = await this.tokenRepository.saveRefreshToken({ 36 tokenId, 37 userDid: did, 38 refreshToken, 39 issuedAt: now, 40 expiresAt, 41 revoked: false, 42 }); 43 44 if (saveResult.isErr()) { 45 return err(saveResult.error); 46 } 47 48 return ok({ 49 accessToken, 50 refreshToken, 51 expiresIn: this.accessTokenExpiresIn, 52 }); 53 } catch (error: any) { 54 return err(error); 55 } 56 } 57 58 async validateToken(token: string): Promise<Result<string | null>> { 59 try { 60 const decoded = jwt.verify(token, this.jwtSecret) as { did: string }; 61 return ok(decoded.did); 62 } catch (error) { 63 return ok(null); // Token is invalid or expired 64 } 65 } 66 67 async refreshToken(refreshToken: string): Promise<Result<TokenPair | null>> { 68 try { 69 // Find the refresh token 70 const findResult = 71 await this.tokenRepository.findRefreshToken(refreshToken); 72 73 if (findResult.isErr()) { 74 return err(findResult.error); 75 } 76 77 const tokenData = findResult.unwrap(); 78 if (!tokenData) { 79 return ok(null); 80 } 81 82 // Check if token is expired 83 if (new Date() > tokenData.expiresAt) { 84 await this.revokeToken(refreshToken); 85 return ok(null); 86 } 87 88 // Generate new tokens 89 const newTokens = await this.generateToken(tokenData.userDid); 90 91 // Revoke old token 92 await this.revokeToken(refreshToken); 93 94 return newTokens; 95 } catch (error: any) { 96 return err(error); 97 } 98 } 99 100 async revokeToken(refreshToken: string): Promise<Result<void>> { 101 try { 102 const revokeResult = 103 await this.tokenRepository.revokeRefreshToken(refreshToken); 104 105 if (revokeResult.isErr()) { 106 return err(revokeResult.error); 107 } 108 109 return ok(undefined); 110 } catch (error: any) { 111 return err(error); 112 } 113 } 114}