@withwiz/toolkit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +162 -0
- package/dist/auth/adapters/prisma/index.d.ts +43 -0
- package/dist/auth/adapters/prisma/index.js +284 -0
- package/dist/auth/core/email/token-generator.d.ts +43 -0
- package/dist/auth/core/email/token-generator.js +7 -0
- package/dist/auth/core/jwt/client.d.ts +87 -0
- package/dist/auth/core/jwt/client.js +36 -0
- package/dist/auth/core/jwt/index.d.ts +110 -0
- package/dist/auth/core/jwt/index.js +10 -0
- package/dist/auth/core/jwt/types.d.ts +6 -0
- package/dist/auth/core/jwt/types.js +13 -0
- package/dist/auth/core/oauth/index.d.ts +51 -0
- package/dist/auth/core/oauth/index.js +12 -0
- package/dist/auth/core/password/client-helper.d.ts +44 -0
- package/dist/auth/core/password/client-helper.js +28 -0
- package/dist/auth/core/password/index.d.ts +71 -0
- package/dist/auth/core/password/index.js +14 -0
- package/dist/auth/errors/index.d.ts +49 -0
- package/dist/auth/errors/index.js +17 -0
- package/dist/auth/index.d.ts +21 -0
- package/dist/auth/index.js +97 -0
- package/dist/auth/types/index.d.ts +213 -0
- package/dist/auth/types/index.js +13 -0
- package/dist/cache/cache-config.d.ts +73 -0
- package/dist/cache/cache-config.js +12 -0
- package/dist/cache/cache-defaults.d.ts +141 -0
- package/dist/cache/cache-defaults.js +33 -0
- package/dist/cache/cache-env.d.ts +75 -0
- package/dist/cache/cache-env.js +25 -0
- package/dist/cache/cache-factory.d.ts +34 -0
- package/dist/cache/cache-factory.js +28 -0
- package/dist/cache/cache-invalidation.d.ts +90 -0
- package/dist/cache/cache-invalidation.js +24 -0
- package/dist/cache/cache-keys-legacy.d.ts +35 -0
- package/dist/cache/cache-keys-legacy.js +7 -0
- package/dist/cache/cache-redis.d.ts +74 -0
- package/dist/cache/cache-redis.js +24 -0
- package/dist/cache/cache-types.d.ts +151 -0
- package/dist/cache/cache-types.js +9 -0
- package/dist/cache/cache-wrapper.d.ts +27 -0
- package/dist/cache/cache-wrapper.js +22 -0
- package/dist/cache/cache.d.ts +14 -0
- package/dist/cache/cache.js +112 -0
- package/dist/cache/hybrid-cache-manager.d.ts +148 -0
- package/dist/cache/hybrid-cache-manager.js +13 -0
- package/dist/cache/index.d.ts +21 -0
- package/dist/cache/index.js +112 -0
- package/dist/cache/inmemory-cache-manager.d.ts +163 -0
- package/dist/cache/inmemory-cache-manager.js +9 -0
- package/dist/cache/noop-cache-manager.d.ts +36 -0
- package/dist/cache/noop-cache-manager.js +11 -0
- package/dist/cache/redis-cache-manager.d.ts +34 -0
- package/dist/cache/redis-cache-manager.js +11 -0
- package/dist/chunk-26Y7VEYG.js +93 -0
- package/dist/chunk-2DVWSDST.js +119 -0
- package/dist/chunk-2KAPUVIS.js +155 -0
- package/dist/chunk-2TO7WUKK.js +93 -0
- package/dist/chunk-34WAGUT5.js +117 -0
- package/dist/chunk-3DZA6AGS.js +120 -0
- package/dist/chunk-4DPSCTX4.js +212 -0
- package/dist/chunk-4KJXENRM.js +64 -0
- package/dist/chunk-4NWJ3WCZ.js +28 -0
- package/dist/chunk-4ODT3Q4A.js +86 -0
- package/dist/chunk-5ATB5D6S.js +40 -0
- package/dist/chunk-62FLBG6B.js +34 -0
- package/dist/chunk-62Q7DN5G.js +25 -0
- package/dist/chunk-65LHDFU3.js +242 -0
- package/dist/chunk-6C7HQIX4.js +13 -0
- package/dist/chunk-6D3HHYER.js +32 -0
- package/dist/chunk-6LTZCXNC.js +326 -0
- package/dist/chunk-7VJNLGAS.js +110 -0
- package/dist/chunk-7XFHGAJP.js +0 -0
- package/dist/chunk-A6EAAWMK.js +50 -0
- package/dist/chunk-AHDPGRXS.js +51 -0
- package/dist/chunk-AIH3F7JV.js +76 -0
- package/dist/chunk-AIHQBQ3E.js +109 -0
- package/dist/chunk-BKGVSC6S.js +152 -0
- package/dist/chunk-COK4ZXNG.js +0 -0
- package/dist/chunk-DEEJBDJE.js +47 -0
- package/dist/chunk-DH2ZHGW2.js +53 -0
- package/dist/chunk-EBUEBEJX.js +0 -0
- package/dist/chunk-EEUBKZV4.js +54 -0
- package/dist/chunk-EQYTE7WD.js +139 -0
- package/dist/chunk-EUQATJLI.js +180 -0
- package/dist/chunk-EZC6ETFW.js +80 -0
- package/dist/chunk-EZR55KV2.js +249 -0
- package/dist/chunk-F6LCSFSU.js +31 -0
- package/dist/chunk-FOKAATUQ.js +62 -0
- package/dist/chunk-FW3IEJ7H.js +71 -0
- package/dist/chunk-G26T2PRQ.js +53 -0
- package/dist/chunk-G4NI37NN.js +257 -0
- package/dist/chunk-GCZOXUDV.js +132 -0
- package/dist/chunk-GDWEDUHO.js +55 -0
- package/dist/chunk-GL2NANFH.js +434 -0
- package/dist/chunk-GPBOMJSZ.js +136 -0
- package/dist/chunk-H5I5GWAA.js +94 -0
- package/dist/chunk-HGC4CCKB.js +29 -0
- package/dist/chunk-HV3DGSSH.js +447 -0
- package/dist/chunk-I47QEDTX.js +193 -0
- package/dist/chunk-IAJNC34M.js +102 -0
- package/dist/chunk-IHXRF3BH.js +215 -0
- package/dist/chunk-IJEZ7G7S.js +26 -0
- package/dist/chunk-IQQKKUAV.js +151 -0
- package/dist/chunk-JBCDEAMW.js +35 -0
- package/dist/chunk-JLLMTTQ4.js +75 -0
- package/dist/chunk-JS5VI3OW.js +143 -0
- package/dist/chunk-KAWVMIRJ.js +44 -0
- package/dist/chunk-KMCJIL57.js +214 -0
- package/dist/chunk-KWTBD4CM.js +145 -0
- package/dist/chunk-KXAWBFJN.js +310 -0
- package/dist/chunk-L25BNU3E.js +56 -0
- package/dist/chunk-L76O3X3D.js +197 -0
- package/dist/chunk-LNV2E4I6.js +63 -0
- package/dist/chunk-MLGO3HLS.js +329 -0
- package/dist/chunk-MRJE6OX5.js +22 -0
- package/dist/chunk-MYLGYX4K.js +57 -0
- package/dist/chunk-N4YGR5WH.js +310 -0
- package/dist/chunk-OIVXOT2X.js +80 -0
- package/dist/chunk-ORMEWXMH.js +37 -0
- package/dist/chunk-POKGHK3L.js +57 -0
- package/dist/chunk-Q7IP4JMW.js +69 -0
- package/dist/chunk-RJUVBBZG.js +27 -0
- package/dist/chunk-S73334QY.js +89 -0
- package/dist/chunk-SLG26KHZ.js +101 -0
- package/dist/chunk-SR65BF6X.js +82 -0
- package/dist/chunk-SS56XFLI.js +19 -0
- package/dist/chunk-T3LJYAMO.js +277 -0
- package/dist/chunk-TDZJ6SAI.js +34 -0
- package/dist/chunk-TEIYA7U4.js +72 -0
- package/dist/chunk-TMVS4F7E.js +88 -0
- package/dist/chunk-TRBKJ7JT.js +137 -0
- package/dist/chunk-TXGNSECL.js +84 -0
- package/dist/chunk-TZAP5T4N.js +188 -0
- package/dist/chunk-UCYQNHST.js +24 -0
- package/dist/chunk-ULF5RDDX.js +0 -0
- package/dist/chunk-UXQRU3EM.js +167 -0
- package/dist/chunk-V5K5FYU7.js +200 -0
- package/dist/chunk-VDXB5DCY.js +68 -0
- package/dist/chunk-VSGKVZB4.js +47 -0
- package/dist/chunk-VWODEQ5C.js +204 -0
- package/dist/chunk-WDUFQFDP.js +193 -0
- package/dist/chunk-WHR7HPWF.js +126 -0
- package/dist/chunk-WSQMXMTL.js +122 -0
- package/dist/chunk-XHZ5L4FO.js +103 -0
- package/dist/chunk-XPASCCUA.js +404 -0
- package/dist/chunk-XRRPEBKB.js +231 -0
- package/dist/chunk-Y2TUZFCP.js +0 -0
- package/dist/chunk-Y3OTJH2S.js +473 -0
- package/dist/chunk-YBSHN67U.js +161 -0
- package/dist/chunk-YJ3TLEW3.js +100 -0
- package/dist/chunk-YJWLWUFK.js +105 -0
- package/dist/chunk-Z4D4CMDA.js +488 -0
- package/dist/chunk-ZHVUK5OY.js +314 -0
- package/dist/chunk-ZTN4X5FN.js +29 -0
- package/dist/chunk-ZZIKRBJU.js +96 -0
- package/dist/components/ui/Alert.d.ts +12 -0
- package/dist/components/ui/Alert.js +10 -0
- package/dist/components/ui/Badge.d.ts +7 -0
- package/dist/components/ui/Badge.js +8 -0
- package/dist/components/ui/Button.d.ts +7 -0
- package/dist/components/ui/Button.js +8 -0
- package/dist/components/ui/DataTable.d.ts +103 -0
- package/dist/components/ui/DataTable.js +606 -0
- package/dist/components/ui/DomainDisplay.d.ts +12 -0
- package/dist/components/ui/DomainDisplay.js +31 -0
- package/dist/components/ui/Input.d.ts +5 -0
- package/dist/components/ui/Input.js +8 -0
- package/dist/components/ui/Label.d.ts +5 -0
- package/dist/components/ui/Label.js +8 -0
- package/dist/components/ui/Pagination.d.ts +42 -0
- package/dist/components/ui/Pagination.js +20 -0
- package/dist/components/ui/Select.d.ts +15 -0
- package/dist/components/ui/Select.js +27 -0
- package/dist/components/ui/Skeleton.d.ts +6 -0
- package/dist/components/ui/Skeleton.js +8 -0
- package/dist/components/ui/TimezoneDisplay.d.ts +22 -0
- package/dist/components/ui/TimezoneDisplay.js +83 -0
- package/dist/components/ui/Tooltip.d.ts +21 -0
- package/dist/components/ui/Tooltip.js +94 -0
- package/dist/components/ui/WorldMapChart.d.ts +17 -0
- package/dist/components/ui/WorldMapChart.js +250 -0
- package/dist/components/ui/loading-bar.d.ts +20 -0
- package/dist/components/ui/loading-bar.js +15 -0
- package/dist/constants/error-codes.d.ts +389 -0
- package/dist/constants/error-codes.js +27 -0
- package/dist/constants/index.d.ts +11 -0
- package/dist/constants/index.js +85 -0
- package/dist/constants/messages.d.ts +83 -0
- package/dist/constants/messages.js +13 -0
- package/dist/constants/pagination.d.ts +43 -0
- package/dist/constants/pagination.js +15 -0
- package/dist/constants/security.d.ts +66 -0
- package/dist/constants/security.js +23 -0
- package/dist/constants/validation.d.ts +60 -0
- package/dist/constants/validation.js +19 -0
- package/dist/error/ErrorBoundary.d.ts +47 -0
- package/dist/error/app-error.d.ts +144 -0
- package/dist/error/app-error.js +10 -0
- package/dist/error/components/EmptyState.d.ts +50 -0
- package/dist/error/components/ErrorAlert.d.ts +50 -0
- package/dist/error/components/ErrorPage.d.ts +39 -0
- package/dist/error/components/LoadingState.d.ts +37 -0
- package/dist/error/components/index.d.ts +13 -0
- package/dist/error/components/index.js +18 -0
- package/dist/error/core/locale-detector.d.ts +44 -0
- package/dist/error/core/locale-detector.js +9 -0
- package/dist/error/error-display.d.ts +55 -0
- package/dist/error/error-display.js +24 -0
- package/dist/error/error-handler.d.ts +118 -0
- package/dist/error/error-handler.js +18 -0
- package/dist/error/friendly-messages-v2.d.ts +46 -0
- package/dist/error/friendly-messages-v2.js +15 -0
- package/dist/error/friendly-messages.d.ts +22 -0
- package/dist/error/friendly-messages.js +12 -0
- package/dist/error/hooks/index.d.ts +7 -0
- package/dist/error/hooks/index.js +14 -0
- package/dist/error/hooks/useErrorHandler.d.ts +67 -0
- package/dist/error/hooks/useErrorHandler.js +14 -0
- package/dist/error/index.d.ts +26 -0
- package/dist/error/index.js +289 -0
- package/dist/error/logging/error-logger.d.ts +77 -0
- package/dist/error/logging/error-logger.js +10 -0
- package/dist/error/logging/index.d.ts +9 -0
- package/dist/error/logging/index.js +35 -0
- package/dist/error/logging/transports/base.d.ts +30 -0
- package/dist/error/logging/transports/base.js +7 -0
- package/dist/error/logging/transports/console.d.ts +40 -0
- package/dist/error/logging/transports/console.js +9 -0
- package/dist/error/logging/transports/file.d.ts +49 -0
- package/dist/error/logging/transports/file.js +8 -0
- package/dist/error/logging/transports/index.d.ts +12 -0
- package/dist/error/logging/transports/index.js +25 -0
- package/dist/error/logging/transports/sentry.d.ts +44 -0
- package/dist/error/logging/transports/sentry.js +9 -0
- package/dist/error/logging/transports/slack.d.ts +51 -0
- package/dist/error/logging/transports/slack.js +9 -0
- package/dist/error/logging/types.d.ts +83 -0
- package/dist/error/logging/types.js +7 -0
- package/dist/error/messages/en.d.ts +5 -0
- package/dist/error/messages/en.js +7 -0
- package/dist/error/messages/index.d.ts +40 -0
- package/dist/error/messages/index.js +17 -0
- package/dist/error/messages/ko.d.ts +5 -0
- package/dist/error/messages/ko.js +7 -0
- package/dist/error/messages/types.d.ts +30 -0
- package/dist/error/messages/types.js +0 -0
- package/dist/error/recovery/circuit-breaker.d.ts +85 -0
- package/dist/error/recovery/circuit-breaker.js +9 -0
- package/dist/error/recovery/degradation.d.ts +56 -0
- package/dist/error/recovery/degradation.js +7 -0
- package/dist/error/recovery/fallback.d.ts +55 -0
- package/dist/error/recovery/fallback.js +11 -0
- package/dist/error/recovery/index.d.ts +12 -0
- package/dist/error/recovery/index.js +26 -0
- package/dist/error/recovery/retry.d.ts +44 -0
- package/dist/error/recovery/retry.js +7 -0
- package/dist/geolocation/batch-processor.d.ts +33 -0
- package/dist/geolocation/batch-processor.js +10 -0
- package/dist/geolocation/index.d.ts +14 -0
- package/dist/geolocation/index.js +36 -0
- package/dist/geolocation/providers/base-provider.d.ts +33 -0
- package/dist/geolocation/providers/base-provider.js +9 -0
- package/dist/geolocation/providers/index.d.ts +54 -0
- package/dist/geolocation/providers/index.js +29 -0
- package/dist/geolocation/providers/ip-api-provider.d.ts +17 -0
- package/dist/geolocation/providers/ip-api-provider.js +8 -0
- package/dist/geolocation/providers/ipapi-co-provider.d.ts +17 -0
- package/dist/geolocation/providers/ipapi-co-provider.js +8 -0
- package/dist/geolocation/providers/ipgeolocation-provider.d.ts +18 -0
- package/dist/geolocation/providers/ipgeolocation-provider.js +8 -0
- package/dist/geolocation/providers/maxmind-provider.d.ts +18 -0
- package/dist/geolocation/providers/maxmind-provider.js +8 -0
- package/dist/hooks/useDataTable.d.ts +51 -0
- package/dist/hooks/useDataTable.js +149 -0
- package/dist/hooks/useDebounce.d.ts +7 -0
- package/dist/hooks/useDebounce.js +7 -0
- package/dist/hooks/useExitIntent.d.ts +35 -0
- package/dist/hooks/useExitIntent.js +72 -0
- package/dist/hooks/useTimezone.d.ts +19 -0
- package/dist/hooks/useTimezone.js +11 -0
- package/dist/logger/logger.d.ts +11 -0
- package/dist/logger/logger.js +17 -0
- package/dist/middleware/auth.d.ts +87 -0
- package/dist/middleware/auth.js +20 -0
- package/dist/middleware/cors.d.ts +30 -0
- package/dist/middleware/cors.js +10 -0
- package/dist/middleware/error-handler.d.ts +23 -0
- package/dist/middleware/error-handler.js +13 -0
- package/dist/middleware/index.d.ts +16 -0
- package/dist/middleware/index.js +72 -0
- package/dist/middleware/init-request.d.ts +18 -0
- package/dist/middleware/init-request.js +8 -0
- package/dist/middleware/middleware-chain.d.ts +53 -0
- package/dist/middleware/middleware-chain.js +8 -0
- package/dist/middleware/rate-limit.d.ts +82 -0
- package/dist/middleware/rate-limit.js +14 -0
- package/dist/middleware/response-logger.d.ts +22 -0
- package/dist/middleware/response-logger.js +8 -0
- package/dist/middleware/security.d.ts +31 -0
- package/dist/middleware/security.js +9 -0
- package/dist/middleware/types.d.ts +45 -0
- package/dist/middleware/types.js +0 -0
- package/dist/middleware/wrappers.d.ts +91 -0
- package/dist/middleware/wrappers.js +32 -0
- package/dist/storage/r2-storage.d.ts +38 -0
- package/dist/storage/r2-storage.js +105 -0
- package/dist/system/cpu.d.ts +2 -0
- package/dist/system/cpu.js +9 -0
- package/dist/system/disk.d.ts +2 -0
- package/dist/system/disk.js +9 -0
- package/dist/system/environment.d.ts +8 -0
- package/dist/system/environment.js +9 -0
- package/dist/system/health-check.d.ts +26 -0
- package/dist/system/health-check.js +10 -0
- package/dist/system/index.d.ts +51 -0
- package/dist/system/index.js +194 -0
- package/dist/system/memory.d.ts +2 -0
- package/dist/system/memory.js +9 -0
- package/dist/system/network.d.ts +2 -0
- package/dist/system/network.js +9 -0
- package/dist/system/types.d.ts +93 -0
- package/dist/system/types.js +0 -0
- package/dist/system/utils.d.ts +12 -0
- package/dist/system/utils.js +26 -0
- package/dist/types/api.d.ts +80 -0
- package/dist/types/api.js +0 -0
- package/dist/types/database.d.ts +38 -0
- package/dist/types/database.js +0 -0
- package/dist/types/env.d.ts +105 -0
- package/dist/types/env.js +0 -0
- package/dist/types/geoip.d.ts +152 -0
- package/dist/types/geoip.js +0 -0
- package/dist/types/i18n.d.ts +11 -0
- package/dist/types/i18n.js +0 -0
- package/dist/types/qr-code.d.ts +139 -0
- package/dist/types/qr-code.js +75 -0
- package/dist/types/user.d.ts +54 -0
- package/dist/types/user.js +0 -0
- package/dist/utils/api-helpers.d.ts +147 -0
- package/dist/utils/api-helpers.js +30 -0
- package/dist/utils/client/client-utils.d.ts +3 -0
- package/dist/utils/client/client-utils.js +9 -0
- package/dist/utils/client/qr-code.d.ts +16 -0
- package/dist/utils/client/qr-code.js +215 -0
- package/dist/utils/cors.d.ts +40 -0
- package/dist/utils/cors.js +21 -0
- package/dist/utils/csv-export.d.ts +97 -0
- package/dist/utils/csv-export.js +20 -0
- package/dist/utils/error-message-formatter.d.ts +17 -0
- package/dist/utils/error-message-formatter.js +11 -0
- package/dist/utils/error-processor.d.ts +70 -0
- package/dist/utils/error-processor.js +34 -0
- package/dist/utils/format-number.d.ts +17 -0
- package/dist/utils/format-number.js +9 -0
- package/dist/utils/index.d.ts +13 -0
- package/dist/utils/index.js +160 -0
- package/dist/utils/input-validation.d.ts +88 -0
- package/dist/utils/input-validation.js +223 -0
- package/dist/utils/ip-utils.d.ts +15 -0
- package/dist/utils/ip-utils.js +91 -0
- package/dist/utils/optimistic-lock.d.ts +27 -0
- package/dist/utils/optimistic-lock.js +16 -0
- package/dist/utils/sanitizer.d.ts +72 -0
- package/dist/utils/sanitizer.js +19 -0
- package/dist/utils/shared-utils.d.ts +25 -0
- package/dist/utils/shared-utils.js +43 -0
- package/dist/utils/short-code-generator.d.ts +24 -0
- package/dist/utils/short-code-generator.js +9 -0
- package/dist/utils/timezone.d.ts +56 -0
- package/dist/utils/timezone.js +29 -0
- package/dist/utils/type-guards.d.ts +164 -0
- package/dist/utils/type-guards.js +59 -0
- package/dist/utils/url-normalizer.d.ts +53 -0
- package/dist/utils/url-normalizer.js +21 -0
- package/dist/validators/index.d.ts +7 -0
- package/dist/validators/index.js +13 -0
- package/dist/validators/password-validator.d.ts +86 -0
- package/dist/validators/password-validator.js +13 -0
- package/dist/world_countries-C2WUL2CQ.js +279 -0
- package/package.json +129 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ErrorProcessor - 중앙 집중식 에러 처리
|
|
3
|
+
*
|
|
4
|
+
* API 라우트와 미들웨어에서 발생하는 모든 에러를 일관되게 처리합니다.
|
|
5
|
+
* 5자리 HTTP 확장 에러 코드 체계를 사용합니다.
|
|
6
|
+
*/
|
|
7
|
+
import { NextRequest, NextResponse } from 'next/server';
|
|
8
|
+
import type { ISerializedError } from '@withwiz/error/app-error';
|
|
9
|
+
export type ProcessedError = ISerializedError;
|
|
10
|
+
/**
|
|
11
|
+
* 에러 핸들링 옵션
|
|
12
|
+
*/
|
|
13
|
+
export interface IErrorHandlerOptions {
|
|
14
|
+
/** 커스텀 에러 핸들러 함수 */
|
|
15
|
+
customErrorHandler?: (error: unknown, request: NextRequest) => NextResponse;
|
|
16
|
+
/** 커스텀 응답 보존 여부 (기본값: false) */
|
|
17
|
+
preserveCustomResponses?: boolean;
|
|
18
|
+
/** 에러 로깅 레벨 (기본값: 'error') */
|
|
19
|
+
logLevel?: 'debug' | 'info' | 'warn' | 'error';
|
|
20
|
+
/** 민감한 정보 마스킹 여부 (기본값: true) */
|
|
21
|
+
maskSensitiveInfo?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 중앙 에러 처리기
|
|
25
|
+
*/
|
|
26
|
+
export declare class ErrorProcessor {
|
|
27
|
+
/**
|
|
28
|
+
* 에러를 처리하여 표준화된 응답으로 변환
|
|
29
|
+
*/
|
|
30
|
+
static process(error: unknown): ProcessedError;
|
|
31
|
+
/**
|
|
32
|
+
* Zod 검증 에러 처리
|
|
33
|
+
*/
|
|
34
|
+
private static handleZodError;
|
|
35
|
+
/**
|
|
36
|
+
* Prisma 에러 추출 및 처리
|
|
37
|
+
*/
|
|
38
|
+
private static extractPrismaError;
|
|
39
|
+
/**
|
|
40
|
+
* 에러를 NextResponse로 변환
|
|
41
|
+
*/
|
|
42
|
+
static toResponse(error: unknown, requestPath?: string): NextResponse;
|
|
43
|
+
/**
|
|
44
|
+
* 에러 핸들러 래퍼 함수 (간단한 버전)
|
|
45
|
+
* try-catch 블록을 대체하여 사용
|
|
46
|
+
*/
|
|
47
|
+
static withErrorHandling<T extends (...args: unknown[]) => Promise<NextResponse>>(handler: T): T;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 에러 핸들링 미들웨어 (고급 버전)
|
|
51
|
+
* 로깅, 민감 정보 마스킹 등 추가 기능 제공
|
|
52
|
+
*/
|
|
53
|
+
export declare function withErrorHandling<T extends unknown[], TRequest extends NextRequest = NextRequest>(handler: (request: TRequest, ...args: T) => Promise<NextResponse>, options?: IErrorHandlerOptions): (request: TRequest, ...args: T) => Promise<NextResponse>;
|
|
54
|
+
/**
|
|
55
|
+
* Prisma 에러 처리 헬퍼
|
|
56
|
+
*/
|
|
57
|
+
export declare function handlePrismaError(error: unknown): NextResponse;
|
|
58
|
+
/**
|
|
59
|
+
* 비즈니스 로직 에러를 위한 헬퍼들
|
|
60
|
+
*/
|
|
61
|
+
export declare function throwBusinessRuleError(message?: string, code?: number): never;
|
|
62
|
+
export declare function throwNotFoundError(message?: string, code?: number): never;
|
|
63
|
+
export declare function throwConflictError(message?: string, code?: number): never;
|
|
64
|
+
export declare function throwForbiddenError(message?: string, code?: number): never;
|
|
65
|
+
export declare function throwUnauthorizedError(message?: string, code?: number): never;
|
|
66
|
+
export declare function throwValidationError(message?: string, code?: number): never;
|
|
67
|
+
export declare function throwBadRequestError(message?: string, code?: number): never;
|
|
68
|
+
export declare const processError: typeof ErrorProcessor.process;
|
|
69
|
+
export declare const errorToResponse: typeof ErrorProcessor.toResponse;
|
|
70
|
+
export default ErrorProcessor;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ErrorProcessor,
|
|
3
|
+
errorToResponse,
|
|
4
|
+
error_processor_default,
|
|
5
|
+
handlePrismaError,
|
|
6
|
+
processError,
|
|
7
|
+
throwBadRequestError,
|
|
8
|
+
throwBusinessRuleError,
|
|
9
|
+
throwConflictError,
|
|
10
|
+
throwForbiddenError,
|
|
11
|
+
throwNotFoundError,
|
|
12
|
+
throwUnauthorizedError,
|
|
13
|
+
throwValidationError,
|
|
14
|
+
withErrorHandling
|
|
15
|
+
} from "../chunk-XPASCCUA.js";
|
|
16
|
+
import "../chunk-MLGO3HLS.js";
|
|
17
|
+
import "../chunk-Y3OTJH2S.js";
|
|
18
|
+
import "../chunk-EZR55KV2.js";
|
|
19
|
+
import "../chunk-ORMEWXMH.js";
|
|
20
|
+
export {
|
|
21
|
+
ErrorProcessor,
|
|
22
|
+
error_processor_default as default,
|
|
23
|
+
errorToResponse,
|
|
24
|
+
handlePrismaError,
|
|
25
|
+
processError,
|
|
26
|
+
throwBadRequestError,
|
|
27
|
+
throwBusinessRuleError,
|
|
28
|
+
throwConflictError,
|
|
29
|
+
throwForbiddenError,
|
|
30
|
+
throwNotFoundError,
|
|
31
|
+
throwUnauthorizedError,
|
|
32
|
+
throwValidationError,
|
|
33
|
+
withErrorHandling
|
|
34
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 숫자를 포맷팅하여 표시합니다.
|
|
3
|
+
* - 999,999 이하: 그대로 표시 (예: 999,999)
|
|
4
|
+
* - 1,000,000 ~ 9,999,999: 그대로 표시 (예: 1,234,567)
|
|
5
|
+
* - 10,000,000 이상: 줄여서 표시 (예: 10.5M)
|
|
6
|
+
*
|
|
7
|
+
* @param num - 포맷팅할 숫자
|
|
8
|
+
* @returns 포맷팅된 문자열
|
|
9
|
+
*/
|
|
10
|
+
export declare function formatNumber(num: number | string | null | undefined): string;
|
|
11
|
+
/**
|
|
12
|
+
* 차트용 숫자 포맷팅 함수
|
|
13
|
+
*
|
|
14
|
+
* @param num - 포맷팅할 숫자
|
|
15
|
+
* @returns 포맷팅된 문자열
|
|
16
|
+
*/
|
|
17
|
+
export declare function formatChartNumber(num: number | null | undefined): string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @withwiz/utils
|
|
3
|
+
*
|
|
4
|
+
* 범용 유틸리티 모듈
|
|
5
|
+
* 프로젝트 독립적인 재사용 가능한 유틸리티 함수들
|
|
6
|
+
*/
|
|
7
|
+
export * from './sanitizer';
|
|
8
|
+
export { ErrorProcessor, withErrorHandling, handlePrismaError, throwBusinessRuleError, throwNotFoundError, throwConflictError, throwForbiddenError, throwUnauthorizedError, throwValidationError, throwBadRequestError, processError, errorToResponse, } from './error-processor';
|
|
9
|
+
export type { IErrorHandlerOptions, ProcessedError } from './error-processor';
|
|
10
|
+
export * from './csv-export';
|
|
11
|
+
export * from './cors';
|
|
12
|
+
export * from './api-helpers';
|
|
13
|
+
export * from './type-guards';
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import {
|
|
2
|
+
removeEventHandlers,
|
|
3
|
+
sanitizeArray,
|
|
4
|
+
sanitizeHtml,
|
|
5
|
+
sanitizeInput,
|
|
6
|
+
sanitizeObjectFields,
|
|
7
|
+
sanitizeUrl
|
|
8
|
+
} from "../chunk-SR65BF6X.js";
|
|
9
|
+
import {
|
|
10
|
+
isApiErrorResponse,
|
|
11
|
+
isApiSuccessResponse,
|
|
12
|
+
isArray,
|
|
13
|
+
isBoolean,
|
|
14
|
+
isDateParseable,
|
|
15
|
+
isDefined,
|
|
16
|
+
isEmpty,
|
|
17
|
+
isEmptyArray,
|
|
18
|
+
isEmptyObject,
|
|
19
|
+
isEmptyString,
|
|
20
|
+
isFunction,
|
|
21
|
+
isIPAddress,
|
|
22
|
+
isIPv4,
|
|
23
|
+
isIPv6,
|
|
24
|
+
isISODateString,
|
|
25
|
+
isJSONSerializable,
|
|
26
|
+
isNotNull,
|
|
27
|
+
isNumber,
|
|
28
|
+
isObject,
|
|
29
|
+
isPresent,
|
|
30
|
+
isSortOrder,
|
|
31
|
+
isString,
|
|
32
|
+
isValidDate,
|
|
33
|
+
isValidEmail,
|
|
34
|
+
isValidJSON,
|
|
35
|
+
isValidUrl
|
|
36
|
+
} from "../chunk-EUQATJLI.js";
|
|
37
|
+
import {
|
|
38
|
+
getAllowedOrigins,
|
|
39
|
+
getCorsConfig,
|
|
40
|
+
initCorsConfig,
|
|
41
|
+
isOriginAllowed,
|
|
42
|
+
setCorsHeaders,
|
|
43
|
+
withCORS,
|
|
44
|
+
withPublicCORS,
|
|
45
|
+
withRestrictedCORS
|
|
46
|
+
} from "../chunk-GCZOXUDV.js";
|
|
47
|
+
import {
|
|
48
|
+
boolFormatter,
|
|
49
|
+
createCsvHeader,
|
|
50
|
+
createSimpleCsvResponse,
|
|
51
|
+
createStreamingCsvResponse,
|
|
52
|
+
dateFormatter,
|
|
53
|
+
escapeCsvField,
|
|
54
|
+
rowToCsv
|
|
55
|
+
} from "../chunk-BKGVSC6S.js";
|
|
56
|
+
import {
|
|
57
|
+
ErrorProcessor,
|
|
58
|
+
errorToResponse,
|
|
59
|
+
handlePrismaError,
|
|
60
|
+
processError,
|
|
61
|
+
throwBadRequestError,
|
|
62
|
+
throwBusinessRuleError,
|
|
63
|
+
throwConflictError,
|
|
64
|
+
throwForbiddenError,
|
|
65
|
+
throwNotFoundError,
|
|
66
|
+
throwUnauthorizedError,
|
|
67
|
+
throwValidationError,
|
|
68
|
+
withErrorHandling
|
|
69
|
+
} from "../chunk-XPASCCUA.js";
|
|
70
|
+
import {
|
|
71
|
+
createPaginatedResponse,
|
|
72
|
+
getReferer,
|
|
73
|
+
getSearchParam,
|
|
74
|
+
getUserAgent,
|
|
75
|
+
parseBooleanParam,
|
|
76
|
+
parseFilters,
|
|
77
|
+
parseNumberParam,
|
|
78
|
+
parsePagination,
|
|
79
|
+
parseRequestBody,
|
|
80
|
+
parseSort,
|
|
81
|
+
requireAdmin,
|
|
82
|
+
validateAndParse
|
|
83
|
+
} from "../chunk-2KAPUVIS.js";
|
|
84
|
+
import "../chunk-MLGO3HLS.js";
|
|
85
|
+
import "../chunk-Y3OTJH2S.js";
|
|
86
|
+
import "../chunk-EZR55KV2.js";
|
|
87
|
+
import "../chunk-ORMEWXMH.js";
|
|
88
|
+
export {
|
|
89
|
+
ErrorProcessor,
|
|
90
|
+
boolFormatter,
|
|
91
|
+
createCsvHeader,
|
|
92
|
+
createPaginatedResponse,
|
|
93
|
+
createSimpleCsvResponse,
|
|
94
|
+
createStreamingCsvResponse,
|
|
95
|
+
dateFormatter,
|
|
96
|
+
errorToResponse,
|
|
97
|
+
escapeCsvField,
|
|
98
|
+
getAllowedOrigins,
|
|
99
|
+
getCorsConfig,
|
|
100
|
+
getReferer,
|
|
101
|
+
getSearchParam,
|
|
102
|
+
getUserAgent,
|
|
103
|
+
handlePrismaError,
|
|
104
|
+
initCorsConfig,
|
|
105
|
+
isApiErrorResponse,
|
|
106
|
+
isApiSuccessResponse,
|
|
107
|
+
isArray,
|
|
108
|
+
isBoolean,
|
|
109
|
+
isDateParseable,
|
|
110
|
+
isDefined,
|
|
111
|
+
isEmpty,
|
|
112
|
+
isEmptyArray,
|
|
113
|
+
isEmptyObject,
|
|
114
|
+
isEmptyString,
|
|
115
|
+
isFunction,
|
|
116
|
+
isIPAddress,
|
|
117
|
+
isIPv4,
|
|
118
|
+
isIPv6,
|
|
119
|
+
isISODateString,
|
|
120
|
+
isJSONSerializable,
|
|
121
|
+
isNotNull,
|
|
122
|
+
isNumber,
|
|
123
|
+
isObject,
|
|
124
|
+
isOriginAllowed,
|
|
125
|
+
isPresent,
|
|
126
|
+
isSortOrder,
|
|
127
|
+
isString,
|
|
128
|
+
isValidDate,
|
|
129
|
+
isValidEmail,
|
|
130
|
+
isValidJSON,
|
|
131
|
+
isValidUrl,
|
|
132
|
+
parseBooleanParam,
|
|
133
|
+
parseFilters,
|
|
134
|
+
parseNumberParam,
|
|
135
|
+
parsePagination,
|
|
136
|
+
parseRequestBody,
|
|
137
|
+
parseSort,
|
|
138
|
+
processError,
|
|
139
|
+
removeEventHandlers,
|
|
140
|
+
requireAdmin,
|
|
141
|
+
rowToCsv,
|
|
142
|
+
sanitizeArray,
|
|
143
|
+
sanitizeHtml,
|
|
144
|
+
sanitizeInput,
|
|
145
|
+
sanitizeObjectFields,
|
|
146
|
+
sanitizeUrl,
|
|
147
|
+
setCorsHeaders,
|
|
148
|
+
throwBadRequestError,
|
|
149
|
+
throwBusinessRuleError,
|
|
150
|
+
throwConflictError,
|
|
151
|
+
throwForbiddenError,
|
|
152
|
+
throwNotFoundError,
|
|
153
|
+
throwUnauthorizedError,
|
|
154
|
+
throwValidationError,
|
|
155
|
+
validateAndParse,
|
|
156
|
+
withCORS,
|
|
157
|
+
withErrorHandling,
|
|
158
|
+
withPublicCORS,
|
|
159
|
+
withRestrictedCORS
|
|
160
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 입력 검증 유틸리티
|
|
3
|
+
*
|
|
4
|
+
* XSS, SQL Injection, Path Traversal 등 보안 위협을 방어합니다.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* URL 검증 옵션
|
|
8
|
+
*/
|
|
9
|
+
export interface URLValidationOptions {
|
|
10
|
+
allowedSchemes?: string[];
|
|
11
|
+
maxLength?: number;
|
|
12
|
+
requireProtocol?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* URL 안전성 검증
|
|
16
|
+
*
|
|
17
|
+
* @param url - 검증할 URL
|
|
18
|
+
* @param options - 검증 옵션
|
|
19
|
+
* @returns 검증 결과 { valid: boolean, error?: string, sanitized?: string }
|
|
20
|
+
*/
|
|
21
|
+
export declare function validateURL(url: string, options?: URLValidationOptions): {
|
|
22
|
+
valid: boolean;
|
|
23
|
+
error?: string;
|
|
24
|
+
sanitized?: string;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* XSS 방지: HTML 특수 문자 이스케이프
|
|
28
|
+
*
|
|
29
|
+
* @param input - 이스케이프할 문자열
|
|
30
|
+
* @returns 이스케이프된 문자열
|
|
31
|
+
*/
|
|
32
|
+
export declare function escapeHTML(input: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* XSS 패턴 탐지
|
|
35
|
+
*
|
|
36
|
+
* @param input - 검증할 문자열
|
|
37
|
+
* @returns XSS 패턴 발견 시 true
|
|
38
|
+
*/
|
|
39
|
+
export declare function detectXSS(input: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Path Traversal 공격 탐지
|
|
42
|
+
*
|
|
43
|
+
* @param input - 검증할 경로
|
|
44
|
+
* @returns Path Traversal 패턴 발견 시 true
|
|
45
|
+
*/
|
|
46
|
+
export declare function detectPathTraversal(input: string): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* SQL Injection 패턴 탐지
|
|
49
|
+
*
|
|
50
|
+
* @param input - 검증할 문자열
|
|
51
|
+
* @returns SQL Injection 패턴 발견 시 true
|
|
52
|
+
*/
|
|
53
|
+
export declare function detectSQLInjection(input: string): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* 입력 문자열 정제
|
|
56
|
+
*
|
|
57
|
+
* @param input - 정제할 문자열
|
|
58
|
+
* @param options - 정제 옵션
|
|
59
|
+
* @returns 정제된 문자열
|
|
60
|
+
*/
|
|
61
|
+
export declare function sanitizeInput(input: string, options?: {
|
|
62
|
+
maxLength?: number;
|
|
63
|
+
allowHTML?: boolean;
|
|
64
|
+
trim?: boolean;
|
|
65
|
+
}): string;
|
|
66
|
+
/**
|
|
67
|
+
* 파일 이름 검증
|
|
68
|
+
*
|
|
69
|
+
* @param filename - 검증할 파일 이름
|
|
70
|
+
* @returns 검증 결과
|
|
71
|
+
*/
|
|
72
|
+
export declare function validateFilename(filename: string): {
|
|
73
|
+
valid: boolean;
|
|
74
|
+
error?: string;
|
|
75
|
+
sanitized?: string;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* 종합 입력 검증
|
|
79
|
+
*
|
|
80
|
+
* @param input - 검증할 입력
|
|
81
|
+
* @param type - 입력 타입
|
|
82
|
+
* @returns 검증 결과
|
|
83
|
+
*/
|
|
84
|
+
export declare function validateInput(input: string, type: 'text' | 'url' | 'filename' | 'html'): {
|
|
85
|
+
valid: boolean;
|
|
86
|
+
error?: string;
|
|
87
|
+
sanitized?: string;
|
|
88
|
+
};
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import "../chunk-ORMEWXMH.js";
|
|
2
|
+
|
|
3
|
+
// src/utils/input-validation.ts
|
|
4
|
+
var DANGEROUS_URL_SCHEMES = [
|
|
5
|
+
"javascript:",
|
|
6
|
+
"data:",
|
|
7
|
+
"file:",
|
|
8
|
+
"vbscript:",
|
|
9
|
+
"about:",
|
|
10
|
+
"chrome:",
|
|
11
|
+
"chrome-extension:",
|
|
12
|
+
"moz-extension:",
|
|
13
|
+
"ms-its:",
|
|
14
|
+
"ms-itss:",
|
|
15
|
+
"its:",
|
|
16
|
+
"mk:",
|
|
17
|
+
"view-source:"
|
|
18
|
+
];
|
|
19
|
+
var ALLOWED_URL_SCHEMES = [
|
|
20
|
+
"http:",
|
|
21
|
+
"https:",
|
|
22
|
+
"ftp:",
|
|
23
|
+
"ftps:",
|
|
24
|
+
"mailto:",
|
|
25
|
+
"tel:",
|
|
26
|
+
"sms:"
|
|
27
|
+
];
|
|
28
|
+
function validateURL(url, options = {}) {
|
|
29
|
+
const {
|
|
30
|
+
allowedSchemes = ALLOWED_URL_SCHEMES,
|
|
31
|
+
maxLength = 2048,
|
|
32
|
+
requireProtocol = true
|
|
33
|
+
} = options;
|
|
34
|
+
if (!url || typeof url !== "string") {
|
|
35
|
+
return { valid: false, error: "URL is required" };
|
|
36
|
+
}
|
|
37
|
+
if (url.length > maxLength) {
|
|
38
|
+
return { valid: false, error: `URL exceeds maximum length of ${maxLength}` };
|
|
39
|
+
}
|
|
40
|
+
const trimmedUrl = url.trim();
|
|
41
|
+
const hasProtocol = /^[a-z][a-z0-9+.-]*:/i.test(trimmedUrl);
|
|
42
|
+
if (requireProtocol && !hasProtocol) {
|
|
43
|
+
return { valid: false, error: "URL must include a protocol (http:// or https://)" };
|
|
44
|
+
}
|
|
45
|
+
const urlLower = trimmedUrl.toLowerCase();
|
|
46
|
+
for (const scheme of DANGEROUS_URL_SCHEMES) {
|
|
47
|
+
if (urlLower.startsWith(scheme)) {
|
|
48
|
+
return { valid: false, error: `Dangerous URL scheme detected: ${scheme}` };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (hasProtocol) {
|
|
52
|
+
const scheme = trimmedUrl.split(":")[0].toLowerCase() + ":";
|
|
53
|
+
if (!allowedSchemes.includes(scheme)) {
|
|
54
|
+
return { valid: false, error: `URL scheme not allowed: ${scheme}` };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const urlToParse = hasProtocol ? trimmedUrl : `https://${trimmedUrl}`;
|
|
59
|
+
const parsed = new URL(urlToParse);
|
|
60
|
+
if (parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1") {
|
|
61
|
+
if (process.env.NODE_ENV === "production") {
|
|
62
|
+
return { valid: false, error: "Internal URLs are not allowed" };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
valid: true,
|
|
67
|
+
sanitized: parsed.toString()
|
|
68
|
+
};
|
|
69
|
+
} catch (error) {
|
|
70
|
+
return { valid: false, error: "Invalid URL format" };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function escapeHTML(input) {
|
|
74
|
+
if (typeof input !== "string") {
|
|
75
|
+
return "";
|
|
76
|
+
}
|
|
77
|
+
return input.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'").replace(/\//g, "/");
|
|
78
|
+
}
|
|
79
|
+
function detectXSS(input) {
|
|
80
|
+
if (typeof input !== "string") {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
const xssPatterns = [
|
|
84
|
+
/<script[^>]*>.*?<\/script>/gi,
|
|
85
|
+
/javascript:/gi,
|
|
86
|
+
/on\w+\s*=/gi,
|
|
87
|
+
// onclick=, onerror= 등
|
|
88
|
+
/<iframe/gi,
|
|
89
|
+
/<object/gi,
|
|
90
|
+
/<embed/gi,
|
|
91
|
+
/<applet/gi,
|
|
92
|
+
/<meta/gi,
|
|
93
|
+
/<link/gi,
|
|
94
|
+
/<style/gi,
|
|
95
|
+
/eval\s*\(/gi,
|
|
96
|
+
/expression\s*\(/gi,
|
|
97
|
+
/vbscript:/gi,
|
|
98
|
+
/data:text\/html/gi
|
|
99
|
+
];
|
|
100
|
+
return xssPatterns.some((pattern) => pattern.test(input));
|
|
101
|
+
}
|
|
102
|
+
function detectPathTraversal(input) {
|
|
103
|
+
if (typeof input !== "string") {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
const traversalPatterns = [
|
|
107
|
+
/\.\./g,
|
|
108
|
+
// ../
|
|
109
|
+
/\.\\/g,
|
|
110
|
+
// .\
|
|
111
|
+
/%2e%2e/gi,
|
|
112
|
+
// URL 인코딩된 ..
|
|
113
|
+
/%252e/gi,
|
|
114
|
+
// 이중 URL 인코딩
|
|
115
|
+
/\\/g,
|
|
116
|
+
// 백슬래시
|
|
117
|
+
/\/\//g
|
|
118
|
+
// 이중 슬래시
|
|
119
|
+
];
|
|
120
|
+
return traversalPatterns.some((pattern) => pattern.test(input));
|
|
121
|
+
}
|
|
122
|
+
function detectSQLInjection(input) {
|
|
123
|
+
if (typeof input !== "string") {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
const sqlPatterns = [
|
|
127
|
+
/(\b(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC|EXECUTE|UNION|DECLARE)\b)/gi,
|
|
128
|
+
/--/g,
|
|
129
|
+
// SQL 주석
|
|
130
|
+
/\/\*/g,
|
|
131
|
+
// SQL 블록 주석
|
|
132
|
+
/;.*?/g,
|
|
133
|
+
// 세미콜론 (쿼리 구분)
|
|
134
|
+
/'\s*(OR|AND)\s*'?\d/gi,
|
|
135
|
+
// ' OR 1=1
|
|
136
|
+
/\bxp_\w+/gi,
|
|
137
|
+
// SQL Server 확장 프로시저
|
|
138
|
+
/\bsp_\w+/gi
|
|
139
|
+
// SQL Server 저장 프로시저
|
|
140
|
+
];
|
|
141
|
+
return sqlPatterns.some((pattern) => pattern.test(input));
|
|
142
|
+
}
|
|
143
|
+
function sanitizeInput(input, options = {}) {
|
|
144
|
+
const { maxLength = 1e4, allowHTML = false, trim = true } = options;
|
|
145
|
+
if (typeof input !== "string") {
|
|
146
|
+
return "";
|
|
147
|
+
}
|
|
148
|
+
let sanitized = input;
|
|
149
|
+
if (trim) {
|
|
150
|
+
sanitized = sanitized.trim();
|
|
151
|
+
}
|
|
152
|
+
if (sanitized.length > maxLength) {
|
|
153
|
+
sanitized = sanitized.substring(0, maxLength);
|
|
154
|
+
}
|
|
155
|
+
if (!allowHTML) {
|
|
156
|
+
sanitized = escapeHTML(sanitized);
|
|
157
|
+
}
|
|
158
|
+
sanitized = sanitized.replace(/\0/g, "");
|
|
159
|
+
sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
|
|
160
|
+
return sanitized;
|
|
161
|
+
}
|
|
162
|
+
function validateFilename(filename) {
|
|
163
|
+
if (!filename || typeof filename !== "string") {
|
|
164
|
+
return { valid: false, error: "Filename is required" };
|
|
165
|
+
}
|
|
166
|
+
if (detectPathTraversal(filename)) {
|
|
167
|
+
return { valid: false, error: "Path traversal detected in filename" };
|
|
168
|
+
}
|
|
169
|
+
const dangerousExtensions = [
|
|
170
|
+
".exe",
|
|
171
|
+
".bat",
|
|
172
|
+
".cmd",
|
|
173
|
+
".com",
|
|
174
|
+
".pif",
|
|
175
|
+
".scr",
|
|
176
|
+
".vbs",
|
|
177
|
+
".js",
|
|
178
|
+
".sh",
|
|
179
|
+
".php",
|
|
180
|
+
".asp",
|
|
181
|
+
".aspx",
|
|
182
|
+
".jsp"
|
|
183
|
+
];
|
|
184
|
+
const ext = filename.toLowerCase().substring(filename.lastIndexOf("."));
|
|
185
|
+
if (dangerousExtensions.includes(ext)) {
|
|
186
|
+
return { valid: false, error: `Dangerous file extension: ${ext}` };
|
|
187
|
+
}
|
|
188
|
+
const sanitized = filename.replace(/[^a-zA-Z0-9._-]/g, "_").replace(/\.{2,}/g, ".").substring(0, 255);
|
|
189
|
+
return { valid: true, sanitized };
|
|
190
|
+
}
|
|
191
|
+
function validateInput(input, type) {
|
|
192
|
+
switch (type) {
|
|
193
|
+
case "url":
|
|
194
|
+
return validateURL(input);
|
|
195
|
+
case "filename":
|
|
196
|
+
return validateFilename(input);
|
|
197
|
+
case "text":
|
|
198
|
+
if (detectXSS(input)) {
|
|
199
|
+
return { valid: false, error: "XSS pattern detected" };
|
|
200
|
+
}
|
|
201
|
+
if (detectSQLInjection(input)) {
|
|
202
|
+
return { valid: false, error: "SQL Injection pattern detected" };
|
|
203
|
+
}
|
|
204
|
+
return { valid: true, sanitized: sanitizeInput(input) };
|
|
205
|
+
case "html":
|
|
206
|
+
if (detectXSS(input)) {
|
|
207
|
+
return { valid: false, error: "Dangerous HTML pattern detected" };
|
|
208
|
+
}
|
|
209
|
+
return { valid: true, sanitized: input };
|
|
210
|
+
default:
|
|
211
|
+
return { valid: false, error: "Unknown input type" };
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
export {
|
|
215
|
+
detectPathTraversal,
|
|
216
|
+
detectSQLInjection,
|
|
217
|
+
detectXSS,
|
|
218
|
+
escapeHTML,
|
|
219
|
+
sanitizeInput,
|
|
220
|
+
validateFilename,
|
|
221
|
+
validateInput,
|
|
222
|
+
validateURL
|
|
223
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare function isPrivateIP(ip: string): boolean;
|
|
2
|
+
export declare function isIPv6(ip: string): boolean;
|
|
3
|
+
export declare function normalizeIP(ip: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* 클라이언트 IP 주소 추출 (서버에서만 사용)
|
|
6
|
+
*
|
|
7
|
+
* Cloudflare 환경 최적화:
|
|
8
|
+
* 1. CF-Connecting-IP: Cloudflare가 설정하는 실제 클라이언트 IP (가장 신뢰)
|
|
9
|
+
* 2. True-Client-IP: Cloudflare Enterprise에서 사용
|
|
10
|
+
* 3. X-Real-IP: Nginx 등 신뢰할 수 있는 리버스 프록시
|
|
11
|
+
* 4. X-Forwarded-For: 첫 번째 IP가 실제 클라이언트 (Cloudflare가 추가)
|
|
12
|
+
* 5. X-Client-IP: 일부 프록시에서 사용
|
|
13
|
+
*/
|
|
14
|
+
export declare function extractClientIp(headers: Headers): string | null;
|
|
15
|
+
export declare function isValidIP(ip: string): boolean;
|