Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 22 additions & 12 deletions src/claims/claims.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,17 @@ export class ClaimsController {
@ApiBearerAuth()
@ApiOperation({ summary: 'Submit a manual claim for a policy' })
@ApiResponse({ status: 201, description: 'Claim submitted successfully' })
@ApiResponse({ status: 403, description: 'Claimant does not match authenticated wallet' })
@ApiResponse({ status: 409, description: 'Claim already exists for this policy' })
async submitClaim(@Body() dto: SubmitClaimDto, @Req() req: AuthenticatedRequest) {
const walletAddress = req.wallet || dto.claimant;
const claimId = await this.claims.submitClaim(walletAddress, dto.policyId);
const authedWallet = req.user?.walletAddress || req.wallet;
if (!authedWallet) {
throw new UnauthorizedException('Not authenticated');
}
if (dto.claimant && dto.claimant !== authedWallet) {
throw new ForbiddenException('Claimant does not match authenticated wallet');
}
const claimId = await this.claims.submitClaim(authedWallet, dto.policyId);
return { success: true, data: { claimId } };
}

Expand All @@ -47,11 +54,12 @@ export class ClaimsController {
@Query('limit') limit: string,
@Req() req: AuthenticatedRequest,
) {
const targetWallet = wallet || req.wallet;
if (!targetWallet) {
throw new UnauthorizedException('Wallet address is required');
const authedWallet = req.user?.walletAddress || req.wallet;
if (!authedWallet) {
throw new UnauthorizedException('Not authenticated');
}
if (req.wallet && req.wallet !== targetWallet) {
const targetWallet = wallet || authedWallet;
if (targetWallet !== authedWallet) {
throw new ForbiddenException('Wallet address does not match authenticated user');
}
const result = await this.claims.getClaimsByWallet(
Expand Down Expand Up @@ -89,7 +97,8 @@ export class ClaimsController {
if (!claim) {
throw new NotFoundException('Claim not found');
}
if (claim.claimant !== req.wallet) {
const authedWallet = req.user?.walletAddress || req.wallet;
if (claim.claimant !== authedWallet) {
throw new ForbiddenException('Claim belongs to a different wallet');
}
return { success: true, data: claim };
Expand All @@ -110,12 +119,13 @@ export class ClaimsController {
@Query('limit') limit: string,
@Req() req: AuthenticatedRequest,
) {
const targetWallet = wallet || req.wallet;
if (!targetWallet) {
throw new UnauthorizedException('Wallet address is required');
const authedWallet = req.user?.walletAddress || req.wallet;
if (!authedWallet) {
throw new UnauthorizedException('Not authenticated');
}
if (req.wallet && req.wallet !== targetWallet) {
throw new UnauthorizedException('Cannot read claims for another wallet');
const targetWallet = wallet || authedWallet;
if (targetWallet !== authedWallet) {
throw new ForbiddenException('Cannot read claims for another wallet');
}
const result = await this.claims.getClaimsByWallet(
targetWallet,
Expand Down
32 changes: 23 additions & 9 deletions src/policy/policy.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
HttpCode,
HttpStatus,
NotFoundException,
ForbiddenException,
BadRequestException,
UseGuards,
Req,
Expand Down Expand Up @@ -56,30 +57,38 @@ export class PolicyController {
@Query('limit') limit: string = '20',
@Req() req: AuthenticatedRequest,
) {
const targetWallet = wallet || req.wallet;
if (!targetWallet) {
const authedWallet = req.user?.walletAddress || req.wallet;
if (!authedWallet) {
throw new BadRequestException('wallet query param required');
}
if (req.wallet && req.wallet !== targetWallet) {
throw new UnauthorizedException('Cannot fetch policies for another wallet');
const targetWallet = wallet || authedWallet;
if (targetWallet !== authedWallet) {
throw new ForbiddenException('Cannot fetch policies for another wallet');
}
const pageNum = Math.max(1, parseInt(page, 10) || 1);
const limitNum = Math.min(100, Math.max(1, parseInt(limit, 10) || 20));
const result = await this.policy.getUserPolicies(targetWallet, pageNum, limitNum);
return { success: true, ...result };
}

/** GET /api/v1/policies/:id — get a single policy by ID */
/** GET /api/v1/policies/:id — get a single policy by ID (owner only) */
@Get('policies/:id')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
@ApiOperation({ summary: 'Get a single policy by ID' })
@ApiParam({ name: 'id', description: 'Policy UUID' })
@ApiResponse({ status: 200, description: 'Returns the policy details' })
@ApiResponse({ status: 403, description: 'Policy belongs to a different wallet' })
@ApiResponse({ status: 404, description: 'Policy not found' })
async getPolicy(@Param('id') id: string) {
async getPolicy(@Param('id') id: string, @Req() req: AuthenticatedRequest) {
const policyData = await this.policy.getPolicy(id);
if (!policyData) {
throw new NotFoundException(`Policy ${id} not found`);
}
const authedWallet = req.user?.walletAddress || req.wallet;
if (policyData.policyholder !== authedWallet) {
throw new ForbiddenException('Policy belongs to a different wallet');
}
return { success: true, data: policyData };
}

Expand All @@ -92,8 +101,9 @@ export class PolicyController {
@ApiResponse({ status: 200, description: 'Returns premium quote for the requested coverage' })
@ApiResponse({ status: 400, description: 'Invalid request body' })
async buyPolicy(@Req() req: AuthenticatedRequest, @Body() dto: BuyPolicyDto) {
if (dto.walletAddress !== req.wallet) {
throw new UnauthorizedException('Wallet address does not match authenticated user');
const authedWallet = req.user?.walletAddress || req.wallet;
if (dto.walletAddress !== authedWallet) {
throw new ForbiddenException('Wallet address does not match authenticated user');
}
const products = await this.policy.getActiveProducts();
const product = products.find((p) => p.id === dto.productId);
Expand Down Expand Up @@ -135,7 +145,11 @@ export class PolicyController {
@ApiOperation({ summary: 'Submit signed XDR to complete policy purchase on-chain' })
@ApiResponse({ status: 200, description: 'Policy created on-chain and persisted; returns policyId and txHash' })
@ApiResponse({ status: 400, description: 'Invalid request body or on-chain submission failed' })
async confirmPolicy(@Body() dto: ConfirmPolicyDto) {
async confirmPolicy(@Body() dto: ConfirmPolicyDto, @Req() req: AuthenticatedRequest) {
const authedWallet = req.user?.walletAddress || req.wallet;
if (dto.walletAddress !== authedWallet) {
throw new ForbiddenException('Wallet address does not match authenticated user');
}
const result = await this.policy.confirmAndCreatePolicy(dto);
return { success: true, data: result };
}
Expand Down
Loading