mcp-wordpress 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +568 -0
  3. package/bin/mcp-wordpress.js +12 -0
  4. package/bin/setup.js +302 -0
  5. package/bin/status.js +359 -0
  6. package/dist/client/WordPressClient.d.ts +81 -0
  7. package/dist/client/WordPressClient.d.ts.map +1 -0
  8. package/dist/client/WordPressClient.js +354 -0
  9. package/dist/client/WordPressClient.js.map +1 -0
  10. package/dist/client/api.d.ts +140 -0
  11. package/dist/client/api.d.ts.map +1 -0
  12. package/dist/client/api.js +727 -0
  13. package/dist/client/api.js.map +1 -0
  14. package/dist/client/auth.d.ts +121 -0
  15. package/dist/client/auth.d.ts.map +1 -0
  16. package/dist/client/auth.js +430 -0
  17. package/dist/client/auth.js.map +1 -0
  18. package/dist/client/managers/AuthenticationManager.d.ts +39 -0
  19. package/dist/client/managers/AuthenticationManager.d.ts.map +1 -0
  20. package/dist/client/managers/AuthenticationManager.js +159 -0
  21. package/dist/client/managers/AuthenticationManager.js.map +1 -0
  22. package/dist/client/managers/BaseManager.d.ts +22 -0
  23. package/dist/client/managers/BaseManager.d.ts.map +1 -0
  24. package/dist/client/managers/BaseManager.js +47 -0
  25. package/dist/client/managers/BaseManager.js.map +1 -0
  26. package/dist/client/managers/RequestManager.d.ts +45 -0
  27. package/dist/client/managers/RequestManager.d.ts.map +1 -0
  28. package/dist/client/managers/RequestManager.js +161 -0
  29. package/dist/client/managers/RequestManager.js.map +1 -0
  30. package/dist/client/managers/index.d.ts +8 -0
  31. package/dist/client/managers/index.d.ts.map +1 -0
  32. package/dist/client/managers/index.js +8 -0
  33. package/dist/client/managers/index.js.map +1 -0
  34. package/dist/index.d.ts +19 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +264 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/server.d.ts +7 -0
  39. package/dist/server.d.ts.map +1 -0
  40. package/dist/server.js +7 -0
  41. package/dist/server.js.map +1 -0
  42. package/dist/tools/auth.d.ts +44 -0
  43. package/dist/tools/auth.d.ts.map +1 -0
  44. package/dist/tools/auth.js +126 -0
  45. package/dist/tools/auth.js.map +1 -0
  46. package/dist/tools/base.d.ts +37 -0
  47. package/dist/tools/base.d.ts.map +1 -0
  48. package/dist/tools/base.js +60 -0
  49. package/dist/tools/base.js.map +1 -0
  50. package/dist/tools/comments.d.ts +33 -0
  51. package/dist/tools/comments.d.ts.map +1 -0
  52. package/dist/tools/comments.js +228 -0
  53. package/dist/tools/comments.js.map +1 -0
  54. package/dist/tools/index.d.ts +9 -0
  55. package/dist/tools/index.d.ts.map +1 -0
  56. package/dist/tools/index.js +9 -0
  57. package/dist/tools/index.js.map +1 -0
  58. package/dist/tools/media.d.ts +29 -0
  59. package/dist/tools/media.d.ts.map +1 -0
  60. package/dist/tools/media.js +208 -0
  61. package/dist/tools/media.js.map +1 -0
  62. package/dist/tools/pages.d.ts +30 -0
  63. package/dist/tools/pages.d.ts.map +1 -0
  64. package/dist/tools/pages.js +211 -0
  65. package/dist/tools/pages.js.map +1 -0
  66. package/dist/tools/posts.d.ts +30 -0
  67. package/dist/tools/posts.d.ts.map +1 -0
  68. package/dist/tools/posts.js +240 -0
  69. package/dist/tools/posts.js.map +1 -0
  70. package/dist/tools/site.d.ts +31 -0
  71. package/dist/tools/site.d.ts.map +1 -0
  72. package/dist/tools/site.js +192 -0
  73. package/dist/tools/site.js.map +1 -0
  74. package/dist/tools/taxonomies.d.ts +37 -0
  75. package/dist/tools/taxonomies.d.ts.map +1 -0
  76. package/dist/tools/taxonomies.js +280 -0
  77. package/dist/tools/taxonomies.js.map +1 -0
  78. package/dist/tools/users.d.ts +28 -0
  79. package/dist/tools/users.d.ts.map +1 -0
  80. package/dist/tools/users.js +201 -0
  81. package/dist/tools/users.js.map +1 -0
  82. package/dist/types/client.d.ts +215 -0
  83. package/dist/types/client.d.ts.map +1 -0
  84. package/dist/types/client.js +72 -0
  85. package/dist/types/client.js.map +1 -0
  86. package/dist/types/index.d.ts +157 -0
  87. package/dist/types/index.d.ts.map +1 -0
  88. package/dist/types/index.js +12 -0
  89. package/dist/types/index.js.map +1 -0
  90. package/dist/types/mcp.d.ts +178 -0
  91. package/dist/types/mcp.d.ts.map +1 -0
  92. package/dist/types/mcp.js +7 -0
  93. package/dist/types/mcp.js.map +1 -0
  94. package/dist/types/wordpress.d.ts +443 -0
  95. package/dist/types/wordpress.d.ts.map +1 -0
  96. package/dist/types/wordpress.js +7 -0
  97. package/dist/types/wordpress.js.map +1 -0
  98. package/dist/utils/debug.d.ts +63 -0
  99. package/dist/utils/debug.d.ts.map +1 -0
  100. package/dist/utils/debug.js +195 -0
  101. package/dist/utils/debug.js.map +1 -0
  102. package/dist/utils/error.d.ts +19 -0
  103. package/dist/utils/error.d.ts.map +1 -0
  104. package/dist/utils/error.js +71 -0
  105. package/dist/utils/error.js.map +1 -0
  106. package/dist/utils/toolWrapper.d.ts +36 -0
  107. package/dist/utils/toolWrapper.d.ts.map +1 -0
  108. package/dist/utils/toolWrapper.js +90 -0
  109. package/dist/utils/toolWrapper.js.map +1 -0
  110. package/package.json +115 -0
  111. package/src/client/api.ts +1043 -0
  112. package/src/client/auth.ts +527 -0
  113. package/src/client/managers/AuthenticationManager.ts +190 -0
  114. package/src/client/managers/BaseManager.ts +73 -0
  115. package/src/client/managers/RequestManager.ts +214 -0
  116. package/src/client/managers/index.ts +8 -0
  117. package/src/index.ts +337 -0
  118. package/src/server.ts +7 -0
  119. package/src/tools/auth.ts +153 -0
  120. package/src/tools/comments.ts +263 -0
  121. package/src/tools/index.ts +8 -0
  122. package/src/tools/media.ts +240 -0
  123. package/src/tools/pages.ts +246 -0
  124. package/src/tools/posts.ts +277 -0
  125. package/src/tools/site.ts +227 -0
  126. package/src/tools/taxonomies.ts +322 -0
  127. package/src/tools/users.ts +233 -0
  128. package/src/types/client.ts +304 -0
  129. package/src/types/index.ts +207 -0
  130. package/src/types/mcp.ts +247 -0
  131. package/src/types/wordpress.ts +491 -0
  132. package/src/utils/debug.ts +258 -0
  133. package/src/utils/error.ts +88 -0
  134. package/src/utils/toolWrapper.ts +105 -0
