@marlinjai/email-mcp 1.7.0 → 1.7.1
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 +2 -0
- package/dist/index.js +34 -17
- package/dist/index.js.map +3 -3
- package/dist/setup/wizard.js +32 -15
- package/dist/setup/wizard.js.map +3 -3
- package/package.json +1 -1
package/dist/setup/wizard.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
// src/setup/wizard.ts
|
|
5
|
-
import
|
|
5
|
+
import crypto4 from "node:crypto";
|
|
6
6
|
import { exec } from "node:child_process";
|
|
7
7
|
|
|
8
8
|
// src/setup/prompts.ts
|
|
@@ -276,6 +276,7 @@ var OAuthCallbackServer = class {
|
|
|
276
276
|
rejectCode = null;
|
|
277
277
|
timeoutMs;
|
|
278
278
|
timeoutHandle = null;
|
|
279
|
+
expectedState = null;
|
|
279
280
|
constructor(timeoutMs = 12e4) {
|
|
280
281
|
this.timeoutMs = timeoutMs;
|
|
281
282
|
}
|
|
@@ -286,7 +287,12 @@ var OAuthCallbackServer = class {
|
|
|
286
287
|
if (url.pathname === "/callback" || url.pathname === "/") {
|
|
287
288
|
const code = url.searchParams.get("code");
|
|
288
289
|
const error = url.searchParams.get("error");
|
|
289
|
-
|
|
290
|
+
const state = url.searchParams.get("state");
|
|
291
|
+
if (code && this.expectedState !== null && state !== this.expectedState) {
|
|
292
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
293
|
+
res.end(ERROR_HTML);
|
|
294
|
+
this.rejectCode?.(new Error("OAuth error: state mismatch, callback did not come from the authorization request we started"));
|
|
295
|
+
} else if (code) {
|
|
290
296
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
291
297
|
res.end(SUCCESS_HTML);
|
|
292
298
|
this.resolveCode?.(code);
|
|
@@ -311,7 +317,13 @@ var OAuthCallbackServer = class {
|
|
|
311
317
|
this.server.on("error", reject);
|
|
312
318
|
});
|
|
313
319
|
}
|
|
314
|
-
|
|
320
|
+
/**
|
|
321
|
+
* Resolve with the authorization code once the browser is redirected back.
|
|
322
|
+
* Pass the `state` that was put into the authorization URL: callbacks whose
|
|
323
|
+
* state does not match are rejected instead of resolved (CSRF protection).
|
|
324
|
+
*/
|
|
325
|
+
waitForCode(expectedState) {
|
|
326
|
+
this.expectedState = expectedState ?? null;
|
|
315
327
|
return new Promise((resolve, reject) => {
|
|
316
328
|
this.resolveCode = (code) => {
|
|
317
329
|
if (this.timeoutHandle) clearTimeout(this.timeoutHandle);
|
|
@@ -381,15 +393,17 @@ var GmailAuth = class {
|
|
|
381
393
|
getAuthUrl(redirectUri, scopeMode) {
|
|
382
394
|
const codeVerifier = crypto2.randomBytes(32).toString("base64url");
|
|
383
395
|
const codeChallenge = crypto2.createHash("sha256").update(codeVerifier).digest("base64url");
|
|
396
|
+
const state = crypto2.randomBytes(16).toString("base64url");
|
|
384
397
|
this.oauth2Client = new OAuth2Client(this.clientId, this.clientSecret, redirectUri);
|
|
385
398
|
const url = this.oauth2Client.generateAuthUrl({
|
|
386
399
|
access_type: "offline",
|
|
387
400
|
scope: GMAIL_SCOPES[resolveScopeMode(scopeMode)],
|
|
388
401
|
prompt: "consent",
|
|
389
402
|
code_challenge: codeChallenge,
|
|
390
|
-
code_challenge_method: "S256"
|
|
403
|
+
code_challenge_method: "S256",
|
|
404
|
+
state
|
|
391
405
|
});
|
|
392
|
-
return { url, codeVerifier };
|
|
406
|
+
return { url, codeVerifier, state };
|
|
393
407
|
}
|
|
394
408
|
async exchangeCode(code, codeVerifier) {
|
|
395
409
|
const { tokens } = await this.oauth2Client.getToken({ code, codeVerifier });
|
|
@@ -421,6 +435,7 @@ var GmailAuth = class {
|
|
|
421
435
|
};
|
|
422
436
|
|
|
423
437
|
// src/providers/outlook/auth.ts
|
|
438
|
+
import crypto3 from "node:crypto";
|
|
424
439
|
import fs2 from "node:fs";
|
|
425
440
|
import path2 from "node:path";
|
|
426
441
|
import os2 from "node:os";
|
|
@@ -471,13 +486,15 @@ var OutlookAuth = class _OutlookAuth {
|
|
|
471
486
|
}
|
|
472
487
|
async getAuthUrl(redirectUri) {
|
|
473
488
|
const { verifier, challenge } = await this.cryptoProvider.generatePkceCodes();
|
|
489
|
+
const state = crypto3.randomBytes(16).toString("base64url");
|
|
474
490
|
const url = await this.pca.getAuthCodeUrl({
|
|
475
491
|
scopes: _OutlookAuth.SCOPES,
|
|
476
492
|
redirectUri,
|
|
477
493
|
codeChallenge: challenge,
|
|
478
|
-
codeChallengeMethod: "S256"
|
|
494
|
+
codeChallengeMethod: "S256",
|
|
495
|
+
state
|
|
479
496
|
});
|
|
480
|
-
return { url, codeVerifier: verifier };
|
|
497
|
+
return { url, codeVerifier: verifier, state };
|
|
481
498
|
}
|
|
482
499
|
async exchangeCode(code, codeVerifier, redirectUri) {
|
|
483
500
|
const result = await this.pca.acquireTokenByCode({
|
|
@@ -2887,7 +2904,7 @@ async function setupGmail(scopeModeFlag) {
|
|
|
2887
2904
|
const port = await server.start();
|
|
2888
2905
|
const redirectUri = `http://localhost:${port}/callback`;
|
|
2889
2906
|
const gmailAuth = new GmailAuth(GMAIL_CLIENT_ID, GMAIL_CLIENT_SECRET, redirectUri);
|
|
2890
|
-
const { url, codeVerifier } = gmailAuth.getAuthUrl(redirectUri, scopeMode);
|
|
2907
|
+
const { url, codeVerifier, state } = gmailAuth.getAuthUrl(redirectUri, scopeMode);
|
|
2891
2908
|
console.log("\nOpening browser for Google authorization...");
|
|
2892
2909
|
console.log(`If the browser does not open, visit:
|
|
2893
2910
|
${url}
|
|
@@ -2895,7 +2912,7 @@ ${url}
|
|
|
2895
2912
|
openBrowser(url);
|
|
2896
2913
|
let code;
|
|
2897
2914
|
try {
|
|
2898
|
-
code = await server.waitForCode();
|
|
2915
|
+
code = await server.waitForCode(state);
|
|
2899
2916
|
} catch (err) {
|
|
2900
2917
|
server.shutdown();
|
|
2901
2918
|
throw new Error(`OAuth flow failed: ${err.message}`);
|
|
@@ -2911,7 +2928,7 @@ ${url}
|
|
|
2911
2928
|
if (!email) throw new Error("Could not retrieve Gmail address from profile");
|
|
2912
2929
|
console.log(`Authenticated as ${email}`);
|
|
2913
2930
|
const name = await promptAccountName("Gmail");
|
|
2914
|
-
const id =
|
|
2931
|
+
const id = crypto4.randomUUID();
|
|
2915
2932
|
const creds = {
|
|
2916
2933
|
id,
|
|
2917
2934
|
name,
|
|
@@ -2928,7 +2945,7 @@ async function setupOutlook() {
|
|
|
2928
2945
|
const port = await server.start();
|
|
2929
2946
|
const redirectUri = `http://localhost:${port}`;
|
|
2930
2947
|
const outlookAuth = new OutlookAuth(OUTLOOK_CLIENT_ID);
|
|
2931
|
-
const { url, codeVerifier } = await outlookAuth.getAuthUrl(redirectUri);
|
|
2948
|
+
const { url, codeVerifier, state } = await outlookAuth.getAuthUrl(redirectUri);
|
|
2932
2949
|
console.log("\nOpening browser for Microsoft authorization...");
|
|
2933
2950
|
console.log(`If the browser does not open, visit:
|
|
2934
2951
|
${url}
|
|
@@ -2936,7 +2953,7 @@ ${url}
|
|
|
2936
2953
|
openBrowser(url);
|
|
2937
2954
|
let code;
|
|
2938
2955
|
try {
|
|
2939
|
-
code = await server.waitForCode();
|
|
2956
|
+
code = await server.waitForCode(state);
|
|
2940
2957
|
} catch (err) {
|
|
2941
2958
|
server.shutdown();
|
|
2942
2959
|
throw new Error(`OAuth flow failed: ${err.message}`);
|
|
@@ -2949,7 +2966,7 @@ ${url}
|
|
|
2949
2966
|
if (!email) throw new Error("Could not retrieve email from Microsoft account");
|
|
2950
2967
|
console.log(`Authenticated as ${email}`);
|
|
2951
2968
|
const name = await promptAccountName("Outlook");
|
|
2952
|
-
const id =
|
|
2969
|
+
const id = crypto4.randomUUID();
|
|
2953
2970
|
const creds = {
|
|
2954
2971
|
id,
|
|
2955
2972
|
name,
|
|
@@ -2981,7 +2998,7 @@ async function setupICloud() {
|
|
|
2981
2998
|
password = await askPassword("App-specific password:");
|
|
2982
2999
|
}
|
|
2983
3000
|
const name = await promptAccountName("iCloud");
|
|
2984
|
-
const id =
|
|
3001
|
+
const id = crypto4.randomUUID();
|
|
2985
3002
|
const creds = {
|
|
2986
3003
|
id,
|
|
2987
3004
|
name,
|
|
@@ -3022,7 +3039,7 @@ async function setupIMAP() {
|
|
|
3022
3039
|
smtpPort = parseInt(smtpPortStr, 10);
|
|
3023
3040
|
}
|
|
3024
3041
|
const name = await promptAccountName("IMAP");
|
|
3025
|
-
const id =
|
|
3042
|
+
const id = crypto4.randomUUID();
|
|
3026
3043
|
const creds = {
|
|
3027
3044
|
id,
|
|
3028
3045
|
name,
|