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.
Files changed (251) hide show
  1. package/README.md +210 -182
  2. package/dist/cache/CacheInvalidation.d.ts +3 -3
  3. package/dist/cache/CacheInvalidation.d.ts.map +1 -1
  4. package/dist/cache/CacheInvalidation.js +119 -119
  5. package/dist/cache/CacheInvalidation.js.map +1 -1
  6. package/dist/cache/CacheManager.d.ts +5 -0
  7. package/dist/cache/CacheManager.d.ts.map +1 -1
  8. package/dist/cache/CacheManager.js +26 -16
  9. package/dist/cache/CacheManager.js.map +1 -1
  10. package/dist/cache/HttpCacheWrapper.d.ts +1 -1
  11. package/dist/cache/HttpCacheWrapper.d.ts.map +1 -1
  12. package/dist/cache/HttpCacheWrapper.js +29 -29
  13. package/dist/cache/HttpCacheWrapper.js.map +1 -1
  14. package/dist/cache/__tests__/CacheInvalidation.test.js +96 -94
  15. package/dist/cache/__tests__/CacheInvalidation.test.js.map +1 -1
  16. package/dist/cache/__tests__/CacheManager.test.js +113 -113
  17. package/dist/cache/__tests__/CacheManager.test.js.map +1 -1
  18. package/dist/cache/__tests__/CachedWordPressClient.test.js +102 -99
  19. package/dist/cache/__tests__/CachedWordPressClient.test.js.map +1 -1
  20. package/dist/cache/__tests__/HttpCacheWrapper.test.js +98 -95
  21. package/dist/cache/__tests__/HttpCacheWrapper.test.js.map +1 -1
  22. package/dist/cache/index.d.ts +7 -7
  23. package/dist/cache/index.d.ts.map +1 -1
  24. package/dist/cache/index.js +4 -4
  25. package/dist/cache/index.js.map +1 -1
  26. package/dist/client/CachedWordPressClient.d.ts +4 -4
  27. package/dist/client/CachedWordPressClient.d.ts.map +1 -1
  28. package/dist/client/CachedWordPressClient.js +55 -51
  29. package/dist/client/CachedWordPressClient.js.map +1 -1
  30. package/dist/client/api.d.ts +10 -10
  31. package/dist/client/api.js +158 -158
  32. package/dist/client/api.js.map +1 -1
  33. package/dist/client/auth.d.ts +2 -2
  34. package/dist/client/auth.js +72 -72
  35. package/dist/client/managers/AuthenticationManager.d.ts +2 -2
  36. package/dist/client/managers/AuthenticationManager.js +46 -46
  37. package/dist/client/managers/BaseManager.d.ts +1 -1
  38. package/dist/client/managers/BaseManager.js +9 -9
  39. package/dist/client/managers/RequestManager.d.ts +5 -3
  40. package/dist/client/managers/RequestManager.d.ts.map +1 -1
  41. package/dist/client/managers/RequestManager.js +39 -19
  42. package/dist/client/managers/RequestManager.js.map +1 -1
  43. package/dist/client/managers/index.d.ts +3 -3
  44. package/dist/client/managers/index.js +3 -3
  45. package/dist/config/ConfigurationSchema.d.ts +2 -2
  46. package/dist/config/ConfigurationSchema.d.ts.map +1 -1
  47. package/dist/config/ConfigurationSchema.js +40 -40
  48. package/dist/config/ConfigurationSchema.js.map +1 -1
  49. package/dist/config/ServerConfiguration.d.ts +2 -2
  50. package/dist/config/ServerConfiguration.js +35 -35
  51. package/dist/config/ServerConfiguration.js.map +1 -1
  52. package/dist/docs/DocumentationGenerator.d.ts.map +1 -1
  53. package/dist/docs/DocumentationGenerator.js +296 -255
  54. package/dist/docs/DocumentationGenerator.js.map +1 -1
  55. package/dist/docs/MarkdownFormatter.d.ts +1 -1
  56. package/dist/docs/MarkdownFormatter.d.ts.map +1 -1
  57. package/dist/docs/MarkdownFormatter.js +60 -51
  58. package/dist/docs/MarkdownFormatter.js.map +1 -1
  59. package/dist/docs/index.d.ts +3 -3
  60. package/dist/docs/index.d.ts.map +1 -1
  61. package/dist/docs/index.js +2 -2
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +16 -16
  64. package/dist/index.js.map +1 -1
  65. package/dist/mcp-wordpress-1.3.0.tgz +0 -0
  66. package/dist/performance/MetricsCollector.d.ts +3 -3
  67. package/dist/performance/MetricsCollector.d.ts.map +1 -1
  68. package/dist/performance/MetricsCollector.js +33 -27
  69. package/dist/performance/MetricsCollector.js.map +1 -1
  70. package/dist/performance/PerformanceAnalytics.d.ts +12 -12
  71. package/dist/performance/PerformanceAnalytics.d.ts.map +1 -1
  72. package/dist/performance/PerformanceAnalytics.js +200 -154
  73. package/dist/performance/PerformanceAnalytics.js.map +1 -1
  74. package/dist/performance/PerformanceMonitor.d.ts +5 -5
  75. package/dist/performance/PerformanceMonitor.d.ts.map +1 -1
  76. package/dist/performance/PerformanceMonitor.js +53 -52
  77. package/dist/performance/PerformanceMonitor.js.map +1 -1
  78. package/dist/performance/index.d.ts +6 -6
  79. package/dist/performance/index.d.ts.map +1 -1
  80. package/dist/performance/index.js +3 -3
  81. package/dist/security/InputValidator.d.ts +1 -1
  82. package/dist/security/InputValidator.d.ts.map +1 -1
  83. package/dist/security/InputValidator.js +111 -88
  84. package/dist/security/InputValidator.js.map +1 -1
  85. package/dist/security/SecurityConfig.d.ts +5 -5
  86. package/dist/security/SecurityConfig.js +92 -92
  87. package/dist/security/SecurityConfig.js.map +1 -1
  88. package/dist/server/ConnectionTester.d.ts +1 -1
  89. package/dist/server/ConnectionTester.d.ts.map +1 -1
  90. package/dist/server/ConnectionTester.js +4 -4
  91. package/dist/server/ConnectionTester.js.map +1 -1
  92. package/dist/server/ToolRegistry.d.ts +2 -2
  93. package/dist/server/ToolRegistry.d.ts.map +1 -1
  94. package/dist/server/ToolRegistry.js +35 -32
  95. package/dist/server/ToolRegistry.js.map +1 -1
  96. package/dist/server.d.ts +2 -2
  97. package/dist/server.js +2 -2
  98. package/dist/tools/BaseToolManager.js +5 -5
  99. package/dist/tools/auth.d.ts +2 -2
  100. package/dist/tools/auth.d.ts.map +1 -1
  101. package/dist/tools/auth.js +32 -31
  102. package/dist/tools/auth.js.map +1 -1
  103. package/dist/tools/cache.d.ts +1 -1
  104. package/dist/tools/cache.d.ts.map +1 -1
  105. package/dist/tools/cache.js +71 -71
  106. package/dist/tools/cache.js.map +1 -1
  107. package/dist/tools/comments.d.ts +2 -2
  108. package/dist/tools/comments.d.ts.map +1 -1
  109. package/dist/tools/comments.js +79 -79
  110. package/dist/tools/comments.js.map +1 -1
  111. package/dist/tools/index.d.ts +10 -10
  112. package/dist/tools/index.js +10 -10
  113. package/dist/tools/media.d.ts +2 -2
  114. package/dist/tools/media.js +80 -80
  115. package/dist/tools/pages.d.ts +2 -2
  116. package/dist/tools/pages.d.ts.map +1 -1
  117. package/dist/tools/pages.js +75 -75
  118. package/dist/tools/pages.js.map +1 -1
  119. package/dist/tools/performance.d.ts +1 -1
  120. package/dist/tools/performance.d.ts.map +1 -1
  121. package/dist/tools/performance.js +311 -287
  122. package/dist/tools/performance.js.map +1 -1
  123. package/dist/tools/posts.d.ts +2 -2
  124. package/dist/tools/posts.d.ts.map +1 -1
  125. package/dist/tools/posts.js +94 -94
  126. package/dist/tools/posts.js.map +1 -1
  127. package/dist/tools/site.d.ts +2 -2
  128. package/dist/tools/site.d.ts.map +1 -1
  129. package/dist/tools/site.js +60 -60
  130. package/dist/tools/site.js.map +1 -1
  131. package/dist/tools/taxonomies.d.ts +2 -2
  132. package/dist/tools/taxonomies.js +89 -89
  133. package/dist/tools/users.d.ts +2 -2
  134. package/dist/tools/users.js +68 -68
  135. package/dist/tools/users.js.map +1 -1
  136. package/dist/types/client.d.ts +13 -13
  137. package/dist/types/client.d.ts.map +1 -1
  138. package/dist/types/client.js +12 -12
  139. package/dist/types/client.js.map +1 -1
  140. package/dist/types/index.d.ts +19 -19
  141. package/dist/types/index.d.ts.map +1 -1
  142. package/dist/types/index.js +3 -3
  143. package/dist/types/mcp.d.ts +7 -7
  144. package/dist/types/wordpress.d.ts +21 -21
  145. package/dist/types/wordpress.d.ts.map +1 -1
  146. package/dist/utils/debug.d.ts +2 -2
  147. package/dist/utils/debug.js +28 -28
  148. package/dist/utils/error.d.ts.map +1 -1
  149. package/dist/utils/error.js +13 -13
  150. package/dist/utils/error.js.map +1 -1
  151. package/dist/utils/toolWrapper.d.ts.map +1 -1
  152. package/dist/utils/toolWrapper.js +5 -5
  153. package/dist/utils/toolWrapper.js.map +1 -1
  154. package/dist/utils/validation.d.ts.map +1 -1
  155. package/dist/utils/validation.js +41 -31
  156. package/dist/utils/validation.js.map +1 -1
  157. package/docs/CACHING.md +36 -2
  158. package/docs/DOCKER.md +24 -18
  159. package/docs/PERFORMANCE_MONITORING.md +49 -1
  160. package/docs/SECURITY_TESTING.md +30 -1
  161. package/docs/api/README.md +9 -1
  162. package/docs/api/summary.json +1 -1
  163. package/docs/contract-testing.md +24 -3
  164. package/docs/developer/GITHUB_ACTIONS_SETUP.md +8 -2
  165. package/docs/developer/MAINTENANCE.md +29 -3
  166. package/docs/developer/MIGRATION_GUIDE.md +13 -1
  167. package/docs/developer/NPM_AUTH_SETUP.md +13 -2
  168. package/docs/developer/REFACTORING.md +31 -1
  169. package/docs/releases/COMMUNITY_ANNOUNCEMENT_v1.1.2.md +18 -7
  170. package/docs/releases/RELEASE_NOTES_v1.1.2.md +31 -5
  171. package/docs/user-guides/DOCKER_SETUP.md +264 -0
  172. package/docs/user-guides/DTX_SETUP.md +327 -0
  173. package/docs/user-guides/NPM_SETUP.md +109 -0
  174. package/docs/user-guides/NPX_SETUP.md +281 -0
  175. package/docs/wordpress-rest-api-authentication-troubleshooting.md +13 -2
  176. package/package.json +27 -8
  177. package/src/cache/CacheInvalidation.ts +140 -132
  178. package/src/cache/CacheManager.ts +40 -29
  179. package/src/cache/HttpCacheWrapper.ts +105 -68
  180. package/src/cache/__tests__/CacheInvalidation.test.ts +123 -118
  181. package/src/cache/__tests__/CacheManager.test.ts +156 -152
  182. package/src/cache/__tests__/CachedWordPressClient.test.ts +131 -116
  183. package/src/cache/__tests__/HttpCacheWrapper.test.ts +118 -115
  184. package/src/cache/index.ts +13 -13
  185. package/src/client/CachedWordPressClient.ts +90 -80
  186. package/src/client/api.ts +205 -205
  187. package/src/client/auth.ts +80 -80
  188. package/src/client/managers/AuthenticationManager.ts +61 -61
  189. package/src/client/managers/BaseManager.ts +11 -11
  190. package/src/client/managers/RequestManager.ts +79 -47
  191. package/src/client/managers/index.ts +3 -3
  192. package/src/config/ConfigurationSchema.ts +44 -44
  193. package/src/config/ServerConfiguration.ts +39 -39
  194. package/src/docs/DocumentationGenerator.ts +402 -295
  195. package/src/docs/MarkdownFormatter.ts +94 -69
  196. package/src/docs/index.ts +4 -4
  197. package/src/index.ts +24 -21
  198. package/src/performance/MetricsCollector.ts +90 -58
  199. package/src/performance/PerformanceAnalytics.ts +386 -262
  200. package/src/performance/PerformanceMonitor.ts +152 -118
  201. package/src/performance/index.ts +9 -9
  202. package/src/security/InputValidator.ts +148 -91
  203. package/src/security/SecurityConfig.ts +94 -94
  204. package/src/server/ConnectionTester.ts +21 -15
  205. package/src/server/ToolRegistry.ts +64 -51
  206. package/src/server.ts +2 -2
  207. package/src/tools/BaseToolManager.ts +6 -6
  208. package/src/tools/auth.ts +42 -37
  209. package/src/tools/cache.ts +85 -81
  210. package/src/tools/comments.ts +93 -91
  211. package/src/tools/index.ts +10 -10
  212. package/src/tools/media.ts +89 -89
  213. package/src/tools/pages.ts +89 -87
  214. package/src/tools/performance.ts +443 -352
  215. package/src/tools/posts.ts +109 -107
  216. package/src/tools/site.ts +86 -77
  217. package/src/tools/taxonomies.ts +102 -102
  218. package/src/tools/users.ts +77 -77
  219. package/src/types/client.ts +157 -60
  220. package/src/types/index.ts +49 -27
  221. package/src/types/mcp.ts +15 -15
  222. package/src/types/wordpress.ts +57 -29
  223. package/src/utils/debug.ts +37 -37
  224. package/src/utils/error.ts +47 -25
  225. package/src/utils/toolWrapper.ts +12 -8
  226. package/src/utils/validation.ts +116 -65
  227. package/dist/client/WordPressClient.d.ts +0 -81
  228. package/dist/client/WordPressClient.d.ts.map +0 -1
  229. package/dist/client/WordPressClient.js +0 -354
  230. package/dist/client/WordPressClient.js.map +0 -1
  231. package/dist/performance/AnomalyDetector.d.ts +0 -63
  232. package/dist/performance/AnomalyDetector.d.ts.map +0 -1
  233. package/dist/performance/AnomalyDetector.js +0 -222
  234. package/dist/performance/AnomalyDetector.js.map +0 -1
  235. package/dist/performance/BenchmarkAnalyzer.d.ts +0 -67
  236. package/dist/performance/BenchmarkAnalyzer.d.ts.map +0 -1
  237. package/dist/performance/BenchmarkAnalyzer.js +0 -301
  238. package/dist/performance/BenchmarkAnalyzer.js.map +0 -1
  239. package/dist/performance/TrendAnalyzer.d.ts +0 -69
  240. package/dist/performance/TrendAnalyzer.d.ts.map +0 -1
  241. package/dist/performance/TrendAnalyzer.js +0 -203
  242. package/dist/performance/TrendAnalyzer.js.map +0 -1
  243. package/dist/tools/BaseToolClass.d.ts +0 -76
  244. package/dist/tools/BaseToolClass.d.ts.map +0 -1
  245. package/dist/tools/BaseToolClass.js +0 -104
  246. package/dist/tools/BaseToolClass.js.map +0 -1
  247. package/dist/tools/base.d.ts +0 -37
  248. package/dist/tools/base.d.ts.map +0 -1
  249. package/dist/tools/base.js +0 -60
  250. package/dist/tools/base.js.map +0 -1
  251. 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 'zod';
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 = /('|(\\')|(;)|(\\x00)|(\\n)|(\\r)|(\\x1a)|(\\x22)|(\\x27)|(\\x5c)|(\\x60))/i;
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.string()
21
- .max(10000, 'String too long')
22
- .refine(val => !SCRIPT_PATTERN.test(val), 'Script tags not allowed')
23
- .refine(val => !val.includes('javascript:'), 'JavaScript URLs not allowed')
24
- .refine(val => !val.includes('data:'), 'Data URLs not allowed')
25
- .refine(val => !val.includes('onerror='), 'Event handlers not allowed')
26
- .refine(val => !val.includes('onload='), 'Event handlers not allowed')
27
- .refine(val => !val.includes('onfocus='), 'Event handlers not allowed'),
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.string()
31
- .max(100000, 'Content too long')
32
- .refine(val => !SCRIPT_PATTERN.test(val), 'Script tags not allowed')
33
- .refine(val => !val.includes('javascript:'), 'JavaScript URLs not allowed')
34
- .refine(val => !val.includes('on[a-z]+='), 'Event handlers not allowed'),
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.string()
38
- .url('Invalid URL format')
39
- .regex(URL_PATTERN, 'URL contains invalid characters')
40
- .refine(val => !val.includes('javascript:'), 'JavaScript URLs not allowed')
41
- .refine(val => !val.includes('data:'), 'Data URLs not allowed'),
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.string()
45
- .email('Invalid email format')
46
- .regex(EMAIL_PATTERN, 'Email contains invalid characters')
47
- .max(254, 'Email too long'),
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.string()
51
- .min(1, 'Slug cannot be empty')
52
- .max(100, 'Slug too long')
53
- .regex(SLUG_PATTERN, 'Slug can only contain lowercase letters, numbers, and hyphens'),
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.string()
57
- .max(1000000, 'Content too long')
58
- .refine(val => !SCRIPT_PATTERN.test(val), 'Script tags not allowed in content')
59
- .refine(val => !val.includes('javascript:'), 'JavaScript URLs not allowed'),
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.string()
63
- .min(1, 'Site ID cannot be empty')
64
- .max(50, 'Site ID too long')
65
- .regex(/^[a-zA-Z0-9\-_]+$/, 'Site ID can only contain letters, numbers, hyphens, and underscores'),
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.number()
69
- .int('ID must be an integer')
70
- .positive('ID must be positive')
71
- .max(999999999, 'ID too large'),
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.string()
75
- .max(500, 'Search query too long')
76
- .refine(val => !SQL_INJECTION_PATTERN.test(val), 'Invalid characters in search query')
77
- .refine(val => !val.includes('--'), 'SQL comments not allowed')
78
- .refine(val => !val.includes('/*'), 'SQL comments not allowed'),
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.string()
82
- .max(500, 'File path too long')
83
- .refine(val => !val.includes('..'), 'Path traversal not allowed')
84
- .refine(val => !val.includes('<'), 'Invalid characters in path')
85
- .refine(val => !val.includes('>'), 'Invalid characters in path'),
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.string()
93
- .regex(/^[a-zA-Z0-9\s]{24}$/, 'Invalid application password format')
94
- .transform(val => val.replace(/\s/g, ' ')) // Normalize spaces
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, '') // Remove script tags
107
- .replace(/javascript:/gi, '') // Remove javascript: URLs
108
- .replace(/data:/gi, '') // Remove data: URLs
109
- .replace(/on[a-z]+\s*=/gi, '') // Remove event handlers
110
- .replace(/<iframe[^>]*>/gi, '') // Remove iframes
111
- .replace(/<object[^>]*>/gi, '') // Remove objects
112
- .replace(/<embed[^>]*>/gi, ''); // Remove embeds
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, '') // Remove quotes and backslashes
121
- .replace(/--/g, '') // Remove SQL comments
122
- .replace(/\/\*/g, '') // Remove SQL comments
123
- .replace(/\*/g, '') // Remove wildcards
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, '') // Remove directory traversal
134
- .replace(/[<>]/g, '') // Remove angle brackets
135
- .replace(/[|&;$`\\]/g, '') // Remove shell metacharacters
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, '&amp;')
145
- .replace(/</g, '&lt;')
146
- .replace(/>/g, '&gt;')
147
- .replace(/"/g, '&quot;')
148
- .replace(/'/g, '&#x27;');
179
+ .replace(/&/g, "&amp;")
180
+ .replace(/</g, "&lt;")
181
+ .replace(/>/g, "&gt;")
182
+ .replace(/"/g, "&quot;")
183
+ .replace(/'/g, "&#x27;");
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 (target: any, propertyName: string, descriptor: PropertyDescriptor) {
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: error instanceof z.ZodError ? error.errors : (error instanceof Error ? error.message : String(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 ? error.errors : [{ message: error instanceof Error ? error.message : String(error) }]
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 = 'SecurityValidationError';
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(['publish', 'draft', 'private', 'pending']).optional(),
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(['post', 'page', 'any']).optional(),
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(['asc', 'desc']).optional()
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<string, { count: number; resetTime: number }>();
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, { count: 1, resetTime: now + this.WINDOW_MS });
347
+ this.requestCounts.set(key, {
348
+ count: 1,
349
+ resetTime: now + this.WINDOW_MS,
350
+ });
294
351
  return true;
295
352
  }
296
353