@@ -0,0 +1,527 @@
1
+ /**
2
+ * WordPress Authentication Handler
3
+ * Manages different authentication methods for WordPress REST API
4
+ */
5
+
6
+ import { logger, debug } from "../utils/debug.js";
7
+ import * as http from "http";
8
+ import { URL } from "url";
9
+ import type {
10
+ IAuthProvider,
11
+ IWordPressClient,
12
+ AuthMethod,
13
+ AuthConfig,
14
+ AuthenticationError,
15
+ } from "../types/client.js";
16
+ import type { WordPressUser } from "../types/wordpress.js";
17
+
18
+ export class WordPressAuth {
19
+ private client: IWordPressClient;
20
+ private authType: AuthMethod;
21
+
22
+ constructor(client: IWordPressClient) {
23
+ this.client = client;
24
+ this.authType = client.config.auth.method;
25
+ }
26
+
27
+ /**
28
+ * Handle authentication based on type
29
+ */
30
+ async authenticate(): Promise<boolean> {
31
+ try {
32
+ switch (this.authType) {
33
+ case "app-password":
34
+ return await this.handleAppPasswordAuth();
35
+ case "jwt":
36
+ return await this.handleJWTAuth();
37
+ case "basic":
38
+ return await this.handleBasicAuth();
39
+ case "api-key":
40
+ return await this.handleAPIKeyAuth();
41
+ case "cookie":
42
+ return await this.handleCookieAuth();
43
+ default:
44
+ throw new Error(`Unsupported authentication type: ${this.authType}`);
45
+ }
46
+ } catch (error) {
47
+ logger.error("Authentication failed:", error);
48
+ throw error;
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Handle Application Password authentication
54
+ */
55
+ private async handleAppPasswordAuth(): Promise<boolean> {
56
+ const { username, appPassword } = this.client.config.auth;
57
+
58
+ if (!username || !appPassword) {
59
+ throw new Error(
60
+ "Application Password authentication requires WORDPRESS_USERNAME and WORDPRESS_APP_PASSWORD. " +
61
+ "Visit your WordPress admin → Users → Profile → Application Passwords to create one.",
62
+ );
63
+ }
64
+
65
+ // Test the credentials by attempting to get current user
66
+ try {
67
+ const user = await this.client.getCurrentUser();
68
+ logger.log(
69
+ `✅ Application Password authentication successful for user: ${user.name} (${user.username})`,
70
+ );
71
+ return true;
72
+ } catch (error) {
73
+ const message =
74
+ "Application Password authentication failed. Please check your credentials and ensure the application password is valid.";
75
+ logger.error(message, error);
76
+ throw new Error(message);
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Handle Basic authentication (username + password)
82
+ */
83
+ private async handleBasicAuth(): Promise<boolean> {
84
+ const { username, password } = this.client.config.auth;
85
+
86
+ if (!username || !password) {
87
+ throw new Error(
88
+ "Basic authentication requires WORDPRESS_USERNAME and WORDPRESS_PASSWORD",
89
+ );
90
+ }
91
+
92
+ try {
93
+ const user = await this.client.getCurrentUser();
94
+ logger.log(
95
+ `✅ Basic authentication successful for user: ${user.name} (${user.username})`,
96
+ );
97
+ return true;
98
+ } catch (error) {
99
+ const message =
100
+ "Basic authentication failed. Please check your username and password.";
101
+ logger.error(message, error);
102
+ throw new Error(message);
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Handle JWT authentication
108
+ */
109
+ private async handleJWTAuth(): Promise<boolean> {
110
+ const { username, password, secret } = this.client.config.auth;
111
+
112
+ if (!username || !password || !secret) {
113
+ throw new Error(
114
+ "JWT authentication requires WORDPRESS_USERNAME, WORDPRESS_PASSWORD, and WORDPRESS_JWT_SECRET. " +
115
+ "Install and configure the JWT Authentication plugin first.",
116
+ );
117
+ }
118
+
119
+ try {
120
+ // The JWT token should be obtained during client authentication
121
+ const user = await this.client.getCurrentUser();
122
+ logger.log(
123
+ `✅ JWT authentication successful for user: ${user.name} (${user.username})`,
124
+ );
125
+ return true;
126
+ } catch (error) {
127
+ const message =
128
+ "JWT authentication failed. Please check your credentials and ensure the JWT plugin is installed and configured.";
129
+ logger.error(message, error);
130
+ throw new Error(message);
131
+ }
132
+ }
133
+
134
+ /**
135
+ * Handle API Key authentication
136
+ */
137
+ private async handleAPIKeyAuth(): Promise<boolean> {
138
+ const { apiKey } = this.client.config.auth;
139
+
140
+ if (!apiKey) {
141
+ throw new Error("API Key authentication requires WORDPRESS_API_KEY");
142
+ }
143
+
144
+ try {
145
+ // Test API key by making a simple request
146
+ await this.client.getSiteInfo();
147
+ logger.log("✅ API Key authentication successful");
148
+ return true;
149
+ } catch (error) {
150
+ const message =
151
+ "API Key authentication failed. Please check your API key.";
152
+ logger.error(message, error);
153
+ throw new Error(message);
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Handle Cookie authentication
159
+ */
160
+ private async handleCookieAuth(): Promise<boolean> {
161
+ const { nonce } = this.client.config.auth;
162
+
163
+ if (!nonce) {
164
+ logger.warn(
165
+ "Cookie authentication: No nonce provided, authentication may fail for write operations",
166
+ );
167
+ }
168
+
169
+ try {
170
+ // Test with a simple read operation
171
+ await this.client.getSiteInfo();
172
+ logger.log(
173
+ "✅ Cookie authentication configured (note: write operations may require valid nonce)",
174
+ );
175
+ return true;
176
+ } catch (error) {
177
+ const message =
178
+ "Cookie authentication failed. Please ensure you are properly logged into WordPress.";
179
+ logger.error(message, error);
180
+ throw new Error(message);
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Refresh authentication (for JWT and OAuth)
186
+ */
187
+ async refreshAuth(): Promise<boolean> {
188
+ switch (this.authType) {
189
+ case "jwt":
190
+ return await this.refreshJWTToken();
191
+ default:
192
+ logger.log(`Authentication refresh not supported for ${this.authType}`);
193
+ return true;
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Refresh JWT token
199
+ */
200
+ private async refreshJWTToken(): Promise<boolean> {
201
+ try {
202
+ // Re-authenticate to get a new token
203
+ return await this.handleJWTAuth();
204
+ } catch (error) {
205
+ logger.error("Failed to refresh JWT token:", error);
206
+ return false;
207
+ }
208
+ }
209
+
210
+ /**
211
+ * Validate current authentication
212
+ */
213
+ async validateAuth(): Promise<boolean> {
214
+ try {
215
+ await this.client.getCurrentUser();
216
+ return true;
217
+ } catch (error) {
218
+ logger.error("Authentication validation failed:", error);
219
+ return false;
220
+ }
221
+ }
222
+
223
+ /**
224
+ * Get authentication status information
225
+ */
226
+ async getAuthStatus(): Promise<{
227
+ authenticated: boolean;
228
+ method: AuthMethod;
229
+ user?: WordPressUser;
230
+ error?: string;
231
+ }> {
232
+ try {
233
+ const user = await this.client.getCurrentUser();
234
+ return {
235
+ authenticated: true,
236
+ method: this.authType,
237
+ user,
238
+ };
239
+ } catch (error) {
240
+ return {
241
+ authenticated: false,
242
+ method: this.authType,
243
+ error: (error as Error).message,
244
+ };
245
+ }
246
+ }
247
+
248
+ /**
249
+ * Switch authentication method
250
+ */
251
+ async switchAuthMethod(newConfig: AuthConfig): Promise<boolean> {
252
+ // Update client configuration
253
+ (this.client.config as any).auth = newConfig;
254
+ this.authType = newConfig.method;
255
+
256
+ // Re-authenticate with new method
257
+ return await this.authenticate();
258
+ }
259
+
260
+ /**
261
+ * Start OAuth 2.0 flow (for future implementation)
262
+ */
263
+ async startOAuthFlow(): Promise<{ authUrl: string; state: string }> {
264
+ const { clientId } = this.client.config.auth;
265
+
266
+ if (!clientId) {
267
+ throw new Error("OAuth requires client ID");
268
+ }
269
+
270
+ const state = this.generateRandomState();
271
+ const redirectUri = "http://localhost:8080/oauth/callback";
272
+
273
+ const authUrl = new URL("/oauth/authorize", this.client.config.baseUrl);
274
+ authUrl.searchParams.append("client_id", clientId);
275
+ authUrl.searchParams.append("redirect_uri", redirectUri);
276
+ authUrl.searchParams.append("response_type", "code");
277
+ authUrl.searchParams.append("state", state);
278
+ authUrl.searchParams.append("scope", "read write");
279
+
280
+ return {
281
+ authUrl: authUrl.toString(),
282
+ state,
283
+ };
284
+ }
285
+
286
+ /**
287
+ * Complete OAuth 2.0 flow (for future implementation)
288
+ */
289
+ async completeOAuthFlow(code: string, state: string): Promise<boolean> {
290
+ // This would implement the OAuth token exchange
291
+ // For now, this is a placeholder
292
+ throw new Error("OAuth flow not yet implemented");
293
+ }
294
+
295
+ /**
296
+ * Generate random state for OAuth
297
+ */
298
+ private generateRandomState(length = 32): string {
299
+ const chars =
300
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
301
+ let result = "";
302
+ for (let i = 0; i < length; i++) {
303
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
304
+ }
305
+ return result;
306
+ }
307
+
308
+ /**
309
+ * Get authentication headers for the current method
310
+ */
311
+ getAuthHeaders(): Record<string, string> {
312
+ const headers: Record<string, string> = {};
313
+ const auth = this.client.config.auth;
314
+
315
+ switch (this.authType) {
316
+ case "app-password":
317
+ if (auth.username && auth.appPassword) {
318
+ const credentials = Buffer.from(
319
+ `${auth.username}:${auth.appPassword}`,
320
+ ).toString("base64");
321
+ headers["Authorization"] = `Basic ${credentials}`;
322
+ }
323
+ break;
324
+ case "basic":
325
+ if (auth.username && auth.password) {
326
+ const credentials = Buffer.from(
327
+ `${auth.username}:${auth.password}`,
328
+ ).toString("base64");
329
+ headers["Authorization"] = `Basic ${credentials}`;
330
+ }
331
+ break;
332
+
333
+ case "jwt":
334
+ if (auth.token) {
335
+ headers["Authorization"] = `Bearer ${auth.token}`;
336
+ }
337
+ break;
338
+
339
+ case "api-key":
340
+ if (auth.apiKey) {
341
+ headers["X-API-Key"] = auth.apiKey;
342
+ }
343
+ break;
344
+
345
+ case "cookie":
346
+ if (auth.nonce) {
347
+ headers["X-WP-Nonce"] = auth.nonce;
348
+ }
349
+ break;
350
+ }
351
+
352
+ return headers;
353
+ }
354
+
355
+ /**
356
+ * Check if authentication method requires additional setup
357
+ */
358
+ requiresSetup(): boolean {
359
+ switch (this.authType) {
360
+ case "jwt":
361
+ return !this.client.config.auth.secret;
362
+ case "api-key":
363
+ return !this.client.config.auth.apiKey;
364
+ case "app-password":
365
+ return (
366
+ !this.client.config.auth.username ||
367
+ !this.client.config.auth.appPassword
368
+ );
369
+ case "basic":
370
+ return (
371
+ !this.client.config.auth.username || !this.client.config.auth.password
372
+ );
373
+ case "cookie":
374
+ return false; // Cookie auth can work without additional setup
375
+ default:
376
+ return true;
377
+ }
378
+ }
379
+
380
+ /**
381
+ * Get setup instructions for the current authentication method
382
+ */
383
+ getSetupInstructions(): string {
384
+ switch (this.authType) {
385
+ case "app-password":
386
+ return `
387
+ To set up Application Password authentication:
388
+ 1. Log into your WordPress admin dashboard
389
+ 2. Go to Users → Profile (or Users → All Users → Edit your user)
390
+ 3. Scroll down to "Application Passwords" section
391
+ 4. Enter a name for this application (e.g., "MCP WordPress Server")
392
+ 5. Click "Add New Application Password"
393
+ 6. Copy the generated password and set it as WORDPRESS_APP_PASSWORD
394
+ 7. Set WORDPRESS_USERNAME to your WordPress username
395
+ `;
396
+
397
+ case "jwt":
398
+ return `
399
+ To set up JWT authentication:
400
+ 1. Install the "JWT Authentication for WP REST API" plugin
401
+ 2. Add JWT_AUTH_SECRET_KEY to your wp-config.php file
402
+ 3. Configure the plugin settings
403
+ 4. Set WORDPRESS_JWT_SECRET environment variable
404
+ 5. Set WORDPRESS_USERNAME and WORDPRESS_PASSWORD
405
+ `;
406
+
407
+ case "api-key":
408
+ return `
409
+ To set up API Key authentication:
410
+ 1. Install an API Key plugin (varies by plugin)
411
+ 2. Generate an API key in the plugin settings
412
+ 3. Set WORDPRESS_API_KEY environment variable
413
+ `;
414
+
415
+ case "basic":
416
+ return `
417
+ To set up Basic authentication:
418
+ 1. Set WORDPRESS_USERNAME to your WordPress username
419
+ 2. Set WORDPRESS_PASSWORD to your WordPress password
420
+ Note: This method is less secure than Application Passwords
421
+ `;
422
+
423
+ case "cookie":
424
+ return `
425
+ Cookie authentication is automatically configured when you're logged into WordPress.
426
+ For write operations, you may need to set WORDPRESS_COOKIE_NONCE.
427
+ `;
428
+
429
+ default:
430
+ return "No setup instructions available for this authentication method.";
431
+ }
432
+ }
433
+ }
434
+
435
+ /**
436
+ * Authentication Provider implementations
437
+ */
438
+
439
+ export class AppPasswordAuthProvider implements IAuthProvider {
440
+ readonly method: AuthMethod = "app-password";
441
+
442
+ async authenticate(client: IWordPressClient): Promise<boolean> {
443
+ const auth = new WordPressAuth(client);
444
+ return auth.authenticate();
445
+ }
446
+
447
+ addAuthHeaders(headers: Record<string, string>): void {
448
+ // Implementation handled by WordPressAuth
449
+ }
450
+ }
451
+
452
+ export class JWTAuthProvider implements IAuthProvider {
453
+ readonly method: AuthMethod = "jwt";
454
+
455
+ async authenticate(client: IWordPressClient): Promise<boolean> {
456
+ const auth = new WordPressAuth(client);
457
+ return auth.authenticate();
458
+ }
459
+
460
+ addAuthHeaders(headers: Record<string, string>): void {
461
+ // Implementation handled by WordPressAuth
462
+ }
463
+
464
+ async refreshAuth(): Promise<boolean> {
465
+ // JWT token refresh logic
466
+ return true;
467
+ }
468
+ }
469
+
470
+ export class BasicAuthProvider implements IAuthProvider {
471
+ readonly method: AuthMethod = "basic";
472
+
473
+ async authenticate(client: IWordPressClient): Promise<boolean> {
474
+ const auth = new WordPressAuth(client);
475
+ return auth.authenticate();
476
+ }
477
+
478
+ addAuthHeaders(headers: Record<string, string>): void {
479
+ // Implementation handled by WordPressAuth
480
+ }
481
+ }
482
+
483
+ export class APIKeyAuthProvider implements IAuthProvider {
484
+ readonly method: AuthMethod = "api-key";
485
+
486
+ async authenticate(client: IWordPressClient): Promise<boolean> {
487
+ const auth = new WordPressAuth(client);
488
+ return auth.authenticate();
489
+ }
490
+
491
+ addAuthHeaders(headers: Record<string, string>): void {
492
+ // Implementation handled by WordPressAuth
493
+ }
494
+ }
495
+
496
+ export class CookieAuthProvider implements IAuthProvider {
497
+ readonly method: AuthMethod = "cookie";
498
+
499
+ async authenticate(client: IWordPressClient): Promise<boolean> {
500
+ const auth = new WordPressAuth(client);
501
+ return auth.authenticate();
502
+ }
503
+
504
+ addAuthHeaders(headers: Record<string, string>): void {
505
+ // Implementation handled by WordPressAuth
506
+ }
507
+ }
508
+
509
+ /**
510
+ * Factory function to create appropriate auth provider
511
+ */
512
+ export function createAuthProvider(method: AuthMethod): IAuthProvider {
513
+ switch (method) {
514
+ case "app-password":
515
+ return new AppPasswordAuthProvider();
516
+ case "jwt":
517
+ return new JWTAuthProvider();
518
+ case "basic":
519
+ return new BasicAuthProvider();
520
+ case "api-key":
521
+ return new APIKeyAuthProvider();
522
+ case "cookie":
523
+ return new CookieAuthProvider();
524
+ default:
525
+ throw new Error(`Unsupported authentication method: ${method}`);
526
+ }
527
+ }
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Authentication Manager
3
+ * Handles all authentication methods and token management
4
+ */
5
+
6
+ import type { AuthConfig, AuthMethod } from "../../types/client.js";
7
+ import { AuthenticationError } from "../../types/client.js";
8
+ import { BaseManager } from "./BaseManager.js";
9
+ import { debug } from "../../utils/debug.js";
10
+
11
+ export class AuthenticationManager extends BaseManager {
12
+ private jwtToken: string | null = null;
13
+ private authenticated: boolean = false;
14
+
15
+ /**
16
+ * Get authentication from environment variables
17
+ */
18
+ static getAuthFromEnv(): AuthConfig {
19
+ const method: AuthMethod =
20
+ (process.env.WORDPRESS_AUTH_METHOD as AuthMethod) || "app-password";
21
+
22
+ switch (method) {
23
+ case "app-password":
24
+ return {
25
+ method: "app-password",
26
+ username: process.env.WORDPRESS_USERNAME || "",
27
+ appPassword: process.env.WORDPRESS_APP_PASSWORD || "",
28
+ };
29
+
30
+ case "jwt":
31
+ return {
32
+ method: "jwt",
33
+ username: process.env.WORDPRESS_USERNAME || "",
34
+ password: process.env.WORDPRESS_JWT_PASSWORD || process.env.WORDPRESS_PASSWORD || "",
35
+ secret: process.env.WORDPRESS_JWT_SECRET || "",
36
+ };
37
+
38
+ case "basic":
39
+ return {
40
+ method: "basic",
41
+ username: process.env.WORDPRESS_USERNAME || "",
42
+ password: process.env.WORDPRESS_PASSWORD || "",
43
+ };
44
+
45
+ case "api-key":
46
+ return {
47
+ method: "api-key",
48
+ apiKey: process.env.WORDPRESS_API_KEY || "",
49
+ };
50
+
51
+ default:
52
+ throw new AuthenticationError(`Unsupported authentication method: ${method}`, method);
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Get authentication headers for requests
58
+ */
59
+ async getAuthHeaders(): Promise<Record<string, string>> {
60
+ const auth = this.config.auth;
61
+
62
+ switch (auth.method) {
63
+ case "app-password":
64
+ if (!auth.username || !auth.appPassword) {
65
+ throw new AuthenticationError("Username and app password are required", auth.method);
66
+ }
67
+
68
+ const credentials = Buffer.from(`${auth.username}:${auth.appPassword}`).toString("base64");
69
+ return { Authorization: `Basic ${credentials}` };
70
+
71
+ case "jwt":
72
+ if (!this.jwtToken) {
73
+ await this.authenticateJWT();
74
+ }
75
+ return { Authorization: `Bearer ${this.jwtToken}` };
76
+
77
+ case "basic":
78
+ if (!auth.username || !auth.password) {
79
+ throw new AuthenticationError("Username and password are required", auth.method);
80
+ }
81
+
82
+ const basicCredentials = Buffer.from(`${auth.username}:${auth.password}`).toString("base64");
83
+ return { Authorization: `Basic ${basicCredentials}` };
84
+
85
+ case "api-key":
86
+ if (!auth.apiKey) {
87
+ throw new AuthenticationError("API key is required", auth.method);
88
+ }
89
+ return { "X-API-Key": auth.apiKey };
90
+
91
+ default:
92
+ throw new AuthenticationError(`Unsupported authentication method: ${auth.method}`, auth.method);
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Authenticate using JWT
98
+ */
99
+ private async authenticateJWT(): Promise<void> {
100
+ const auth = this.config.auth;
101
+
102
+ if (auth.method !== "jwt" || !auth.username || !auth.password) {
103
+ throw new AuthenticationError("JWT authentication requires username and password", "jwt");
104
+ }
105
+
106
+ try {
107
+ // This would need the RequestManager instance to make the request
108
+ // For now, we'll throw an error indicating this needs to be implemented
109
+ throw new AuthenticationError("JWT authentication requires RequestManager integration", "jwt");
110
+
111
+ } catch (error) {
112
+ this.handleError(error, "JWT authentication");
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Test authentication
118
+ */
119
+ async testAuthentication(): Promise<boolean> {
120
+ try {
121
+ const headers = await this.getAuthHeaders();
122
+ debug.log("Authentication headers prepared", { method: this.config.auth.method });
123
+
124
+ // This would need the RequestManager to actually test the connection
125
+ // For now, we'll return true if headers can be generated
126
+ this.authenticated = true;
127
+ return true;
128
+
129
+ } catch (error) {
130
+ this.authenticated = false;
131
+ debug.log("Authentication test failed", error);
132
+ return false;
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Get authentication status
138
+ */
139
+ isAuthenticated(): boolean {
140
+ return this.authenticated;
141
+ }
142
+
143
+ /**
144
+ * Clear authentication state
145
+ */
146
+ clearAuthentication(): void {
147
+ this.jwtToken = null;
148
+ this.authenticated = false;
149
+ }
150
+
151
+ /**
152
+ * Validate authentication configuration
153
+ */
154
+ validateAuthConfig(): void {
155
+ const auth = this.config.auth;
156
+
157
+ if (!auth.method) {
158
+ throw new AuthenticationError("Authentication method is required", "app-password");
159
+ }
160
+
161
+ switch (auth.method) {
162
+ case "app-password":
163
+ if (!auth.username || !auth.appPassword) {
164
+ throw new AuthenticationError("App password authentication requires username and appPassword", "app-password");
165
+ }
166
+ break;
167
+
168
+ case "jwt":
169
+ if (!auth.username || !auth.password || !auth.secret) {
170
+ throw new AuthenticationError("JWT authentication requires username, password, and secret", "jwt");
171
+ }
172
+ break;
173
+
174
+ case "basic":
175
+ if (!auth.username || !auth.password) {
176
+ throw new AuthenticationError("Basic authentication requires username and password", "basic");
177
+ }
178
+ break;
179
+
180
+ case "api-key":
181
+ if (!auth.apiKey) {
182
+ throw new AuthenticationError("API key authentication requires apiKey", "api-key");
183
+ }
184
+ break;
185
+
186
+ default:
187
+ throw new AuthenticationError(`Unsupported authentication method: ${auth.method}`, auth.method);
188
+ }
189
+ }
190
+ }