diff --git a/src/app.controller.ts b/src/app.controller.ts index 7efb73a..4976b66 100644 --- a/src/app.controller.ts +++ b/src/app.controller.ts @@ -8,12 +8,41 @@ import { import { AppService } from "./app.service"; import { RateLimit } from "./common/decorators/rate-limit.decorator"; import { JwtAuthGuard } from "./core/auth/jwt.guard"; +import { Public } from "./common/decorators/public.decorator"; @ApiTags("Info") @Controller() export class AppController { constructor(private readonly appService: AppService) {} + @Public() + @Get("health") + @RateLimit({ level: "free", limit: 2, windowMs: 60000 }) // Max 2 requests per minute for health + @ApiOperation({ + summary: "Health Check", + description: "Check if the API is running and healthy", + operationId: "getHealth", + }) + @ApiResponse({ + status: 200, + description: "Service is healthy", + schema: { + type: "object", + properties: { + status: { type: "string", example: "OK" }, + timestamp: { type: "string", example: "2024-02-25T05:30:00.000Z" }, + }, + }, + }) + @ApiResponse({ + status: 429, + description: "Too many requests", + }) + getHealth(): { status: string; timestamp: string } { + return this.appService.getHealth(); + } + + @Public() @Get("info") @RateLimit({ level: "standard" }) // Default standard level @ApiOperation({ diff --git a/src/app.module.ts b/src/app.module.ts index d8d2c1d..4968816 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -28,7 +28,7 @@ import { PortfolioModule } from "./investment/portfolio/portfolio.module"; import { RiskManagementModule } from "./investment/risk-management/risk-management.module"; // Modules – defi -import { DeFiModule } from "./defi/defi/defi.module"; +import { DeFiModule } from "./defi/defi.module"; // Modules – growth import { AlertsModule } from "./growth/alerts/alerts.module"; @@ -60,21 +60,23 @@ import { PerformanceMetric } from "./investment/portfolio/entities/performance-m import { BacktestResult } from "./investment/portfolio/entities/backtest-result.entity"; // DeFi entities -import { DeFiPosition } from "./defi/defi/entities/defi-position.entity"; -import { DeFiYieldRecord } from "./defi/defi/entities/defi-yield-record.entity"; -import { DeFiTransaction } from "./defi/defi/entities/defi-transaction.entity"; -import { DeFiYieldStrategy } from "./defi/defi/entities/defi-yield-strategy.entity"; -import { DeFiRiskAssessment } from "./defi/defi/entities/defi-risk-assessment.entity"; +import { DeFiPosition } from "./defi/entities/defi-position.entity"; +import { DeFiYieldRecord } from "./defi/entities/defi-yield-record.entity"; +import { DeFiTransaction } from "./defi/entities/defi-transaction.entity"; +import { DeFiYieldStrategy } from "./defi/entities/defi-yield-strategy.entity"; +import { DeFiRiskAssessment } from "./defi/entities/defi-risk-assessment.entity"; // Alerts entities import { Alert } from "./growth/alerts/entities/alert.entity"; import { AlertTriggerLog } from "./growth/alerts/entities/alert-trigger-log.entity"; +import { AlertPreference } from "./growth/alerts/entities/alert-preference.entity"; // Guards import { APP_FILTER } from "@nestjs/core"; import { ThrottlerUserIpGuard } from "./common/guard/throttler.guard"; import { RolesGuard } from "./common/guard/roles.guard"; import { KycGuard } from "./common/guard/kyc.guard"; +import { StrategyAuthGuard } from "./core/auth/guards/strategy-auth.guard"; import { GlobalExceptionFilter } from "./common/filters/global-exception.filter"; import { SubmissionVerifierService } from "./blockchain/oracle/submission-verifier.service"; @@ -143,6 +145,7 @@ import { SubmissionVerifierService } from "./blockchain/oracle/submission-verifi DeFiRiskAssessment, Alert, AlertTriggerLog, + AlertPreference, ], synchronize: !isProduction, logging: isProduction ? ["error"] : ["error", "warn", "schema"], @@ -187,6 +190,10 @@ import { SubmissionVerifierService } from "./blockchain/oracle/submission-verifi provide: APP_FILTER, useClass: GlobalExceptionFilter, }, + { + provide: APP_GUARD, + useClass: StrategyAuthGuard, + }, { provide: APP_GUARD, useClass: ThrottlerUserIpGuard, diff --git a/src/core/auth/auth.module.ts b/src/core/auth/auth.module.ts index 606fa46..7768f94 100644 --- a/src/core/auth/auth.module.ts +++ b/src/core/auth/auth.module.ts @@ -29,6 +29,32 @@ import { EmailVerification } from "./entities/email-verification.entity"; import { Wallet } from "./entities/wallet.entity"; import { RefreshToken, TwoFactorAuth } from "./entities/auth.entity"; +/** + * AuthModule — Authentication Architecture Overview + * + * Three auth flows are supported: + * + * 1. **Legacy flow** (AuthService / WalletAuthService) + * - Email+password registration/login (AuthService) and wallet-signature login + * (WalletAuthService). These services issue single short-lived JWTs and are + * retained for backward compatibility. New code should NOT call them. + * - Token revocation is handled by `TokenBlacklistService` (AuthService.logout). + * + * 2. **Enhanced flow** (EnhancedAuthService) + * - Superset of the legacy flow: adds refresh-token rotation, TOTP/backup-code + * 2FA, account-activity tracking, and proper revocation via + * `revokeAllRefreshTokens`. Prefer this service for all new email+password + * features. + * + * 3. **Strategy flow** (StrategyAuthService + StrategyAuthGuard) + * - Pluggable, registry-driven system. Strategies (WalletStrategy, + * TraditionalStrategy, OAuthStrategy, ApiKeyStrategy) are registered at + * module init and tried in sequence by `StrategyAuthGuard`. + * - `StrategyAuthGuard` is registered as a **global guard** in AppModule so + * every route is protected by default. Mark public routes with `@Public()`. + * - Use `@AllowedStrategies('wallet', 'traditional')` to restrict which + * strategies are accepted on a per-route basis. + */ @Module({ imports: [ ConfigModule, diff --git a/src/core/auth/auth.service.ts b/src/core/auth/auth.service.ts index c223644..f8b01d6 100644 --- a/src/core/auth/auth.service.ts +++ b/src/core/auth/auth.service.ts @@ -22,6 +22,10 @@ export class AuthService { private readonly tokenBlacklist: TokenBlacklistService, ) {} + /** + * @deprecated Use EnhancedAuthService instead. + * This method lacks refresh-token rotation and 2FA support. + */ async register( registerDto: RegisterDto, ): Promise<{ token: string; user: Partial }> { @@ -104,6 +108,10 @@ export class AuthService { }; } + /** + * @deprecated Use EnhancedAuthService instead. + * This method lacks refresh-token rotation and 2FA support. + */ async login( loginDto: LoginDto, ): Promise<{ token: string; user: Partial }> {