diff --git a/src/modules/user/infrastructure/services/FakeJwtTokenService.ts b/src/modules/user/infrastructure/services/FakeJwtTokenService.ts index 4ba53fa0..50b88e45 100644 --- a/src/modules/user/infrastructure/services/FakeJwtTokenService.ts +++ b/src/modules/user/infrastructure/services/FakeJwtTokenService.ts @@ -1,23 +1,54 @@ +import jwt from 'jsonwebtoken'; +import { v4 as uuidv4 } from 'uuid'; import { Result, ok, err } from 'src/shared/core/Result'; import { ITokenService } from '../../application/services/ITokenService'; import { ITokenRepository } from '../../domain/repositories/ITokenRepository'; import { TokenPair } from '../../application/dtos/TokenDTO'; export class FakeJwtTokenService implements ITokenService { - constructor(private tokenRepository: ITokenRepository) {} + private jwtSecret: string; + private accessTokenExpiresIn: number = 3600; // 1 hour + private refreshTokenExpiresIn: number = 2592000; // 30 days + + constructor(private tokenRepository: ITokenRepository) { + this.jwtSecret = process.env.MOCK_ACCESS_TOKEN || 'mock-access-token-123'; + } async generateToken(did: string): Promise> { try { - // Use mock tokens from environment variables - const mockAccessToken = - process.env.MOCK_ACCESS_TOKEN || 'mock-access-token-123'; - const mockRefreshToken = - process.env.MOCK_REFRESH_TOKEN || 'mock-refresh-token-456'; + // Generate actual JWT access token + const accessToken = jwt.sign( + { did, iat: Math.floor(Date.now() / 1000) }, + this.jwtSecret, + { expiresIn: this.accessTokenExpiresIn }, + ); + + // Generate refresh token + const refreshToken = uuidv4(); + const tokenId = uuidv4(); + const now = new Date(); + const expiresAt = new Date( + now.getTime() + this.refreshTokenExpiresIn * 1000, + ); + + // Store refresh token + const saveResult = await this.tokenRepository.saveRefreshToken({ + tokenId, + userDid: did, + refreshToken, + issuedAt: now, + expiresAt, + revoked: false, + }); + + if (saveResult.isErr()) { + return err(saveResult.error); + } return ok({ - accessToken: mockAccessToken, - refreshToken: mockRefreshToken, - expiresIn: 3600, // 1 hour + accessToken, + refreshToken, + expiresIn: this.accessTokenExpiresIn, }); } catch (error: any) { return err(error); @@ -26,40 +57,41 @@ export class FakeJwtTokenService implements ITokenService { async validateToken(token: string): Promise> { try { - // Use mock data from environment variables - const mockAccessToken = - process.env.MOCK_ACCESS_TOKEN || 'mock-access-token-123'; - const mockDid = process.env.BSKY_DID || 'did:plc:mock123'; - - // Return mock DID if token matches mock token - if (token === mockAccessToken) { - return ok(mockDid); - } - - return ok(null); - } catch (error: any) { - return err(error); + const decoded = jwt.verify(token, this.jwtSecret) as { did: string }; + return ok(decoded.did); + } catch (error) { + return ok(null); // Token is invalid or expired } } async refreshToken(refreshToken: string): Promise> { try { - // Use mock tokens from environment variables - const mockRefreshToken = - process.env.MOCK_REFRESH_TOKEN || 'mock-refresh-token-456'; - const mockAccessToken = - process.env.MOCK_ACCESS_TOKEN || 'mock-access-token-123'; - - // Return new tokens if refresh token matches mock token - if (refreshToken === mockRefreshToken) { - return ok({ - accessToken: mockAccessToken, - refreshToken: mockRefreshToken, - expiresIn: 3600, // 1 hour - }); + // Find the refresh token + const findResult = + await this.tokenRepository.findRefreshToken(refreshToken); + + if (findResult.isErr()) { + return err(findResult.error); + } + + const tokenData = findResult.unwrap(); + if (!tokenData) { + return ok(null); + } + + // Check if token is expired + if (new Date() > tokenData.expiresAt) { + await this.revokeToken(refreshToken); + return ok(null); } - return ok(null); + // Generate new tokens + const newTokens = await this.generateToken(tokenData.userDid); + + // Revoke old token + await this.revokeToken(refreshToken); + + return newTokens; } catch (error: any) { return err(error); } @@ -67,7 +99,13 @@ export class FakeJwtTokenService implements ITokenService { async revokeToken(refreshToken: string): Promise> { try { - // Mock token revocation - always succeeds + const revokeResult = + await this.tokenRepository.revokeRefreshToken(refreshToken); + + if (revokeResult.isErr()) { + return err(revokeResult.error); + } + return ok(undefined); } catch (error: any) { return err(error);