@withwiz/toolkit 0.3.1 → 0.3.2
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/dist/auth/core/jwt/index.js +1 -1
- package/dist/auth/index.js +4 -4
- package/dist/{chunk-BDY3AOX5.js → chunk-A6V6XVPZ.js} +1 -1
- package/dist/{chunk-JR7GVCQX.js → chunk-BKJPYZYO.js} +10 -7
- package/dist/{chunk-SR65BF6X.js → chunk-N54KGJPU.js} +9 -1
- package/dist/{chunk-LD7POV6B.js → chunk-NQS7UT6X.js} +2 -2
- package/dist/{chunk-2ATBAIRL.js → chunk-R6YVUU6I.js} +1 -1
- package/dist/constants/index.js +24 -24
- package/dist/error/error-display.js +2 -2
- package/dist/error/index.js +10 -10
- package/dist/middleware/auth.js +2 -2
- package/dist/middleware/error-handler.js +2 -2
- package/dist/middleware/index.js +5 -5
- package/dist/middleware/wrappers.js +5 -5
- package/dist/utils/index.js +1 -1
- package/dist/utils/ip-utils.d.ts +9 -6
- package/dist/utils/ip-utils.js +3 -6
- package/dist/utils/sanitizer.d.ts +5 -4
- package/dist/utils/sanitizer.js +1 -1
- package/dist/utils/short-code-generator.d.ts +2 -1
- package/dist/utils/short-code-generator.js +3 -1
- package/dist/utils/url-normalizer.js +22 -1
- package/package.json +1 -1
- package/dist/{chunk-IJCVFLEY.js → chunk-TQJDNWBL.js} +3 -3
package/dist/auth/index.js
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TokenGenerator
|
|
3
3
|
} from "../chunk-GDWEDUHO.js";
|
|
4
|
-
import {
|
|
5
|
-
OAuthManager
|
|
6
|
-
} from "../chunk-V5K5FYU7.js";
|
|
7
4
|
import {
|
|
8
5
|
JWTClientManager,
|
|
9
6
|
clearStoredTokens,
|
|
@@ -20,6 +17,9 @@ import {
|
|
|
20
17
|
isTokenExpiringSoon,
|
|
21
18
|
storeTokens
|
|
22
19
|
} from "../chunk-XRRPEBKB.js";
|
|
20
|
+
import {
|
|
21
|
+
OAuthManager
|
|
22
|
+
} from "../chunk-V5K5FYU7.js";
|
|
23
23
|
import {
|
|
24
24
|
DEFAULT_PASSWORD_CONFIG,
|
|
25
25
|
createPasswordHasher,
|
|
@@ -44,7 +44,7 @@ import {
|
|
|
44
44
|
import {
|
|
45
45
|
JWTManager,
|
|
46
46
|
JWTService
|
|
47
|
-
} from "../chunk-
|
|
47
|
+
} from "../chunk-R6YVUU6I.js";
|
|
48
48
|
import {
|
|
49
49
|
AUTH_ERROR_CODES,
|
|
50
50
|
AuthError,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
AUTH_ERROR_CODE_MAP
|
|
3
3
|
} from "./chunk-2KDLKHTO.js";
|
|
4
|
-
import {
|
|
5
|
-
getErrorMessage
|
|
6
|
-
} from "./chunk-Y2JYA2AR.js";
|
|
7
4
|
import {
|
|
8
5
|
AppError
|
|
9
6
|
} from "./chunk-KXXROUA5.js";
|
|
7
|
+
import {
|
|
8
|
+
getErrorMessage
|
|
9
|
+
} from "./chunk-Y2JYA2AR.js";
|
|
10
10
|
import {
|
|
11
11
|
ERROR_CODES,
|
|
12
12
|
classifyError
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
import { NextResponse } from "next/server";
|
|
29
29
|
import { z } from "zod";
|
|
30
30
|
var errorHandlerMiddleware = async (context, next) => {
|
|
31
|
-
var _a
|
|
31
|
+
var _a;
|
|
32
32
|
try {
|
|
33
33
|
return await next();
|
|
34
34
|
} catch (error) {
|
|
@@ -75,7 +75,11 @@ var errorHandlerMiddleware = async (context, next) => {
|
|
|
75
75
|
);
|
|
76
76
|
}
|
|
77
77
|
const classified = error instanceof Error ? classifyError(error) : ERROR_CODES.INTERNAL_SERVER_ERROR;
|
|
78
|
-
logger.error("[ErrorHandler] Unexpected error:",
|
|
78
|
+
logger.error("[ErrorHandler] Unexpected error:", {
|
|
79
|
+
error,
|
|
80
|
+
requestId: context.requestId,
|
|
81
|
+
stack: error instanceof Error ? error.stack : void 0
|
|
82
|
+
});
|
|
79
83
|
let isProduction = false;
|
|
80
84
|
try {
|
|
81
85
|
isProduction = getCommonConfig().nodeEnv === "production";
|
|
@@ -87,8 +91,7 @@ var errorHandlerMiddleware = async (context, next) => {
|
|
|
87
91
|
classified.code,
|
|
88
92
|
safeMessage,
|
|
89
93
|
context.locale,
|
|
90
|
-
context.requestId
|
|
91
|
-
!isProduction && error instanceof Error ? { stack: (_b = error.stack) == null ? void 0 : _b.split("\n").slice(0, 5) } : void 0
|
|
94
|
+
context.requestId
|
|
92
95
|
);
|
|
93
96
|
}
|
|
94
97
|
};
|
|
@@ -7,7 +7,15 @@ function sanitizeHtml(input) {
|
|
|
7
7
|
if (!input || typeof input !== "string") {
|
|
8
8
|
return "";
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
let result = input;
|
|
11
|
+
result = result.replace(/<[^>]*>/g, "");
|
|
12
|
+
result = result.replace(/</gi, "<").replace(/>/gi, ">");
|
|
13
|
+
result = result.replace(/<[^>]*>/g, "");
|
|
14
|
+
result = result.replace(/&#(\d+);/g, (_, dec) => String.fromCharCode(Number(dec))).replace(/&#x([0-9a-fA-F]+);/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
|
|
15
|
+
result = result.replace(/<[^>]*>/g, "");
|
|
16
|
+
result = result.replace(/<[^>]*$/g, "");
|
|
17
|
+
result = result.replace(/&/gi, "&").replace(/"/gi, '"').replace(/'/gi, "'").replace(///gi, "/");
|
|
18
|
+
return result.trim();
|
|
11
19
|
}
|
|
12
20
|
function removeEventHandlers(input) {
|
|
13
21
|
if (!input || typeof input !== "string") {
|
|
@@ -17,13 +17,13 @@ import {
|
|
|
17
17
|
adminMiddleware,
|
|
18
18
|
authMiddleware,
|
|
19
19
|
optionalAuthMiddleware
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-A6V6XVPZ.js";
|
|
21
21
|
import {
|
|
22
22
|
corsMiddleware
|
|
23
23
|
} from "./chunk-KGHWGLED.js";
|
|
24
24
|
import {
|
|
25
25
|
errorHandlerMiddleware
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-BKJPYZYO.js";
|
|
27
27
|
|
|
28
28
|
// src/middleware/wrappers.ts
|
|
29
29
|
function withPublicApi(handler) {
|
|
@@ -25,7 +25,7 @@ var JWTManager = class {
|
|
|
25
25
|
});
|
|
26
26
|
return jwt;
|
|
27
27
|
} catch (error) {
|
|
28
|
-
this.logger.error("Failed to create access token", { error, payload });
|
|
28
|
+
this.logger.error("Failed to create access token", { error, userId: payload.userId });
|
|
29
29
|
throw new JWTError(
|
|
30
30
|
"Access token creation failed",
|
|
31
31
|
"TOKEN_CREATION_FAILED"
|
package/dist/constants/index.js
CHANGED
|
@@ -1,14 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
API_KEY,
|
|
3
|
-
CSRF,
|
|
4
|
-
EMAIL_VERIFICATION,
|
|
5
|
-
JWT_DEFAULTS,
|
|
6
|
-
MAGIC_LINK,
|
|
7
|
-
OAUTH,
|
|
8
|
-
PASSWORD_RESET,
|
|
9
|
-
SECURITY_HEADERS,
|
|
10
|
-
SESSION
|
|
11
|
-
} from "../chunk-JLLMTTQ4.js";
|
|
12
1
|
import {
|
|
13
2
|
DATE,
|
|
14
3
|
FILE_UPLOAD,
|
|
@@ -18,19 +7,6 @@ import {
|
|
|
18
7
|
URL,
|
|
19
8
|
USER_INPUT
|
|
20
9
|
} from "../chunk-LNV2E4I6.js";
|
|
21
|
-
import {
|
|
22
|
-
GENERIC_CONFIRM_MESSAGES,
|
|
23
|
-
GENERIC_ERROR_MESSAGES,
|
|
24
|
-
GENERIC_INFO_MESSAGES,
|
|
25
|
-
GENERIC_SUCCESS_MESSAGES
|
|
26
|
-
} from "../chunk-2TO7WUKK.js";
|
|
27
|
-
import {
|
|
28
|
-
DATE_RANGE,
|
|
29
|
-
FILTER_OPTIONS,
|
|
30
|
-
PAGE_SIZES,
|
|
31
|
-
PAGINATION,
|
|
32
|
-
SORT_OPTIONS
|
|
33
|
-
} from "../chunk-VDXB5DCY.js";
|
|
34
10
|
import {
|
|
35
11
|
ERROR_CODES,
|
|
36
12
|
HTTP_STATUS,
|
|
@@ -45,6 +21,30 @@ import {
|
|
|
45
21
|
getHttpStatus,
|
|
46
22
|
getLogLevel
|
|
47
23
|
} from "../chunk-SNVGJPPX.js";
|
|
24
|
+
import {
|
|
25
|
+
GENERIC_CONFIRM_MESSAGES,
|
|
26
|
+
GENERIC_ERROR_MESSAGES,
|
|
27
|
+
GENERIC_INFO_MESSAGES,
|
|
28
|
+
GENERIC_SUCCESS_MESSAGES
|
|
29
|
+
} from "../chunk-2TO7WUKK.js";
|
|
30
|
+
import {
|
|
31
|
+
DATE_RANGE,
|
|
32
|
+
FILTER_OPTIONS,
|
|
33
|
+
PAGE_SIZES,
|
|
34
|
+
PAGINATION,
|
|
35
|
+
SORT_OPTIONS
|
|
36
|
+
} from "../chunk-VDXB5DCY.js";
|
|
37
|
+
import {
|
|
38
|
+
API_KEY,
|
|
39
|
+
CSRF,
|
|
40
|
+
EMAIL_VERIFICATION,
|
|
41
|
+
JWT_DEFAULTS,
|
|
42
|
+
MAGIC_LINK,
|
|
43
|
+
OAUTH,
|
|
44
|
+
PASSWORD_RESET,
|
|
45
|
+
SECURITY_HEADERS,
|
|
46
|
+
SESSION
|
|
47
|
+
} from "../chunk-JLLMTTQ4.js";
|
|
48
48
|
import "../chunk-ORMEWXMH.js";
|
|
49
49
|
export {
|
|
50
50
|
API_KEY,
|
|
@@ -5,7 +5,8 @@ import {
|
|
|
5
5
|
getErrorIcon,
|
|
6
6
|
handleApiResponse,
|
|
7
7
|
showFriendlyError
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-TQJDNWBL.js";
|
|
9
|
+
import "../chunk-KXXROUA5.js";
|
|
9
10
|
import {
|
|
10
11
|
getErrorDisplayInfo,
|
|
11
12
|
getFriendlyMessage
|
|
@@ -13,7 +14,6 @@ import {
|
|
|
13
14
|
import "../chunk-Y2JYA2AR.js";
|
|
14
15
|
import "../chunk-HCF3C3AQ.js";
|
|
15
16
|
import "../chunk-IYXMGIEP.js";
|
|
16
|
-
import "../chunk-KXXROUA5.js";
|
|
17
17
|
import "../chunk-SNVGJPPX.js";
|
|
18
18
|
import "../chunk-ORMEWXMH.js";
|
|
19
19
|
export {
|
package/dist/error/index.js
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
LocaleDetector
|
|
3
3
|
} from "../chunk-XHZ5L4FO.js";
|
|
4
|
+
import {
|
|
5
|
+
extractErrorInfo,
|
|
6
|
+
formatInlineError,
|
|
7
|
+
getDefaultErrorCode,
|
|
8
|
+
getErrorIcon,
|
|
9
|
+
handleApiResponse,
|
|
10
|
+
showFriendlyError
|
|
11
|
+
} from "../chunk-TQJDNWBL.js";
|
|
4
12
|
import {
|
|
5
13
|
AUTH_ERROR_CODE_MAP,
|
|
6
14
|
ErrorResponse,
|
|
@@ -9,13 +17,8 @@ import {
|
|
|
9
17
|
withErrorHandler
|
|
10
18
|
} from "../chunk-2KDLKHTO.js";
|
|
11
19
|
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
getDefaultErrorCode,
|
|
15
|
-
getErrorIcon,
|
|
16
|
-
handleApiResponse,
|
|
17
|
-
showFriendlyError
|
|
18
|
-
} from "../chunk-IJCVFLEY.js";
|
|
20
|
+
AppError
|
|
21
|
+
} from "../chunk-KXXROUA5.js";
|
|
19
22
|
import {
|
|
20
23
|
formatFriendlyError,
|
|
21
24
|
getErrorDisplayInfo,
|
|
@@ -30,9 +33,6 @@ import {
|
|
|
30
33
|
} from "../chunk-Y2JYA2AR.js";
|
|
31
34
|
import "../chunk-HCF3C3AQ.js";
|
|
32
35
|
import "../chunk-IYXMGIEP.js";
|
|
33
|
-
import {
|
|
34
|
-
AppError
|
|
35
|
-
} from "../chunk-KXXROUA5.js";
|
|
36
36
|
import {
|
|
37
37
|
ERROR_CODES,
|
|
38
38
|
HTTP_STATUS,
|
package/dist/middleware/auth.js
CHANGED
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
initializeAuthMiddleware,
|
|
5
5
|
optionalAuthMiddleware,
|
|
6
6
|
setAccessTokenBlacklistChecker
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-A6V6XVPZ.js";
|
|
8
8
|
import "../chunk-KXXROUA5.js";
|
|
9
9
|
import "../chunk-SNVGJPPX.js";
|
|
10
10
|
import "../chunk-OZE5KUS3.js";
|
|
11
|
-
import "../chunk-
|
|
11
|
+
import "../chunk-R6YVUU6I.js";
|
|
12
12
|
import "../chunk-AIH3F7JV.js";
|
|
13
13
|
import "../chunk-GQVBWZLH.js";
|
|
14
14
|
import "../chunk-OHBAELPZ.js";
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
errorHandlerMiddleware
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-BKJPYZYO.js";
|
|
4
4
|
import "../chunk-2KDLKHTO.js";
|
|
5
|
+
import "../chunk-KXXROUA5.js";
|
|
5
6
|
import "../chunk-Y2JYA2AR.js";
|
|
6
7
|
import "../chunk-HCF3C3AQ.js";
|
|
7
8
|
import "../chunk-IYXMGIEP.js";
|
|
8
|
-
import "../chunk-KXXROUA5.js";
|
|
9
9
|
import "../chunk-SNVGJPPX.js";
|
|
10
10
|
import "../chunk-AIH3F7JV.js";
|
|
11
11
|
import "../chunk-GQVBWZLH.js";
|
package/dist/middleware/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
withCustomApi,
|
|
5
5
|
withOptionalAuthApi,
|
|
6
6
|
withPublicApi
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-NQS7UT6X.js";
|
|
8
8
|
import {
|
|
9
9
|
initRequestMiddleware
|
|
10
10
|
} from "../chunk-62Q7DN5G.js";
|
|
@@ -29,24 +29,24 @@ import {
|
|
|
29
29
|
initializeAuthMiddleware,
|
|
30
30
|
optionalAuthMiddleware,
|
|
31
31
|
setAccessTokenBlacklistChecker
|
|
32
|
-
} from "../chunk-
|
|
32
|
+
} from "../chunk-A6V6XVPZ.js";
|
|
33
33
|
import {
|
|
34
34
|
corsMiddleware,
|
|
35
35
|
validateCorsConfiguration
|
|
36
36
|
} from "../chunk-KGHWGLED.js";
|
|
37
37
|
import {
|
|
38
38
|
errorHandlerMiddleware
|
|
39
|
-
} from "../chunk-
|
|
39
|
+
} from "../chunk-BKJPYZYO.js";
|
|
40
40
|
import "../chunk-XHZ5L4FO.js";
|
|
41
41
|
import "../chunk-2KDLKHTO.js";
|
|
42
|
+
import "../chunk-KXXROUA5.js";
|
|
42
43
|
import "../chunk-Y2JYA2AR.js";
|
|
43
44
|
import "../chunk-HCF3C3AQ.js";
|
|
44
45
|
import "../chunk-IYXMGIEP.js";
|
|
45
|
-
import "../chunk-KXXROUA5.js";
|
|
46
46
|
import "../chunk-SNVGJPPX.js";
|
|
47
47
|
import "../chunk-GFWGLWTS.js";
|
|
48
48
|
import "../chunk-OZE5KUS3.js";
|
|
49
|
-
import "../chunk-
|
|
49
|
+
import "../chunk-R6YVUU6I.js";
|
|
50
50
|
import "../chunk-AIH3F7JV.js";
|
|
51
51
|
import "../chunk-GQVBWZLH.js";
|
|
52
52
|
import "../chunk-OHBAELPZ.js";
|
|
@@ -4,25 +4,25 @@ import {
|
|
|
4
4
|
withCustomApi,
|
|
5
5
|
withOptionalAuthApi,
|
|
6
6
|
withPublicApi
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-NQS7UT6X.js";
|
|
8
8
|
import "../chunk-62Q7DN5G.js";
|
|
9
9
|
import "../chunk-FPESPW6P.js";
|
|
10
10
|
import "../chunk-6MI4XLWC.js";
|
|
11
11
|
import "../chunk-OIRAH57Y.js";
|
|
12
12
|
import "../chunk-QVWDWROP.js";
|
|
13
|
-
import "../chunk-
|
|
13
|
+
import "../chunk-A6V6XVPZ.js";
|
|
14
14
|
import "../chunk-KGHWGLED.js";
|
|
15
|
-
import "../chunk-
|
|
15
|
+
import "../chunk-BKJPYZYO.js";
|
|
16
16
|
import "../chunk-XHZ5L4FO.js";
|
|
17
17
|
import "../chunk-2KDLKHTO.js";
|
|
18
|
+
import "../chunk-KXXROUA5.js";
|
|
18
19
|
import "../chunk-Y2JYA2AR.js";
|
|
19
20
|
import "../chunk-HCF3C3AQ.js";
|
|
20
21
|
import "../chunk-IYXMGIEP.js";
|
|
21
|
-
import "../chunk-KXXROUA5.js";
|
|
22
22
|
import "../chunk-SNVGJPPX.js";
|
|
23
23
|
import "../chunk-GFWGLWTS.js";
|
|
24
24
|
import "../chunk-OZE5KUS3.js";
|
|
25
|
-
import "../chunk-
|
|
25
|
+
import "../chunk-R6YVUU6I.js";
|
|
26
26
|
import "../chunk-AIH3F7JV.js";
|
|
27
27
|
import "../chunk-GQVBWZLH.js";
|
|
28
28
|
import "../chunk-OHBAELPZ.js";
|
package/dist/utils/index.js
CHANGED
package/dist/utils/ip-utils.d.ts
CHANGED
|
@@ -4,12 +4,15 @@ export declare function normalizeIP(ip: string): string;
|
|
|
4
4
|
/**
|
|
5
5
|
* 클라이언트 IP 주소 추출 (서버에서만 사용)
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
* 1. CF-Connecting-IP: Cloudflare가
|
|
9
|
-
* 2. True-Client-IP: Cloudflare Enterprise에서
|
|
10
|
-
* 3. X-
|
|
11
|
-
*
|
|
12
|
-
*
|
|
7
|
+
* 신뢰 가능한 프록시 헤더만 사용:
|
|
8
|
+
* 1. CF-Connecting-IP: Cloudflare Proxy가 강제 설정 (스푸핑 불가)
|
|
9
|
+
* 2. True-Client-IP: Cloudflare Enterprise에서 설정
|
|
10
|
+
* 3. X-Forwarded-For: 마지막 IP = 직전 프록시가 추가한 실제 클라이언트 IP
|
|
11
|
+
*
|
|
12
|
+
* 보안 참고:
|
|
13
|
+
* - X-Real-IP, X-Client-IP 등 클라이언트가 임의 설정 가능한 헤더는 사용하지 않음
|
|
14
|
+
* - X-Forwarded-For의 첫 번째 IP는 클라이언트가 조작 가능하므로 마지막 IP를 사용
|
|
15
|
+
* - Cloudflare Proxy 환경에서는 CF-Connecting-IP가 항상 설정되므로 폴백에 도달하지 않음
|
|
13
16
|
*/
|
|
14
17
|
export declare function extractClientIp(headers: Headers): string | null;
|
|
15
18
|
export declare function isValidIP(ip: string): boolean;
|
package/dist/utils/ip-utils.js
CHANGED
|
@@ -54,17 +54,14 @@ function extractClientIp(headers) {
|
|
|
54
54
|
if (cf && isValidIP(cf.trim())) return cf.trim();
|
|
55
55
|
const trueClientIp = headers.get("true-client-ip");
|
|
56
56
|
if (trueClientIp && isValidIP(trueClientIp.trim())) return trueClientIp.trim();
|
|
57
|
-
const xri = headers.get("x-real-ip");
|
|
58
|
-
if (xri && isValidIP(xri.trim())) return xri.trim();
|
|
59
57
|
const xff = headers.get("x-forwarded-for");
|
|
60
58
|
if (xff) {
|
|
61
59
|
const ips = xff.split(",").map((ip) => ip.trim()).filter(Boolean);
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
const lastIp = ips[ips.length - 1];
|
|
61
|
+
if (lastIp && isValidIP(lastIp)) {
|
|
62
|
+
return lastIp;
|
|
64
63
|
}
|
|
65
64
|
}
|
|
66
|
-
const xc = headers.get("x-client-ip");
|
|
67
|
-
if (xc && isValidIP(xc.trim())) return xc.trim();
|
|
68
65
|
return null;
|
|
69
66
|
}
|
|
70
67
|
function isValidIP(ip) {
|
|
@@ -8,15 +8,16 @@
|
|
|
8
8
|
*/
|
|
9
9
|
/**
|
|
10
10
|
* XSS 방지를 위한 HTML 태그 제거
|
|
11
|
-
* - 모든 HTML 태그 제거
|
|
12
|
-
* -
|
|
11
|
+
* - 모든 HTML 태그 제거 (named + numeric 엔티티로 인코딩된 태그 포함)
|
|
12
|
+
* - 닫는 >가 없는 불완전 태그 제거 (HTML5 파서 우회 방지)
|
|
13
|
+
* - HTML 엔티티를 디코딩하여 원본 텍스트 반환
|
|
13
14
|
* - 공백 정리
|
|
14
15
|
*
|
|
15
16
|
* @param input - 정제할 문자열
|
|
16
|
-
* @returns
|
|
17
|
+
* @returns 태그가 제거된 순수 텍스트 (React 등 텍스트 컨텍스트에서 사용)
|
|
17
18
|
*
|
|
18
19
|
* @example
|
|
19
|
-
* sanitizeHtml('<script>alert("xss")</script>Hello') // 'Hello'
|
|
20
|
+
* sanitizeHtml('<script>alert("xss")</script>Hello') // 'alert("xss")Hello'
|
|
20
21
|
* sanitizeHtml('Hello <b>World</b>') // 'Hello World'
|
|
21
22
|
*/
|
|
22
23
|
export declare function sanitizeHtml(input: string): string;
|
package/dist/utils/sanitizer.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import "../chunk-ORMEWXMH.js";
|
|
2
2
|
|
|
3
3
|
// src/utils/short-code-generator.ts
|
|
4
|
+
import { randomBytes } from "crypto";
|
|
4
5
|
function generateShortCode(length = 8) {
|
|
5
6
|
if (!Number.isInteger(length) || length <= 0) {
|
|
6
7
|
throw new Error("length must be a positive integer");
|
|
7
8
|
}
|
|
8
9
|
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
10
|
+
const bytes = randomBytes(length);
|
|
9
11
|
let result = "";
|
|
10
12
|
for (let i = 0; i < length; i++) {
|
|
11
|
-
result += chars.charAt(
|
|
13
|
+
result += chars.charAt(bytes[i] % chars.length);
|
|
12
14
|
}
|
|
13
15
|
return result;
|
|
14
16
|
}
|
|
@@ -39,11 +39,21 @@ var SUPPORTED_SCHEMES = [
|
|
|
39
39
|
"maps:",
|
|
40
40
|
"geo:"
|
|
41
41
|
];
|
|
42
|
+
var DANGEROUS_SCHEMES = [
|
|
43
|
+
"javascript:",
|
|
44
|
+
"vbscript:",
|
|
45
|
+
"data:",
|
|
46
|
+
"file:",
|
|
47
|
+
"blob:"
|
|
48
|
+
];
|
|
42
49
|
var CUSTOM_SCHEME_PATTERN = /^[a-zA-Z][a-zA-Z0-9+.-]*:/;
|
|
43
50
|
function hasValidScheme(url) {
|
|
44
51
|
try {
|
|
45
52
|
const urlObj = new URL(url);
|
|
46
|
-
const protocol = urlObj.protocol;
|
|
53
|
+
const protocol = urlObj.protocol.toLowerCase();
|
|
54
|
+
if (DANGEROUS_SCHEMES.includes(protocol)) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
47
57
|
if (SUPPORTED_SCHEMES.includes(protocol)) {
|
|
48
58
|
return true;
|
|
49
59
|
}
|
|
@@ -69,6 +79,9 @@ function normalizeUrl(url) {
|
|
|
69
79
|
}
|
|
70
80
|
const scheme = extractScheme(normalized);
|
|
71
81
|
if (scheme) {
|
|
82
|
+
if (DANGEROUS_SCHEMES.includes(scheme.toLowerCase() + ":")) {
|
|
83
|
+
return "";
|
|
84
|
+
}
|
|
72
85
|
return normalized;
|
|
73
86
|
}
|
|
74
87
|
if (normalized.startsWith("//")) {
|
|
@@ -88,6 +101,14 @@ function validateUrl(url, options) {
|
|
|
88
101
|
try {
|
|
89
102
|
const urlObj = new URL(normalized);
|
|
90
103
|
const protocol = urlObj.protocol;
|
|
104
|
+
if (DANGEROUS_SCHEMES.includes(protocol.toLowerCase())) {
|
|
105
|
+
return {
|
|
106
|
+
isValid: false,
|
|
107
|
+
message: `\uBCF4\uC548\uC0C1 \uD5C8\uC6A9\uB418\uC9C0 \uC54A\uB294 \uD504\uB85C\uD1A0\uCF5C\uC785\uB2C8\uB2E4: ${protocol}`,
|
|
108
|
+
messageKey: "unsupportedProtocol",
|
|
109
|
+
messageParams: { protocol }
|
|
110
|
+
};
|
|
111
|
+
}
|
|
91
112
|
const isSupported = SUPPORTED_SCHEMES.includes(protocol);
|
|
92
113
|
const isCustom = CUSTOM_SCHEME_PATTERN.test(normalized);
|
|
93
114
|
if (!isSupported && !isCustom) {
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AppError
|
|
3
|
+
} from "./chunk-KXXROUA5.js";
|
|
1
4
|
import {
|
|
2
5
|
getErrorDisplayInfo,
|
|
3
6
|
getFriendlyMessage
|
|
4
7
|
} from "./chunk-S54PFAEU.js";
|
|
5
|
-
import {
|
|
6
|
-
AppError
|
|
7
|
-
} from "./chunk-KXXROUA5.js";
|
|
8
8
|
import {
|
|
9
9
|
getErrorCategory
|
|
10
10
|
} from "./chunk-SNVGJPPX.js";
|