@vlian/framework 1.2.25 → 1.2.37

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.
Files changed (213) hide show
  1. package/dist/analytics.umd.js +208 -2395
  2. package/dist/analytics.umd.js.map +1 -1
  3. package/dist/core/error/ErrorHandler.cjs.map +1 -1
  4. package/dist/core/error/ErrorHandler.d.ts +1 -1
  5. package/dist/core/error/ErrorHandler.js.map +1 -1
  6. package/dist/core/router/monitoring/RouterMonitoring.cjs +1 -1
  7. package/dist/core/router/monitoring/RouterMonitoring.cjs.map +1 -1
  8. package/dist/core/router/monitoring/RouterMonitoring.js +1 -1
  9. package/dist/core/router/monitoring/RouterMonitoring.js.map +1 -1
  10. package/dist/core/router/utils/adapters/react-router/transform.cjs +4 -0
  11. package/dist/core/router/utils/adapters/react-router/transform.cjs.map +1 -1
  12. package/dist/core/router/utils/adapters/react-router/transform.js +4 -0
  13. package/dist/core/router/utils/adapters/react-router/transform.js.map +1 -1
  14. package/dist/core/startup/initializeServices.cjs +1 -1
  15. package/dist/core/startup/initializeServices.cjs.map +1 -1
  16. package/dist/core/startup/initializeServices.d.ts +1 -1
  17. package/dist/core/startup/initializeServices.js +1 -1
  18. package/dist/core/startup/initializeServices.js.map +1 -1
  19. package/dist/core/startup/performanceTracker.cjs.map +1 -1
  20. package/dist/core/startup/performanceTracker.d.ts +1 -1
  21. package/dist/core/startup/performanceTracker.js.map +1 -1
  22. package/dist/core/startup/renderApp.cjs +1 -1
  23. package/dist/core/startup/renderApp.cjs.map +1 -1
  24. package/dist/core/startup/renderApp.d.ts +1 -1
  25. package/dist/core/startup/renderApp.js +1 -1
  26. package/dist/core/startup/renderApp.js.map +1 -1
  27. package/dist/core/startup/startApp.cjs +2 -2
  28. package/dist/core/startup/startApp.cjs.map +1 -1
  29. package/dist/core/startup/startApp.js +3 -3
  30. package/dist/core/startup/startApp.js.map +1 -1
  31. package/dist/core/types.d.ts +1 -1
  32. package/dist/core/types.js.map +1 -1
  33. package/dist/index.cjs +15 -2
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.ts +6 -4
  36. package/dist/index.js +5 -4
  37. package/dist/index.js.map +1 -1
  38. package/dist/index.umd.js +11648 -32616
  39. package/dist/index.umd.js.map +1 -1
  40. package/dist/kernel/constants.cjs +67 -0
  41. package/dist/kernel/constants.cjs.map +1 -0
  42. package/dist/kernel/constants.d.ts +5 -0
  43. package/dist/kernel/constants.js +43 -0
  44. package/dist/kernel/constants.js.map +1 -0
  45. package/dist/kernel/index.cjs +40 -0
  46. package/dist/kernel/index.cjs.map +1 -0
  47. package/dist/kernel/index.d.ts +3 -0
  48. package/dist/kernel/index.js +4 -0
  49. package/dist/kernel/index.js.map +1 -0
  50. package/dist/kernel/kernel.cjs +296 -0
  51. package/dist/kernel/kernel.cjs.map +1 -0
  52. package/dist/kernel/kernel.d.ts +40 -0
  53. package/dist/kernel/kernel.js +272 -0
  54. package/dist/kernel/kernel.js.map +1 -0
  55. package/dist/kernel/manager/cacheManager.cjs +46 -0
  56. package/dist/kernel/manager/cacheManager.cjs.map +1 -0
  57. package/dist/kernel/manager/cacheManager.d.ts +6 -0
  58. package/dist/kernel/manager/cacheManager.js +36 -0
  59. package/dist/kernel/manager/cacheManager.js.map +1 -0
  60. package/dist/kernel/manager/i18nManager.cjs +68 -0
  61. package/dist/kernel/manager/i18nManager.cjs.map +1 -0
  62. package/dist/kernel/manager/i18nManager.d.ts +8 -0
  63. package/dist/kernel/manager/i18nManager.js +58 -0
  64. package/dist/kernel/manager/i18nManager.js.map +1 -0
  65. package/dist/kernel/manager/index.cjs +30 -0
  66. package/dist/kernel/manager/index.cjs.map +1 -0
  67. package/dist/kernel/manager/index.d.ts +4 -0
  68. package/dist/kernel/manager/index.js +6 -0
  69. package/dist/kernel/manager/index.js.map +1 -0
  70. package/dist/kernel/manager/loggerManager.cjs +70 -0
  71. package/dist/kernel/manager/loggerManager.cjs.map +1 -0
  72. package/dist/kernel/manager/loggerManager.d.ts +14 -0
  73. package/dist/kernel/manager/loggerManager.js +60 -0
  74. package/dist/kernel/manager/loggerManager.js.map +1 -0
  75. package/dist/kernel/manager/persistence.cjs +93 -0
  76. package/dist/kernel/manager/persistence.cjs.map +1 -0
  77. package/dist/kernel/manager/persistence.d.ts +3 -0
  78. package/dist/kernel/manager/persistence.js +75 -0
  79. package/dist/kernel/manager/persistence.js.map +1 -0
  80. package/dist/kernel/manager/themeManager.cjs +85 -0
  81. package/dist/kernel/manager/themeManager.cjs.map +1 -0
  82. package/dist/kernel/manager/themeManager.d.ts +9 -0
  83. package/dist/kernel/manager/themeManager.js +75 -0
  84. package/dist/kernel/manager/themeManager.js.map +1 -0
  85. package/dist/kernel/types.cjs +6 -0
  86. package/dist/kernel/types.cjs.map +1 -0
  87. package/dist/kernel/types.d.ts +72 -0
  88. package/dist/kernel/types.js +3 -0
  89. package/dist/kernel/types.js.map +1 -0
  90. package/dist/request/adapter.d.ts +1 -0
  91. package/dist/request/core.d.ts +1 -0
  92. package/dist/request/index.d.ts +1 -42
  93. package/dist/request/plugin/csrfPlugin.d.ts +2 -2
  94. package/dist/request/plugin/queue.d.ts +2 -2
  95. package/dist/request/plugin.d.ts +1 -0
  96. package/dist/request/runtime.d.ts +1 -0
  97. package/dist/request/types.d.ts +1 -394
  98. package/dist/request/utils.d.ts +1 -0
  99. package/dist/state.umd.js +1 -1
  100. package/dist/utils/csrf.cjs +13 -152
  101. package/dist/utils/csrf.cjs.map +1 -1
  102. package/dist/utils/csrf.d.ts +1 -72
  103. package/dist/utils/csrf.js +1 -142
  104. package/dist/utils/csrf.js.map +1 -1
  105. package/dist/utils/errors/ErrorCodes.cjs +6 -76
  106. package/dist/utils/errors/ErrorCodes.cjs.map +1 -1
  107. package/dist/utils/errors/ErrorCodes.d.ts +1 -45
  108. package/dist/utils/errors/ErrorCodes.js +1 -84
  109. package/dist/utils/errors/ErrorCodes.js.map +1 -1
  110. package/dist/utils/errors.cjs +15 -344
  111. package/dist/utils/errors.cjs.map +1 -1
  112. package/dist/utils/errors.d.ts +1 -183
  113. package/dist/utils/errors.js +1 -352
  114. package/dist/utils/errors.js.map +1 -1
  115. package/dist/utils/logger.cjs +5 -374
  116. package/dist/utils/logger.cjs.map +1 -1
  117. package/dist/utils/logger.d.ts +2 -189
  118. package/dist/utils/logger.js +1 -379
  119. package/dist/utils/logger.js.map +1 -1
  120. package/dist/utils/logger.types.cjs +3 -12
  121. package/dist/utils/logger.types.cjs.map +1 -1
  122. package/dist/utils/logger.types.d.ts +2 -57
  123. package/dist/utils/logger.types.js +1 -10
  124. package/dist/utils/logger.types.js.map +1 -1
  125. package/dist/utils/monitoring.cjs +11 -302
  126. package/dist/utils/monitoring.cjs.map +1 -1
  127. package/dist/utils/monitoring.d.ts +1 -163
  128. package/dist/utils/monitoring.js +1 -294
  129. package/dist/utils/monitoring.js.map +1 -1
  130. package/dist/utils/performance.cjs +5 -352
  131. package/dist/utils/performance.cjs.map +1 -1
  132. package/dist/utils/performance.d.ts +2 -246
  133. package/dist/utils/performance.js +1 -354
  134. package/dist/utils/performance.js.map +1 -1
  135. package/dist/utils/resourceLoader.cjs +5 -303
  136. package/dist/utils/resourceLoader.cjs.map +1 -1
  137. package/dist/utils/resourceLoader.d.ts +2 -130
  138. package/dist/utils/resourceLoader.js +1 -305
  139. package/dist/utils/resourceLoader.js.map +1 -1
  140. package/dist/utils/runtimeSecurity.cjs +2 -140
  141. package/dist/utils/runtimeSecurity.cjs.map +1 -1
  142. package/dist/utils/runtimeSecurity.d.ts +2 -104
  143. package/dist/utils/runtimeSecurity.js +1 -141
  144. package/dist/utils/runtimeSecurity.js.map +1 -1
  145. package/dist/utils/security.cjs +3 -314
  146. package/dist/utils/security.cjs.map +1 -1
  147. package/dist/utils/security.d.ts +2 -80
  148. package/dist/utils/security.js +1 -311
  149. package/dist/utils/security.js.map +1 -1
  150. package/dist/utils/traceId.cjs +10 -111
  151. package/dist/utils/traceId.cjs.map +1 -1
  152. package/dist/utils/traceId.d.ts +1 -63
  153. package/dist/utils/traceId.js +1 -116
  154. package/dist/utils/traceId.js.map +1 -1
  155. package/dist/utils/validation.cjs +3 -173
  156. package/dist/utils/validation.cjs.map +1 -1
  157. package/dist/utils/validation.d.ts +2 -110
  158. package/dist/utils/validation.js +1 -175
  159. package/dist/utils/validation.js.map +1 -1
  160. package/package.json +15 -24
  161. package/dist/lazy/index.cjs +0 -104
  162. package/dist/lazy/index.cjs.map +0 -1
  163. package/dist/lazy/index.d.ts +0 -19
  164. package/dist/lazy/index.js +0 -24
  165. package/dist/lazy/index.js.map +0 -1
  166. package/dist/request/adapter/RequestAdapter.cjs +0 -78
  167. package/dist/request/adapter/RequestAdapter.cjs.map +0 -1
  168. package/dist/request/adapter/axiosAdapter.cjs +0 -164
  169. package/dist/request/adapter/axiosAdapter.cjs.map +0 -1
  170. package/dist/request/adapter/fetchAdapter.cjs +0 -134
  171. package/dist/request/adapter/fetchAdapter.cjs.map +0 -1
  172. package/dist/request/adapter/index.cjs +0 -80
  173. package/dist/request/adapter/index.cjs.map +0 -1
  174. package/dist/request/adapter/kyAdapter.cjs +0 -191
  175. package/dist/request/adapter/kyAdapter.cjs.map +0 -1
  176. package/dist/request/adapter/undiciAdapter.cjs +0 -213
  177. package/dist/request/adapter/undiciAdapter.cjs.map +0 -1
  178. package/dist/request/core/RequestClient.cjs +0 -558
  179. package/dist/request/core/RequestClient.cjs.map +0 -1
  180. package/dist/request/core/index.cjs +0 -15
  181. package/dist/request/core/index.cjs.map +0 -1
  182. package/dist/request/index.cjs +0 -149
  183. package/dist/request/index.cjs.map +0 -1
  184. package/dist/request/plugin/RequestPlugin.cjs +0 -218
  185. package/dist/request/plugin/RequestPlugin.cjs.map +0 -1
  186. package/dist/request/plugin/cache.cjs +0 -269
  187. package/dist/request/plugin/cache.cjs.map +0 -1
  188. package/dist/request/plugin/csrfPlugin.cjs +0 -40
  189. package/dist/request/plugin/csrfPlugin.cjs.map +0 -1
  190. package/dist/request/plugin/index.cjs +0 -53
  191. package/dist/request/plugin/index.cjs.map +0 -1
  192. package/dist/request/plugin/monitoring.cjs +0 -216
  193. package/dist/request/plugin/monitoring.cjs.map +0 -1
  194. package/dist/request/plugin/queue.cjs +0 -140
  195. package/dist/request/plugin/queue.cjs.map +0 -1
  196. package/dist/request/plugin/retry.cjs +0 -98
  197. package/dist/request/plugin/retry.cjs.map +0 -1
  198. package/dist/request/plugin/validation.cjs +0 -121
  199. package/dist/request/plugin/validation.cjs.map +0 -1
  200. package/dist/request/runtime/RequestContext.cjs +0 -77
  201. package/dist/request/runtime/RequestContext.cjs.map +0 -1
  202. package/dist/request/runtime/index.cjs +0 -32
  203. package/dist/request/runtime/index.cjs.map +0 -1
  204. package/dist/request/types.cjs +0 -112
  205. package/dist/request/types.cjs.map +0 -1
  206. package/dist/request/utils/RequestQueueManager.cjs +0 -168
  207. package/dist/request/utils/RequestQueueManager.cjs.map +0 -1
  208. package/dist/request/utils/dependencyCheck.cjs +0 -237
  209. package/dist/request/utils/dependencyCheck.cjs.map +0 -1
  210. package/dist/request/utils/index.cjs +0 -30
  211. package/dist/request/utils/index.cjs.map +0 -1
  212. package/dist/request.umd.js +0 -5392
  213. package/dist/request.umd.js.map +0 -1
