msoutlook-mcp 0.1.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 +134 -0
- package/dist/api/calendar.d.ts +90 -0
- package/dist/api/calendar.d.ts.map +1 -0
- package/dist/api/calendar.js +102 -0
- package/dist/api/calendar.js.map +1 -0
- package/dist/api/client.d.ts +14 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +93 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/contacts.d.ts +43 -0
- package/dist/api/contacts.d.ts.map +1 -0
- package/dist/api/contacts.js +45 -0
- package/dist/api/contacts.js.map +1 -0
- package/dist/api/mail.d.ts +90 -0
- package/dist/api/mail.d.ts.map +1 -0
- package/dist/api/mail.js +148 -0
- package/dist/api/mail.js.map +1 -0
- package/dist/api/people.d.ts +28 -0
- package/dist/api/people.d.ts.map +1 -0
- package/dist/api/people.js +16 -0
- package/dist/api/people.js.map +1 -0
- package/dist/auth/browser-login.d.ts +26 -0
- package/dist/auth/browser-login.d.ts.map +1 -0
- package/dist/auth/browser-login.js +398 -0
- package/dist/auth/browser-login.js.map +1 -0
- package/dist/auth/index.d.ts +34 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +89 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/session-store.d.ts +38 -0
- package/dist/auth/session-store.d.ts.map +1 -0
- package/dist/auth/session-store.js +163 -0
- package/dist/auth/session-store.js.map +1 -0
- package/dist/auth/token-extractor.d.ts +46 -0
- package/dist/auth/token-extractor.d.ts.map +1 -0
- package/dist/auth/token-extractor.js +126 -0
- package/dist/auth/token-extractor.js.map +1 -0
- package/dist/auth/token-refresh.d.ts +23 -0
- package/dist/auth/token-refresh.d.ts.map +1 -0
- package/dist/auth/token-refresh.js +133 -0
- package/dist/auth/token-refresh.js.map +1 -0
- package/dist/browser/cookie-import.d.ts +30 -0
- package/dist/browser/cookie-import.d.ts.map +1 -0
- package/dist/browser/cookie-import.js +446 -0
- package/dist/browser/cookie-import.js.map +1 -0
- package/dist/constants.d.ts +27 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +39 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +20 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/auth-tools.d.ts +6 -0
- package/dist/tools/auth-tools.d.ts.map +1 -0
- package/dist/tools/auth-tools.js +116 -0
- package/dist/tools/auth-tools.js.map +1 -0
- package/dist/tools/calendar-tools.d.ts +6 -0
- package/dist/tools/calendar-tools.d.ts.map +1 -0
- package/dist/tools/calendar-tools.js +168 -0
- package/dist/tools/calendar-tools.js.map +1 -0
- package/dist/tools/contact-tools.d.ts +6 -0
- package/dist/tools/contact-tools.d.ts.map +1 -0
- package/dist/tools/contact-tools.js +105 -0
- package/dist/tools/contact-tools.js.map +1 -0
- package/dist/tools/mail-tools.d.ts +6 -0
- package/dist/tools/mail-tools.d.ts.map +1 -0
- package/dist/tools/mail-tools.js +196 -0
- package/dist/tools/mail-tools.js.map +1 -0
- package/dist/utils/http.d.ts +15 -0
- package/dist/utils/http.d.ts.map +1 -0
- package/dist/utils/http.js +48 -0
- package/dist/utils/http.js.map +1 -0
- package/dist/utils/logger.d.ts +10 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +21 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP-based token refresh.
|
|
3
|
+
*
|
|
4
|
+
* Uses the OWA first-party client ID (public SPA — no client secret needed) to
|
|
5
|
+
* exchange a cached refresh token for new access tokens via the standard
|
|
6
|
+
* OAuth2 token endpoint.
|
|
7
|
+
*
|
|
8
|
+
* Key detail (from msteams-mcp): the Origin header is REQUIRED for SPA
|
|
9
|
+
* client IDs. Azure AD validates that refresh token grants from SPA clients
|
|
10
|
+
* include a cross-origin Origin header matching a registered redirect URI.
|
|
11
|
+
* Without it Azure AD returns AADSTS9002327.
|
|
12
|
+
*/
|
|
13
|
+
import { logger } from '../utils/logger.js';
|
|
14
|
+
import { OWA_CLIENT_ID, OWA_SCOPE, GRAPH_SCOPE, OWA_BASE } from '../constants.js';
|
|
15
|
+
import { readTokenCache, writeTokenCache } from './session-store.js';
|
|
16
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
17
|
+
// Concurrent refresh guards — separate per resource so an OWA refresh doesn't
|
|
18
|
+
// block a Graph refresh (mirrors msteams-mcp's guard, split by scope).
|
|
19
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
20
|
+
let owaRefreshInProgress = false;
|
|
21
|
+
let graphRefreshInProgress = false;
|
|
22
|
+
const REFRESH_TIMEOUT_MS = 10_000;
|
|
23
|
+
async function callTokenEndpoint(tenantId, refreshToken, scope) {
|
|
24
|
+
const url = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`;
|
|
25
|
+
const body = new URLSearchParams({
|
|
26
|
+
client_id: OWA_CLIENT_ID,
|
|
27
|
+
grant_type: 'refresh_token',
|
|
28
|
+
refresh_token: refreshToken,
|
|
29
|
+
scope,
|
|
30
|
+
});
|
|
31
|
+
const controller = new AbortController();
|
|
32
|
+
const timer = setTimeout(() => controller.abort(), REFRESH_TIMEOUT_MS);
|
|
33
|
+
try {
|
|
34
|
+
const res = await fetch(url, {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
headers: {
|
|
37
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
38
|
+
// Required for SPA public clients — Azure AD returns AADSTS9002327 without this
|
|
39
|
+
'Origin': OWA_BASE,
|
|
40
|
+
},
|
|
41
|
+
body: body.toString(),
|
|
42
|
+
signal: controller.signal,
|
|
43
|
+
});
|
|
44
|
+
if (!res.ok) {
|
|
45
|
+
const text = await res.text().catch(() => '');
|
|
46
|
+
logger.warn(`Token refresh HTTP ${res.status}`, text.slice(0, 200));
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
return await res.json();
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
53
|
+
logger.warn('Token refresh request timed out');
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
logger.warn('Token refresh network error', err instanceof Error ? err.message : String(err));
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
clearTimeout(timer);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
65
|
+
// Public refresh functions
|
|
66
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
67
|
+
/**
|
|
68
|
+
* Refresh the OWA access token via HTTP.
|
|
69
|
+
* Returns the new access token on success, null on failure.
|
|
70
|
+
* Prevents concurrent refresh races with module-level guard.
|
|
71
|
+
*/
|
|
72
|
+
export async function refreshOwaToken() {
|
|
73
|
+
if (owaRefreshInProgress) {
|
|
74
|
+
logger.debug('OWA token refresh already in progress');
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const cache = readTokenCache();
|
|
78
|
+
if (!cache?.refreshToken || !cache.tenantId) {
|
|
79
|
+
logger.debug('No refresh token or tenant ID cached');
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
owaRefreshInProgress = true;
|
|
83
|
+
try {
|
|
84
|
+
logger.debug('Refreshing OWA access token via HTTP');
|
|
85
|
+
const response = await callTokenEndpoint(cache.tenantId, cache.refreshToken, OWA_SCOPE);
|
|
86
|
+
if (!response)
|
|
87
|
+
return null;
|
|
88
|
+
const updated = {
|
|
89
|
+
...cache,
|
|
90
|
+
owaToken: response.access_token,
|
|
91
|
+
owaTokenExpiry: Date.now() + response.expires_in * 1000,
|
|
92
|
+
refreshToken: response.refresh_token ?? cache.refreshToken,
|
|
93
|
+
extractedAt: Date.now(),
|
|
94
|
+
};
|
|
95
|
+
writeTokenCache(updated);
|
|
96
|
+
logger.info('OWA token refreshed successfully');
|
|
97
|
+
return response.access_token;
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
owaRefreshInProgress = false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Refresh the Graph access token via HTTP.
|
|
105
|
+
*/
|
|
106
|
+
export async function refreshGraphToken() {
|
|
107
|
+
if (graphRefreshInProgress)
|
|
108
|
+
return null;
|
|
109
|
+
const cache = readTokenCache();
|
|
110
|
+
if (!cache?.refreshToken || !cache.tenantId)
|
|
111
|
+
return null;
|
|
112
|
+
graphRefreshInProgress = true;
|
|
113
|
+
try {
|
|
114
|
+
logger.debug('Refreshing Graph access token via HTTP');
|
|
115
|
+
const response = await callTokenEndpoint(cache.tenantId, cache.refreshToken, GRAPH_SCOPE);
|
|
116
|
+
if (!response)
|
|
117
|
+
return null;
|
|
118
|
+
const updated = {
|
|
119
|
+
...cache,
|
|
120
|
+
graphToken: response.access_token,
|
|
121
|
+
graphTokenExpiry: Date.now() + response.expires_in * 1000,
|
|
122
|
+
refreshToken: response.refresh_token ?? cache.refreshToken,
|
|
123
|
+
extractedAt: Date.now(),
|
|
124
|
+
};
|
|
125
|
+
writeTokenCache(updated);
|
|
126
|
+
logger.info('Graph token refreshed successfully');
|
|
127
|
+
return response.access_token;
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
graphRefreshInProgress = false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=token-refresh.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-refresh.js","sourceRoot":"","sources":["../../src/auth/token-refresh.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Import Microsoft SSO cookies from the user's real browser profile into a
|
|
3
|
+
* Playwright context, enabling silent SSO on first login without re-entering
|
|
4
|
+
* credentials.
|
|
5
|
+
*
|
|
6
|
+
* Supports all major platforms:
|
|
7
|
+
* macOS — Chrome/Edge via macOS Keychain, AES-128-CBC
|
|
8
|
+
* Linux — Chrome/Edge via libsecret / "peanuts" fallback, AES-128-CBC
|
|
9
|
+
* Windows — Chrome/Edge via DPAPI (PowerShell), AES-256-GCM
|
|
10
|
+
*
|
|
11
|
+
* SQLite access uses sql.js (pure JS/WASM) — no native build tools needed.
|
|
12
|
+
*
|
|
13
|
+
* Fails gracefully on every error: cookie import is a best-effort optimisation.
|
|
14
|
+
* If it fails the user falls back to a normal headed browser login.
|
|
15
|
+
*
|
|
16
|
+
* NOTE — Chrome 127+ on Windows uses App-Bound Encryption (prefix "APPB")
|
|
17
|
+
* which cannot be decrypted outside the Chrome process. Those cookies are
|
|
18
|
+
* silently skipped. Edge on Windows is unaffected and remains fully supported.
|
|
19
|
+
*/
|
|
20
|
+
import type { BrowserContext } from 'playwright';
|
|
21
|
+
/**
|
|
22
|
+
* Import Microsoft SSO cookies from the user's real browser into the Playwright
|
|
23
|
+
* context. Enables instant silent authentication — OWA recognises the session
|
|
24
|
+
* and skips the login page entirely.
|
|
25
|
+
*
|
|
26
|
+
* @param context - Playwright browser context to inject cookies into
|
|
27
|
+
* @param channel - Browser channel in use: 'chrome', 'msedge', or undefined
|
|
28
|
+
*/
|
|
29
|
+
export declare function importMicrosoftCookies(context: BrowserContext, channel: string | undefined): Promise<void>;
|
|
30
|
+
//# sourceMappingURL=cookie-import.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookie-import.d.ts","sourceRoot":"","sources":["../../src/browser/cookie-import.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAOH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAiXjD;;;;;;;GAOG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,MAAM,GAAG,SAAS,GAC1B,OAAO,CAAC,IAAI,CAAC,CAgHf"}
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Import Microsoft SSO cookies from the user's real browser profile into a
|
|
3
|
+
* Playwright context, enabling silent SSO on first login without re-entering
|
|
4
|
+
* credentials.
|
|
5
|
+
*
|
|
6
|
+
* Supports all major platforms:
|
|
7
|
+
* macOS — Chrome/Edge via macOS Keychain, AES-128-CBC
|
|
8
|
+
* Linux — Chrome/Edge via libsecret / "peanuts" fallback, AES-128-CBC
|
|
9
|
+
* Windows — Chrome/Edge via DPAPI (PowerShell), AES-256-GCM
|
|
10
|
+
*
|
|
11
|
+
* SQLite access uses sql.js (pure JS/WASM) — no native build tools needed.
|
|
12
|
+
*
|
|
13
|
+
* Fails gracefully on every error: cookie import is a best-effort optimisation.
|
|
14
|
+
* If it fails the user falls back to a normal headed browser login.
|
|
15
|
+
*
|
|
16
|
+
* NOTE — Chrome 127+ on Windows uses App-Bound Encryption (prefix "APPB")
|
|
17
|
+
* which cannot be decrypted outside the Chrome process. Those cookies are
|
|
18
|
+
* silently skipped. Edge on Windows is unaffected and remains fully supported.
|
|
19
|
+
*/
|
|
20
|
+
import * as crypto from 'node:crypto';
|
|
21
|
+
import * as fs from 'node:fs';
|
|
22
|
+
import * as os from 'node:os';
|
|
23
|
+
import * as path from 'node:path';
|
|
24
|
+
import { execSync } from 'node:child_process';
|
|
25
|
+
import { logger } from '../utils/logger.js';
|
|
26
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
27
|
+
// Per-platform browser configs
|
|
28
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
29
|
+
function getBrowserConfigs() {
|
|
30
|
+
const home = os.homedir();
|
|
31
|
+
if (process.platform === 'darwin') {
|
|
32
|
+
return {
|
|
33
|
+
chrome: {
|
|
34
|
+
label: 'Chrome',
|
|
35
|
+
dataDir: path.join(home, 'Library', 'Application Support', 'Google', 'Chrome'),
|
|
36
|
+
keychainService: 'Chrome Safe Storage',
|
|
37
|
+
profileEnvVar: 'MSOUTLOOK_CHROME_PROFILE',
|
|
38
|
+
},
|
|
39
|
+
msedge: {
|
|
40
|
+
label: 'Edge',
|
|
41
|
+
dataDir: path.join(home, 'Library', 'Application Support', 'Microsoft Edge'),
|
|
42
|
+
keychainService: 'Microsoft Edge Safe Storage',
|
|
43
|
+
profileEnvVar: 'MSOUTLOOK_EDGE_PROFILE',
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
if (process.platform === 'win32') {
|
|
48
|
+
const localAppData = process.env.LOCALAPPDATA ?? path.join(home, 'AppData', 'Local');
|
|
49
|
+
return {
|
|
50
|
+
chrome: {
|
|
51
|
+
label: 'Chrome',
|
|
52
|
+
dataDir: path.join(localAppData, 'Google', 'Chrome', 'User Data'),
|
|
53
|
+
profileEnvVar: 'MSOUTLOOK_CHROME_PROFILE',
|
|
54
|
+
},
|
|
55
|
+
msedge: {
|
|
56
|
+
label: 'Edge',
|
|
57
|
+
dataDir: path.join(localAppData, 'Microsoft', 'Edge', 'User Data'),
|
|
58
|
+
profileEnvVar: 'MSOUTLOOK_EDGE_PROFILE',
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
// Linux
|
|
63
|
+
return {
|
|
64
|
+
chrome: {
|
|
65
|
+
label: 'Chrome',
|
|
66
|
+
dataDir: path.join(home, '.config', 'google-chrome'),
|
|
67
|
+
keychainService: 'Chrome Safe Storage',
|
|
68
|
+
profileEnvVar: 'MSOUTLOOK_CHROME_PROFILE',
|
|
69
|
+
},
|
|
70
|
+
msedge: {
|
|
71
|
+
label: 'Edge',
|
|
72
|
+
dataDir: path.join(home, '.config', 'microsoft-edge'),
|
|
73
|
+
keychainService: 'Microsoft Edge Safe Storage',
|
|
74
|
+
profileEnvVar: 'MSOUTLOOK_EDGE_PROFILE',
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
79
|
+
// Profile detection
|
|
80
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
81
|
+
function selectProfile(dataDir, envVar) {
|
|
82
|
+
const override = process.env[envVar];
|
|
83
|
+
if (override)
|
|
84
|
+
return override;
|
|
85
|
+
// Chrome/Edge newer versions store cookies at Default/Network/Cookies
|
|
86
|
+
// Try Default profile first (most common), fall back to scanning
|
|
87
|
+
const defaultPath = path.join(dataDir, 'Default');
|
|
88
|
+
if (fs.existsSync(path.join(defaultPath, 'Network', 'Cookies')) ||
|
|
89
|
+
fs.existsSync(path.join(defaultPath, 'Cookies'))) {
|
|
90
|
+
return 'Default';
|
|
91
|
+
}
|
|
92
|
+
// Scan Local State for other profiles
|
|
93
|
+
const localStatePath = path.join(dataDir, 'Local State');
|
|
94
|
+
if (!fs.existsSync(localStatePath))
|
|
95
|
+
return null;
|
|
96
|
+
try {
|
|
97
|
+
const state = JSON.parse(fs.readFileSync(localStatePath, 'utf8'));
|
|
98
|
+
const cache = state.profile?.info_cache ?? {};
|
|
99
|
+
return Object.keys(cache)[0] ?? null;
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/** Returns the Cookies database path, checking both old and new locations. */
|
|
106
|
+
function getCookiesDbPath(dataDir, profile) {
|
|
107
|
+
const base = path.join(dataDir, profile);
|
|
108
|
+
// Newer Chrome/Edge moved cookies into a Network sub-directory
|
|
109
|
+
const newPath = path.join(base, 'Network', 'Cookies');
|
|
110
|
+
if (fs.existsSync(newPath))
|
|
111
|
+
return newPath;
|
|
112
|
+
const oldPath = path.join(base, 'Cookies');
|
|
113
|
+
if (fs.existsSync(oldPath))
|
|
114
|
+
return oldPath;
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
118
|
+
// SQLite reading (sql.js — pure JS/WASM, no native deps)
|
|
119
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
120
|
+
const MICROSOFT_DOMAINS_SQL = [
|
|
121
|
+
'%microsoftonline%',
|
|
122
|
+
'%login.live.com%',
|
|
123
|
+
'%login.microsoft.com%',
|
|
124
|
+
'%microsoft.com%',
|
|
125
|
+
'%office.com%',
|
|
126
|
+
'%office365.com%',
|
|
127
|
+
'%outlook.com%',
|
|
128
|
+
].map(d => `host_key LIKE '${d}'`).join(' OR ');
|
|
129
|
+
async function readCookiesFromDb(dbPath) {
|
|
130
|
+
// Copy to temp to avoid locking conflicts with a running browser
|
|
131
|
+
const tmpDb = path.join(os.tmpdir(), `msoutlook-mcp-cookies-${Date.now()}.db`);
|
|
132
|
+
try {
|
|
133
|
+
fs.copyFileSync(dbPath, tmpDb);
|
|
134
|
+
for (const ext of ['-wal', '-shm']) {
|
|
135
|
+
const src = dbPath + ext;
|
|
136
|
+
if (fs.existsSync(src))
|
|
137
|
+
fs.copyFileSync(src, tmpDb + ext);
|
|
138
|
+
}
|
|
139
|
+
// Dynamic import so sql.js WASM loads lazily (only when cookie import runs)
|
|
140
|
+
const initSqlJs = (await import('sql.js')).default;
|
|
141
|
+
const SQL = await initSqlJs();
|
|
142
|
+
const fileBuffer = fs.readFileSync(tmpDb);
|
|
143
|
+
const db = new SQL.Database(fileBuffer);
|
|
144
|
+
const result = db.exec(`SELECT host_key, name, encrypted_value, path, expires_utc,
|
|
145
|
+
is_secure, is_httponly, samesite
|
|
146
|
+
FROM cookies
|
|
147
|
+
WHERE (${MICROSOFT_DOMAINS_SQL}) AND expires_utc > 0`);
|
|
148
|
+
db.close();
|
|
149
|
+
if (!result[0])
|
|
150
|
+
return [];
|
|
151
|
+
const { columns, values } = result[0];
|
|
152
|
+
const idx = (col) => columns.indexOf(col);
|
|
153
|
+
return values.map(row => ({
|
|
154
|
+
host_key: row[idx('host_key')],
|
|
155
|
+
name: row[idx('name')],
|
|
156
|
+
encrypted_value: Buffer.from(row[idx('encrypted_value')]),
|
|
157
|
+
path: row[idx('path')],
|
|
158
|
+
expires_utc: row[idx('expires_utc')],
|
|
159
|
+
is_secure: row[idx('is_secure')],
|
|
160
|
+
is_httponly: row[idx('is_httponly')],
|
|
161
|
+
samesite: row[idx('samesite')],
|
|
162
|
+
}));
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
logger.debug('Failed to read cookies DB', err instanceof Error ? err.message : String(err));
|
|
166
|
+
return [];
|
|
167
|
+
}
|
|
168
|
+
finally {
|
|
169
|
+
for (const f of [tmpDb, `${tmpDb}-wal`, `${tmpDb}-shm`]) {
|
|
170
|
+
try {
|
|
171
|
+
fs.unlinkSync(f);
|
|
172
|
+
}
|
|
173
|
+
catch { /* ignore */ }
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
178
|
+
// macOS key retrieval (Keychain AES-128-CBC)
|
|
179
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
180
|
+
const macKeyCache = new Map();
|
|
181
|
+
function getMacOSDecryptionKey(keychainService) {
|
|
182
|
+
if (macKeyCache.has(keychainService))
|
|
183
|
+
return macKeyCache.get(keychainService) ?? null;
|
|
184
|
+
try {
|
|
185
|
+
const password = execSync(`security find-generic-password -s "${keychainService}" -w`, { encoding: 'utf8', timeout: 5000 }).trim();
|
|
186
|
+
const key = crypto.pbkdf2Sync(password, 'saltysalt', 1003, 16, 'sha1');
|
|
187
|
+
macKeyCache.set(keychainService, key);
|
|
188
|
+
return key;
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
macKeyCache.set(keychainService, null);
|
|
192
|
+
return null;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
196
|
+
// Linux key retrieval (libsecret → "peanuts" fallback, AES-128-CBC)
|
|
197
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
198
|
+
const linuxKeyCache = new Map();
|
|
199
|
+
function getLinuxDecryptionKey(keychainService) {
|
|
200
|
+
if (linuxKeyCache.has(keychainService))
|
|
201
|
+
return linuxKeyCache.get(keychainService);
|
|
202
|
+
let password = 'peanuts'; // fallback used when no keyring is available
|
|
203
|
+
// Try libsecret first (GNOME / systemd)
|
|
204
|
+
const appName = keychainService.toLowerCase().includes('edge') ? 'microsoft-edge' : 'chrome';
|
|
205
|
+
const secretToolAttempts = [
|
|
206
|
+
`secret-tool lookup xdg:schema chrome_libsecret_os_crypt_password_v2 application ${appName}`,
|
|
207
|
+
`secret-tool lookup xdg:schema chrome_libsecret_os_crypt_password_v1 application ${appName}`,
|
|
208
|
+
`secret-tool lookup service "${keychainService}" account "${appName}"`,
|
|
209
|
+
];
|
|
210
|
+
for (const cmd of secretToolAttempts) {
|
|
211
|
+
try {
|
|
212
|
+
const result = execSync(cmd, { encoding: 'utf8', timeout: 3000 }).trim();
|
|
213
|
+
if (result) {
|
|
214
|
+
password = result;
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
catch { /* continue */ }
|
|
219
|
+
}
|
|
220
|
+
// Linux uses 1 PBKDF2 iteration (vs 1003 on macOS)
|
|
221
|
+
const key = crypto.pbkdf2Sync(password, 'saltysalt', 1, 16, 'sha1');
|
|
222
|
+
linuxKeyCache.set(keychainService, key);
|
|
223
|
+
return key;
|
|
224
|
+
}
|
|
225
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
226
|
+
// Windows key retrieval (DPAPI via PowerShell + AES-256-GCM)
|
|
227
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
228
|
+
let windowsAesKeyCache = null;
|
|
229
|
+
function getWindowsDecryptionKey(dataDir) {
|
|
230
|
+
if (!windowsAesKeyCache)
|
|
231
|
+
windowsAesKeyCache = new Map();
|
|
232
|
+
if (windowsAesKeyCache.has(dataDir))
|
|
233
|
+
return windowsAesKeyCache.get(dataDir) ?? null;
|
|
234
|
+
try {
|
|
235
|
+
const localStatePath = path.join(dataDir, 'Local State');
|
|
236
|
+
if (!fs.existsSync(localStatePath))
|
|
237
|
+
return null;
|
|
238
|
+
const localState = JSON.parse(fs.readFileSync(localStatePath, 'utf8'));
|
|
239
|
+
const encryptedKeyB64 = localState.os_crypt?.encrypted_key;
|
|
240
|
+
if (!encryptedKeyB64)
|
|
241
|
+
return null;
|
|
242
|
+
// The key is base64-encoded; first 5 bytes are the literal ASCII "DPAPI" prefix
|
|
243
|
+
const encryptedKeyBytes = Buffer.from(encryptedKeyB64, 'base64');
|
|
244
|
+
const dpapiBlob = encryptedKeyBytes.subarray(5); // strip "DPAPI"
|
|
245
|
+
const dpapiB64 = dpapiBlob.toString('base64');
|
|
246
|
+
// Use PowerShell (always available on Windows 10+) to call CryptUnprotectData
|
|
247
|
+
const psScript = `Add-Type -AssemblyName System.Security; [System.Convert]::ToBase64String([System.Security.Cryptography.ProtectedData]::Unprotect([System.Convert]::FromBase64String('${dpapiB64}'), $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser))`;
|
|
248
|
+
const decryptedB64 = execSync(`powershell -NoProfile -NonInteractive -Command "${psScript}"`, { encoding: 'utf8', timeout: 10_000 }).trim();
|
|
249
|
+
const key = Buffer.from(decryptedB64, 'base64');
|
|
250
|
+
windowsAesKeyCache.set(dataDir, key);
|
|
251
|
+
return key;
|
|
252
|
+
}
|
|
253
|
+
catch (err) {
|
|
254
|
+
logger.debug('Windows DPAPI key retrieval failed', err instanceof Error ? err.message : String(err));
|
|
255
|
+
windowsAesKeyCache.set(dataDir, null);
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
260
|
+
// Cookie decryption (platform-aware)
|
|
261
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
262
|
+
/**
|
|
263
|
+
* Strip the 32-byte SHA256(host_key) domain-hash prefix that Chrome/Edge v24+
|
|
264
|
+
* (2024) prepend to the plaintext before encryption. Older cookies have no
|
|
265
|
+
* prefix, so we only strip when the first 32 bytes actually match the hash.
|
|
266
|
+
*/
|
|
267
|
+
function stripDomainHashPrefix(plaintext, hostKey) {
|
|
268
|
+
if (plaintext.length < 32)
|
|
269
|
+
return plaintext;
|
|
270
|
+
const domainHash = crypto.createHash('sha256').update(hostKey).digest();
|
|
271
|
+
return plaintext.subarray(0, 32).equals(domainHash) ? plaintext.subarray(32) : plaintext;
|
|
272
|
+
}
|
|
273
|
+
function decryptCookieValue(encryptedValue, platform, key, hostKey) {
|
|
274
|
+
if (encryptedValue.length < 4)
|
|
275
|
+
return null;
|
|
276
|
+
const prefix = encryptedValue.subarray(0, 3).toString('ascii');
|
|
277
|
+
// App-Bound Encryption (Chrome 127+ on Windows) — cannot decrypt externally
|
|
278
|
+
if (encryptedValue.subarray(0, 4).toString('ascii') === 'APPB') {
|
|
279
|
+
return null;
|
|
280
|
+
}
|
|
281
|
+
if (prefix !== 'v10' && prefix !== 'v11') {
|
|
282
|
+
// Unencrypted plain-text value (legacy)
|
|
283
|
+
return encryptedValue.toString('utf8').replace(/\0/g, '');
|
|
284
|
+
}
|
|
285
|
+
try {
|
|
286
|
+
let plaintext;
|
|
287
|
+
if (platform === 'win32') {
|
|
288
|
+
// Windows: AES-256-GCM
|
|
289
|
+
// Layout: v10 (3 bytes) | nonce (12 bytes) | ciphertext | tag (16 bytes)
|
|
290
|
+
// Minimum valid length = 3 + 12 + 16 = 31 bytes
|
|
291
|
+
if (encryptedValue.length < 31)
|
|
292
|
+
return null;
|
|
293
|
+
const nonce = encryptedValue.subarray(3, 15);
|
|
294
|
+
const ciphertextWithTag = encryptedValue.subarray(15);
|
|
295
|
+
const tag = ciphertextWithTag.subarray(-16);
|
|
296
|
+
const ciphertext = ciphertextWithTag.subarray(0, -16);
|
|
297
|
+
const decipher = crypto.createDecipheriv('aes-256-gcm', key, nonce);
|
|
298
|
+
decipher.setAuthTag(tag);
|
|
299
|
+
plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
// macOS / Linux: AES-128-CBC
|
|
303
|
+
// Layout: v10/v11 (3 bytes) | ciphertext (rest)
|
|
304
|
+
const ciphertext = encryptedValue.subarray(3);
|
|
305
|
+
const iv = Buffer.alloc(16, 0x20); // 16 space characters
|
|
306
|
+
const decipher = crypto.createDecipheriv('aes-128-cbc', key, iv);
|
|
307
|
+
decipher.setAutoPadding(true);
|
|
308
|
+
plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
309
|
+
}
|
|
310
|
+
// Strip the v24+ domain-hash prefix if present, then decode.
|
|
311
|
+
return stripDomainHashPrefix(plaintext, hostKey).toString('utf8');
|
|
312
|
+
}
|
|
313
|
+
catch {
|
|
314
|
+
return null;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
318
|
+
// Cookie conversion helpers
|
|
319
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
320
|
+
function chromeEpochToUnix(ts) {
|
|
321
|
+
return Math.floor(ts / 1_000_000) - 11644473600;
|
|
322
|
+
}
|
|
323
|
+
function sameSiteLabel(v) {
|
|
324
|
+
if (v === 2)
|
|
325
|
+
return 'Strict';
|
|
326
|
+
if (v === 1)
|
|
327
|
+
return 'Lax';
|
|
328
|
+
return 'None';
|
|
329
|
+
}
|
|
330
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
331
|
+
// Main export
|
|
332
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
333
|
+
/**
|
|
334
|
+
* Import Microsoft SSO cookies from the user's real browser into the Playwright
|
|
335
|
+
* context. Enables instant silent authentication — OWA recognises the session
|
|
336
|
+
* and skips the login page entirely.
|
|
337
|
+
*
|
|
338
|
+
* @param context - Playwright browser context to inject cookies into
|
|
339
|
+
* @param channel - Browser channel in use: 'chrome', 'msedge', or undefined
|
|
340
|
+
*/
|
|
341
|
+
export async function importMicrosoftCookies(context, channel) {
|
|
342
|
+
// Opt-out: users who'd rather sign in once manually (and avoid the one-time
|
|
343
|
+
// Keychain/keyring prompt) can set this. The persistent profile then
|
|
344
|
+
// remembers the session for all future logins.
|
|
345
|
+
if (process.env.MSOUTLOOK_SKIP_COOKIE_IMPORT === 'true') {
|
|
346
|
+
logger.debug('Cookie import skipped (MSOUTLOOK_SKIP_COOKIE_IMPORT=true)');
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
const platform = process.platform;
|
|
350
|
+
const configs = getBrowserConfigs();
|
|
351
|
+
const browserKey = channel === 'msedge' ? 'msedge' : 'chrome';
|
|
352
|
+
const config = configs[browserKey];
|
|
353
|
+
if (!config)
|
|
354
|
+
return;
|
|
355
|
+
if (!fs.existsSync(config.dataDir)) {
|
|
356
|
+
logger.debug(`${config.label} data dir not found — skipping cookie import`);
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
const profile = selectProfile(config.dataDir, config.profileEnvVar);
|
|
360
|
+
if (!profile) {
|
|
361
|
+
logger.debug(`No ${config.label} profile found — skipping cookie import`);
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
const dbPath = getCookiesDbPath(config.dataDir, profile);
|
|
365
|
+
if (!dbPath) {
|
|
366
|
+
logger.debug(`No ${config.label} cookies database found — skipping cookie import`);
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
// Retrieve platform-specific decryption key
|
|
370
|
+
let decryptionKey = null;
|
|
371
|
+
if (platform === 'darwin') {
|
|
372
|
+
decryptionKey = getMacOSDecryptionKey(config.keychainService);
|
|
373
|
+
}
|
|
374
|
+
else if (platform === 'linux') {
|
|
375
|
+
decryptionKey = getLinuxDecryptionKey(config.keychainService ?? config.label);
|
|
376
|
+
}
|
|
377
|
+
else if (platform === 'win32') {
|
|
378
|
+
decryptionKey = getWindowsDecryptionKey(config.dataDir);
|
|
379
|
+
}
|
|
380
|
+
if (!decryptionKey) {
|
|
381
|
+
logger.debug(`Could not retrieve ${config.label} decryption key — skipping cookie import`);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
const rawCookies = await readCookiesFromDb(dbPath);
|
|
385
|
+
if (rawCookies.length === 0) {
|
|
386
|
+
logger.debug(`No Microsoft cookies in ${config.label} profile`);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
const nowSec = Math.floor(Date.now() / 1000);
|
|
390
|
+
const playwrightCookies = rawCookies
|
|
391
|
+
.map(c => {
|
|
392
|
+
const value = decryptCookieValue(c.encrypted_value, platform, decryptionKey, c.host_key);
|
|
393
|
+
if (!value)
|
|
394
|
+
return null;
|
|
395
|
+
const expires = chromeEpochToUnix(c.expires_utc);
|
|
396
|
+
if (expires <= nowSec)
|
|
397
|
+
return null; // skip already-expired cookies
|
|
398
|
+
const secure = c.is_secure === 1;
|
|
399
|
+
let sameSite = sameSiteLabel(c.samesite);
|
|
400
|
+
// Chromium rejects SameSite=None cookies that are not Secure ("Invalid cookie fields").
|
|
401
|
+
// Downgrade those to Lax so the batch is always accepted.
|
|
402
|
+
if (sameSite === 'None' && !secure)
|
|
403
|
+
sameSite = 'Lax';
|
|
404
|
+
return {
|
|
405
|
+
name: c.name,
|
|
406
|
+
value,
|
|
407
|
+
domain: c.host_key, // raw host_key, as Chrome stores it (matches msteams-mcp)
|
|
408
|
+
path: c.path || '/',
|
|
409
|
+
expires,
|
|
410
|
+
secure,
|
|
411
|
+
httpOnly: c.is_httponly === 1,
|
|
412
|
+
sameSite,
|
|
413
|
+
};
|
|
414
|
+
})
|
|
415
|
+
.filter((c) => c !== null);
|
|
416
|
+
if (playwrightCookies.length === 0) {
|
|
417
|
+
logger.debug(`No valid ${config.label} cookies to import (decryption failed or all expired)`);
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
// Try the whole batch first (fast path). If Playwright rejects it because a
|
|
421
|
+
// single cookie has invalid fields, fall back to adding them one at a time so
|
|
422
|
+
// one bad cookie can't block the rest.
|
|
423
|
+
try {
|
|
424
|
+
await context.addCookies(playwrightCookies);
|
|
425
|
+
logger.info(`Imported ${playwrightCookies.length} Microsoft SSO cookies from ${config.label} (${platform}) — browser will sign in automatically`);
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
catch {
|
|
429
|
+
logger.debug('Batch cookie inject failed — retrying individually');
|
|
430
|
+
}
|
|
431
|
+
let imported = 0;
|
|
432
|
+
for (const cookie of playwrightCookies) {
|
|
433
|
+
try {
|
|
434
|
+
await context.addCookies([cookie]);
|
|
435
|
+
imported++;
|
|
436
|
+
}
|
|
437
|
+
catch { /* skip the offending cookie */ }
|
|
438
|
+
}
|
|
439
|
+
if (imported > 0) {
|
|
440
|
+
logger.info(`Imported ${imported}/${playwrightCookies.length} Microsoft SSO cookies from ${config.label} (${platform})`);
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
logger.debug('Cookie injection failed for all cookies');
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
//# sourceMappingURL=cookie-import.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookie-import.js","sourceRoot":"","sources":["../../src/browser/cookie-import.ts"],"names":[],"mappings":"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"}
|