@mjquinlan2000/zoom-users-mcp 0.1.1 → 0.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.
package/dist/auth.js
CHANGED
|
@@ -277,7 +277,7 @@ ${authorizeUrl}
|
|
|
277
277
|
|
|
278
278
|
// src/auth.ts
|
|
279
279
|
var { getAccessToken, runCli } = createAuth({
|
|
280
|
-
name: "zoom
|
|
280
|
+
name: "zoom",
|
|
281
281
|
authorizeUrl: "https://zoom.us/oauth/authorize",
|
|
282
282
|
tokenUrl: "https://zoom.us/oauth/token",
|
|
283
283
|
envPrefix: "ZOOM",
|
|
@@ -292,4 +292,4 @@ export {
|
|
|
292
292
|
getAccessToken,
|
|
293
293
|
runCli
|
|
294
294
|
};
|
|
295
|
-
//# sourceMappingURL=chunk-
|
|
295
|
+
//# sourceMappingURL=chunk-JB5WVWDA.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../shared/src/oauth.ts","../src/auth.ts"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport { createCipheriv, createDecipheriv, randomBytes } from \"node:crypto\";\nimport { mkdir, readFile, unlink, writeFile } from \"node:fs/promises\";\nimport {\n createServer,\n type IncomingMessage,\n type ServerResponse,\n} from \"node:http\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport interface OAuthConfig {\n name: string;\n authorizeUrl: string;\n tokenUrl: string;\n envPrefix: string;\n scope?: string;\n supportsRefresh: boolean;\n tokenAuthMethod?: \"body\" | \"basic\";\n}\n\ninterface BaseTokens {\n access_token: string;\n}\n\ninterface RefreshableTokens extends BaseTokens {\n refresh_token: string;\n expires_at: number;\n}\n\ntype StoredTokens = BaseTokens | RefreshableTokens;\n\nfunction isRefreshable(tokens: StoredTokens): tokens is RefreshableTokens {\n return \"refresh_token\" in tokens;\n}\n\ninterface RefreshableTokenResponse {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n}\n\nexport function createAuth(config: OAuthConfig): {\n getAccessToken: () => Promise<string>;\n runCli: (command?: string) => void;\n} {\n const configDir = join(\n process.env.MCP_CONFIG_DIR ?? join(homedir(), \".config\"),\n config.name,\n );\n const legacyTokensPath = join(configDir, \"tokens.json\");\n const encryptedTokensPath = join(configDir, \"tokens\");\n\n function getEncryptionKey(): Buffer {\n const key = process.env.NODE_MCP_SECRET_KEY;\n if (!key) {\n throw new Error(\n \"NODE_MCP_SECRET_KEY environment variable is required. \" +\n \"Generate one with: openssl rand -hex 32\",\n );\n }\n const buf = Buffer.from(key, \"hex\");\n if (buf.length !== 32) {\n throw new Error(\n \"NODE_MCP_SECRET_KEY must be a 64-character hex string (32 bytes). \" +\n \"Generate one with: openssl rand -hex 32\",\n );\n }\n return buf;\n }\n\n function encrypt(plaintext: string): Buffer {\n const key = getEncryptionKey();\n const iv = randomBytes(12);\n const cipher = createCipheriv(\"aes-256-gcm\", key, iv);\n const encrypted = Buffer.concat([\n cipher.update(plaintext, \"utf-8\"),\n cipher.final(),\n ]);\n const authTag = cipher.getAuthTag();\n return Buffer.concat([iv, authTag, encrypted]);\n }\n\n function decrypt(data: Buffer): string {\n const key = getEncryptionKey();\n const iv = data.subarray(0, 12);\n const authTag = data.subarray(12, 28);\n const ciphertext = data.subarray(28);\n const decipher = createDecipheriv(\"aes-256-gcm\", key, iv);\n decipher.setAuthTag(authTag);\n return (\n decipher.update(ciphertext, undefined, \"utf-8\") + decipher.final(\"utf-8\")\n );\n }\n\n async function readTokens(): Promise<StoredTokens | null> {\n try {\n const data = await readFile(encryptedTokensPath);\n return JSON.parse(decrypt(data)) as StoredTokens;\n } catch {\n // Fall back to legacy plaintext tokens.json\n try {\n const data = await readFile(legacyTokensPath, \"utf-8\");\n const tokens = JSON.parse(data) as StoredTokens;\n await writeTokens(tokens);\n await unlink(legacyTokensPath);\n return tokens;\n } catch {\n return null;\n }\n }\n }\n\n async function writeTokens(tokens: StoredTokens): Promise<void> {\n await mkdir(configDir, { recursive: true });\n await writeFile(encryptedTokensPath, encrypt(JSON.stringify(tokens)), {\n mode: 0o600,\n });\n }\n\n function openBrowser(url: string): void {\n const cmd =\n process.platform === \"darwin\"\n ? \"open\"\n : process.platform === \"win32\"\n ? \"start\"\n : \"xdg-open\";\n try {\n execSync(`${cmd} '${url}'`, { stdio: \"ignore\" });\n } catch {\n // No browser available (e.g. headless server) — URL is already printed to console\n }\n }\n\n async function exchangeCode(\n code: string,\n redirectUri: string,\n clientId: string,\n clientSecret: string,\n ): Promise<StoredTokens> {\n const useBasic = config.tokenAuthMethod === \"basic\";\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n };\n const bodyParams: Record<string, string> = {\n grant_type: \"authorization_code\",\n code,\n redirect_uri: redirectUri,\n };\n if (useBasic) {\n headers.Authorization = `Basic ${btoa(`${clientId}:${clientSecret}`)}`;\n } else {\n bodyParams.client_id = clientId;\n bodyParams.client_secret = clientSecret;\n }\n const res = await fetch(config.tokenUrl, {\n method: \"POST\",\n headers,\n body: new URLSearchParams(bodyParams),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Token exchange failed (${res.status}): ${text}`);\n }\n if (config.supportsRefresh) {\n const data = (await res.json()) as RefreshableTokenResponse;\n return {\n access_token: data.access_token,\n refresh_token: data.refresh_token,\n expires_at: Date.now() + data.expires_in * 1000,\n };\n }\n const data = (await res.json()) as { access_token: string };\n return { access_token: data.access_token };\n }\n\n async function refreshAccessToken(\n refreshToken: string,\n clientId: string,\n clientSecret: string,\n ): Promise<RefreshableTokens> {\n const useBasic = config.tokenAuthMethod === \"basic\";\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n };\n const bodyParams: Record<string, string> = {\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n };\n if (useBasic) {\n headers.Authorization = `Basic ${btoa(`${clientId}:${clientSecret}`)}`;\n } else {\n bodyParams.client_id = clientId;\n bodyParams.client_secret = clientSecret;\n }\n const res = await fetch(config.tokenUrl, {\n method: \"POST\",\n headers,\n body: new URLSearchParams(bodyParams),\n });\n if (!res.ok) {\n throw new Error(\"Run 'yarn auth' to re-authenticate.\");\n }\n const data = (await res.json()) as RefreshableTokenResponse;\n return {\n access_token: data.access_token,\n refresh_token: data.refresh_token,\n expires_at: Date.now() + data.expires_in * 1000,\n };\n }\n\n async function getAccessToken(): Promise<string> {\n const envToken = process.env[`${config.envPrefix}_ACCESS_TOKEN`];\n if (envToken) return envToken;\n\n const tokens = await readTokens();\n if (!tokens) {\n throw new Error(\n `No access token available. Set ${config.envPrefix}_ACCESS_TOKEN or run 'yarn auth'.`,\n );\n }\n\n if (config.supportsRefresh && isRefreshable(tokens)) {\n const fiveMinutes = 5 * 60 * 1000;\n if (tokens.expires_at - Date.now() < fiveMinutes) {\n const clientId = process.env[`${config.envPrefix}_CLIENT_ID`];\n const clientSecret = process.env[`${config.envPrefix}_CLIENT_SECRET`];\n if (!clientId || !clientSecret) {\n throw new Error(\n `Token is expiring and ${config.envPrefix}_CLIENT_ID/${config.envPrefix}_CLIENT_SECRET are not set for refresh. Run 'yarn auth'.`,\n );\n }\n const refreshed = await refreshAccessToken(\n tokens.refresh_token,\n clientId,\n clientSecret,\n );\n await writeTokens(refreshed);\n return refreshed.access_token;\n }\n }\n\n return tokens.access_token;\n }\n\n async function authorize(): Promise<void> {\n const clientId = process.env[`${config.envPrefix}_CLIENT_ID`];\n const clientSecret = process.env[`${config.envPrefix}_CLIENT_SECRET`];\n if (!clientId)\n throw new Error(\n `${config.envPrefix}_CLIENT_ID environment variable is required.`,\n );\n if (!clientSecret)\n throw new Error(\n `${config.envPrefix}_CLIENT_SECRET environment variable is required.`,\n );\n\n const redirectUri = process.env[`${config.envPrefix}_REDIRECT_URI`];\n if (!redirectUri)\n throw new Error(\n `${config.envPrefix}_REDIRECT_URI environment variable is required.`,\n );\n\n const redirectUrl = new URL(redirectUri);\n const port =\n Number(redirectUrl.port) ||\n (redirectUrl.protocol === \"https:\" ? 443 : 80);\n const callbackPath = redirectUrl.pathname;\n const state = randomBytes(16).toString(\"hex\");\n\n const { tokens } = await new Promise<{\n tokens: StoredTokens;\n }>((resolve, reject) => {\n const timeout = setTimeout(() => {\n server.close();\n reject(new Error(\"Authorization timed out after 120 seconds.\"));\n }, 120_000);\n\n const server = createServer(\n async (req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url ?? \"/\", `http://${req.headers.host}`);\n if (url.pathname !== callbackPath) {\n res.writeHead(404);\n res.end(\"Not found\");\n return;\n }\n\n const returnedState = url.searchParams.get(\"state\");\n const code = url.searchParams.get(\"code\");\n const error = url.searchParams.get(\"error\");\n\n if (error) {\n res.writeHead(400);\n res.end(`Authorization error: ${error}`);\n clearTimeout(timeout);\n server.close();\n reject(new Error(`Authorization denied: ${error}`));\n return;\n }\n\n if (returnedState !== state) {\n res.writeHead(400);\n res.end(\"State mismatch — possible CSRF attack.\");\n return;\n }\n\n if (!code) {\n res.writeHead(400);\n res.end(\"Missing authorization code.\");\n return;\n }\n\n try {\n const exchangedTokens = await exchangeCode(\n code,\n redirectUri,\n clientId,\n clientSecret,\n );\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(\n \"<h1>Authorization successful!</h1><p>You can close this tab.</p>\",\n );\n clearTimeout(timeout);\n server.close();\n resolve({ tokens: exchangedTokens });\n } catch (err) {\n res.writeHead(500);\n res.end(\"Token exchange failed.\");\n clearTimeout(timeout);\n server.close();\n reject(err);\n }\n },\n );\n\n const params: Record<string, string> = {\n response_type: \"code\",\n client_id: clientId,\n redirect_uri: redirectUri,\n state,\n };\n if (config.scope) {\n params.scope = config.scope;\n }\n\n server.listen(port, \"127.0.0.1\", () => {\n const authorizeUrl = `${config.authorizeUrl}?${new URLSearchParams(params)}`;\n\n console.log(\"Opening browser for authorization...\");\n console.log(`If the browser doesn't open, visit:\\n${authorizeUrl}\\n`);\n openBrowser(authorizeUrl);\n });\n });\n\n await writeTokens(tokens);\n console.log(`Tokens saved to ${encryptedTokensPath}`);\n }\n\n async function refresh(): Promise<void> {\n const clientId = process.env[`${config.envPrefix}_CLIENT_ID`];\n const clientSecret = process.env[`${config.envPrefix}_CLIENT_SECRET`];\n if (!clientId)\n throw new Error(\n `${config.envPrefix}_CLIENT_ID environment variable is required.`,\n );\n if (!clientSecret)\n throw new Error(\n `${config.envPrefix}_CLIENT_SECRET environment variable is required.`,\n );\n\n const tokens = await readTokens();\n if (!tokens || !isRefreshable(tokens)) {\n throw new Error(\n \"No tokens found. Run 'yarn auth' first to authenticate.\",\n );\n }\n\n const refreshed = await refreshAccessToken(\n tokens.refresh_token,\n clientId,\n clientSecret,\n );\n await writeTokens(refreshed);\n console.log(`Tokens refreshed and saved to ${encryptedTokensPath}`);\n }\n\n function runCli(command?: string): void {\n const cmd = command ?? process.argv[2];\n let run: () => Promise<void>;\n if (cmd === \"refresh\" && config.supportsRefresh) {\n run = refresh;\n } else {\n run = authorize;\n }\n run().catch((err) => {\n console.error(err.message ?? err);\n process.exit(1);\n });\n }\n\n return { getAccessToken, runCli };\n}\n","import { createAuth } from \"@mjquinlan2000/shared/oauth.js\";\n\nconst { getAccessToken, runCli } = createAuth({\n name: \"zoom-users-mcp\",\n authorizeUrl: \"https://zoom.us/oauth/authorize\",\n tokenUrl: \"https://zoom.us/oauth/token\",\n envPrefix: \"ZOOM\",\n supportsRefresh: true,\n tokenAuthMethod: \"basic\",\n});\n\nexport { getAccessToken, runCli };\n\nif (process.argv[1] && import.meta.filename === process.argv[1]) {\n runCli();\n}\n"],"mappings":";AAAA,SAAS,gBAAgB;AACzB,SAAS,gBAAgB,kBAAkB,mBAAmB;AAC9D,SAAS,OAAO,UAAU,QAAQ,iBAAiB;AACnD,SACE,oBAGK;AACP,SAAS,eAAe;AACxB,SAAS,YAAY;AAuBrB,SAAS,cAAc,QAAoB;AACzC,SAAO,mBAAmB;AAC5B;AAQM,SAAU,WAAW,QAAmB;AAI5C,QAAM,YAAY,KAChB,QAAQ,IAAI,kBAAkB,KAAK,QAAO,GAAI,SAAS,GACvD,OAAO,IAAI;AAEb,QAAM,mBAAmB,KAAK,WAAW,aAAa;AACtD,QAAM,sBAAsB,KAAK,WAAW,QAAQ;AAEpD,WAAS,mBAAgB;AACvB,UAAM,MAAM,QAAQ,IAAI;AACxB,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MACR,+FAC2C;IAE/C;AACA,UAAM,MAAM,OAAO,KAAK,KAAK,KAAK;AAClC,QAAI,IAAI,WAAW,IAAI;AACrB,YAAM,IAAI,MACR,2GAC2C;IAE/C;AACA,WAAO;EACT;AAEA,WAAS,QAAQ,WAAiB;AAChC,UAAM,MAAM,iBAAgB;AAC5B,UAAM,KAAK,YAAY,EAAE;AACzB,UAAM,SAAS,eAAe,eAAe,KAAK,EAAE;AACpD,UAAM,YAAY,OAAO,OAAO;MAC9B,OAAO,OAAO,WAAW,OAAO;MAChC,OAAO,MAAK;KACb;AACD,UAAM,UAAU,OAAO,WAAU;AACjC,WAAO,OAAO,OAAO,CAAC,IAAI,SAAS,SAAS,CAAC;EAC/C;AAEA,WAAS,QAAQ,MAAY;AAC3B,UAAM,MAAM,iBAAgB;AAC5B,UAAM,KAAK,KAAK,SAAS,GAAG,EAAE;AAC9B,UAAM,UAAU,KAAK,SAAS,IAAI,EAAE;AACpC,UAAM,aAAa,KAAK,SAAS,EAAE;AACnC,UAAM,WAAW,iBAAiB,eAAe,KAAK,EAAE;AACxD,aAAS,WAAW,OAAO;AAC3B,WACE,SAAS,OAAO,YAAY,QAAW,OAAO,IAAI,SAAS,MAAM,OAAO;EAE5E;AAEA,iBAAe,aAAU;AACvB,QAAI;AACF,YAAM,OAAO,MAAM,SAAS,mBAAmB;AAC/C,aAAO,KAAK,MAAM,QAAQ,IAAI,CAAC;IACjC,QAAQ;AAEN,UAAI;AACF,cAAM,OAAO,MAAM,SAAS,kBAAkB,OAAO;AACrD,cAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,cAAM,YAAY,MAAM;AACxB,cAAM,OAAO,gBAAgB;AAC7B,eAAO;MACT,QAAQ;AACN,eAAO;MACT;IACF;EACF;AAEA,iBAAe,YAAY,QAAoB;AAC7C,UAAM,MAAM,WAAW,EAAE,WAAW,KAAI,CAAE;AAC1C,UAAM,UAAU,qBAAqB,QAAQ,KAAK,UAAU,MAAM,CAAC,GAAG;MACpE,MAAM;KACP;EACH;AAEA,WAAS,YAAY,KAAW;AAC9B,UAAM,MACJ,QAAQ,aAAa,WACjB,SACA,QAAQ,aAAa,UACnB,UACA;AACR,QAAI;AACF,eAAS,GAAG,GAAG,KAAK,GAAG,KAAK,EAAE,OAAO,SAAQ,CAAE;IACjD,QAAQ;IAER;EACF;AAEA,iBAAe,aACb,MACA,aACA,UACA,cAAoB;AAEpB,UAAM,WAAW,OAAO,oBAAoB;AAC5C,UAAM,UAAkC;MACtC,gBAAgB;;AAElB,UAAM,aAAqC;MACzC,YAAY;MACZ;MACA,cAAc;;AAEhB,QAAI,UAAU;AACZ,cAAQ,gBAAgB,SAAS,KAAK,GAAG,QAAQ,IAAI,YAAY,EAAE,CAAC;IACtE,OAAO;AACL,iBAAW,YAAY;AACvB,iBAAW,gBAAgB;IAC7B;AACA,UAAM,MAAM,MAAM,MAAM,OAAO,UAAU;MACvC,QAAQ;MACR;MACA,MAAM,IAAI,gBAAgB,UAAU;KACrC;AACD,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,OAAO,MAAM,IAAI,KAAI;AAC3B,YAAM,IAAI,MAAM,0BAA0B,IAAI,MAAM,MAAM,IAAI,EAAE;IAClE;AACA,QAAI,OAAO,iBAAiB;AAC1B,YAAMA,QAAQ,MAAM,IAAI,KAAI;AAC5B,aAAO;QACL,cAAcA,MAAK;QACnB,eAAeA,MAAK;QACpB,YAAY,KAAK,IAAG,IAAKA,MAAK,aAAa;;IAE/C;AACA,UAAM,OAAQ,MAAM,IAAI,KAAI;AAC5B,WAAO,EAAE,cAAc,KAAK,aAAY;EAC1C;AAEA,iBAAe,mBACb,cACA,UACA,cAAoB;AAEpB,UAAM,WAAW,OAAO,oBAAoB;AAC5C,UAAM,UAAkC;MACtC,gBAAgB;;AAElB,UAAM,aAAqC;MACzC,YAAY;MACZ,eAAe;;AAEjB,QAAI,UAAU;AACZ,cAAQ,gBAAgB,SAAS,KAAK,GAAG,QAAQ,IAAI,YAAY,EAAE,CAAC;IACtE,OAAO;AACL,iBAAW,YAAY;AACvB,iBAAW,gBAAgB;IAC7B;AACA,UAAM,MAAM,MAAM,MAAM,OAAO,UAAU;MACvC,QAAQ;MACR;MACA,MAAM,IAAI,gBAAgB,UAAU;KACrC;AACD,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,IAAI,MAAM,qCAAqC;IACvD;AACA,UAAM,OAAQ,MAAM,IAAI,KAAI;AAC5B,WAAO;MACL,cAAc,KAAK;MACnB,eAAe,KAAK;MACpB,YAAY,KAAK,IAAG,IAAK,KAAK,aAAa;;EAE/C;AAEA,iBAAeC,kBAAc;AAC3B,UAAM,WAAW,QAAQ,IAAI,GAAG,OAAO,SAAS,eAAe;AAC/D,QAAI;AAAU,aAAO;AAErB,UAAM,SAAS,MAAM,WAAU;AAC/B,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MACR,kCAAkC,OAAO,SAAS,mCAAmC;IAEzF;AAEA,QAAI,OAAO,mBAAmB,cAAc,MAAM,GAAG;AACnD,YAAM,cAAc,IAAI,KAAK;AAC7B,UAAI,OAAO,aAAa,KAAK,IAAG,IAAK,aAAa;AAChD,cAAM,WAAW,QAAQ,IAAI,GAAG,OAAO,SAAS,YAAY;AAC5D,cAAM,eAAe,QAAQ,IAAI,GAAG,OAAO,SAAS,gBAAgB;AACpE,YAAI,CAAC,YAAY,CAAC,cAAc;AAC9B,gBAAM,IAAI,MACR,yBAAyB,OAAO,SAAS,cAAc,OAAO,SAAS,0DAA0D;QAErI;AACA,cAAM,YAAY,MAAM,mBACtB,OAAO,eACP,UACA,YAAY;AAEd,cAAM,YAAY,SAAS;AAC3B,eAAO,UAAU;MACnB;IACF;AAEA,WAAO,OAAO;EAChB;AAEA,iBAAe,YAAS;AACtB,UAAM,WAAW,QAAQ,IAAI,GAAG,OAAO,SAAS,YAAY;AAC5D,UAAM,eAAe,QAAQ,IAAI,GAAG,OAAO,SAAS,gBAAgB;AACpE,QAAI,CAAC;AACH,YAAM,IAAI,MACR,GAAG,OAAO,SAAS,8CAA8C;AAErE,QAAI,CAAC;AACH,YAAM,IAAI,MACR,GAAG,OAAO,SAAS,kDAAkD;AAGzE,UAAM,cAAc,QAAQ,IAAI,GAAG,OAAO,SAAS,eAAe;AAClE,QAAI,CAAC;AACH,YAAM,IAAI,MACR,GAAG,OAAO,SAAS,iDAAiD;AAGxE,UAAM,cAAc,IAAI,IAAI,WAAW;AACvC,UAAM,OACJ,OAAO,YAAY,IAAI,MACtB,YAAY,aAAa,WAAW,MAAM;AAC7C,UAAM,eAAe,YAAY;AACjC,UAAM,QAAQ,YAAY,EAAE,EAAE,SAAS,KAAK;AAE5C,UAAM,EAAE,OAAM,IAAK,MAAM,IAAI,QAE1B,CAAC,SAAS,WAAU;AACrB,YAAM,UAAU,WAAW,MAAK;AAC9B,eAAO,MAAK;AACZ,eAAO,IAAI,MAAM,4CAA4C,CAAC;MAChE,GAAG,IAAO;AAEV,YAAM,SAAS,aACb,OAAO,KAAsB,QAAuB;AAClD,cAAM,MAAM,IAAI,IAAI,IAAI,OAAO,KAAK,UAAU,IAAI,QAAQ,IAAI,EAAE;AAChE,YAAI,IAAI,aAAa,cAAc;AACjC,cAAI,UAAU,GAAG;AACjB,cAAI,IAAI,WAAW;AACnB;QACF;AAEA,cAAM,gBAAgB,IAAI,aAAa,IAAI,OAAO;AAClD,cAAM,OAAO,IAAI,aAAa,IAAI,MAAM;AACxC,cAAM,QAAQ,IAAI,aAAa,IAAI,OAAO;AAE1C,YAAI,OAAO;AACT,cAAI,UAAU,GAAG;AACjB,cAAI,IAAI,wBAAwB,KAAK,EAAE;AACvC,uBAAa,OAAO;AACpB,iBAAO,MAAK;AACZ,iBAAO,IAAI,MAAM,yBAAyB,KAAK,EAAE,CAAC;AAClD;QACF;AAEA,YAAI,kBAAkB,OAAO;AAC3B,cAAI,UAAU,GAAG;AACjB,cAAI,IAAI,6CAAwC;AAChD;QACF;AAEA,YAAI,CAAC,MAAM;AACT,cAAI,UAAU,GAAG;AACjB,cAAI,IAAI,6BAA6B;AACrC;QACF;AAEA,YAAI;AACF,gBAAM,kBAAkB,MAAM,aAC5B,MACA,aACA,UACA,YAAY;AAEd,cAAI,UAAU,KAAK,EAAE,gBAAgB,YAAW,CAAE;AAClD,cAAI,IACF,kEAAkE;AAEpE,uBAAa,OAAO;AACpB,iBAAO,MAAK;AACZ,kBAAQ,EAAE,QAAQ,gBAAe,CAAE;QACrC,SAAS,KAAK;AACZ,cAAI,UAAU,GAAG;AACjB,cAAI,IAAI,wBAAwB;AAChC,uBAAa,OAAO;AACpB,iBAAO,MAAK;AACZ,iBAAO,GAAG;QACZ;MACF,CAAC;AAGH,YAAM,SAAiC;QACrC,eAAe;QACf,WAAW;QACX,cAAc;QACd;;AAEF,UAAI,OAAO,OAAO;AAChB,eAAO,QAAQ,OAAO;MACxB;AAEA,aAAO,OAAO,MAAM,aAAa,MAAK;AACpC,cAAM,eAAe,GAAG,OAAO,YAAY,IAAI,IAAI,gBAAgB,MAAM,CAAC;AAE1E,gBAAQ,IAAI,sCAAsC;AAClD,gBAAQ,IAAI;EAAwC,YAAY;CAAI;AACpE,oBAAY,YAAY;MAC1B,CAAC;IACH,CAAC;AAED,UAAM,YAAY,MAAM;AACxB,YAAQ,IAAI,mBAAmB,mBAAmB,EAAE;EACtD;AAEA,iBAAe,UAAO;AACpB,UAAM,WAAW,QAAQ,IAAI,GAAG,OAAO,SAAS,YAAY;AAC5D,UAAM,eAAe,QAAQ,IAAI,GAAG,OAAO,SAAS,gBAAgB;AACpE,QAAI,CAAC;AACH,YAAM,IAAI,MACR,GAAG,OAAO,SAAS,8CAA8C;AAErE,QAAI,CAAC;AACH,YAAM,IAAI,MACR,GAAG,OAAO,SAAS,kDAAkD;AAGzE,UAAM,SAAS,MAAM,WAAU;AAC/B,QAAI,CAAC,UAAU,CAAC,cAAc,MAAM,GAAG;AACrC,YAAM,IAAI,MACR,yDAAyD;IAE7D;AAEA,UAAM,YAAY,MAAM,mBACtB,OAAO,eACP,UACA,YAAY;AAEd,UAAM,YAAY,SAAS;AAC3B,YAAQ,IAAI,iCAAiC,mBAAmB,EAAE;EACpE;AAEA,WAASC,QAAO,SAAgB;AAC9B,UAAM,MAAM,WAAW,QAAQ,KAAK,CAAC;AACrC,QAAI;AACJ,QAAI,QAAQ,aAAa,OAAO,iBAAiB;AAC/C,YAAM;IACR,OAAO;AACL,YAAM;IACR;AACA,QAAG,EAAG,MAAM,CAAC,QAAO;AAClB,cAAQ,MAAM,IAAI,WAAW,GAAG;AAChC,cAAQ,KAAK,CAAC;IAChB,CAAC;EACH;AAEA,SAAO,EAAE,gBAAAD,iBAAgB,QAAAC,QAAM;AACjC;;;AChZA,IAAM,EAAE,gBAAgB,OAAO,IAAI,WAAW;AAAA,EAC5C,MAAM;AAAA,EACN,cAAc;AAAA,EACd,UAAU;AAAA,EACV,WAAW;AAAA,EACX,iBAAiB;AAAA,EACjB,iBAAiB;AACnB,CAAC;AAID,IAAI,QAAQ,KAAK,CAAC,KAAK,YAAY,aAAa,QAAQ,KAAK,CAAC,GAAG;AAC/D,SAAO;AACT;","names":["data","getAccessToken","runCli"]}
|
|
1
|
+
{"version":3,"sources":["../../shared/src/oauth.ts","../src/auth.ts"],"sourcesContent":["import { execSync } from \"node:child_process\";\nimport { createCipheriv, createDecipheriv, randomBytes } from \"node:crypto\";\nimport { mkdir, readFile, unlink, writeFile } from \"node:fs/promises\";\nimport {\n createServer,\n type IncomingMessage,\n type ServerResponse,\n} from \"node:http\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport interface OAuthConfig {\n name: string;\n authorizeUrl: string;\n tokenUrl: string;\n envPrefix: string;\n scope?: string;\n supportsRefresh: boolean;\n tokenAuthMethod?: \"body\" | \"basic\";\n}\n\ninterface BaseTokens {\n access_token: string;\n}\n\ninterface RefreshableTokens extends BaseTokens {\n refresh_token: string;\n expires_at: number;\n}\n\ntype StoredTokens = BaseTokens | RefreshableTokens;\n\nfunction isRefreshable(tokens: StoredTokens): tokens is RefreshableTokens {\n return \"refresh_token\" in tokens;\n}\n\ninterface RefreshableTokenResponse {\n access_token: string;\n refresh_token: string;\n expires_in: number;\n}\n\nexport function createAuth(config: OAuthConfig): {\n getAccessToken: () => Promise<string>;\n runCli: (command?: string) => void;\n} {\n const configDir = join(\n process.env.MCP_CONFIG_DIR ?? join(homedir(), \".config\"),\n config.name,\n );\n const legacyTokensPath = join(configDir, \"tokens.json\");\n const encryptedTokensPath = join(configDir, \"tokens\");\n\n function getEncryptionKey(): Buffer {\n const key = process.env.NODE_MCP_SECRET_KEY;\n if (!key) {\n throw new Error(\n \"NODE_MCP_SECRET_KEY environment variable is required. \" +\n \"Generate one with: openssl rand -hex 32\",\n );\n }\n const buf = Buffer.from(key, \"hex\");\n if (buf.length !== 32) {\n throw new Error(\n \"NODE_MCP_SECRET_KEY must be a 64-character hex string (32 bytes). \" +\n \"Generate one with: openssl rand -hex 32\",\n );\n }\n return buf;\n }\n\n function encrypt(plaintext: string): Buffer {\n const key = getEncryptionKey();\n const iv = randomBytes(12);\n const cipher = createCipheriv(\"aes-256-gcm\", key, iv);\n const encrypted = Buffer.concat([\n cipher.update(plaintext, \"utf-8\"),\n cipher.final(),\n ]);\n const authTag = cipher.getAuthTag();\n return Buffer.concat([iv, authTag, encrypted]);\n }\n\n function decrypt(data: Buffer): string {\n const key = getEncryptionKey();\n const iv = data.subarray(0, 12);\n const authTag = data.subarray(12, 28);\n const ciphertext = data.subarray(28);\n const decipher = createDecipheriv(\"aes-256-gcm\", key, iv);\n decipher.setAuthTag(authTag);\n return (\n decipher.update(ciphertext, undefined, \"utf-8\") + decipher.final(\"utf-8\")\n );\n }\n\n async function readTokens(): Promise<StoredTokens | null> {\n try {\n const data = await readFile(encryptedTokensPath);\n return JSON.parse(decrypt(data)) as StoredTokens;\n } catch {\n // Fall back to legacy plaintext tokens.json\n try {\n const data = await readFile(legacyTokensPath, \"utf-8\");\n const tokens = JSON.parse(data) as StoredTokens;\n await writeTokens(tokens);\n await unlink(legacyTokensPath);\n return tokens;\n } catch {\n return null;\n }\n }\n }\n\n async function writeTokens(tokens: StoredTokens): Promise<void> {\n await mkdir(configDir, { recursive: true });\n await writeFile(encryptedTokensPath, encrypt(JSON.stringify(tokens)), {\n mode: 0o600,\n });\n }\n\n function openBrowser(url: string): void {\n const cmd =\n process.platform === \"darwin\"\n ? \"open\"\n : process.platform === \"win32\"\n ? \"start\"\n : \"xdg-open\";\n try {\n execSync(`${cmd} '${url}'`, { stdio: \"ignore\" });\n } catch {\n // No browser available (e.g. headless server) — URL is already printed to console\n }\n }\n\n async function exchangeCode(\n code: string,\n redirectUri: string,\n clientId: string,\n clientSecret: string,\n ): Promise<StoredTokens> {\n const useBasic = config.tokenAuthMethod === \"basic\";\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n };\n const bodyParams: Record<string, string> = {\n grant_type: \"authorization_code\",\n code,\n redirect_uri: redirectUri,\n };\n if (useBasic) {\n headers.Authorization = `Basic ${btoa(`${clientId}:${clientSecret}`)}`;\n } else {\n bodyParams.client_id = clientId;\n bodyParams.client_secret = clientSecret;\n }\n const res = await fetch(config.tokenUrl, {\n method: \"POST\",\n headers,\n body: new URLSearchParams(bodyParams),\n });\n if (!res.ok) {\n const text = await res.text();\n throw new Error(`Token exchange failed (${res.status}): ${text}`);\n }\n if (config.supportsRefresh) {\n const data = (await res.json()) as RefreshableTokenResponse;\n return {\n access_token: data.access_token,\n refresh_token: data.refresh_token,\n expires_at: Date.now() + data.expires_in * 1000,\n };\n }\n const data = (await res.json()) as { access_token: string };\n return { access_token: data.access_token };\n }\n\n async function refreshAccessToken(\n refreshToken: string,\n clientId: string,\n clientSecret: string,\n ): Promise<RefreshableTokens> {\n const useBasic = config.tokenAuthMethod === \"basic\";\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n };\n const bodyParams: Record<string, string> = {\n grant_type: \"refresh_token\",\n refresh_token: refreshToken,\n };\n if (useBasic) {\n headers.Authorization = `Basic ${btoa(`${clientId}:${clientSecret}`)}`;\n } else {\n bodyParams.client_id = clientId;\n bodyParams.client_secret = clientSecret;\n }\n const res = await fetch(config.tokenUrl, {\n method: \"POST\",\n headers,\n body: new URLSearchParams(bodyParams),\n });\n if (!res.ok) {\n throw new Error(\"Run 'yarn auth' to re-authenticate.\");\n }\n const data = (await res.json()) as RefreshableTokenResponse;\n return {\n access_token: data.access_token,\n refresh_token: data.refresh_token,\n expires_at: Date.now() + data.expires_in * 1000,\n };\n }\n\n async function getAccessToken(): Promise<string> {\n const envToken = process.env[`${config.envPrefix}_ACCESS_TOKEN`];\n if (envToken) return envToken;\n\n const tokens = await readTokens();\n if (!tokens) {\n throw new Error(\n `No access token available. Set ${config.envPrefix}_ACCESS_TOKEN or run 'yarn auth'.`,\n );\n }\n\n if (config.supportsRefresh && isRefreshable(tokens)) {\n const fiveMinutes = 5 * 60 * 1000;\n if (tokens.expires_at - Date.now() < fiveMinutes) {\n const clientId = process.env[`${config.envPrefix}_CLIENT_ID`];\n const clientSecret = process.env[`${config.envPrefix}_CLIENT_SECRET`];\n if (!clientId || !clientSecret) {\n throw new Error(\n `Token is expiring and ${config.envPrefix}_CLIENT_ID/${config.envPrefix}_CLIENT_SECRET are not set for refresh. Run 'yarn auth'.`,\n );\n }\n const refreshed = await refreshAccessToken(\n tokens.refresh_token,\n clientId,\n clientSecret,\n );\n await writeTokens(refreshed);\n return refreshed.access_token;\n }\n }\n\n return tokens.access_token;\n }\n\n async function authorize(): Promise<void> {\n const clientId = process.env[`${config.envPrefix}_CLIENT_ID`];\n const clientSecret = process.env[`${config.envPrefix}_CLIENT_SECRET`];\n if (!clientId)\n throw new Error(\n `${config.envPrefix}_CLIENT_ID environment variable is required.`,\n );\n if (!clientSecret)\n throw new Error(\n `${config.envPrefix}_CLIENT_SECRET environment variable is required.`,\n );\n\n const redirectUri = process.env[`${config.envPrefix}_REDIRECT_URI`];\n if (!redirectUri)\n throw new Error(\n `${config.envPrefix}_REDIRECT_URI environment variable is required.`,\n );\n\n const redirectUrl = new URL(redirectUri);\n const port =\n Number(redirectUrl.port) ||\n (redirectUrl.protocol === \"https:\" ? 443 : 80);\n const callbackPath = redirectUrl.pathname;\n const state = randomBytes(16).toString(\"hex\");\n\n const { tokens } = await new Promise<{\n tokens: StoredTokens;\n }>((resolve, reject) => {\n const timeout = setTimeout(() => {\n server.close();\n reject(new Error(\"Authorization timed out after 120 seconds.\"));\n }, 120_000);\n\n const server = createServer(\n async (req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url ?? \"/\", `http://${req.headers.host}`);\n if (url.pathname !== callbackPath) {\n res.writeHead(404);\n res.end(\"Not found\");\n return;\n }\n\n const returnedState = url.searchParams.get(\"state\");\n const code = url.searchParams.get(\"code\");\n const error = url.searchParams.get(\"error\");\n\n if (error) {\n res.writeHead(400);\n res.end(`Authorization error: ${error}`);\n clearTimeout(timeout);\n server.close();\n reject(new Error(`Authorization denied: ${error}`));\n return;\n }\n\n if (returnedState !== state) {\n res.writeHead(400);\n res.end(\"State mismatch — possible CSRF attack.\");\n return;\n }\n\n if (!code) {\n res.writeHead(400);\n res.end(\"Missing authorization code.\");\n return;\n }\n\n try {\n const exchangedTokens = await exchangeCode(\n code,\n redirectUri,\n clientId,\n clientSecret,\n );\n res.writeHead(200, { \"Content-Type\": \"text/html\" });\n res.end(\n \"<h1>Authorization successful!</h1><p>You can close this tab.</p>\",\n );\n clearTimeout(timeout);\n server.close();\n resolve({ tokens: exchangedTokens });\n } catch (err) {\n res.writeHead(500);\n res.end(\"Token exchange failed.\");\n clearTimeout(timeout);\n server.close();\n reject(err);\n }\n },\n );\n\n const params: Record<string, string> = {\n response_type: \"code\",\n client_id: clientId,\n redirect_uri: redirectUri,\n state,\n };\n if (config.scope) {\n params.scope = config.scope;\n }\n\n server.listen(port, \"127.0.0.1\", () => {\n const authorizeUrl = `${config.authorizeUrl}?${new URLSearchParams(params)}`;\n\n console.log(\"Opening browser for authorization...\");\n console.log(`If the browser doesn't open, visit:\\n${authorizeUrl}\\n`);\n openBrowser(authorizeUrl);\n });\n });\n\n await writeTokens(tokens);\n console.log(`Tokens saved to ${encryptedTokensPath}`);\n }\n\n async function refresh(): Promise<void> {\n const clientId = process.env[`${config.envPrefix}_CLIENT_ID`];\n const clientSecret = process.env[`${config.envPrefix}_CLIENT_SECRET`];\n if (!clientId)\n throw new Error(\n `${config.envPrefix}_CLIENT_ID environment variable is required.`,\n );\n if (!clientSecret)\n throw new Error(\n `${config.envPrefix}_CLIENT_SECRET environment variable is required.`,\n );\n\n const tokens = await readTokens();\n if (!tokens || !isRefreshable(tokens)) {\n throw new Error(\n \"No tokens found. Run 'yarn auth' first to authenticate.\",\n );\n }\n\n const refreshed = await refreshAccessToken(\n tokens.refresh_token,\n clientId,\n clientSecret,\n );\n await writeTokens(refreshed);\n console.log(`Tokens refreshed and saved to ${encryptedTokensPath}`);\n }\n\n function runCli(command?: string): void {\n const cmd = command ?? process.argv[2];\n let run: () => Promise<void>;\n if (cmd === \"refresh\" && config.supportsRefresh) {\n run = refresh;\n } else {\n run = authorize;\n }\n run().catch((err) => {\n console.error(err.message ?? err);\n process.exit(1);\n });\n }\n\n return { getAccessToken, runCli };\n}\n","import { createAuth } from \"@mjquinlan2000/shared/oauth.js\";\n\nconst { getAccessToken, runCli } = createAuth({\n name: \"zoom\",\n authorizeUrl: \"https://zoom.us/oauth/authorize\",\n tokenUrl: \"https://zoom.us/oauth/token\",\n envPrefix: \"ZOOM\",\n supportsRefresh: true,\n tokenAuthMethod: \"basic\",\n});\n\nexport { getAccessToken, runCli };\n\nif (process.argv[1] && import.meta.filename === process.argv[1]) {\n runCli();\n}\n"],"mappings":"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","names":["data","getAccessToken","runCli"]}
|