@@ -1,143 +1,3 @@
1
- import { SecurityUtils } from "./security";
2
- /**
3
- * 运行时安全工具类
4
- */ export class RuntimeSecurity {
5
- /**
6
- * 应用 CSP
7
- *
8
- * 注意:通过 meta 标签设置 CSP 不如 HTTP 头安全,建议在服务器端设置 CSP 头。
9
- * 此方法仅作为补充措施。
10
- */ static applyCSP(config) {
11
- if (typeof document === 'undefined') {
12
- return;
13
- }
14
- try {
15
- const cspHeader = SecurityUtils.generateCSP(config);
16
- // 创建或更新 meta 标签
17
- let metaCSP = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
18
- if (!metaCSP) {
19
- metaCSP = document.createElement('meta');
20
- metaCSP.setAttribute('http-equiv', 'Content-Security-Policy');
21
- // 插入到 head 的开头,确保优先级
22
- document.head.insertBefore(metaCSP, document.head.firstChild);
23
- }
24
- metaCSP.setAttribute('content', cspHeader);
25
- // 添加 CSP 违规报告(如果支持)
26
- if (typeof window !== 'undefined' && 'reporting' in window) {
27
- // 可以添加 CSP 违规监听器
28
- window.addEventListener('securitypolicyviolation', (event)=>{
29
- console.warn('CSP 违规:', {
30
- violatedDirective: event.violatedDirective,
31
- blockedURI: event.blockedURI
32
- });
33
- });
34
- }
35
- } catch (error) {
36
- console.error('应用 CSP 失败:', error);
37
- }
38
- }
39
- /**
40
- * 应用安全头(通过 meta 标签,实际应该由服务器设置)
41
- */ static applySecurityHeaders(config) {
42
- if (typeof document === 'undefined') {
43
- return;
44
- }
45
- // X-Frame-Options
46
- if (config.xFrameOptions) {
47
- let meta = document.querySelector('meta[http-equiv="X-Frame-Options"]');
48
- if (!meta) {
49
- meta = document.createElement('meta');
50
- meta.setAttribute('http-equiv', 'X-Frame-Options');
51
- document.head.appendChild(meta);
52
- }
53
- meta.setAttribute('content', config.xFrameOptions);
54
- }
55
- // X-Content-Type-Options
56
- if (config.xContentTypeOptions !== false) {
57
- let meta = document.querySelector('meta[http-equiv="X-Content-Type-Options"]');
58
- if (!meta) {
59
- meta = document.createElement('meta');
60
- meta.setAttribute('http-equiv', 'X-Content-Type-Options');
61
- document.head.appendChild(meta);
62
- }
63
- meta.setAttribute('content', 'nosniff');
64
- }
65
- // X-XSS-Protection
66
- if (config.xXSSProtection !== false) {
67
- let meta = document.querySelector('meta[http-equiv="X-XSS-Protection"]');
68
- if (!meta) {
69
- meta = document.createElement('meta');
70
- meta.setAttribute('http-equiv', 'X-XSS-Protection');
71
- document.head.appendChild(meta);
72
- }
73
- meta.setAttribute('content', '1; mode=block');
74
- }
75
- // Referrer-Policy
76
- if (config.referrerPolicy) {
77
- let meta = document.querySelector('meta[name="referrer"]');
78
- if (!meta) {
79
- meta = document.createElement('meta');
80
- meta.setAttribute('name', 'referrer');
81
- document.head.appendChild(meta);
82
- }
83
- meta.setAttribute('content', config.referrerPolicy);
84
- }
85
- }
86
- /**
87
- * 检查运行时安全
88
- */ static checkRuntimeSecurity() {
89
- const issues = [];
90
- if (typeof window === 'undefined') {
91
- return {
92
- safe: true,
93
- issues: []
94
- };
95
- }
96
- // 检查是否在 HTTPS 环境下
97
- if (window.location.protocol !== 'https:' && window.location.hostname !== 'localhost') {
98
- issues.push('应用未在 HTTPS 环境下运行');
99
- }
100
- // 检查是否有危险的全局对象
101
- if (window.eval) {
102
- issues.push('检测到危险的 eval 函数');
103
- }
104
- // 检查是否有危险的 innerHTML 使用
105
- // 这个检查需要在代码层面进行,这里只是示例
106
- return {
107
- safe: issues.length === 0,
108
- issues
109
- };
110
- }
111
- /**
112
- * 初始化运行时安全
113
- */ static initialize(options = {}) {
114
- const { enableCSP = false, enableSecurityHeaders = false, enableRuntimeChecks = false, csp, securityHeaders } = options;
115
- // 应用 CSP
116
- if (enableCSP && csp) {
117
- this.applyCSP(csp);
118
- }
119
- // 应用安全头
120
- if (enableSecurityHeaders && securityHeaders) {
121
- this.applySecurityHeaders(securityHeaders);
122
- }
123
- // 运行时检查
124
- if (enableRuntimeChecks) {
125
- const checkResult = this.checkRuntimeSecurity();
126
- if (!checkResult.safe) {
127
- console.warn('运行时安全检查发现问题:', checkResult.issues);
128
- }
129
- }
130
- }
131
- /**
132
- * 验证 URL 安全性
133
- */ static validateUrl(url) {
134
- return SecurityUtils.isSafeUrl(url);
135
- }
136
- /**
137
- * 验证并清理用户输入
138
- */ static sanitizeUserInput(input) {
139
- return SecurityUtils.validateInput(input);
140
- }
141
- }
1
+ export { RuntimeSecurity } from "@vlian/utils";
142
2
 
