brightspace-mcp-server 1.6.3 → 3.0.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 +43 -35
- package/build/api/client.d.ts +37 -10
- package/build/api/client.d.ts.map +1 -1
- package/build/api/client.js +158 -100
- package/build/api/client.js.map +1 -1
- package/build/api/errors.d.ts +4 -0
- package/build/api/errors.d.ts.map +1 -1
- package/build/api/errors.js +7 -0
- package/build/api/errors.js.map +1 -1
- package/build/auth/auth-cooldown.d.ts +24 -0
- package/build/auth/auth-cooldown.d.ts.map +1 -0
- package/build/auth/auth-cooldown.js +60 -0
- package/build/auth/auth-cooldown.js.map +1 -0
- package/build/auth/auth-lock.d.ts +7 -0
- package/build/auth/auth-lock.d.ts.map +1 -0
- package/build/auth/auth-lock.js +162 -0
- package/build/auth/auth-lock.js.map +1 -0
- package/build/auth/auth-runner.d.ts +30 -9
- package/build/auth/auth-runner.d.ts.map +1 -1
- package/build/auth/auth-runner.js +171 -56
- package/build/auth/auth-runner.js.map +1 -1
- package/build/auth/browser-auth.d.ts +19 -87
- package/build/auth/browser-auth.d.ts.map +1 -1
- package/build/auth/browser-auth.js +266 -614
- package/build/auth/browser-auth.js.map +1 -1
- package/build/auth/browser-state-store.d.ts +19 -0
- package/build/auth/browser-state-store.d.ts.map +1 -0
- package/build/auth/browser-state-store.js +101 -0
- package/build/auth/browser-state-store.js.map +1 -0
- package/build/auth/credential-store.d.ts +29 -0
- package/build/auth/credential-store.d.ts.map +1 -0
- package/build/auth/credential-store.js +233 -0
- package/build/auth/credential-store.js.map +1 -0
- package/build/auth/encrypted-store.d.ts +25 -0
- package/build/auth/encrypted-store.d.ts.map +1 -0
- package/build/auth/encrypted-store.js +61 -0
- package/build/auth/encrypted-store.js.map +1 -0
- package/build/auth/legacy-profile.d.ts +3 -0
- package/build/auth/legacy-profile.d.ts.map +1 -0
- package/build/auth/legacy-profile.js +41 -0
- package/build/auth/legacy-profile.js.map +1 -0
- package/build/auth/legacy-state.d.ts +14 -0
- package/build/auth/legacy-state.d.ts.map +1 -0
- package/build/auth/legacy-state.js +107 -0
- package/build/auth/legacy-state.js.map +1 -0
- package/build/auth/purdue-sso.d.ts +25 -36
- package/build/auth/purdue-sso.d.ts.map +1 -1
- package/build/auth/purdue-sso.js +210 -191
- package/build/auth/purdue-sso.js.map +1 -1
- package/build/auth/session-store.d.ts +16 -38
- package/build/auth/session-store.d.ts.map +1 -1
- package/build/auth/session-store.js +157 -152
- package/build/auth/session-store.js.map +1 -1
- package/build/auth/sso-flow.d.ts +16 -4
- package/build/auth/sso-flow.d.ts.map +1 -1
- package/build/auth/sso-flow.js +24 -2
- package/build/auth/sso-flow.js.map +1 -1
- package/build/auth/suny-sso.d.ts +6 -2
- package/build/auth/suny-sso.d.ts.map +1 -1
- package/build/auth/suny-sso.js +17 -24
- package/build/auth/suny-sso.js.map +1 -1
- package/build/auth/token-manager.d.ts +10 -3
- package/build/auth/token-manager.d.ts.map +1 -1
- package/build/auth/token-manager.js +62 -26
- package/build/auth/token-manager.js.map +1 -1
- package/build/auth/token-mint.d.ts +2 -2
- package/build/auth/token-mint.d.ts.map +1 -1
- package/build/auth/token-mint.js +31 -9
- package/build/auth/token-mint.js.map +1 -1
- package/build/auth-cli.d.ts +1 -7
- package/build/auth-cli.d.ts.map +1 -1
- package/build/auth-cli.js +71 -70
- package/build/auth-cli.js.map +1 -1
- package/build/index.js +20 -64
- package/build/index.js.map +1 -1
- package/build/setup.js +44 -19
- package/build/setup.js.map +1 -1
- package/build/tools/tool-helpers.d.ts +7 -1
- package/build/tools/tool-helpers.d.ts.map +1 -1
- package/build/tools/tool-helpers.js +96 -11
- package/build/tools/tool-helpers.js.map +1 -1
- package/build/types/index.d.ts +6 -0
- package/build/types/index.d.ts.map +1 -1
- package/build/utils/browser-install.d.ts +23 -0
- package/build/utils/browser-install.d.ts.map +1 -0
- package/build/utils/browser-install.js +33 -0
- package/build/utils/browser-install.js.map +1 -0
- package/build/utils/commands.d.ts +26 -0
- package/build/utils/commands.d.ts.map +1 -0
- package/build/utils/commands.js +26 -0
- package/build/utils/commands.js.map +1 -0
- package/build/utils/config-store.d.ts +1 -0
- package/build/utils/config-store.d.ts.map +1 -1
- package/build/utils/config-store.js +3 -0
- package/build/utils/config-store.js.map +1 -1
- package/build/utils/config.d.ts +2 -1
- package/build/utils/config.d.ts.map +1 -1
- package/build/utils/config.js +32 -10
- package/build/utils/config.js.map +1 -1
- package/build/utils/download-errors.d.ts +45 -0
- package/build/utils/download-errors.d.ts.map +1 -0
- package/build/utils/download-errors.js +45 -0
- package/build/utils/download-errors.js.map +1 -0
- package/build/utils/download-helpers.d.ts.map +1 -1
- package/build/utils/download-helpers.js +2 -1
- package/build/utils/download-helpers.js.map +1 -1
- package/build/utils/file-validator.d.ts +1 -1
- package/build/utils/file-validator.d.ts.map +1 -1
- package/build/utils/file-validator.js +47 -7
- package/build/utils/file-validator.js.map +1 -1
- package/build/utils/install-sites.d.ts +61 -0
- package/build/utils/install-sites.d.ts.map +1 -0
- package/build/utils/install-sites.js +207 -0
- package/build/utils/install-sites.js.map +1 -0
- package/build/utils/secure-config.d.ts +6 -0
- package/build/utils/secure-config.d.ts.map +1 -0
- package/build/utils/secure-config.js +57 -0
- package/build/utils/secure-config.js.map +1 -0
- package/build/utils/self-update.d.ts +61 -0
- package/build/utils/self-update.d.ts.map +1 -0
- package/build/utils/self-update.js +92 -0
- package/build/utils/self-update.js.map +1 -0
- package/build/utils/update-checker.d.ts +85 -7
- package/build/utils/update-checker.d.ts.map +1 -1
- package/build/utils/update-checker.js +141 -36
- package/build/utils/update-checker.js.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { hostname } from "node:os";
|
|
4
|
+
import { randomUUID } from "node:crypto";
|
|
5
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
6
|
+
/**
|
|
7
|
+
* Windows refuses to rename or remove a directory while any process still
|
|
8
|
+
* holds a handle inside it. Every contender for a stale lock is doing exactly
|
|
9
|
+
* that: reclaim.lock lives inside the directory the winner is trying to rename,
|
|
10
|
+
* so the loser's own scan blocks the winner. POSIX renames by inode and never
|
|
11
|
+
* sees this.
|
|
12
|
+
*
|
|
13
|
+
* The condition clears in milliseconds, so a short retry turns a spurious
|
|
14
|
+
* EPERM into an ordinary release instead of an unhandled crash.
|
|
15
|
+
*/
|
|
16
|
+
const CONTENTION_CODES = new Set(["EPERM", "EBUSY", "EACCES", "ENOTEMPTY"]);
|
|
17
|
+
const RENAME_ATTEMPTS = 5;
|
|
18
|
+
/**
|
|
19
|
+
* Rename, tolerating Windows contention. Resolves true when the directory
|
|
20
|
+
* moved, false when it is already gone or contention never cleared. Only a
|
|
21
|
+
* genuinely unexpected error is thrown, so callers decide what a failed
|
|
22
|
+
* rename means rather than being handed an ambiguous EPERM.
|
|
23
|
+
*/
|
|
24
|
+
async function renameThroughContention(from, to) {
|
|
25
|
+
for (let attempt = 0; attempt < RENAME_ATTEMPTS; attempt += 1) {
|
|
26
|
+
try {
|
|
27
|
+
await fs.rename(from, to);
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
const code = error.code ?? "";
|
|
32
|
+
if (code === "ENOENT")
|
|
33
|
+
return false;
|
|
34
|
+
if (!CONTENTION_CODES.has(code))
|
|
35
|
+
throw error;
|
|
36
|
+
await delay(10 * (attempt + 1));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
export class AuthenticationInProgressError extends Error {
|
|
42
|
+
code = "AUTH_IN_PROGRESS";
|
|
43
|
+
constructor() {
|
|
44
|
+
super("Authentication already in progress. Retry after the current authentication finishes.");
|
|
45
|
+
this.name = "AuthenticationInProgressError";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function readOwner(lockPath) {
|
|
49
|
+
try {
|
|
50
|
+
const owner = JSON.parse(await fs.readFile(path.join(lockPath, "owner.json"), "utf8"));
|
|
51
|
+
if (Number.isSafeInteger(owner.pid) && owner.pid > 0 && typeof owner.host === "string" && typeof owner.nonce === "string")
|
|
52
|
+
return owner;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// An incomplete or unknown lock is not proof that its owner is gone.
|
|
56
|
+
}
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
function isDead(owner) {
|
|
60
|
+
// Session directories are local-only. DHCP can change the host's name
|
|
61
|
+
// without changing this process table, so only PID liveness decides.
|
|
62
|
+
try {
|
|
63
|
+
process.kill(owner.pid, 0);
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
return error.code === "ESRCH";
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/** Remove only our fixed metadata names, after the directory was retired. */
|
|
71
|
+
async function cleanRetired(lockPath) {
|
|
72
|
+
await fs.unlink(path.join(lockPath, "owner.json")).catch(() => { });
|
|
73
|
+
await cleanChild(path.join(lockPath, "reclaim.lock"));
|
|
74
|
+
await fs.rmdir(lockPath).catch(() => { });
|
|
75
|
+
}
|
|
76
|
+
async function cleanChild(childPath) {
|
|
77
|
+
try {
|
|
78
|
+
if ((await fs.lstat(childPath)).isDirectory())
|
|
79
|
+
await cleanRetired(childPath);
|
|
80
|
+
}
|
|
81
|
+
catch { /* Already absent. */ }
|
|
82
|
+
}
|
|
83
|
+
class Lease {
|
|
84
|
+
directory;
|
|
85
|
+
owner;
|
|
86
|
+
constructor(directory, owner) {
|
|
87
|
+
this.directory = directory;
|
|
88
|
+
this.owner = owner;
|
|
89
|
+
}
|
|
90
|
+
async release() {
|
|
91
|
+
const current = await readOwner(this.directory);
|
|
92
|
+
if (current?.nonce !== this.owner.nonce)
|
|
93
|
+
return;
|
|
94
|
+
const retired = `${this.directory}.released.${this.owner.nonce}`;
|
|
95
|
+
// Releasing must never throw. It runs in a finally, so an exception here
|
|
96
|
+
// would mask the real failure and strand the lock for everyone else.
|
|
97
|
+
if (await renameThroughContention(this.directory, retired)) {
|
|
98
|
+
await cleanRetired(retired);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
// Contention never cleared. Clear the directory where it stands so the
|
|
102
|
+
// next process sees no owner rather than a lock nobody holds.
|
|
103
|
+
await cleanRetired(this.directory);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/** Acquire a process-shared lock without waiting or relying on its age. */
|
|
107
|
+
export async function acquireProcessLock(lockPath) {
|
|
108
|
+
await fs.mkdir(path.dirname(lockPath), { recursive: true, mode: 0o700 });
|
|
109
|
+
const lease = await acquireLease(lockPath, 0);
|
|
110
|
+
return () => lease.release();
|
|
111
|
+
}
|
|
112
|
+
async function acquireLease(lockPath, depth) {
|
|
113
|
+
if (depth > 16)
|
|
114
|
+
throw new AuthenticationInProgressError();
|
|
115
|
+
const owner = { pid: process.pid, host: hostname(), nonce: randomUUID() };
|
|
116
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
117
|
+
try {
|
|
118
|
+
await fs.mkdir(lockPath, { mode: 0o700 });
|
|
119
|
+
try {
|
|
120
|
+
await fs.writeFile(path.join(lockPath, "owner.json"), JSON.stringify(owner), { flag: "wx", mode: 0o600 });
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
await fs.rmdir(lockPath).catch(() => { });
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
return new Lease(lockPath, owner);
|
|
127
|
+
}
|
|
128
|
+
catch (error) {
|
|
129
|
+
if (error.code === "ENOENT")
|
|
130
|
+
throw new AuthenticationInProgressError();
|
|
131
|
+
if (error.code !== "EEXIST")
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
const stale = await readOwner(lockPath);
|
|
135
|
+
if (!stale || !isDead(stale))
|
|
136
|
+
throw new AuthenticationInProgressError();
|
|
137
|
+
// Recovery gets its own process lock within the stale directory. If a
|
|
138
|
+
// recovering process crashes, the same dead-owner rules recover its lock.
|
|
139
|
+
// Keep this claim in the directory during rename to serialize contenders.
|
|
140
|
+
const claim = await acquireLease(path.join(lockPath, "reclaim.lock"), depth + 1);
|
|
141
|
+
try {
|
|
142
|
+
const current = await readOwner(lockPath);
|
|
143
|
+
if (current?.nonce !== stale.nonce || !isDead(current))
|
|
144
|
+
throw new AuthenticationInProgressError();
|
|
145
|
+
const retired = `${lockPath}.stale.${owner.nonce}`;
|
|
146
|
+
// A rename blocked by contention means another contender is inside this
|
|
147
|
+
// directory recovering the same stale lock. That is someone else holding
|
|
148
|
+
// authentication, not a failure of ours.
|
|
149
|
+
if (!await renameThroughContention(lockPath, retired)) {
|
|
150
|
+
throw new AuthenticationInProgressError();
|
|
151
|
+
}
|
|
152
|
+
claim.directory = path.join(retired, "reclaim.lock");
|
|
153
|
+
await claim.release();
|
|
154
|
+
await cleanRetired(retired);
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
await claim.release();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
throw new AuthenticationInProgressError();
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=auth-lock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-lock.js","sourceRoot":"","sources":["../../src/auth/auth-lock.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,24 +3,45 @@
|
|
|
3
3
|
* Copyright (c) 2026 Rohan Muppa. All rights reserved.
|
|
4
4
|
* Licensed under MIT — see LICENSE file for details.
|
|
5
5
|
*/
|
|
6
|
+
import { AuthError } from "../utils/errors.js";
|
|
7
|
+
export type AuthFailureKind = "busy" | "cooldown" | "unsupported" | "secureStorage" | "transport" | "timeout" | "failed";
|
|
8
|
+
export declare class AuthProcessError extends AuthError {
|
|
9
|
+
readonly kind: AuthFailureKind;
|
|
10
|
+
constructor(kind: AuthFailureKind, message: string);
|
|
11
|
+
}
|
|
12
|
+
export interface AuthRunnerOptions {
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
onProgress?: (line: string) => void;
|
|
15
|
+
}
|
|
6
16
|
/**
|
|
7
17
|
* Launches the brightspace-auth CLI as a child process to
|
|
8
18
|
* re-authenticate when the current session has expired.
|
|
9
19
|
*
|
|
10
|
-
* The child
|
|
11
|
-
*
|
|
12
|
-
* as CWD (so dotenv can find the .env file).
|
|
20
|
+
* The child inherits the parent's resolved environment and working directory,
|
|
21
|
+
* so both processes read the same account configuration and .env file.
|
|
13
22
|
*/
|
|
14
23
|
export declare class AuthRunner {
|
|
15
|
-
|
|
24
|
+
/**
|
|
25
|
+
* The login this process already started, if one is still running.
|
|
26
|
+
*
|
|
27
|
+
* Every tool call funnels here the moment the saved session is gone, and a
|
|
28
|
+
* stdio MCP server serves tool calls concurrently. Without a latch, two cold
|
|
29
|
+
* calls both see no token and both spawn a login: two browsers racing the
|
|
30
|
+
* same cross-process lock, and at Purdue two Authenticator prompts on the
|
|
31
|
+
* user's phone for one request. Holding the in-flight Promise makes every
|
|
32
|
+
* caller await the same login and read the same outcome.
|
|
33
|
+
*/
|
|
34
|
+
private inFlight;
|
|
16
35
|
private readonly scriptPath;
|
|
17
|
-
private readonly
|
|
18
|
-
|
|
36
|
+
private readonly timeoutMs;
|
|
37
|
+
private readonly onProgress?;
|
|
38
|
+
constructor(options?: AuthRunnerOptions);
|
|
19
39
|
/**
|
|
20
|
-
*
|
|
21
|
-
* Returns true
|
|
22
|
-
* Prevents concurrent auth attempts via a simple mutex.
|
|
40
|
+
* Authenticate, joining the login this process already started if there is
|
|
41
|
+
* one. Returns true on success and throws a useful error on failure.
|
|
23
42
|
*/
|
|
24
43
|
run(): Promise<boolean>;
|
|
44
|
+
/** One child process, start to finish. */
|
|
45
|
+
private spawnAuth;
|
|
25
46
|
}
|
|
26
47
|
//# sourceMappingURL=auth-runner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-runner.d.ts","sourceRoot":"","sources":["../../src/auth/auth-runner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"auth-runner.d.ts","sourceRoot":"","sources":["../../src/auth/auth-runner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAY/C,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,UAAU,GAAG,aAAa,GAAG,eAAe,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEzH,qBAAa,gBAAiB,SAAQ,SAAS;aACjB,IAAI,EAAE,eAAe;gBAArB,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM;CAInE;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AAkDD;;;;;;GAMG;AACH,qBAAa,UAAU;IACrB;;;;;;;;;OASG;IACH,OAAO,CAAC,QAAQ,CAAiC;IACjD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAyB;gBAEzC,OAAO,GAAE,iBAAsB;IAQ3C;;;OAGG;IACG,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;IAkB7B,0CAA0C;YAC5B,SAAS;CAgGxB"}
|
|
@@ -3,17 +3,47 @@
|
|
|
3
3
|
* Copyright (c) 2026 Rohan Muppa. All rights reserved.
|
|
4
4
|
* Licensed under MIT — see LICENSE file for details.
|
|
5
5
|
*/
|
|
6
|
-
import { spawn } from "node:child_process";
|
|
6
|
+
import { spawn, execFileSync } from "node:child_process";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import * as path from "node:path";
|
|
9
9
|
import { log } from "../utils/logger.js";
|
|
10
|
+
import { AuthError } from "../utils/errors.js";
|
|
11
|
+
import { AUTH_COMMAND } from "../utils/commands.js";
|
|
10
12
|
/**
|
|
11
13
|
* Timeout for the auth process. It has to outlast the child's own MFA wait,
|
|
12
14
|
* which is five minutes: a person has to find their phone, unlock it, and read
|
|
13
15
|
* a number off the screen. A shorter parent budget would kill the child in the
|
|
14
16
|
* middle of a sign-in the user was still completing.
|
|
15
17
|
*/
|
|
16
|
-
const AUTH_TIMEOUT_MS =
|
|
18
|
+
const AUTH_TIMEOUT_MS = 8 * 60 * 1000;
|
|
19
|
+
const KILL_GRACE_MS = 5000;
|
|
20
|
+
export class AuthProcessError extends AuthError {
|
|
21
|
+
kind;
|
|
22
|
+
constructor(kind, message) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.kind = kind;
|
|
25
|
+
this.name = "AuthProcessError";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** Chromium can lead a separate process group, so a forced stop needs its PID. */
|
|
29
|
+
function descendantPids(parentPid) {
|
|
30
|
+
const rows = execFileSync("ps", ["-eo", "pid=,ppid="], {
|
|
31
|
+
encoding: "utf8", timeout: 1000,
|
|
32
|
+
}).trim().split("\n").map(line => line.trim().split(/\s+/).map(Number));
|
|
33
|
+
const descendants = [];
|
|
34
|
+
const visited = new Set([parentPid]);
|
|
35
|
+
const visit = (parent) => {
|
|
36
|
+
for (const [pid, ppid] of rows) {
|
|
37
|
+
if (ppid === parent && Number.isInteger(pid) && pid > 1 && !visited.has(pid)) {
|
|
38
|
+
visited.add(pid);
|
|
39
|
+
visit(pid);
|
|
40
|
+
descendants.push(pid);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
visit(parentPid);
|
|
45
|
+
return descendants;
|
|
46
|
+
}
|
|
17
47
|
/**
|
|
18
48
|
* Forward a child stream to the server log, one line at a time.
|
|
19
49
|
*
|
|
@@ -45,74 +75,159 @@ function forwardLines(stream, emit) {
|
|
|
45
75
|
* Launches the brightspace-auth CLI as a child process to
|
|
46
76
|
* re-authenticate when the current session has expired.
|
|
47
77
|
*
|
|
48
|
-
* The child
|
|
49
|
-
*
|
|
50
|
-
* as CWD (so dotenv can find the .env file).
|
|
78
|
+
* The child inherits the parent's resolved environment and working directory,
|
|
79
|
+
* so both processes read the same account configuration and .env file.
|
|
51
80
|
*/
|
|
52
81
|
export class AuthRunner {
|
|
53
|
-
|
|
82
|
+
/**
|
|
83
|
+
* The login this process already started, if one is still running.
|
|
84
|
+
*
|
|
85
|
+
* Every tool call funnels here the moment the saved session is gone, and a
|
|
86
|
+
* stdio MCP server serves tool calls concurrently. Without a latch, two cold
|
|
87
|
+
* calls both see no token and both spawn a login: two browsers racing the
|
|
88
|
+
* same cross-process lock, and at Purdue two Authenticator prompts on the
|
|
89
|
+
* user's phone for one request. Holding the in-flight Promise makes every
|
|
90
|
+
* caller await the same login and read the same outcome.
|
|
91
|
+
*/
|
|
92
|
+
inFlight = null;
|
|
54
93
|
scriptPath;
|
|
55
|
-
|
|
56
|
-
|
|
94
|
+
timeoutMs;
|
|
95
|
+
onProgress;
|
|
96
|
+
constructor(options = {}) {
|
|
57
97
|
// Resolve paths relative to this file's compiled location (build/auth/auth-runner.js)
|
|
58
98
|
const thisDir = path.dirname(fileURLToPath(import.meta.url));
|
|
59
99
|
this.scriptPath = path.resolve(thisDir, "..", "auth-cli.js");
|
|
60
|
-
this.
|
|
100
|
+
this.timeoutMs = options.timeoutMs ?? AUTH_TIMEOUT_MS;
|
|
101
|
+
this.onProgress = options.onProgress;
|
|
61
102
|
}
|
|
62
103
|
/**
|
|
63
|
-
*
|
|
64
|
-
* Returns true
|
|
65
|
-
* Prevents concurrent auth attempts via a simple mutex.
|
|
104
|
+
* Authenticate, joining the login this process already started if there is
|
|
105
|
+
* one. Returns true on success and throws a useful error on failure.
|
|
66
106
|
*/
|
|
67
107
|
async run() {
|
|
68
|
-
if (this.
|
|
69
|
-
log("DEBUG", "
|
|
70
|
-
return
|
|
108
|
+
if (this.inFlight) {
|
|
109
|
+
log("DEBUG", "Joining the authentication already in flight");
|
|
110
|
+
return this.inFlight;
|
|
71
111
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
resolve(true);
|
|
112
|
+
// The latch is released by the flow that owns it, as it settles, so a
|
|
113
|
+
// failed login is never replayed: the tool call after a declined MFA
|
|
114
|
+
// prompt starts a fresh attempt rather than inheriting the stale
|
|
115
|
+
// rejection. Ownership is checked because a caller could in principle
|
|
116
|
+
// clear the latch while this flow is still running.
|
|
117
|
+
const flow = this.spawnAuth().finally(() => {
|
|
118
|
+
if (this.inFlight === flow)
|
|
119
|
+
this.inFlight = null;
|
|
120
|
+
});
|
|
121
|
+
this.inFlight = flow;
|
|
122
|
+
return flow;
|
|
123
|
+
}
|
|
124
|
+
/** One child process, start to finish. */
|
|
125
|
+
async spawnAuth() {
|
|
126
|
+
log("INFO", "Auto-launching brightspace-auth...");
|
|
127
|
+
return await new Promise((resolve, reject) => {
|
|
128
|
+
const child = spawn(process.execPath, // use the same Node binary
|
|
129
|
+
[this.scriptPath, "--automatic"], {
|
|
130
|
+
cwd: process.cwd(),
|
|
131
|
+
env: { ...process.env },
|
|
132
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
133
|
+
detached: process.platform !== "win32",
|
|
134
|
+
});
|
|
135
|
+
let timedOut = false;
|
|
136
|
+
let settled = false;
|
|
137
|
+
let killTimer;
|
|
138
|
+
const kill = (signal) => {
|
|
139
|
+
try {
|
|
140
|
+
if (child.pid && process.platform === "win32") {
|
|
141
|
+
execFileSync("taskkill", ["/pid", String(child.pid), "/t", "/f"], {
|
|
142
|
+
stdio: "ignore", timeout: 5000,
|
|
143
|
+
});
|
|
105
144
|
}
|
|
106
|
-
else {
|
|
107
|
-
|
|
108
|
-
|
|
145
|
+
else if (child.pid) {
|
|
146
|
+
if (signal === "SIGKILL") {
|
|
147
|
+
try {
|
|
148
|
+
for (const pid of descendantPids(child.pid)) {
|
|
149
|
+
try {
|
|
150
|
+
process.kill(pid, "SIGKILL");
|
|
151
|
+
}
|
|
152
|
+
catch { /* Already exited. */ }
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch { /* Still terminate the owned process group if ps is unavailable. */ }
|
|
156
|
+
}
|
|
157
|
+
process.kill(-child.pid, signal);
|
|
109
158
|
}
|
|
110
|
-
|
|
159
|
+
else
|
|
160
|
+
child.kill(signal);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
// The child may already have exited between close and cleanup.
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
const onExit = () => kill("SIGTERM");
|
|
167
|
+
process.once("exit", onExit);
|
|
168
|
+
const finish = (error) => {
|
|
169
|
+
if (settled)
|
|
170
|
+
return;
|
|
171
|
+
settled = true;
|
|
172
|
+
clearTimeout(timer);
|
|
173
|
+
if (killTimer)
|
|
174
|
+
clearTimeout(killTimer);
|
|
175
|
+
process.off("exit", onExit);
|
|
176
|
+
if (error)
|
|
177
|
+
reject(error);
|
|
178
|
+
else
|
|
179
|
+
resolve(true);
|
|
180
|
+
};
|
|
181
|
+
const timer = setTimeout(() => {
|
|
182
|
+
timedOut = true;
|
|
183
|
+
kill("SIGTERM");
|
|
184
|
+
killTimer = setTimeout(() => {
|
|
185
|
+
kill("SIGKILL");
|
|
186
|
+
finish(new AuthProcessError("timeout", `Authentication timed out. Run ${AUTH_COMMAND} to try again.`));
|
|
187
|
+
}, KILL_GRACE_MS);
|
|
188
|
+
}, this.timeoutMs);
|
|
189
|
+
forwardLines(child.stderr, (line) => {
|
|
190
|
+
log("INFO", line);
|
|
191
|
+
try {
|
|
192
|
+
this.onProgress?.(line);
|
|
193
|
+
}
|
|
194
|
+
catch { /* Logging must not interrupt authentication. */ }
|
|
111
195
|
});
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
196
|
+
// Piped and drained rather than ignored: a full stdout pipe would
|
|
197
|
+
// block the child mid-login.
|
|
198
|
+
forwardLines(child.stdout, (line) => log("DEBUG", line));
|
|
199
|
+
child.on("error", (error) => {
|
|
200
|
+
if (settled)
|
|
201
|
+
return;
|
|
202
|
+
log("ERROR", "Auto-auth process failed", error.message);
|
|
203
|
+
kill("SIGKILL");
|
|
204
|
+
finish(new AuthProcessError("failed", `Could not start authentication. Run ${AUTH_COMMAND} for details.`));
|
|
205
|
+
});
|
|
206
|
+
child.on("close", (code) => {
|
|
207
|
+
if (settled)
|
|
208
|
+
return;
|
|
209
|
+
if (timedOut) {
|
|
210
|
+
kill("SIGKILL");
|
|
211
|
+
finish(new AuthProcessError("timeout", `Authentication timed out. Run ${AUTH_COMMAND} to try again.`));
|
|
212
|
+
}
|
|
213
|
+
else if (code === 0) {
|
|
214
|
+
log("INFO", "Auto-auth completed successfully");
|
|
215
|
+
finish();
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
const failures = {
|
|
219
|
+
2: ["busy", "Authentication already in progress in another process. Complete that attempt, then retry."],
|
|
220
|
+
3: ["cooldown", `Automatic MFA is paused after an unsuccessful attempt. Run ${AUTH_COMMAND} to retry immediately.`],
|
|
221
|
+
4: ["unsupported", "This identity provider cannot complete headless authentication. See the authentication logs."],
|
|
222
|
+
5: ["secureStorage", "The native credential store is unavailable or locked. Unlock it and retry."],
|
|
223
|
+
6: ["transport", "Brightspace authentication is temporarily unavailable because of a network or server failure. Your saved session was preserved. Try again later."],
|
|
224
|
+
};
|
|
225
|
+
const [kind, message] = failures[code ?? -1] ?? ["failed", `Authentication failed. Run ${AUTH_COMMAND} to try again.`];
|
|
226
|
+
kill("SIGKILL");
|
|
227
|
+
finish(new AuthProcessError(kind, message));
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
});
|
|
116
231
|
}
|
|
117
232
|
}
|
|
118
233
|
//# sourceMappingURL=auth-runner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-runner.js","sourceRoot":"","sources":["../../src/auth/auth-runner.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"auth-runner.js","sourceRoot":"","sources":["../../src/auth/auth-runner.ts"],"names":[],"mappings":"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"}
|