/** * Identity Linking Controller * * API endpoints for cross-instance identity verification and management. */ import { Controller, Post, Get, Patch, Delete, Body, Param, UseGuards } from "@nestjs/common"; import { Throttle } from "@nestjs/throttler"; import { AuthGuard } from "../auth/guards/auth.guard"; import { IdentityLinkingService } from "./identity-linking.service"; import { IdentityResolutionService } from "./identity-resolution.service"; import { CurrentUser } from "../auth/decorators/current-user.decorator"; import type { VerifyIdentityDto, ResolveIdentityDto, BulkResolveIdentityDto, CreateIdentityMappingDto, UpdateIdentityMappingDto, } from "./dto/identity-linking.dto"; import type { IdentityVerificationResponse, IdentityResolutionResponse, BulkIdentityResolutionResponse, IdentityMappingValidation, } from "./types/identity-linking.types"; import type { FederatedIdentity } from "./types/oidc.types"; /** * User object from authentication */ interface AuthenticatedUser { id: string; email: string; name: string; } @Controller("federation/identity") export class IdentityLinkingController { constructor( private readonly identityLinkingService: IdentityLinkingService, private readonly identityResolutionService: IdentityResolutionService ) {} /** * POST /api/v1/federation/identity/verify * * Verify a user's identity from a remote instance. * Validates signature and OIDC token. * Rate limit: "strict" tier (10 req/min) - public endpoint requiring authentication */ @Post("verify") @UseGuards(AuthGuard) @Throttle({ strict: { limit: 10, ttl: 60000 } }) async verifyIdentity(@Body() dto: VerifyIdentityDto): Promise { return this.identityLinkingService.verifyIdentity(dto); } /** * POST /api/v1/federation/identity/resolve * * Resolve a remote user to a local user. */ @Post("resolve") @UseGuards(AuthGuard) async resolveIdentity(@Body() dto: ResolveIdentityDto): Promise { return this.identityResolutionService.resolveIdentity(dto.remoteInstanceId, dto.remoteUserId); } /** * POST /api/v1/federation/identity/bulk-resolve * * Bulk resolve multiple remote users to local users. */ @Post("bulk-resolve") @UseGuards(AuthGuard) async bulkResolveIdentity( @Body() dto: BulkResolveIdentityDto ): Promise { return this.identityResolutionService.bulkResolveIdentities( dto.remoteInstanceId, dto.remoteUserIds ); } /** * GET /api/v1/federation/identity/me * * Get the current user's federated identities. */ @Get("me") @UseGuards(AuthGuard) async getCurrentUserIdentities( @CurrentUser() user: AuthenticatedUser ): Promise { return this.identityLinkingService.listUserIdentities(user.id); } /** * POST /api/v1/federation/identity/link * * Create a new identity mapping for the current user. */ @Post("link") @UseGuards(AuthGuard) async createIdentityMapping( @CurrentUser() user: AuthenticatedUser, @Body() dto: CreateIdentityMappingDto ): Promise { return this.identityLinkingService.createIdentityMapping(user.id, dto); } /** * PATCH /api/v1/federation/identity/:remoteInstanceId * * Update an existing identity mapping. */ @Patch(":remoteInstanceId") @UseGuards(AuthGuard) async updateIdentityMapping( @CurrentUser() user: AuthenticatedUser, @Param("remoteInstanceId") remoteInstanceId: string, @Body() dto: UpdateIdentityMappingDto ): Promise { return this.identityLinkingService.updateIdentityMapping(user.id, remoteInstanceId, dto); } /** * DELETE /api/v1/federation/identity/:remoteInstanceId * * Revoke an identity mapping. */ @Delete(":remoteInstanceId") @UseGuards(AuthGuard) async revokeIdentityMapping( @CurrentUser() user: AuthenticatedUser, @Param("remoteInstanceId") remoteInstanceId: string ): Promise<{ success: boolean }> { await this.identityLinkingService.revokeIdentityMapping(user.id, remoteInstanceId); return { success: true }; } /** * GET /api/v1/federation/identity/:remoteInstanceId/validate * * Validate an identity mapping exists and is valid. */ @Get(":remoteInstanceId/validate") @UseGuards(AuthGuard) async validateIdentityMapping( @CurrentUser() user: AuthenticatedUser, @Param("remoteInstanceId") remoteInstanceId: string ): Promise { return this.identityLinkingService.validateIdentityMapping(user.id, remoteInstanceId); } }