143
3
  //# sourceMappingURL=runtimeSecurity.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/runtimeSecurity.ts"],"sourcesContent":["import { SecurityUtils } from './security';\n\n/**\n * CSP 配置\n */\nexport interface CSPConfig {\n defaultSrc?: string[];\n scriptSrc?: string[];\n styleSrc?: string[];\n imgSrc?: string[];\n connectSrc?: string[];\n fontSrc?: string[];\n frameSrc?: string[];\n}\n\n/**\n * 安全头配置\n */\nexport interface SecurityHeadersConfig {\n /**\n * Content Security Policy\n */\n csp?: CSPConfig | string;\n /**\n * X-Frame-Options\n */\n xFrameOptions?: 'DENY' | 'SAMEORIGIN' | 'ALLOW-FROM';\n /**\n * X-Content-Type-Options\n */\n xContentTypeOptions?: boolean;\n /**\n * X-XSS-Protection\n */\n xXSSProtection?: boolean;\n /**\n * Referrer-Policy\n */\n referrerPolicy?: 'no-referrer' | 'no-referrer-when-downgrade' | 'origin' | 'origin-when-cross-origin' | 'same-origin' | 'strict-origin' | 'strict-origin-when-cross-origin' | 'unsafe-url';\n /**\n * Permissions-Policy\n */\n permissionsPolicy?: Record<string, string[]>;\n}\n\n/**\n * 运行时安全检查选项\n */\nexport interface RuntimeSecurityOptions {\n /**\n * 是否启用 CSP\n */\n enableCSP?: boolean;\n /**\n * 是否启用安全头\n */\n enableSecurityHeaders?: boolean;\n /**\n * 是否启用运行时检查\n */\n enableRuntimeChecks?: boolean;\n /**\n * CSP 配置\n */\n csp?: CSPConfig;\n /**\n * 安全头配置\n */\n securityHeaders?: SecurityHeadersConfig;\n}\n\n/**\n * 运行时安全工具类\n */\nexport class RuntimeSecurity {\n /**\n * 应用 CSP\n * \n * 注意:通过 meta 标签设置 CSP 不如 HTTP 头安全,建议在服务器端设置 CSP 头。\n * 此方法仅作为补充措施。\n */\n static applyCSP(config: CSPConfig): void {\n if (typeof document === 'undefined') {\n return;\n }\n\n try {\n const cspHeader = SecurityUtils.generateCSP(config);\n\n // 创建或更新 meta 标签\n let metaCSP = document.querySelector('meta[http-equiv=\"Content-Security-Policy\"]');\n if (!metaCSP) {\n metaCSP = document.createElement('meta');\n metaCSP.setAttribute('http-equiv', 'Content-Security-Policy');\n // 插入到 head 的开头,确保优先级\n document.head.insertBefore(metaCSP, document.head.firstChild);\n }\n metaCSP.setAttribute('content', cspHeader);\n\n // 添加 CSP 违规报告(如果支持)\n if (typeof window !== 'undefined' && 'reporting' in window) {\n // 可以添加 CSP 违规监听器\n window.addEventListener('securitypolicyviolation', (event) => {\n console.warn('CSP 违规:', {\n violatedDirective: (event as any).violatedDirective,\n blockedURI: (event as any).blockedURI,\n });\n });\n }\n } catch (error) {\n console.error('应用 CSP 失败:', error);\n }\n }\n\n /**\n * 应用安全头(通过 meta 标签,实际应该由服务器设置)\n */\n static applySecurityHeaders(config: SecurityHeadersConfig): void {\n if (typeof document === 'undefined') {\n return;\n }\n\n // X-Frame-Options\n if (config.xFrameOptions) {\n let meta = document.querySelector('meta[http-equiv=\"X-Frame-Options\"]');\n if (!meta) {\n meta = document.createElement('meta');\n meta.setAttribute('http-equiv', 'X-Frame-Options');\n document.head.appendChild(meta);\n }\n meta.setAttribute('content', config.xFrameOptions);\n }\n\n // X-Content-Type-Options\n if (config.xContentTypeOptions !== false) {\n let meta = document.querySelector('meta[http-equiv=\"X-Content-Type-Options\"]');\n if (!meta) {\n meta = document.createElement('meta');\n meta.setAttribute('http-equiv', 'X-Content-Type-Options');\n document.head.appendChild(meta);\n }\n meta.setAttribute('content', 'nosniff');\n }\n\n // X-XSS-Protection\n if (config.xXSSProtection !== false) {\n let meta = document.querySelector('meta[http-equiv=\"X-XSS-Protection\"]');\n if (!meta) {\n meta = document.createElement('meta');\n meta.setAttribute('http-equiv', 'X-XSS-Protection');\n document.head.appendChild(meta);\n }\n meta.setAttribute('content', '1; mode=block');\n }\n\n // Referrer-Policy\n if (config.referrerPolicy) {\n let meta = document.querySelector('meta[name=\"referrer\"]');\n if (!meta) {\n meta = document.createElement('meta');\n meta.setAttribute('name', 'referrer');\n document.head.appendChild(meta);\n }\n meta.setAttribute('content', config.referrerPolicy);\n }\n }\n\n /**\n * 检查运行时安全\n */\n static checkRuntimeSecurity(): {\n safe: boolean;\n issues: string[];\n } {\n const issues: string[] = [];\n\n if (typeof window === 'undefined') {\n return { safe: true, issues: [] };\n }\n\n // 检查是否在 HTTPS 环境下\n if (window.location.protocol !== 'https:' && window.location.hostname !== 'localhost') {\n issues.push('应用未在 HTTPS 环境下运行');\n }\n\n // 检查是否有危险的全局对象\n if ((window as any).eval) {\n issues.push('检测到危险的 eval 函数');\n }\n\n // 检查是否有危险的 innerHTML 使用\n // 这个检查需要在代码层面进行,这里只是示例\n\n return {\n safe: issues.length === 0,\n issues,\n };\n }\n\n /**\n * 初始化运行时安全\n */\n static initialize(options: RuntimeSecurityOptions = {}): void {\n const {\n enableCSP = false,\n enableSecurityHeaders = false,\n enableRuntimeChecks = false,\n csp,\n securityHeaders,\n } = options;\n\n // 应用 CSP\n if (enableCSP && csp) {\n this.applyCSP(csp);\n }\n\n // 应用安全头\n if (enableSecurityHeaders && securityHeaders) {\n this.applySecurityHeaders(securityHeaders);\n }\n\n // 运行时检查\n if (enableRuntimeChecks) {\n const checkResult = this.checkRuntimeSecurity();\n if (!checkResult.safe) {\n console.warn('运行时安全检查发现问题:', checkResult.issues);\n }\n }\n }\n\n /**\n * 验证 URL 安全性\n */\n static validateUrl(url: string): boolean {\n return SecurityUtils.isSafeUrl(url);\n }\n\n /**\n * 验证并清理用户输入\n */\n static sanitizeUserInput(input: unknown): {\n safe: boolean;\n sanitized?: string;\n } {\n return SecurityUtils.validateInput(input);\n }\n}\n"],"names":["SecurityUtils","RuntimeSecurity","applyCSP","config","document","cspHeader","generateCSP","metaCSP","querySelector","createElement","setAttribute","head","insertBefore","firstChild","window","addEventListener","event","console","warn","violatedDirective","blockedURI","error","applySecurityHeaders","xFrameOptions","meta","appendChild","xContentTypeOptions","xXSSProtection","referrerPolicy","checkRuntimeSecurity","issues","safe","location","protocol","hostname","push","eval","length","initialize","options","enableCSP","enableSecurityHeaders","enableRuntimeChecks","csp","securityHeaders","checkResult","validateUrl","url","isSafeUrl","sanitizeUserInput","input","validateInput"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/utils/runtimeSecurity.ts"],"sourcesContent":["export { RuntimeSecurity } from '@vlian/utils';\nexport type { RuntimeSecurityOptions, CSPConfig, SecurityHeadersConfig } from '@vlian/utils';\n"],"names":["RuntimeSecurity"],"mappings":"AAAA,SAASA,eAAe,QAAQ,eAAe"}
