mcp-wordpress 1.2.2 → 1.3.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 +210 -182
- package/dist/cache/CacheInvalidation.d.ts +3 -3
- package/dist/cache/CacheInvalidation.d.ts.map +1 -1
- package/dist/cache/CacheInvalidation.js +119 -119
- package/dist/cache/CacheInvalidation.js.map +1 -1
- package/dist/cache/CacheManager.d.ts +5 -0
- package/dist/cache/CacheManager.d.ts.map +1 -1
- package/dist/cache/CacheManager.js +26 -16
- package/dist/cache/CacheManager.js.map +1 -1
- package/dist/cache/HttpCacheWrapper.d.ts +1 -1
- package/dist/cache/HttpCacheWrapper.d.ts.map +1 -1
- package/dist/cache/HttpCacheWrapper.js +29 -29
- package/dist/cache/HttpCacheWrapper.js.map +1 -1
- package/dist/cache/__tests__/CacheInvalidation.test.js +96 -94
- package/dist/cache/__tests__/CacheInvalidation.test.js.map +1 -1
- package/dist/cache/__tests__/CacheManager.test.js +113 -113
- package/dist/cache/__tests__/CacheManager.test.js.map +1 -1
- package/dist/cache/__tests__/CachedWordPressClient.test.js +102 -99
- package/dist/cache/__tests__/CachedWordPressClient.test.js.map +1 -1
- package/dist/cache/__tests__/HttpCacheWrapper.test.js +98 -95
- package/dist/cache/__tests__/HttpCacheWrapper.test.js.map +1 -1
- package/dist/cache/index.d.ts +7 -7
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +4 -4
- package/dist/cache/index.js.map +1 -1
- package/dist/client/CachedWordPressClient.d.ts +4 -4
- package/dist/client/CachedWordPressClient.d.ts.map +1 -1
- package/dist/client/CachedWordPressClient.js +55 -51
- package/dist/client/CachedWordPressClient.js.map +1 -1
- package/dist/client/api.d.ts +10 -10
- package/dist/client/api.js +158 -158
- package/dist/client/api.js.map +1 -1
- package/dist/client/auth.d.ts +2 -2
- package/dist/client/auth.js +72 -72
- package/dist/client/managers/AuthenticationManager.d.ts +2 -2
- package/dist/client/managers/AuthenticationManager.js +46 -46
- package/dist/client/managers/BaseManager.d.ts +1 -1
- package/dist/client/managers/BaseManager.js +9 -9
- package/dist/client/managers/RequestManager.d.ts +5 -3
- package/dist/client/managers/RequestManager.d.ts.map +1 -1
- package/dist/client/managers/RequestManager.js +39 -19
- package/dist/client/managers/RequestManager.js.map +1 -1
- package/dist/client/managers/index.d.ts +3 -3
- package/dist/client/managers/index.js +3 -3
- package/dist/config/ConfigurationSchema.d.ts +2 -2
- package/dist/config/ConfigurationSchema.d.ts.map +1 -1
- package/dist/config/ConfigurationSchema.js +40 -40
- package/dist/config/ConfigurationSchema.js.map +1 -1
- package/dist/config/ServerConfiguration.d.ts +2 -2
- package/dist/config/ServerConfiguration.js +35 -35
- package/dist/config/ServerConfiguration.js.map +1 -1
- package/dist/docs/DocumentationGenerator.d.ts.map +1 -1
- package/dist/docs/DocumentationGenerator.js +296 -255
- package/dist/docs/DocumentationGenerator.js.map +1 -1
- package/dist/docs/MarkdownFormatter.d.ts +1 -1
- package/dist/docs/MarkdownFormatter.d.ts.map +1 -1
- package/dist/docs/MarkdownFormatter.js +60 -51
- package/dist/docs/MarkdownFormatter.js.map +1 -1
- package/dist/docs/index.d.ts +3 -3
- package/dist/docs/index.d.ts.map +1 -1
- package/dist/docs/index.js +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -16
- package/dist/index.js.map +1 -1
- package/dist/mcp-wordpress-1.3.0.tgz +0 -0
- package/dist/performance/MetricsCollector.d.ts +3 -3
- package/dist/performance/MetricsCollector.d.ts.map +1 -1
- package/dist/performance/MetricsCollector.js +33 -27
- package/dist/performance/MetricsCollector.js.map +1 -1
- package/dist/performance/PerformanceAnalytics.d.ts +12 -12
- package/dist/performance/PerformanceAnalytics.d.ts.map +1 -1
- package/dist/performance/PerformanceAnalytics.js +200 -154
- package/dist/performance/PerformanceAnalytics.js.map +1 -1
- package/dist/performance/PerformanceMonitor.d.ts +5 -5
- package/dist/performance/PerformanceMonitor.d.ts.map +1 -1
- package/dist/performance/PerformanceMonitor.js +53 -52
- package/dist/performance/PerformanceMonitor.js.map +1 -1
- package/dist/performance/index.d.ts +6 -6
- package/dist/performance/index.d.ts.map +1 -1
- package/dist/performance/index.js +3 -3
- package/dist/security/InputValidator.d.ts +1 -1
- package/dist/security/InputValidator.d.ts.map +1 -1
- package/dist/security/InputValidator.js +111 -88
- package/dist/security/InputValidator.js.map +1 -1
- package/dist/security/SecurityConfig.d.ts +5 -5
- package/dist/security/SecurityConfig.js +92 -92
- package/dist/security/SecurityConfig.js.map +1 -1
- package/dist/server/ConnectionTester.d.ts +1 -1
- package/dist/server/ConnectionTester.d.ts.map +1 -1
- package/dist/server/ConnectionTester.js +4 -4
- package/dist/server/ConnectionTester.js.map +1 -1
- package/dist/server/ToolRegistry.d.ts +2 -2
- package/dist/server/ToolRegistry.d.ts.map +1 -1
- package/dist/server/ToolRegistry.js +35 -32
- package/dist/server/ToolRegistry.js.map +1 -1
- package/dist/server.d.ts +2 -2
- package/dist/server.js +2 -2
- package/dist/tools/BaseToolManager.js +5 -5
- package/dist/tools/auth.d.ts +2 -2
- package/dist/tools/auth.d.ts.map +1 -1
- package/dist/tools/auth.js +32 -31
- package/dist/tools/auth.js.map +1 -1
- package/dist/tools/cache.d.ts +1 -1
- package/dist/tools/cache.d.ts.map +1 -1
- package/dist/tools/cache.js +71 -71
- package/dist/tools/cache.js.map +1 -1
- package/dist/tools/comments.d.ts +2 -2
- package/dist/tools/comments.d.ts.map +1 -1
- package/dist/tools/comments.js +79 -79
- package/dist/tools/comments.js.map +1 -1
- package/dist/tools/index.d.ts +10 -10
- package/dist/tools/index.js +10 -10
- package/dist/tools/media.d.ts +2 -2
- package/dist/tools/media.js +80 -80
- package/dist/tools/pages.d.ts +2 -2
- package/dist/tools/pages.d.ts.map +1 -1
- package/dist/tools/pages.js +75 -75
- package/dist/tools/pages.js.map +1 -1
- package/dist/tools/performance.d.ts +1 -1
- package/dist/tools/performance.d.ts.map +1 -1
- package/dist/tools/performance.js +311 -287
- package/dist/tools/performance.js.map +1 -1
- package/dist/tools/posts.d.ts +2 -2
- package/dist/tools/posts.d.ts.map +1 -1
- package/dist/tools/posts.js +94 -94
- package/dist/tools/posts.js.map +1 -1
- package/dist/tools/site.d.ts +2 -2
- package/dist/tools/site.d.ts.map +1 -1
- package/dist/tools/site.js +60 -60
- package/dist/tools/site.js.map +1 -1
- package/dist/tools/taxonomies.d.ts +2 -2
- package/dist/tools/taxonomies.js +89 -89
- package/dist/tools/users.d.ts +2 -2
- package/dist/tools/users.js +68 -68
- package/dist/tools/users.js.map +1 -1
- package/dist/types/client.d.ts +13 -13
- package/dist/types/client.d.ts.map +1 -1
- package/dist/types/client.js +12 -12
- package/dist/types/client.js.map +1 -1
- package/dist/types/index.d.ts +19 -19
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +3 -3
- package/dist/types/mcp.d.ts +7 -7
- package/dist/types/wordpress.d.ts +21 -21
- package/dist/types/wordpress.d.ts.map +1 -1
- package/dist/utils/debug.d.ts +2 -2
- package/dist/utils/debug.js +28 -28
- package/dist/utils/error.d.ts.map +1 -1
- package/dist/utils/error.js +13 -13
- package/dist/utils/error.js.map +1 -1
- package/dist/utils/toolWrapper.d.ts.map +1 -1
- package/dist/utils/toolWrapper.js +5 -5
- package/dist/utils/toolWrapper.js.map +1 -1
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +41 -31
- package/dist/utils/validation.js.map +1 -1
- package/docs/CACHING.md +36 -2
- package/docs/DOCKER.md +24 -18
- package/docs/PERFORMANCE_MONITORING.md +49 -1
- package/docs/SECURITY_TESTING.md +30 -1
- package/docs/api/README.md +9 -1
- package/docs/api/summary.json +1 -1
- package/docs/contract-testing.md +24 -3
- package/docs/developer/GITHUB_ACTIONS_SETUP.md +8 -2
- package/docs/developer/MAINTENANCE.md +29 -3
- package/docs/developer/MIGRATION_GUIDE.md +13 -1
- package/docs/developer/NPM_AUTH_SETUP.md +13 -2
- package/docs/developer/REFACTORING.md +31 -1
- package/docs/releases/COMMUNITY_ANNOUNCEMENT_v1.1.2.md +18 -7
- package/docs/releases/RELEASE_NOTES_v1.1.2.md +31 -5
- package/docs/user-guides/DOCKER_SETUP.md +264 -0
- package/docs/user-guides/DTX_SETUP.md +327 -0
- package/docs/user-guides/NPM_SETUP.md +109 -0
- package/docs/user-guides/NPX_SETUP.md +281 -0
- package/docs/wordpress-rest-api-authentication-troubleshooting.md +13 -2
- package/package.json +27 -8
- package/src/cache/CacheInvalidation.ts +140 -132
- package/src/cache/CacheManager.ts +40 -29
- package/src/cache/HttpCacheWrapper.ts +105 -68
- package/src/cache/__tests__/CacheInvalidation.test.ts +123 -118
- package/src/cache/__tests__/CacheManager.test.ts +156 -152
- package/src/cache/__tests__/CachedWordPressClient.test.ts +131 -116
- package/src/cache/__tests__/HttpCacheWrapper.test.ts +118 -115
- package/src/cache/index.ts +13 -13
- package/src/client/CachedWordPressClient.ts +90 -80
- package/src/client/api.ts +205 -205
- package/src/client/auth.ts +80 -80
- package/src/client/managers/AuthenticationManager.ts +61 -61
- package/src/client/managers/BaseManager.ts +11 -11
- package/src/client/managers/RequestManager.ts +79 -47
- package/src/client/managers/index.ts +3 -3
- package/src/config/ConfigurationSchema.ts +44 -44
- package/src/config/ServerConfiguration.ts +39 -39
- package/src/docs/DocumentationGenerator.ts +402 -295
- package/src/docs/MarkdownFormatter.ts +94 -69
- package/src/docs/index.ts +4 -4
- package/src/index.ts +24 -21
- package/src/performance/MetricsCollector.ts +90 -58
- package/src/performance/PerformanceAnalytics.ts +386 -262
- package/src/performance/PerformanceMonitor.ts +152 -118
- package/src/performance/index.ts +9 -9
- package/src/security/InputValidator.ts +148 -91
- package/src/security/SecurityConfig.ts +94 -94
- package/src/server/ConnectionTester.ts +21 -15
- package/src/server/ToolRegistry.ts +64 -51
- package/src/server.ts +2 -2
- package/src/tools/BaseToolManager.ts +6 -6
- package/src/tools/auth.ts +42 -37
- package/src/tools/cache.ts +85 -81
- package/src/tools/comments.ts +93 -91
- package/src/tools/index.ts +10 -10
- package/src/tools/media.ts +89 -89
- package/src/tools/pages.ts +89 -87
- package/src/tools/performance.ts +443 -352
- package/src/tools/posts.ts +109 -107
- package/src/tools/site.ts +86 -77
- package/src/tools/taxonomies.ts +102 -102
- package/src/tools/users.ts +77 -77
- package/src/types/client.ts +157 -60
- package/src/types/index.ts +49 -27
- package/src/types/mcp.ts +15 -15
- package/src/types/wordpress.ts +57 -29
- package/src/utils/debug.ts +37 -37
- package/src/utils/error.ts +47 -25
- package/src/utils/toolWrapper.ts +12 -8
- package/src/utils/validation.ts +116 -65
- package/dist/client/WordPressClient.d.ts +0 -81
- package/dist/client/WordPressClient.d.ts.map +0 -1
- package/dist/client/WordPressClient.js +0 -354
- package/dist/client/WordPressClient.js.map +0 -1
- package/dist/performance/AnomalyDetector.d.ts +0 -63
- package/dist/performance/AnomalyDetector.d.ts.map +0 -1
- package/dist/performance/AnomalyDetector.js +0 -222
- package/dist/performance/AnomalyDetector.js.map +0 -1
- package/dist/performance/BenchmarkAnalyzer.d.ts +0 -67
- package/dist/performance/BenchmarkAnalyzer.d.ts.map +0 -1
- package/dist/performance/BenchmarkAnalyzer.js +0 -301
- package/dist/performance/BenchmarkAnalyzer.js.map +0 -1
- package/dist/performance/TrendAnalyzer.d.ts +0 -69
- package/dist/performance/TrendAnalyzer.d.ts.map +0 -1
- package/dist/performance/TrendAnalyzer.js +0 -203
- package/dist/performance/TrendAnalyzer.js.map +0 -1
- package/dist/tools/BaseToolClass.d.ts +0 -76
- package/dist/tools/BaseToolClass.d.ts.map +0 -1
- package/dist/tools/BaseToolClass.js +0 -104
- package/dist/tools/BaseToolClass.js.map +0 -1
- package/dist/tools/base.d.ts +0 -37
- package/dist/tools/base.d.ts.map +0 -1
- package/dist/tools/base.js +0 -60
- package/dist/tools/base.js.map +0 -1
- package/docs/user-guides/CLAUDE_DESKTOP_SETUP.md +0 -187
|
@@ -3,95 +3,130 @@
|
|
|
3
3
|
* Provides security-focused validation for all MCP tool inputs
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import { z } from
|
|
6
|
+
import { z } from "zod";
|
|
7
7
|
|
|
8
8
|
// Common validation patterns
|
|
9
9
|
const URL_PATTERN = /^https?:\/\/[^\s<>'"{}|\\^`\[\]]+$/;
|
|
10
10
|
const EMAIL_PATTERN = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
|
11
11
|
const SLUG_PATTERN = /^[a-z0-9-]+$/;
|
|
12
12
|
const SCRIPT_PATTERN = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi;
|
|
13
|
-
const SQL_INJECTION_PATTERN =
|
|
13
|
+
const SQL_INJECTION_PATTERN =
|
|
14
|
+
/('|(\\')|(;)|(\\x00)|(\\n)|(\\r)|(\\x1a)|(\\x22)|(\\x27)|(\\x5c)|(\\x60))/i;
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Security validation schemas
|
|
17
18
|
*/
|
|
18
19
|
export const SecuritySchemas = {
|
|
19
20
|
// Safe string with XSS protection
|
|
20
|
-
safeString: z
|
|
21
|
-
.
|
|
22
|
-
.
|
|
23
|
-
.refine(val => !
|
|
24
|
-
.refine(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
safeString: z
|
|
22
|
+
.string()
|
|
23
|
+
.max(10000, "String too long")
|
|
24
|
+
.refine((val) => !SCRIPT_PATTERN.test(val), "Script tags not allowed")
|
|
25
|
+
.refine(
|
|
26
|
+
(val) => !val.includes("javascript:"),
|
|
27
|
+
"JavaScript URLs not allowed",
|
|
28
|
+
)
|
|
29
|
+
.refine((val) => !val.includes("data:"), "Data URLs not allowed")
|
|
30
|
+
.refine((val) => !val.includes("onerror="), "Event handlers not allowed")
|
|
31
|
+
.refine((val) => !val.includes("onload="), "Event handlers not allowed")
|
|
32
|
+
.refine((val) => !val.includes("onfocus="), "Event handlers not allowed"),
|
|
28
33
|
|
|
29
34
|
// HTML content with basic sanitization
|
|
30
|
-
htmlContent: z
|
|
31
|
-
.
|
|
32
|
-
.
|
|
33
|
-
.refine(val => !
|
|
34
|
-
.refine(
|
|
35
|
+
htmlContent: z
|
|
36
|
+
.string()
|
|
37
|
+
.max(100000, "Content too long")
|
|
38
|
+
.refine((val) => !SCRIPT_PATTERN.test(val), "Script tags not allowed")
|
|
39
|
+
.refine(
|
|
40
|
+
(val) => !val.includes("javascript:"),
|
|
41
|
+
"JavaScript URLs not allowed",
|
|
42
|
+
)
|
|
43
|
+
.refine((val) => !val.includes("on[a-z]+="), "Event handlers not allowed"),
|
|
35
44
|
|
|
36
45
|
// URL validation
|
|
37
|
-
url: z
|
|
38
|
-
.
|
|
39
|
-
.
|
|
40
|
-
.
|
|
41
|
-
.refine(
|
|
46
|
+
url: z
|
|
47
|
+
.string()
|
|
48
|
+
.url("Invalid URL format")
|
|
49
|
+
.regex(URL_PATTERN, "URL contains invalid characters")
|
|
50
|
+
.refine(
|
|
51
|
+
(val) => !val.includes("javascript:"),
|
|
52
|
+
"JavaScript URLs not allowed",
|
|
53
|
+
)
|
|
54
|
+
.refine((val) => !val.includes("data:"), "Data URLs not allowed"),
|
|
42
55
|
|
|
43
56
|
// Email validation
|
|
44
|
-
email: z
|
|
45
|
-
.
|
|
46
|
-
.
|
|
47
|
-
.
|
|
57
|
+
email: z
|
|
58
|
+
.string()
|
|
59
|
+
.email("Invalid email format")
|
|
60
|
+
.regex(EMAIL_PATTERN, "Email contains invalid characters")
|
|
61
|
+
.max(254, "Email too long"),
|
|
48
62
|
|
|
49
63
|
// Slug validation (for URLs, usernames, etc.)
|
|
50
|
-
slug: z
|
|
51
|
-
.
|
|
52
|
-
.
|
|
53
|
-
.
|
|
64
|
+
slug: z
|
|
65
|
+
.string()
|
|
66
|
+
.min(1, "Slug cannot be empty")
|
|
67
|
+
.max(100, "Slug too long")
|
|
68
|
+
.regex(
|
|
69
|
+
SLUG_PATTERN,
|
|
70
|
+
"Slug can only contain lowercase letters, numbers, and hyphens",
|
|
71
|
+
),
|
|
54
72
|
|
|
55
73
|
// WordPress post/page content
|
|
56
|
-
wpContent: z
|
|
57
|
-
.
|
|
58
|
-
.
|
|
59
|
-
.refine(
|
|
74
|
+
wpContent: z
|
|
75
|
+
.string()
|
|
76
|
+
.max(1000000, "Content too long")
|
|
77
|
+
.refine(
|
|
78
|
+
(val) => !SCRIPT_PATTERN.test(val),
|
|
79
|
+
"Script tags not allowed in content",
|
|
80
|
+
)
|
|
81
|
+
.refine(
|
|
82
|
+
(val) => !val.includes("javascript:"),
|
|
83
|
+
"JavaScript URLs not allowed",
|
|
84
|
+
),
|
|
60
85
|
|
|
61
86
|
// Site ID validation
|
|
62
|
-
siteId: z
|
|
63
|
-
.
|
|
64
|
-
.
|
|
65
|
-
.
|
|
87
|
+
siteId: z
|
|
88
|
+
.string()
|
|
89
|
+
.min(1, "Site ID cannot be empty")
|
|
90
|
+
.max(50, "Site ID too long")
|
|
91
|
+
.regex(
|
|
92
|
+
/^[a-zA-Z0-9\-_]+$/,
|
|
93
|
+
"Site ID can only contain letters, numbers, hyphens, and underscores",
|
|
94
|
+
),
|
|
66
95
|
|
|
67
96
|
// WordPress ID (numeric)
|
|
68
|
-
wpId: z
|
|
69
|
-
.
|
|
70
|
-
.
|
|
71
|
-
.
|
|
97
|
+
wpId: z
|
|
98
|
+
.number()
|
|
99
|
+
.int("ID must be an integer")
|
|
100
|
+
.positive("ID must be positive")
|
|
101
|
+
.max(999999999, "ID too large"),
|
|
72
102
|
|
|
73
103
|
// Search query with SQL injection protection
|
|
74
|
-
searchQuery: z
|
|
75
|
-
.
|
|
76
|
-
.
|
|
77
|
-
.refine(
|
|
78
|
-
|
|
104
|
+
searchQuery: z
|
|
105
|
+
.string()
|
|
106
|
+
.max(500, "Search query too long")
|
|
107
|
+
.refine(
|
|
108
|
+
(val) => !SQL_INJECTION_PATTERN.test(val),
|
|
109
|
+
"Invalid characters in search query",
|
|
110
|
+
)
|
|
111
|
+
.refine((val) => !val.includes("--"), "SQL comments not allowed")
|
|
112
|
+
.refine((val) => !val.includes("/*"), "SQL comments not allowed"),
|
|
79
113
|
|
|
80
114
|
// File path validation
|
|
81
|
-
filePath: z
|
|
82
|
-
.
|
|
83
|
-
.
|
|
84
|
-
.refine(val => !val.includes(
|
|
85
|
-
.refine(val => !val.includes(
|
|
115
|
+
filePath: z
|
|
116
|
+
.string()
|
|
117
|
+
.max(500, "File path too long")
|
|
118
|
+
.refine((val) => !val.includes(".."), "Path traversal not allowed")
|
|
119
|
+
.refine((val) => !val.includes("<"), "Invalid characters in path")
|
|
120
|
+
.refine((val) => !val.includes(">"), "Invalid characters in path"),
|
|
86
121
|
|
|
87
122
|
// Password (for display/logging - never log actual passwords)
|
|
88
|
-
passwordMask: z.string()
|
|
89
|
-
.transform(() => '[REDACTED]'),
|
|
123
|
+
passwordMask: z.string().transform(() => "[REDACTED]"),
|
|
90
124
|
|
|
91
125
|
// WordPress application password format
|
|
92
|
-
appPassword: z
|
|
93
|
-
.
|
|
94
|
-
.
|
|
126
|
+
appPassword: z
|
|
127
|
+
.string()
|
|
128
|
+
.regex(/^[a-zA-Z0-9\s]{24}$/, "Invalid application password format")
|
|
129
|
+
.transform((val) => val.replace(/\s/g, " ")), // Normalize spaces
|
|
95
130
|
};
|
|
96
131
|
|
|
97
132
|
/**
|
|
@@ -103,13 +138,13 @@ export class InputSanitizer {
|
|
|
103
138
|
*/
|
|
104
139
|
static sanitizeHtml(input: string): string {
|
|
105
140
|
return input
|
|
106
|
-
.replace(SCRIPT_PATTERN,
|
|
107
|
-
.replace(/javascript:/gi,
|
|
108
|
-
.replace(/data:/gi,
|
|
109
|
-
.replace(/on[a-z]+\s*=/gi,
|
|
110
|
-
.replace(/<iframe[^>]*>/gi,
|
|
111
|
-
.replace(/<object[^>]*>/gi,
|
|
112
|
-
.replace(/<embed[^>]*>/gi,
|
|
141
|
+
.replace(SCRIPT_PATTERN, "") // Remove script tags
|
|
142
|
+
.replace(/javascript:/gi, "") // Remove javascript: URLs
|
|
143
|
+
.replace(/data:/gi, "") // Remove data: URLs
|
|
144
|
+
.replace(/on[a-z]+\s*=/gi, "") // Remove event handlers
|
|
145
|
+
.replace(/<iframe[^>]*>/gi, "") // Remove iframes
|
|
146
|
+
.replace(/<object[^>]*>/gi, "") // Remove objects
|
|
147
|
+
.replace(/<embed[^>]*>/gi, ""); // Remove embeds
|
|
113
148
|
}
|
|
114
149
|
|
|
115
150
|
/**
|
|
@@ -117,10 +152,10 @@ export class InputSanitizer {
|
|
|
117
152
|
*/
|
|
118
153
|
static sanitizeSearchQuery(query: string): string {
|
|
119
154
|
return query
|
|
120
|
-
.replace(/['"\\;]/g,
|
|
121
|
-
.replace(/--/g,
|
|
122
|
-
.replace(/\/\*/g,
|
|
123
|
-
.replace(/\*/g,
|
|
155
|
+
.replace(/['"\\;]/g, "") // Remove quotes and backslashes
|
|
156
|
+
.replace(/--/g, "") // Remove SQL comments
|
|
157
|
+
.replace(/\/\*/g, "") // Remove SQL comments
|
|
158
|
+
.replace(/\*/g, "") // Remove wildcards
|
|
124
159
|
.trim()
|
|
125
160
|
.substring(0, 500); // Limit length
|
|
126
161
|
}
|
|
@@ -130,9 +165,9 @@ export class InputSanitizer {
|
|
|
130
165
|
*/
|
|
131
166
|
static sanitizeFilePath(path: string): string {
|
|
132
167
|
return path
|
|
133
|
-
.replace(/\.\./g,
|
|
134
|
-
.replace(/[<>]/g,
|
|
135
|
-
.replace(/[|&;$`\\]/g,
|
|
168
|
+
.replace(/\.\./g, "") // Remove directory traversal
|
|
169
|
+
.replace(/[<>]/g, "") // Remove angle brackets
|
|
170
|
+
.replace(/[|&;$`\\]/g, "") // Remove shell metacharacters
|
|
136
171
|
.trim();
|
|
137
172
|
}
|
|
138
173
|
|
|
@@ -141,11 +176,11 @@ export class InputSanitizer {
|
|
|
141
176
|
*/
|
|
142
177
|
static encodeOutput(input: string): string {
|
|
143
178
|
return input
|
|
144
|
-
.replace(/&/g,
|
|
145
|
-
.replace(/</g,
|
|
146
|
-
.replace(/>/g,
|
|
147
|
-
.replace(/"/g,
|
|
148
|
-
.replace(/'/g,
|
|
179
|
+
.replace(/&/g, "&")
|
|
180
|
+
.replace(/</g, "<")
|
|
181
|
+
.replace(/>/g, ">")
|
|
182
|
+
.replace(/"/g, """)
|
|
183
|
+
.replace(/'/g, "'");
|
|
149
184
|
}
|
|
150
185
|
}
|
|
151
186
|
|
|
@@ -153,7 +188,11 @@ export class InputSanitizer {
|
|
|
153
188
|
* Security validation decorator for tool methods
|
|
154
189
|
*/
|
|
155
190
|
export function validateSecurity(schema: z.ZodSchema) {
|
|
156
|
-
return function (
|
|
191
|
+
return function (
|
|
192
|
+
target: any,
|
|
193
|
+
propertyName: string,
|
|
194
|
+
descriptor: PropertyDescriptor,
|
|
195
|
+
) {
|
|
157
196
|
const method = descriptor.value;
|
|
158
197
|
|
|
159
198
|
descriptor.value = async function (...args: any[]) {
|
|
@@ -166,7 +205,7 @@ export function validateSecurity(schema: z.ZodSchema) {
|
|
|
166
205
|
console.log(`Security validation passed for ${propertyName}`, {
|
|
167
206
|
timestamp: new Date().toISOString(),
|
|
168
207
|
method: propertyName,
|
|
169
|
-
paramCount: Object.keys(validatedParams).length
|
|
208
|
+
paramCount: Object.keys(validatedParams).length,
|
|
170
209
|
});
|
|
171
210
|
|
|
172
211
|
// Call original method with validated params
|
|
@@ -176,12 +215,24 @@ export function validateSecurity(schema: z.ZodSchema) {
|
|
|
176
215
|
console.error(`Security validation failed for ${propertyName}`, {
|
|
177
216
|
timestamp: new Date().toISOString(),
|
|
178
217
|
method: propertyName,
|
|
179
|
-
error:
|
|
218
|
+
error:
|
|
219
|
+
error instanceof z.ZodError
|
|
220
|
+
? error.errors
|
|
221
|
+
: error instanceof Error
|
|
222
|
+
? error.message
|
|
223
|
+
: String(error),
|
|
180
224
|
});
|
|
181
225
|
|
|
182
226
|
throw new SecurityValidationError(
|
|
183
227
|
`Security validation failed for ${propertyName}`,
|
|
184
|
-
error instanceof z.ZodError
|
|
228
|
+
error instanceof z.ZodError
|
|
229
|
+
? error.errors
|
|
230
|
+
: [
|
|
231
|
+
{
|
|
232
|
+
message:
|
|
233
|
+
error instanceof Error ? error.message : String(error),
|
|
234
|
+
},
|
|
235
|
+
],
|
|
185
236
|
);
|
|
186
237
|
}
|
|
187
238
|
};
|
|
@@ -198,7 +249,7 @@ export class SecurityValidationError extends Error {
|
|
|
198
249
|
|
|
199
250
|
constructor(message: string, errors: any[] = []) {
|
|
200
251
|
super(message);
|
|
201
|
-
this.name =
|
|
252
|
+
this.name = "SecurityValidationError";
|
|
202
253
|
this.errors = errors;
|
|
203
254
|
}
|
|
204
255
|
}
|
|
@@ -213,10 +264,10 @@ export const ToolSchemas = {
|
|
|
213
264
|
title: SecuritySchemas.safeString.optional(),
|
|
214
265
|
content: SecuritySchemas.wpContent.optional(),
|
|
215
266
|
excerpt: SecuritySchemas.safeString.optional(),
|
|
216
|
-
status: z.enum([
|
|
267
|
+
status: z.enum(["publish", "draft", "private", "pending"]).optional(),
|
|
217
268
|
slug: SecuritySchemas.slug.optional(),
|
|
218
269
|
categories: z.array(SecuritySchemas.wpId).optional(),
|
|
219
|
-
tags: z.array(SecuritySchemas.wpId).optional()
|
|
270
|
+
tags: z.array(SecuritySchemas.wpId).optional(),
|
|
220
271
|
}),
|
|
221
272
|
|
|
222
273
|
// User creation/update
|
|
@@ -227,15 +278,15 @@ export const ToolSchemas = {
|
|
|
227
278
|
password: SecuritySchemas.safeString.optional(),
|
|
228
279
|
roles: z.array(z.string()).optional(),
|
|
229
280
|
firstName: SecuritySchemas.safeString.optional(),
|
|
230
|
-
lastName: SecuritySchemas.safeString.optional()
|
|
281
|
+
lastName: SecuritySchemas.safeString.optional(),
|
|
231
282
|
}),
|
|
232
283
|
|
|
233
284
|
// Search parameters
|
|
234
285
|
searchParams: z.object({
|
|
235
286
|
site: SecuritySchemas.siteId.optional(),
|
|
236
287
|
query: SecuritySchemas.searchQuery,
|
|
237
|
-
type: z.enum([
|
|
238
|
-
limit: z.number().int().min(1).max(100).optional()
|
|
288
|
+
type: z.enum(["post", "page", "any"]).optional(),
|
|
289
|
+
limit: z.number().int().min(1).max(100).optional(),
|
|
239
290
|
}),
|
|
240
291
|
|
|
241
292
|
// Media upload
|
|
@@ -244,7 +295,7 @@ export const ToolSchemas = {
|
|
|
244
295
|
filename: SecuritySchemas.filePath,
|
|
245
296
|
title: SecuritySchemas.safeString.optional(),
|
|
246
297
|
caption: SecuritySchemas.safeString.optional(),
|
|
247
|
-
description: SecuritySchemas.safeString.optional()
|
|
298
|
+
description: SecuritySchemas.safeString.optional(),
|
|
248
299
|
}),
|
|
249
300
|
|
|
250
301
|
// Site settings
|
|
@@ -253,7 +304,7 @@ export const ToolSchemas = {
|
|
|
253
304
|
title: SecuritySchemas.safeString.optional(),
|
|
254
305
|
description: SecuritySchemas.safeString.optional(),
|
|
255
306
|
url: SecuritySchemas.url.optional(),
|
|
256
|
-
adminEmail: SecuritySchemas.email.optional()
|
|
307
|
+
adminEmail: SecuritySchemas.email.optional(),
|
|
257
308
|
}),
|
|
258
309
|
|
|
259
310
|
// Generic list parameters
|
|
@@ -263,21 +314,24 @@ export const ToolSchemas = {
|
|
|
263
314
|
perPage: z.number().int().min(1).max(100).optional(),
|
|
264
315
|
search: SecuritySchemas.searchQuery.optional(),
|
|
265
316
|
orderBy: z.string().max(50).optional(),
|
|
266
|
-
order: z.enum([
|
|
317
|
+
order: z.enum(["asc", "desc"]).optional(),
|
|
267
318
|
}),
|
|
268
319
|
|
|
269
320
|
// ID-based operations
|
|
270
321
|
idParams: z.object({
|
|
271
322
|
site: SecuritySchemas.siteId.optional(),
|
|
272
|
-
id: SecuritySchemas.wpId
|
|
273
|
-
})
|
|
323
|
+
id: SecuritySchemas.wpId,
|
|
324
|
+
}),
|
|
274
325
|
};
|
|
275
326
|
|
|
276
327
|
/**
|
|
277
328
|
* Rate limiting and DoS protection
|
|
278
329
|
*/
|
|
279
330
|
export class SecurityLimiter {
|
|
280
|
-
private static requestCounts = new Map<
|
|
331
|
+
private static requestCounts = new Map<
|
|
332
|
+
string,
|
|
333
|
+
{ count: number; resetTime: number }
|
|
334
|
+
>();
|
|
281
335
|
private static readonly RATE_LIMIT = 1000; // requests per window
|
|
282
336
|
private static readonly WINDOW_MS = 60 * 1000; // 1 minute
|
|
283
337
|
|
|
@@ -290,7 +344,10 @@ export class SecurityLimiter {
|
|
|
290
344
|
const current = this.requestCounts.get(key);
|
|
291
345
|
|
|
292
346
|
if (!current || now > current.resetTime) {
|
|
293
|
-
this.requestCounts.set(key, {
|
|
347
|
+
this.requestCounts.set(key, {
|
|
348
|
+
count: 1,
|
|
349
|
+
resetTime: now + this.WINDOW_MS,
|
|
350
|
+
});
|
|
294
351
|
return true;
|
|
295
352
|
}
|
|
296
353
|
|