From 1ac5e95e08aeb95478298a7eeb2de7aa071f4d2d Mon Sep 17 00:00:00 2001 From: barsa Date: Tue, 24 Feb 2026 11:57:58 +0900 Subject: [PATCH] refactor: core layer quick wins - Rename getRequestFingerprint to getRateLimitFingerprint in rate-limit.util.ts - Delete empty CoreConfigModule wrapper (importers use @nestjs/config directly) - Replace inline admin role check in csrf.controller.ts with @UseGuards(AdminGuard) - Move hashEmailForLogs() from support.logging.ts to core/logging/redaction.util.ts --- apps/bff/src/core/config/config.module.ts | 9 --------- apps/bff/src/core/logging/redaction.util.ts | 11 +++++++++++ apps/bff/src/core/rate-limiting/index.ts | 2 +- apps/bff/src/core/rate-limiting/rate-limit.util.ts | 2 +- .../src/core/security/controllers/csrf.controller.ts | 8 +++----- .../auth/presentation/http/get-started.controller.ts | 8 ++++---- apps/bff/src/modules/orders/orders.module.ts | 4 ++-- apps/bff/src/modules/services/services.module.ts | 4 ++-- apps/bff/src/modules/support/support.controller.ts | 2 +- apps/bff/src/modules/support/support.logging.ts | 10 ---------- apps/bff/src/modules/support/support.service.ts | 2 +- .../src/modules/verification/verification.module.ts | 4 ++-- 12 files changed, 28 insertions(+), 38 deletions(-) delete mode 100644 apps/bff/src/core/config/config.module.ts delete mode 100644 apps/bff/src/modules/support/support.logging.ts diff --git a/apps/bff/src/core/config/config.module.ts b/apps/bff/src/core/config/config.module.ts deleted file mode 100644 index c8c05e38..00000000 --- a/apps/bff/src/core/config/config.module.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Module } from "@nestjs/common"; -import { ConfigModule } from "@nestjs/config"; - -@Module({ - imports: [ConfigModule], - providers: [], - exports: [], -}) -export class CoreConfigModule {} diff --git a/apps/bff/src/core/logging/redaction.util.ts b/apps/bff/src/core/logging/redaction.util.ts index 108f0ab3..26c030ee 100644 --- a/apps/bff/src/core/logging/redaction.util.ts +++ b/apps/bff/src/core/logging/redaction.util.ts @@ -5,6 +5,8 @@ * Prefer allowlists at call sites for best safety; this helper provides a safe baseline. */ +import { createHash } from "node:crypto"; + export type RedactOptions = { /** * Extra keys to redact (case-insensitive, substring match). @@ -107,3 +109,12 @@ export function redactForLogs(value: T, options: RedactOptions = {}): T { return walk(value, 0) as T; } + +/** + * Hash an email for logs (PII minimization). + * Use a short, stable prefix to correlate events without storing the email itself. + */ +export function hashEmailForLogs(email: string): string { + const normalized = email.trim().toLowerCase(); + return createHash("sha256").update(normalized).digest("hex").slice(0, 12); +} diff --git a/apps/bff/src/core/rate-limiting/index.ts b/apps/bff/src/core/rate-limiting/index.ts index c38d3d2e..cbe27c4a 100644 --- a/apps/bff/src/core/rate-limiting/index.ts +++ b/apps/bff/src/core/rate-limiting/index.ts @@ -6,4 +6,4 @@ export { type RateLimitOptions, RATE_LIMIT_KEY, } from "./rate-limit.decorator.js"; -export { getRequestFingerprint } from "./rate-limit.util.js"; +export { getRateLimitFingerprint } from "./rate-limit.util.js"; diff --git a/apps/bff/src/core/rate-limiting/rate-limit.util.ts b/apps/bff/src/core/rate-limiting/rate-limit.util.ts index 7d36a2ec..fb5d30c7 100644 --- a/apps/bff/src/core/rate-limiting/rate-limit.util.ts +++ b/apps/bff/src/core/rate-limiting/rate-limit.util.ts @@ -26,7 +26,7 @@ export function getRequestRateLimitIdentity(request: Request): { * @param request - Express request object * @returns SHA256 hash of IP + User-Agent (truncated to 32 chars) */ -export function getRequestFingerprint(request: Request): string { +export function getRateLimitFingerprint(request: Request): string { const { ip, userAgentHash } = getRequestRateLimitIdentity(request); const combined = `${ip}:${userAgentHash}`; return createHash("sha256").update(combined).digest("hex").slice(0, 32); diff --git a/apps/bff/src/core/security/controllers/csrf.controller.ts b/apps/bff/src/core/security/controllers/csrf.controller.ts index 48da2324..d8c036ff 100644 --- a/apps/bff/src/core/security/controllers/csrf.controller.ts +++ b/apps/bff/src/core/security/controllers/csrf.controller.ts @@ -1,9 +1,10 @@ -import { Controller, Get, Post, Req, Res, Inject, ForbiddenException } from "@nestjs/common"; +import { Controller, Get, Post, Req, Res, Inject, UseGuards } from "@nestjs/common"; import { ConfigService } from "@nestjs/config"; import type { Request, Response } from "express"; import { Logger } from "nestjs-pino"; import { CsrfService } from "../services/csrf.service.js"; import { Public } from "@bff/modules/auth/decorators/public.decorator.js"; +import { AdminGuard } from "../guards/admin.guard.js"; import type { UserAuth } from "@customer-portal/domain/customer"; export type AuthenticatedRequest = Request & { @@ -87,13 +88,10 @@ export class CsrfController { }); } + @UseGuards(AdminGuard) @Get("stats") getCsrfStats(@Req() req: AuthenticatedRequest) { const userId = req.user?.id; - const role = req.user?.role; - if (role !== "ADMIN") { - throw new ForbiddenException("Admin access required"); - } this.logger.debug("CSRF stats requested", { userId, diff --git a/apps/bff/src/modules/auth/presentation/http/get-started.controller.ts b/apps/bff/src/modules/auth/presentation/http/get-started.controller.ts index f3cad3f1..acff25ec 100644 --- a/apps/bff/src/modules/auth/presentation/http/get-started.controller.ts +++ b/apps/bff/src/modules/auth/presentation/http/get-started.controller.ts @@ -2,7 +2,7 @@ import { Controller, Post, Body, UseGuards, Res, Req, HttpCode } from "@nestjs/c import type { Request, Response } from "express"; import { createZodDto } from "nestjs-zod"; -import { RateLimitGuard, RateLimit, getRequestFingerprint } from "@bff/core/rate-limiting/index.js"; +import { RateLimitGuard, RateLimit, getRateLimitFingerprint } from "@bff/core/rate-limiting/index.js"; import { SalesforceWriteThrottleGuard } from "@bff/integrations/salesforce/guards/salesforce-write-throttle.guard.js"; import { Public } from "../../decorators/public.decorator.js"; @@ -68,7 +68,7 @@ export class GetStartedController { @Body() body: SendVerificationCodeRequestDto, @Req() req: Request ): Promise { - const fingerprint = getRequestFingerprint(req); + const fingerprint = getRateLimitFingerprint(req); return this.workflow.sendVerificationCode(body, fingerprint); } @@ -84,7 +84,7 @@ export class GetStartedController { @Body() body: VerifyCodeRequestDto, @Req() req: Request ): Promise { - const fingerprint = getRequestFingerprint(req); + const fingerprint = getRateLimitFingerprint(req); return this.workflow.verifyCode(body, fingerprint); } @@ -103,7 +103,7 @@ export class GetStartedController { @Body() body: GuestEligibilityRequestDto, @Req() req: Request ): Promise { - const fingerprint = getRequestFingerprint(req); + const fingerprint = getRateLimitFingerprint(req); return this.workflow.guestEligibilityCheck(body, fingerprint); } diff --git a/apps/bff/src/modules/orders/orders.module.ts b/apps/bff/src/modules/orders/orders.module.ts index 0102d853..e291322c 100644 --- a/apps/bff/src/modules/orders/orders.module.ts +++ b/apps/bff/src/modules/orders/orders.module.ts @@ -4,7 +4,7 @@ import { CheckoutController } from "./controllers/checkout.controller.js"; import { IntegrationsModule } from "@bff/integrations/integrations.module.js"; import { MappingsModule } from "@bff/modules/id-mappings/mappings.module.js"; import { UsersModule } from "@bff/modules/users/users.module.js"; -import { CoreConfigModule } from "@bff/core/config/config.module.js"; +import { ConfigModule } from "@nestjs/config"; import { ServicesModule } from "@bff/modules/services/services.module.js"; import { CacheModule } from "@bff/infra/cache/cache.module.js"; import { VerificationModule } from "@bff/modules/verification/verification.module.js"; @@ -52,7 +52,7 @@ import { SalesforceOrderFieldConfigModule } from "@bff/integrations/salesforce/c IntegrationsModule, MappingsModule, UsersModule, - CoreConfigModule, + ConfigModule, ServicesModule, CacheModule, VerificationModule, diff --git a/apps/bff/src/modules/services/services.module.ts b/apps/bff/src/modules/services/services.module.ts index ce95b97b..cde57ee8 100644 --- a/apps/bff/src/modules/services/services.module.ts +++ b/apps/bff/src/modules/services/services.module.ts @@ -6,7 +6,7 @@ import { PublicServicesController } from "./public-services.controller.js"; import { AccountServicesController } from "./account-services.controller.js"; import { IntegrationsModule } from "@bff/integrations/integrations.module.js"; import { MappingsModule } from "@bff/modules/id-mappings/mappings.module.js"; -import { CoreConfigModule } from "@bff/core/config/config.module.js"; +import { ConfigModule } from "@nestjs/config"; import { CacheModule } from "@bff/infra/cache/cache.module.js"; import { QueueModule } from "@bff/infra/queue/queue.module.js"; import { WorkflowModule } from "@bff/modules/shared/workflow/index.js"; @@ -22,7 +22,7 @@ import { ServicesCacheService } from "./application/services-cache.service.js"; imports: [ forwardRef(() => IntegrationsModule), MappingsModule, - CoreConfigModule, + ConfigModule, CacheModule, QueueModule, WorkflowModule, diff --git a/apps/bff/src/modules/support/support.controller.ts b/apps/bff/src/modules/support/support.controller.ts index dea2e064..6604546e 100644 --- a/apps/bff/src/modules/support/support.controller.ts +++ b/apps/bff/src/modules/support/support.controller.ts @@ -31,7 +31,7 @@ import { type AddCaseCommentResponse, } from "@customer-portal/domain/support"; import type { RequestWithUser } from "@bff/modules/auth/auth.types.js"; -import { hashEmailForLogs } from "./support.logging.js"; +import { hashEmailForLogs } from "@bff/core/logging/redaction.util.js"; import type { ActionMessageResponse } from "@customer-portal/domain/common"; import { actionMessageResponseSchema } from "@customer-portal/domain/common"; diff --git a/apps/bff/src/modules/support/support.logging.ts b/apps/bff/src/modules/support/support.logging.ts deleted file mode 100644 index 68da4fd3..00000000 --- a/apps/bff/src/modules/support/support.logging.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { createHash } from "node:crypto"; - -/** - * Hash an email for logs (PII minimization). - * Use a short, stable prefix to correlate events without storing the email itself. - */ -export const hashEmailForLogs = (email: string): string => { - const normalized = email.trim().toLowerCase(); - return createHash("sha256").update(normalized).digest("hex").slice(0, 12); -}; diff --git a/apps/bff/src/modules/support/support.service.ts b/apps/bff/src/modules/support/support.service.ts index cc7a1cf1..81b307a7 100644 --- a/apps/bff/src/modules/support/support.service.ts +++ b/apps/bff/src/modules/support/support.service.ts @@ -18,7 +18,7 @@ import { SalesforceCaseService } from "@bff/integrations/salesforce/services/sal import { MappingsService } from "@bff/modules/id-mappings/mappings.service.js"; import { SupportCacheService } from "./support-cache.service.js"; import { extractErrorMessage } from "@bff/core/utils/error.util.js"; -import { hashEmailForLogs } from "./support.logging.js"; +import { hashEmailForLogs } from "@bff/core/logging/redaction.util.js"; /** * Status values that indicate an open/active case diff --git a/apps/bff/src/modules/verification/verification.module.ts b/apps/bff/src/modules/verification/verification.module.ts index f2da431f..dfd0cf72 100644 --- a/apps/bff/src/modules/verification/verification.module.ts +++ b/apps/bff/src/modules/verification/verification.module.ts @@ -3,7 +3,7 @@ import { ResidenceCardController } from "./residence-card.controller.js"; import { ResidenceCardService } from "./residence-card.service.js"; import { IntegrationsModule } from "@bff/integrations/integrations.module.js"; import { MappingsModule } from "@bff/modules/id-mappings/mappings.module.js"; -import { CoreConfigModule } from "@bff/core/config/config.module.js"; +import { ConfigModule } from "@nestjs/config"; import { ServicesModule } from "@bff/modules/services/services.module.js"; import { WorkflowModule } from "@bff/modules/shared/workflow/index.js"; @@ -11,7 +11,7 @@ import { WorkflowModule } from "@bff/modules/shared/workflow/index.js"; imports: [ IntegrationsModule, MappingsModule, - CoreConfigModule, + ConfigModule, forwardRef(() => ServicesModule), WorkflowModule, ],