@@ -10,323 +10,12 @@ function _export(target, all) {
10
10
  }
11
11
  _export(exports, {
12
12
  get SENSITIVE_FIELDS () {
13
- return SENSITIVE_FIELDS;
13
+ return _utils.SENSITIVE_FIELDS;
14
14
  },
15
15
  get SecurityUtils () {
16
- return SecurityUtils;
16
+ return _utils.SecurityUtils;
17
17
  }
18
18
  });
19
- const _dompurify = /*#__PURE__*/ _interop_require_default(require("dompurify"));
20
- const _errors = require("./errors");
21
- function _interop_require_default(obj) {
22
- return obj && obj.__esModule ? obj : {
23
- default: obj
24
- };
25
- }
26
- const SENSITIVE_FIELDS = [
27
- 'password',
28
- 'pwd',
29
- 'passwd',
30
- 'token',
31
- 'secret',
32
- 'key',
33
- 'apiKey',
34
- 'apikey',
35
- 'api_key',
36
- 'accessToken',
37
- 'access_token',
38
- 'refreshToken',
39
- 'refresh_token',
40
- 'authorization',
41
- 'auth',
42
- 'cookie',
43
- 'session',
44
- 'sessionId',
45
- 'session_id',
46
- 'creditCard',
47
- 'credit_card',
48
- 'cardNumber',
49
- 'card_number',
50
- 'cvv',
51
- 'cvc',
52
- 'ssn',
53
- 'socialSecurityNumber',
54
- 'social_security_number',
55
- 'phone',
56
- 'phoneNumber',
57
- 'phone_number',
58
- 'mobile',
59
- 'email',
60
- 'emailAddress',
61
- 'email_address',
62
- 'privateKey',
63
- 'private_key',
64
- 'secretKey',
65
- 'secret_key',
66
- 'apiSecret',
67
- 'api_secret'
68
- ];
69
- /**
70
- * 敏感信息检测模式(正则表达式)
71
- */ const SENSITIVE_PATTERNS = [
72
- /\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/,
73
- /\b\d{3}-\d{2}-\d{4}\b/,
74
- /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/,
75
- /\b\d{10,}\b/
76
- ];
77
- let SecurityUtils = class SecurityUtils {
78
- /**
79
- * 清理 HTML,防止 XSS 攻击
80
- */ static sanitizeHTML(html, config) {
81
- if (typeof window === 'undefined') {
82
- // Node.js 环境,返回原始字符串(需要服务端处理)
83
- return html;
84
- }
85
- try {
86
- if (config?.allowHTML) {
87
- // 默认禁止所有标签,除非明确允许
88
- const allowedTags = config.allowedTags && config.allowedTags.length > 0 ? config.allowedTags : [];
89
- const allowedAttributes = config.allowedAttributes && config.allowedAttributes.length > 0 ? config.allowedAttributes : [];
90
- return _dompurify.default.sanitize(html, {
91
- ALLOWED_TAGS: allowedTags,
92
- ALLOWED_ATTR: allowedAttributes,
93
- FORBID_TAGS: [
94
- 'script',
95
- 'iframe',
96
- 'object',
97
- 'embed',
98
- 'form',
99
- 'link',
100
- 'meta',
101
- 'style'
102
- ],
103
- FORBID_ATTR: [
104
- 'onerror',
105
- 'onload',
106
- 'onclick',
107
- 'onmouseover',
108
- 'onfocus',
109
- 'onblur',
110
- 'onchange'
111
- ],
112
- // 添加更多安全配置
113
- KEEP_CONTENT: false,
114
- RETURN_DOM: false,
115
- RETURN_DOM_FRAGMENT: false,
116
- RETURN_TRUSTED_TYPE: false
117
- });
118
- }
119
- // 默认模式:完全清理,不允许任何 HTML
120
- return _dompurify.default.sanitize(html, {
121
- ALLOWED_TAGS: [],
122
- KEEP_CONTENT: false
123
- });
124
- } catch (error) {
125
- // 错误处理:不泄露敏感信息,记录错误但不抛出详细错误
126
- const errorMessage = error instanceof Error ? error.message : 'Unknown error';
127
- // 只记录错误类型,不记录具体内容
128
- console.error('HTML 清理失败:', errorMessage.substring(0, 50));
129
- // 返回安全的空字符串或清理后的文本
130
- return this.sanitizeText(html);
131
- }
132
- }
133
- /**
134
- * 清理文本内容(移除所有 HTML 标签)
135
- */ static sanitizeText(text) {
136
- if (typeof window === 'undefined') {
137
- return text.replace(/<[^>]*>/g, '');
138
- }
139
- try {
140
- return _dompurify.default.sanitize(text, {
141
- ALLOWED_TAGS: []
142
- });
143
- } catch (error) {
144
- throw new _errors.SecurityError('文本清理失败', error instanceof Error ? error : undefined);
145
- }
146
- }
147
- /**
148
- * 检查字符串是否包含潜在的危险内容
149
- */ static containsDangerousContent(text) {
150
- const dangerousPatterns = [
151
- /<script[\s\S]*?>[\s\S]*?<\/script>/gi,
152
- /javascript:/gi,
153
- /on\w+\s*=/gi,
154
- /<iframe[\s\S]*?>/gi,
155
- /<object[\s\S]*?>/gi,
156
- /<embed[\s\S]*?>/gi,
157
- /<link[\s\S]*?>/gi,
158
- /<meta[\s\S]*?>/gi,
159
- /data:text\/html/gi,
160
- /vbscript:/gi,
161
- /expression\s*\(/gi,
162
- /@import/gi,
163
- /<style[\s\S]*?>[\s\S]*?<\/style>/gi
164
- ];
165
- return dangerousPatterns.some((pattern)=>pattern.test(text));
166
- }
167
- /**
168
- * 验证 URL 是否安全
169
- */ static isSafeUrl(url) {
170
- try {
171
- const urlObj = new URL(url);
172
- // 检查协议
173
- if (![
174
- 'http:',
175
- 'https:'
176
- ].includes(urlObj.protocol)) {
177
- return false;
178
- }
179
- // 检查是否包含危险内容
180
- return !this.containsDangerousContent(url);
181
- } catch {
182
- return false;
183
- }
184
- }
185
- /**
186
- * 检查字段名是否为敏感字段
187
- */ static isSensitiveField(fieldName) {
188
- const lowerFieldName = fieldName.toLowerCase();
189
- return SENSITIVE_FIELDS.some((field)=>lowerFieldName.includes(field.toLowerCase()));
190
- }
191
- /**
192
- * 检查值是否包含敏感信息(基于模式匹配)
193
- */ static containsSensitiveData(value) {
194
- return SENSITIVE_PATTERNS.some((pattern)=>pattern.test(value));
195
- }
196
- /**
197
- * 生成 CSP(Content Security Policy)头
198
- */ static generateCSP(config) {
199
- const directives = [];
200
- const allowUnsafeInline = config?.allowUnsafeInline ?? false;
201
- const allowUnsafeEval = config?.allowUnsafeEval ?? false;
202
- if (config?.defaultSrc) {
203
- directives.push(`default-src ${config.defaultSrc.join(' ')}`);
204
- } else {
205
- directives.push("default-src 'self'");
206
- }
207
- if (config?.scriptSrc) {
208
- directives.push(`script-src ${config.scriptSrc.join(' ')}`);
209
- } else {
210
- // 默认不允许 unsafe-inline 和 unsafe-eval,提高安全性
211
- const scriptSrc = [
212
- "'self'"
213
- ];
214
- if (allowUnsafeInline) {
215
- scriptSrc.push("'unsafe-inline'");
216
- }
217
- if (allowUnsafeEval) {
218
- scriptSrc.push("'unsafe-eval'");
219
- }
220
- directives.push(`script-src ${scriptSrc.join(' ')}`);
221
- }
222
- if (config?.styleSrc) {
223
- directives.push(`style-src ${config.styleSrc.join(' ')}`);
224
- } else {
225
- // 对于样式,可以使用 nonce 或 hash 替代 unsafe-inline
226
- const styleSrc = [
227
- "'self'"
228
- ];
229
- if (allowUnsafeInline) {
230
- styleSrc.push("'unsafe-inline'");
231
- }
232
- directives.push(`style-src ${styleSrc.join(' ')}`);
233
- }
234
- if (config?.imgSrc) {
235
- directives.push(`img-src ${config.imgSrc.join(' ')}`);
236
- } else {
237
- directives.push("img-src 'self' data: https:");
238
- }
239
- if (config?.connectSrc) {
240
- directives.push(`connect-src ${config.connectSrc.join(' ')}`);
241
- } else {
242
- directives.push("connect-src 'self'");
243
- }
244
- if (config?.fontSrc) {
245
- directives.push(`font-src ${config.fontSrc.join(' ')}`);
246
- } else {
247
- directives.push("font-src 'self' data:");
248
- }
249
- if (config?.frameSrc) {
250
- directives.push(`frame-src ${config.frameSrc.join(' ')}`);
251
- } else {
252
- directives.push("frame-src 'none'");
253
- }
254
- return directives.join('; ');
255
- }
256
- /**
257
- * 转义 HTML 特殊字符
258
- */ static escapeHTML(text) {
259
- const map = {
260
- '&': '&amp;',
261
- '<': '&lt;',
262
- '>': '&gt;',
263
- '"': '&quot;',
264
- "'": '&#039;'
265
- };
266
- return text.replace(/[&<>"']/g, (char)=>map[char]);
267
- }
268
- /**
269
- * 验证输入是否安全
270
- */ static validateInput(input) {
271
- if (typeof input !== 'string') {
272
- return {
273
- safe: true
274
- };
275
- }
276
- if (this.containsDangerousContent(input)) {
277
- return {
278
- safe: false,
279
- sanitized: this.sanitizeText(input),
280
- reason: '包含潜在的危险内容'
281
- };
282
- }
283
- // 检查是否包含敏感数据模式
284
- if (this.containsSensitiveData(input)) {
285
- return {
286
- safe: false,
287
- sanitized: this.sanitizeText(input),
288
- reason: '可能包含敏感信息'
289
- };
290
- }
291
- return {
292
- safe: true,
293
- sanitized: input
294
- };
295
- }
296
- /**
297
- * 深度脱敏处理(递归处理嵌套对象)
298
- */ static deepSanitize(data, maxDepth = 10, currentDepth = 0) {
299
- if (currentDepth >= maxDepth) {
300
- return '***'; // 防止无限递归
301
- }
302
- if (data === null || data === undefined) {
303
- return data;
304
- }
305
- if (typeof data === 'string') {
306
- if (this.containsDangerousContent(data) || this.containsSensitiveData(data)) {
307
- return this.sanitizeText(data);
308
- }
309
- return data;
310
- }
311
- if (typeof data === 'number' || typeof data === 'boolean') {
312
- return data;
313
- }
314
- if (Array.isArray(data)) {
315
- return data.map((item)=>this.deepSanitize(item, maxDepth, currentDepth + 1));
316
- }
317
- if (typeof data === 'object') {
318
- const sanitized = {};
319
- for (const [key, value] of Object.entries(data)){
320
- if (this.isSensitiveField(key)) {
321
- sanitized[key] = '***';
322
- } else {
323
- sanitized[key] = this.deepSanitize(value, maxDepth, currentDepth + 1);
324
- }
325
- }
326
- return sanitized;
327
- }
328
- return data;
329
- }
330
- };
19
+ const _utils = require("@vlian/utils");
331
20
 
332
21
  //# sourceMappingURL=security.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/utils/security.ts"],"sourcesContent":["import DOMPurify from 'dompurify';\nimport { SecurityError } from './errors';\n\n/**\n * XSS 防护配置\n */\nexport interface XSSConfig {\n /**\n * 是否允许 HTML 标签\n */\n allowHTML?: boolean;\n /**\n * 允许的 HTML 标签列表\n */\n allowedTags?: string[];\n /**\n * 允许的 HTML 属性列表\n */\n allowedAttributes?: string[];\n}\n\n/**\n * 敏感数据标识(扩展列表)\n */\nexport const SENSITIVE_FIELDS = [\n 'password',\n 'pwd',\n 'passwd',\n 'token',\n 'secret',\n 'key',\n 'apiKey',\n 'apikey',\n 'api_key',\n 'accessToken',\n 'access_token',\n 'refreshToken',\n 'refresh_token',\n 'authorization',\n 'auth',\n 'cookie',\n 'session',\n 'sessionId',\n 'session_id',\n 'creditCard',\n 'credit_card',\n 'cardNumber',\n 'card_number',\n 'cvv',\n 'cvc',\n 'ssn',\n 'socialSecurityNumber',\n 'social_security_number',\n 'phone',\n 'phoneNumber',\n 'phone_number',\n 'mobile',\n 'email',\n 'emailAddress',\n 'email_address',\n 'privateKey',\n 'private_key',\n 'secretKey',\n 'secret_key',\n 'apiSecret',\n 'api_secret',\n] as const;\n\n/**\n * 敏感信息检测模式(正则表达式)\n */\nconst SENSITIVE_PATTERNS = [\n /\\b\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}[\\s-]?\\d{4}\\b/, // 信用卡号\n /\\b\\d{3}-\\d{2}-\\d{4}\\b/, // SSN\n /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b/, // 邮箱(可选,根据需求决定是否脱敏)\n /\\b\\d{10,}\\b/, // 长数字(可能是敏感信息)\n] as const;\n\n/**\n * 安全工具类\n */\nexport class SecurityUtils {\n /**\n * 清理 HTML,防止 XSS 攻击\n */\n static sanitizeHTML(html: string, config?: XSSConfig): string {\n if (typeof window === 'undefined') {\n // Node.js 环境,返回原始字符串(需要服务端处理)\n return html;\n }\n\n try {\n if (config?.allowHTML) {\n // 默认禁止所有标签,除非明确允许\n const allowedTags = config.allowedTags && config.allowedTags.length > 0 \n ? config.allowedTags \n : [];\n const allowedAttributes = config.allowedAttributes && config.allowedAttributes.length > 0\n ? config.allowedAttributes\n : [];\n \n return DOMPurify.sanitize(html, {\n ALLOWED_TAGS: allowedTags,\n ALLOWED_ATTR: allowedAttributes,\n FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'form', 'link', 'meta', 'style'],\n FORBID_ATTR: ['onerror', 'onload', 'onclick', 'onmouseover', 'onfocus', 'onblur', 'onchange'],\n // 添加更多安全配置\n KEEP_CONTENT: false,\n RETURN_DOM: false,\n RETURN_DOM_FRAGMENT: false,\n RETURN_TRUSTED_TYPE: false,\n });\n }\n // 默认模式:完全清理,不允许任何 HTML\n return DOMPurify.sanitize(html, { \n ALLOWED_TAGS: [],\n KEEP_CONTENT: false,\n });\n } catch (error) {\n // 错误处理:不泄露敏感信息,记录错误但不抛出详细错误\n const errorMessage = error instanceof Error ? error.message : 'Unknown error';\n // 只记录错误类型,不记录具体内容\n console.error('HTML 清理失败:', errorMessage.substring(0, 50));\n // 返回安全的空字符串或清理后的文本\n return this.sanitizeText(html);\n }\n }\n\n /**\n * 清理文本内容(移除所有 HTML 标签)\n */\n static sanitizeText(text: string): string {\n if (typeof window === 'undefined') {\n return text.replace(/<[^>]*>/g, '');\n }\n\n try {\n return DOMPurify.sanitize(text, { ALLOWED_TAGS: [] });\n } catch (error) {\n throw new SecurityError('文本清理失败', error instanceof Error ? error : undefined);\n }\n }\n\n /**\n * 检查字符串是否包含潜在的危险内容\n */\n static containsDangerousContent(text: string): boolean {\n const dangerousPatterns = [\n /<script[\\s\\S]*?>[\\s\\S]*?<\\/script>/gi,\n /javascript:/gi,\n /on\\w+\\s*=/gi,\n /<iframe[\\s\\S]*?>/gi,\n /<object[\\s\\S]*?>/gi,\n /<embed[\\s\\S]*?>/gi,\n /<link[\\s\\S]*?>/gi,\n /<meta[\\s\\S]*?>/gi,\n /data:text\\/html/gi,\n /vbscript:/gi,\n /expression\\s*\\(/gi,\n /@import/gi,\n /<style[\\s\\S]*?>[\\s\\S]*?<\\/style>/gi,\n ];\n\n return dangerousPatterns.some((pattern) => pattern.test(text));\n }\n\n /**\n * 验证 URL 是否安全\n */\n static isSafeUrl(url: string): boolean {\n try {\n const urlObj = new URL(url);\n // 检查协议\n if (!['http:', 'https:'].includes(urlObj.protocol)) {\n return false;\n }\n // 检查是否包含危险内容\n return !this.containsDangerousContent(url);\n } catch {\n return false;\n }\n }\n\n /**\n * 检查字段名是否为敏感字段\n */\n static isSensitiveField(fieldName: string): boolean {\n const lowerFieldName = fieldName.toLowerCase();\n return SENSITIVE_FIELDS.some((field) => lowerFieldName.includes(field.toLowerCase()));\n }\n\n /**\n * 检查值是否包含敏感信息(基于模式匹配)\n */\n static containsSensitiveData(value: string): boolean {\n return SENSITIVE_PATTERNS.some((pattern) => pattern.test(value));\n }\n\n /**\n * 生成 CSP(Content Security Policy)头\n */\n static generateCSP(config?: {\n defaultSrc?: string[];\n scriptSrc?: string[];\n styleSrc?: string[];\n imgSrc?: string[];\n connectSrc?: string[];\n fontSrc?: string[];\n frameSrc?: string[];\n allowUnsafeInline?: boolean; // 是否允许 unsafe-inline(不推荐)\n allowUnsafeEval?: boolean; // 是否允许 unsafe-eval(不推荐)\n }): string {\n const directives: string[] = [];\n const allowUnsafeInline = config?.allowUnsafeInline ?? false;\n const allowUnsafeEval = config?.allowUnsafeEval ?? false;\n\n if (config?.defaultSrc) {\n directives.push(`default-src ${config.defaultSrc.join(' ')}`);\n } else {\n directives.push(\"default-src 'self'\");\n }\n\n if (config?.scriptSrc) {\n directives.push(`script-src ${config.scriptSrc.join(' ')}`);\n } else {\n // 默认不允许 unsafe-inline 和 unsafe-eval,提高安全性\n const scriptSrc = [\"'self'\"];\n if (allowUnsafeInline) {\n scriptSrc.push(\"'unsafe-inline'\");\n }\n if (allowUnsafeEval) {\n scriptSrc.push(\"'unsafe-eval'\");\n }\n directives.push(`script-src ${scriptSrc.join(' ')}`);\n }\n\n if (config?.styleSrc) {\n directives.push(`style-src ${config.styleSrc.join(' ')}`);\n } else {\n // 对于样式,可以使用 nonce 或 hash 替代 unsafe-inline\n const styleSrc = [\"'self'\"];\n if (allowUnsafeInline) {\n styleSrc.push(\"'unsafe-inline'\");\n }\n directives.push(`style-src ${styleSrc.join(' ')}`);\n }\n\n if (config?.imgSrc) {\n directives.push(`img-src ${config.imgSrc.join(' ')}`);\n } else {\n directives.push(\"img-src 'self' data: https:\");\n }\n\n if (config?.connectSrc) {\n directives.push(`connect-src ${config.connectSrc.join(' ')}`);\n } else {\n directives.push(\"connect-src 'self'\");\n }\n\n if (config?.fontSrc) {\n directives.push(`font-src ${config.fontSrc.join(' ')}`);\n } else {\n directives.push(\"font-src 'self' data:\");\n }\n\n if (config?.frameSrc) {\n directives.push(`frame-src ${config.frameSrc.join(' ')}`);\n } else {\n directives.push(\"frame-src 'none'\");\n }\n\n return directives.join('; ');\n }\n\n /**\n * 转义 HTML 特殊字符\n */\n static escapeHTML(text: string): string {\n const map: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#039;',\n };\n return text.replace(/[&<>\"']/g, (char) => map[char]);\n }\n\n /**\n * 验证输入是否安全\n */\n static validateInput(input: unknown): {\n safe: boolean;\n sanitized?: string;\n reason?: string;\n } {\n if (typeof input !== 'string') {\n return { safe: true };\n }\n\n if (this.containsDangerousContent(input)) {\n return {\n safe: false,\n sanitized: this.sanitizeText(input),\n reason: '包含潜在的危险内容',\n };\n }\n\n // 检查是否包含敏感数据模式\n if (this.containsSensitiveData(input)) {\n return {\n safe: false,\n sanitized: this.sanitizeText(input),\n reason: '可能包含敏感信息',\n };\n }\n\n return { safe: true, sanitized: input };\n }\n\n /**\n * 深度脱敏处理(递归处理嵌套对象)\n */\n static deepSanitize(data: unknown, maxDepth: number = 10, currentDepth: number = 0): unknown {\n if (currentDepth >= maxDepth) {\n return '***'; // 防止无限递归\n }\n\n if (data === null || data === undefined) {\n return data;\n }\n\n if (typeof data === 'string') {\n if (this.containsDangerousContent(data) || this.containsSensitiveData(data)) {\n return this.sanitizeText(data);\n }\n return data;\n }\n\n if (typeof data === 'number' || typeof data === 'boolean') {\n return data;\n }\n\n if (Array.isArray(data)) {\n return data.map((item) => this.deepSanitize(item, maxDepth, currentDepth + 1));\n }\n\n if (typeof data === 'object') {\n const sanitized: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n if (this.isSensitiveField(key)) {\n sanitized[key] = '***';\n } else {\n sanitized[key] = this.deepSanitize(value, maxDepth, currentDepth + 1);\n }\n }\n return sanitized;\n }\n\n return data;\n }\n}\n"],"names":["SENSITIVE_FIELDS","SecurityUtils","SENSITIVE_PATTERNS","sanitizeHTML","html","config","window","allowHTML","allowedTags","length","allowedAttributes","DOMPurify","sanitize","ALLOWED_TAGS","ALLOWED_ATTR","FORBID_TAGS","FORBID_ATTR","KEEP_CONTENT","RETURN_DOM","RETURN_DOM_FRAGMENT","RETURN_TRUSTED_TYPE","error","errorMessage","Error","message","console","substring","sanitizeText","text","replace","SecurityError","undefined","containsDangerousContent","dangerousPatterns","some","pattern","test","isSafeUrl","url","urlObj","URL","includes","protocol","isSensitiveField","fieldName","lowerFieldName","toLowerCase","field","containsSensitiveData","value","generateCSP","directives","allowUnsafeInline","allowUnsafeEval","defaultSrc","push","join","scriptSrc","styleSrc","imgSrc","connectSrc","fontSrc","frameSrc","escapeHTML","map","char","validateInput","input","safe","sanitized","reason","deepSanitize","data","maxDepth","currentDepth","Array","isArray","item","key","Object","entries"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/utils/security.ts"],"sourcesContent":["export { SecurityUtils, SENSITIVE_FIELDS } from '@vlian/utils';\nexport type { XSSConfig } from '@vlian/utils';\n"],"names":["SENSITIVE_FIELDS","SecurityUtils"],"mappings":";;;;;;;;;;;QAAwBA;eAAAA,uBAAgB;;QAA/BC;eAAAA,oBAAa;;;uBAA0B"}
@@ -1,80 +1,2 @@
1
- /**
2
- * XSS 防护配置
3
- */
4
- export interface XSSConfig {
5
- /**
6
- * 是否允许 HTML 标签
7
- */
8
- allowHTML?: boolean;
9
- /**
10
- * 允许的 HTML 标签列表
11
- */
12
- allowedTags?: string[];
13
- /**
14
- * 允许的 HTML 属性列表
15
- */
16
- allowedAttributes?: string[];
17
- }
18
- /**
19
- * 敏感数据标识(扩展列表)
20
- */
21
- export declare const SENSITIVE_FIELDS: readonly ["password", "pwd", "passwd", "token", "secret", "key", "apiKey", "apikey", "api_key", "accessToken", "access_token", "refreshToken", "refresh_token", "authorization", "auth", "cookie", "session", "sessionId", "session_id", "creditCard", "credit_card", "cardNumber", "card_number", "cvv", "cvc", "ssn", "socialSecurityNumber", "social_security_number", "phone", "phoneNumber", "phone_number", "mobile", "email", "emailAddress", "email_address", "privateKey", "private_key", "secretKey", "secret_key", "apiSecret", "api_secret"];
22
- /**
23
- * 安全工具类
24
- */
25
- export declare class SecurityUtils {
26
- /**
27
- * 清理 HTML,防止 XSS 攻击
28
- */
29
- static sanitizeHTML(html: string, config?: XSSConfig): string;
30
- /**
31
- * 清理文本内容(移除所有 HTML 标签)
32
- */
33
- static sanitizeText(text: string): string;
34
- /**
35
- * 检查字符串是否包含潜在的危险内容
36
- */
37
- static containsDangerousContent(text: string): boolean;
38
- /**
39
- * 验证 URL 是否安全
40
- */
41
- static isSafeUrl(url: string): boolean;
42
- /**
43
- * 检查字段名是否为敏感字段
44
- */
45
- static isSensitiveField(fieldName: string): boolean;
46
- /**
47
- * 检查值是否包含敏感信息(基于模式匹配)
48
- */
49
- static containsSensitiveData(value: string): boolean;
50
- /**
51
- * 生成 CSP(Content Security Policy)头
52
- */
53
- static generateCSP(config?: {
54
- defaultSrc?: string[];
55
- scriptSrc?: string[];
56
- styleSrc?: string[];
57
- imgSrc?: string[];
58
- connectSrc?: string[];
59
- fontSrc?: string[];
60
- frameSrc?: string[];
61
- allowUnsafeInline?: boolean;
62
- allowUnsafeEval?: boolean;
63
- }): string;
64
- /**
65
- * 转义 HTML 特殊字符
66
- */
67
- static escapeHTML(text: string): string;
68
- /**
69
- * 验证输入是否安全
70
- */
71
- static validateInput(input: unknown): {
72
- safe: boolean;
73
- sanitized?: string;
74
- reason?: string;
75
- };
76
- /**
77
- * 深度脱敏处理(递归处理嵌套对象)
78
- */
79
- static deepSanitize(data: unknown, maxDepth?: number, currentDepth?: number): unknown;
80
- }
1
+ export { SecurityUtils, SENSITIVE_FIELDS } from '@vlian/utils';
2
+ export type { XSSConfig } from '@vlian/utils';