brightspace-mcp-server 1.2.6 → 1.5.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.
Files changed (134) hide show
  1. package/README.md +44 -13
  2. package/build/api/cache.d.ts +1 -1
  3. package/build/api/cache.js +1 -1
  4. package/build/api/client.d.ts +1 -1
  5. package/build/api/client.d.ts.map +1 -1
  6. package/build/api/client.js +25 -3
  7. package/build/api/client.js.map +1 -1
  8. package/build/api/errors.d.ts +2 -2
  9. package/build/api/errors.js +2 -2
  10. package/build/api/index.d.ts +1 -1
  11. package/build/api/index.js +1 -1
  12. package/build/api/rate-limiter.d.ts +2 -2
  13. package/build/api/rate-limiter.js +2 -2
  14. package/build/api/types.d.ts +1 -1
  15. package/build/api/types.js +1 -1
  16. package/build/api/version-discovery.d.ts +2 -2
  17. package/build/api/version-discovery.js +2 -2
  18. package/build/auth/auth-runner.d.ts +2 -2
  19. package/build/auth/auth-runner.d.ts.map +1 -1
  20. package/build/auth/auth-runner.js +61 -12
  21. package/build/auth/auth-runner.js.map +1 -1
  22. package/build/auth/browser-auth.d.ts +35 -1
  23. package/build/auth/browser-auth.d.ts.map +1 -1
  24. package/build/auth/browser-auth.js +219 -28
  25. package/build/auth/browser-auth.js.map +1 -1
  26. package/build/auth/index.d.ts +5 -2
  27. package/build/auth/index.d.ts.map +1 -1
  28. package/build/auth/index.js +4 -2
  29. package/build/auth/index.js.map +1 -1
  30. package/build/auth/purdue-sso.d.ts +30 -1
  31. package/build/auth/purdue-sso.d.ts.map +1 -1
  32. package/build/auth/purdue-sso.js +144 -17
  33. package/build/auth/purdue-sso.js.map +1 -1
  34. package/build/auth/session-store.d.ts +1 -1
  35. package/build/auth/session-store.js +1 -1
  36. package/build/auth/sso-flow.d.ts +24 -0
  37. package/build/auth/sso-flow.d.ts.map +1 -0
  38. package/build/auth/sso-flow.js +21 -0
  39. package/build/auth/sso-flow.js.map +1 -0
  40. package/build/auth/suny-sso.d.ts +49 -0
  41. package/build/auth/suny-sso.d.ts.map +1 -0
  42. package/build/auth/suny-sso.js +146 -0
  43. package/build/auth/suny-sso.js.map +1 -0
  44. package/build/auth/token-manager.d.ts +29 -2
  45. package/build/auth/token-manager.d.ts.map +1 -1
  46. package/build/auth/token-manager.js +83 -4
  47. package/build/auth/token-manager.js.map +1 -1
  48. package/build/auth/token-mint.d.ts +32 -0
  49. package/build/auth/token-mint.d.ts.map +1 -0
  50. package/build/auth/token-mint.js +71 -0
  51. package/build/auth/token-mint.js.map +1 -0
  52. package/build/auth-cli.d.ts +1 -1
  53. package/build/auth-cli.js +9 -4
  54. package/build/auth-cli.js.map +1 -1
  55. package/build/index.d.ts +1 -1
  56. package/build/index.js +6 -2
  57. package/build/index.js.map +1 -1
  58. package/build/setup.d.ts +2 -2
  59. package/build/setup.js +31 -5
  60. package/build/setup.js.map +1 -1
  61. package/build/tools/download-file.d.ts +6 -2
  62. package/build/tools/download-file.d.ts.map +1 -1
  63. package/build/tools/download-file.js +27 -7
  64. package/build/tools/download-file.js.map +1 -1
  65. package/build/tools/get-announcements.d.ts +65 -2
  66. package/build/tools/get-announcements.d.ts.map +1 -1
  67. package/build/tools/get-announcements.js +69 -25
  68. package/build/tools/get-announcements.js.map +1 -1
  69. package/build/tools/get-assignments.d.ts +8 -2
  70. package/build/tools/get-assignments.d.ts.map +1 -1
  71. package/build/tools/get-assignments.js +76 -17
  72. package/build/tools/get-assignments.js.map +1 -1
  73. package/build/tools/get-classlist-emails.d.ts +2 -2
  74. package/build/tools/get-classlist-emails.js +2 -2
  75. package/build/tools/get-course-content.d.ts +2 -2
  76. package/build/tools/get-course-content.js +2 -2
  77. package/build/tools/get-discussions.d.ts +1 -1
  78. package/build/tools/get-discussions.js +1 -1
  79. package/build/tools/get-my-courses.d.ts +2 -2
  80. package/build/tools/get-my-courses.d.ts.map +1 -1
  81. package/build/tools/get-my-courses.js +10 -4
  82. package/build/tools/get-my-courses.js.map +1 -1
  83. package/build/tools/get-my-grades.d.ts +1 -1
  84. package/build/tools/get-my-grades.js +1 -1
  85. package/build/tools/get-roster.d.ts +2 -2
  86. package/build/tools/get-roster.js +2 -2
  87. package/build/tools/get-syllabus.d.ts +1 -1
  88. package/build/tools/get-syllabus.js +1 -1
  89. package/build/tools/get-upcoming-due-dates.d.ts +2 -2
  90. package/build/tools/get-upcoming-due-dates.d.ts.map +1 -1
  91. package/build/tools/get-upcoming-due-dates.js +121 -45
  92. package/build/tools/get-upcoming-due-dates.js.map +1 -1
  93. package/build/tools/index.d.ts +2 -2
  94. package/build/tools/index.js +2 -2
  95. package/build/tools/schemas.d.ts +3 -3
  96. package/build/tools/schemas.d.ts.map +1 -1
  97. package/build/tools/schemas.js +11 -5
  98. package/build/tools/schemas.js.map +1 -1
  99. package/build/tools/tool-helpers.d.ts +1 -1
  100. package/build/tools/tool-helpers.js +1 -1
  101. package/build/types/index.d.ts +12 -2
  102. package/build/types/index.d.ts.map +1 -1
  103. package/build/types/index.js +2 -2
  104. package/build/update.d.ts +1 -1
  105. package/build/update.js +1 -1
  106. package/build/utils/config-store.d.ts +3 -2
  107. package/build/utils/config-store.d.ts.map +1 -1
  108. package/build/utils/config-store.js +2 -2
  109. package/build/utils/config-store.js.map +1 -1
  110. package/build/utils/config.d.ts +2 -2
  111. package/build/utils/config.d.ts.map +1 -1
  112. package/build/utils/config.js +3 -2
  113. package/build/utils/config.js.map +1 -1
  114. package/build/utils/course-filter.d.ts +2 -2
  115. package/build/utils/course-filter.js +2 -2
  116. package/build/utils/deep-links.d.ts +15 -0
  117. package/build/utils/deep-links.d.ts.map +1 -0
  118. package/build/utils/deep-links.js +31 -0
  119. package/build/utils/deep-links.js.map +1 -0
  120. package/build/utils/download-helpers.d.ts +2 -2
  121. package/build/utils/download-helpers.js +2 -2
  122. package/build/utils/errors.d.ts +2 -2
  123. package/build/utils/errors.js +2 -2
  124. package/build/utils/file-validator.d.ts +2 -2
  125. package/build/utils/file-validator.d.ts.map +1 -1
  126. package/build/utils/file-validator.js +21 -11
  127. package/build/utils/file-validator.js.map +1 -1
  128. package/build/utils/html-converter.d.ts +2 -2
  129. package/build/utils/html-converter.js +2 -2
  130. package/build/utils/logger.d.ts +2 -2
  131. package/build/utils/logger.js +2 -2
  132. package/build/utils/pdf-extractor.d.ts +2 -2
  133. package/build/utils/pdf-extractor.js +2 -2
  134. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Purdue Brightspace MCP Server
3
- * Copyright (c) 2025 Rohan Muppa. All rights reserved.
3
+ * Copyright (c) 2026 Rohan Muppa. All rights reserved.
4
4
  * Licensed under MIT — see LICENSE file for details.
5
5
  */
6
6
  import { BrowserAuthError } from "../utils/errors.js";
@@ -10,7 +10,28 @@ const SELECTORS = {
10
10
  passwordInput: "input#password",
11
11
  submitButton: 'button[name="_eventId_proceed"]',
12
12
  staySignedInYes: "input[type=submit][value='Yes']",
13
+ // Purdue's proceed button, D2L's own, and the generic submit used by Entra
14
+ // (input#idSIButton9) and most other identity providers.
15
+ formSubmit: 'button[name="_eventId_proceed"], button.d2l-button, input[type="submit"]',
13
16
  };
17
+ // Entra labels the account-name button "Next" and only shows "Sign in" on the
18
+ // view that follows. Both are input#idSIButton9, so the label tells them apart.
19
+ const ACCOUNT_NAME_BUTTON = /^next$/i;
20
+ /**
21
+ * Entra's number-match digits. The tenant shows a two-digit number that has to
22
+ * be typed into Microsoft Authenticator, and nothing else on the machine
23
+ * reveals it, so a headless run stalls forever unless this is scraped and
24
+ * logged. Plain DOM text, no OCR.
25
+ */
26
+ const NUMBER_MATCH_SELECTOR = "#idRichContext_DisplaySign";
27
+ /** How often to look for the number while waiting on MFA. */
28
+ const NUMBER_MATCH_POLL_MS = 2000;
29
+ /** A person has to find their phone, unlock it, and read a prompt. */
30
+ const MFA_TIMEOUT_MS = 5 * 60 * 1000;
31
+ /** Visible text of a button, or the value of a submit input. */
32
+ async function controlLabel(handle) {
33
+ return handle.evaluate((el) => (el.value || el.textContent || "").trim());
34
+ }
14
35
  export class PurdueSSOFlow {
15
36
  config;
16
37
  constructor(config) {
@@ -31,7 +52,7 @@ export class PurdueSSOFlow {
31
52
  */
32
53
  async login(page) {
33
54
  try {
34
- log("INFO", "Starting Purdue SSO login flow");
55
+ log("INFO", "Starting SSO login flow");
35
56
  // Step 1: Handle campus selector on purdue.brightspace.com/d2l/login
36
57
  await this.handleCampusSelector(page);
37
58
  // Step 2: Enter username + password on sso.purdue.edu (Shibboleth)
@@ -73,7 +94,7 @@ export class PurdueSSOFlow {
73
94
  }
74
95
  async handleCampusSelector(page) {
75
96
  const currentUrl = page.url();
76
- if (currentUrl.includes("/d2l/login")) {
97
+ if (currentUrl.includes("purdue.brightspace.com") && currentUrl.includes("/d2l/login")) {
77
98
  // Campus selector buttons are inside a shadow DOM — navigate directly
78
99
  // to Purdue's Shibboleth SAML endpoint instead of clicking them
79
100
  const baseUrl = new URL(currentUrl).origin;
@@ -84,8 +105,11 @@ export class PurdueSSOFlow {
84
105
  }
85
106
  async enterCredentials(page) {
86
107
  try {
87
- log("DEBUG", "Waiting for Shibboleth login form");
88
- await page.waitForSelector(SELECTORS.usernameInput, { timeout: 30000 });
108
+ log("DEBUG", "Waiting for login form");
109
+ // Wait for either Purdue's username or Albany's userName (or typical email fields)
110
+ // Use a shorter timeout so it falls back to manual login quickly if unrecognized
111
+ const usernameSelector = 'input#username, input#userName, input[type="email"]';
112
+ await page.waitForSelector(usernameSelector, { timeout: 10000 });
89
113
  if (!this.config.username) {
90
114
  throw new BrowserAuthError("Username is required for SSO login", "credentials");
91
115
  }
@@ -93,39 +117,142 @@ export class PurdueSSOFlow {
93
117
  throw new BrowserAuthError("Password is required for SSO login", "credentials");
94
118
  }
95
119
  log("INFO", "Entering credentials");
96
- await page.fill(SELECTORS.usernameInput, this.config.username);
97
- await page.fill(SELECTORS.passwordInput, this.config.password);
98
- await page.click(SELECTORS.submitButton);
120
+ const usernameField = await this.findVisible(page, usernameSelector);
121
+ if (usernameField) {
122
+ await usernameField.fill(this.config.username);
123
+ }
124
+ // Microsoft Entra puts a password box on its account-name page as well,
125
+ // but the button there only advances to the next view. Submit the account
126
+ // name first so the password lands on the page that actually signs in.
127
+ await this.submitAccountName(page);
128
+ const passwordSelector = 'input#password, input[type="password"]';
129
+ const passwordField = await this.findVisible(page, passwordSelector);
130
+ if (passwordField) {
131
+ await passwordField.fill(this.config.password);
132
+ }
133
+ const submitButton = await this.findVisible(page, SELECTORS.formSubmit);
134
+ if (submitButton) {
135
+ await submitButton.click();
136
+ }
137
+ else {
138
+ // Fallback: just hit Enter on the password field
139
+ await passwordField?.press('Enter');
140
+ }
99
141
  await page.waitForLoadState("networkidle");
100
142
  }
101
143
  catch (error) {
102
- if (error instanceof BrowserAuthError)
103
- throw error;
104
- throw new BrowserAuthError("Failed to enter credentials", "credentials", error);
144
+ log("WARN", "Automated credentials entry failed, will fallback to manual login.", error);
145
+ throw error;
105
146
  }
106
147
  }
148
+ /**
149
+ * Resolve a control only when it is actually on screen.
150
+ *
151
+ * Entra is a single-page app: the account-name view stays in the DOM once
152
+ * the password view replaces it, so a plain page.$() returns the hidden
153
+ * first-page input or button that precedes the live one in document order.
154
+ * Filling or clicking those stalls on Playwright's actionability wait.
155
+ */
156
+ async findVisible(page, selector) {
157
+ for (const handle of await page.$$(selector)) {
158
+ if (await handle.isVisible())
159
+ return handle;
160
+ }
161
+ return null;
162
+ }
163
+ /**
164
+ * Advance Microsoft Entra's account-name page.
165
+ *
166
+ * That page carries a password box of its own, and Playwright reports it as
167
+ * visible, so presence cannot tell it apart from a single-page form. The
168
+ * button label can: it reads "Next" there and "Sign in" on the view that
169
+ * follows. Filling the password against the account-name page leaves the
170
+ * browser parked with both fields populated and nothing submitted.
171
+ */
172
+ async submitAccountName(page) {
173
+ const submit = await this.findVisible(page, SELECTORS.formSubmit);
174
+ if (!submit)
175
+ return;
176
+ if (!ACCOUNT_NAME_BUTTON.test(await controlLabel(submit)))
177
+ return;
178
+ log("INFO", "Account-name page detected — submitting account name");
179
+ await submit.click();
180
+ // The sign-in view has arrived once the button stops saying "Next".
181
+ for (let attempt = 0; attempt < 30; attempt += 1) {
182
+ await page.waitForTimeout(500);
183
+ const current = await this.findVisible(page, SELECTORS.formSubmit);
184
+ if (current && !ACCOUNT_NAME_BUTTON.test(await controlLabel(current)))
185
+ return;
186
+ }
187
+ log("WARN", "Sign-in page did not appear after submitting the account name");
188
+ }
107
189
  async handleMFA(page) {
190
+ // The number is only on screen while MFA is pending, so the scrape has to
191
+ // run alongside the wait rather than before or after it.
192
+ const pending = { done: false };
193
+ let release = () => { };
194
+ const released = new Promise((resolve) => {
195
+ release = resolve;
196
+ });
197
+ const watcher = this.watchNumberMatch(page, pending, released);
108
198
  try {
109
199
  log("WARN", "Waiting for Microsoft MFA approval on your device...");
110
- log("INFO", "Timeout: 120 seconds");
111
- log("INFO", "Browser is running in headed mode - please approve the MFA request on your phone");
200
+ log("INFO", "Timeout: 5 minutes");
201
+ log("INFO", "Approve the sign-in request in Microsoft Authenticator. If it shows a number, it is printed below.");
112
202
  // Wait for MFA approval by watching for the post-MFA redirect.
113
203
  // Using waitForURL instead of networkidle because networkidle fires
114
204
  // after 500ms of no network activity, which can happen while the MFA
115
- // page UI finishes loading but before the user approves the Duo push.
205
+ // page UI finishes loading but before the user approves the request.
116
206
  await page.waitForURL((url) => {
117
207
  const href = url.toString();
118
208
  return href.includes("/d2l/") ||
119
209
  href.includes("kmsi") ||
120
210
  href.includes("/sso/") ||
121
211
  href.includes("SAMLResponse");
122
- }, { timeout: 120000 });
123
- log("INFO", `MFA completed — redirected to: ${page.url()}`);
212
+ }, { timeout: MFA_TIMEOUT_MS });
213
+ log("INFO", `MFA completed - redirected to: ${page.url()}`);
124
214
  }
125
215
  catch (error) {
126
- throw new BrowserAuthError("MFA approval timed out after 120 seconds", "mfa_approval", error);
216
+ throw new BrowserAuthError("MFA approval timed out after 5 minutes", "mfa_approval", error);
217
+ }
218
+ finally {
219
+ pending.done = true;
220
+ release();
221
+ await watcher;
222
+ }
223
+ }
224
+ /**
225
+ * Log Entra's number-match digits until the MFA wait is over.
226
+ *
227
+ * Only a CHANGED value is logged: Entra re-mints the number whenever the
228
+ * user asks for a new request, and repeating the same digits every two
229
+ * seconds would bury everything else in the log.
230
+ */
231
+ async watchNumberMatch(page, pending, released) {
232
+ let last = null;
233
+ while (!pending.done) {
234
+ const number = await this.readNumberMatch(page);
235
+ if (number && number !== last) {
236
+ last = number;
237
+ log("WARN", `Number match: ${number}. Enter it in Microsoft Authenticator.`);
238
+ }
239
+ // Racing the release keeps the wait from outliving the MFA it watches.
240
+ await Promise.race([
241
+ page.waitForTimeout(NUMBER_MATCH_POLL_MS).catch(() => { }),
242
+ released,
243
+ ]);
127
244
  }
128
245
  }
246
+ /** The digits on screen, or null when Entra is not showing any. */
247
+ async readNumberMatch(page) {
248
+ const sign = page.locator(NUMBER_MATCH_SELECTOR).first();
249
+ // isVisible answers immediately rather than waiting out a timeout, so the
250
+ // runs that never show a number keep the poll on its two-second rhythm.
251
+ if (!(await sign.isVisible().catch(() => false)))
252
+ return null;
253
+ const text = await sign.textContent().catch(() => null);
254
+ return text?.trim() || null;
255
+ }
129
256
  async handleStaySignedIn(page) {
130
257
  try {
131
258
  log("DEBUG", "Checking for 'Stay signed in?' prompt");
@@ -1 +1 @@
1
- {"version":3,"file":"purdue-sso.js","sourceRoot":"","sources":["../../src/auth/purdue-sso.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"purdue-sso.js","sourceRoot":"","sources":["../../src/auth/purdue-sso.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAEzC,MAAM,SAAS,GAAG;IAChB,aAAa,EAAE,gBAAgB;IAC/B,aAAa,EAAE,gBAAgB;IAC/B,YAAY,EAAE,iCAAiC;IAC/C,eAAe,EAAE,iCAAiC;IAClD,2EAA2E;IAC3E,yDAAyD;IACzD,UAAU,EAAE,0EAA0E;CAC9E,CAAC;AAEX,8EAA8E;AAC9E,gFAAgF;AAChF,MAAM,mBAAmB,GAAG,SAAS,CAAC;AAEtC;;;;;GAKG;AACH,MAAM,qBAAqB,GAAG,4BAA4B,CAAC;AAE3D,6DAA6D;AAC7D,MAAM,oBAAoB,GAAG,IAAI,CAAC;AAElC,sEAAsE;AACtE,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAErC,gEAAgE;AAChE,KAAK,UAAU,YAAY,CACzB,MAA+C;IAE/C,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,EAAE,CAC5B,CAAE,EAAuB,CAAC,KAAK,IAAI,EAAE,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAChE,CAAC;AACJ,CAAC;AAOD,MAAM,OAAO,aAAa;IAChB,MAAM,CAAkB;IAEhC,YAAY,MAAuB;QACjC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC/D,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,KAAK,CAAC,IAAU;QACpB,IAAI,CAAC;YACH,GAAG,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAC;YAEvC,qEAAqE;YACrE,MAAM,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;YAEtC,mEAAmE;YACnE,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;YAElC,yDAAyD;YACzD,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAE3B,0CAA0C;YAC1C,MAAM,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAEpC,2DAA2D;YAC3D,MAAM,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YAC1D,GAAG,CAAC,MAAM,EAAE,6CAA6C,CAAC,CAAC;YAE3D,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,OAAO,EAAE,uBAAuB,EAAE,KAAK,CAAC,CAAC;YAC7C,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,WAAW,CAAC,IAAU;QAC1B,IAAI,CAAC;YACH,GAAG,CAAC,MAAM,EAAE,mDAAmD,CAAC,CAAC;YACjE,GAAG,CAAC,MAAM,EAAE,0DAA0D,CAAC,CAAC;YAExE,6EAA6E;YAC7E,MAAM,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;YAEtC,+DAA+D;YAC/D,GAAG,CAAC,MAAM,EAAE,8DAA8D,CAAC,CAAC;YAC5E,MAAM,IAAI,CAAC,UAAU,CAAC,aAAa,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YAC1D,GAAG,CAAC,MAAM,EAAE,oDAAoD,CAAC,CAAC;YAElE,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,OAAO,EAAE,uCAAuC,EAAE,KAAK,CAAC,CAAC;YAC7D,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,oBAAoB,CAAC,IAAU;QAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC9B,IAAI,UAAU,CAAC,QAAQ,CAAC,wBAAwB,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YACvF,sEAAsE;YACtE,gEAAgE;YAChE,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC;YAC3C,GAAG,CAAC,MAAM,EAAE,kEAAkE,CAAC,CAAC;YAChF,MAAM,IAAI,CAAC,IAAI,CACb,GAAG,OAAO,iFAAiF,EAC3F,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,EAAE,KAAK,EAAE,CAC7C,CAAC;QACJ,CAAC;QACD,wEAAwE;IAC1E,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAC,IAAU;QACvC,IAAI,CAAC;YACH,GAAG,CAAC,OAAO,EAAE,wBAAwB,CAAC,CAAC;YAEvC,mFAAmF;YACnF,iFAAiF;YACjF,MAAM,gBAAgB,GAAG,qDAAqD,CAAC;YAC/E,MAAM,IAAI,CAAC,eAAe,CAAC,gBAAgB,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YAEjE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;gBAC1B,MAAM,IAAI,gBAAgB,CACxB,oCAAoC,EACpC,aAAa,CACd,CAAC;YACJ,CAAC;YAED,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;gBAC1B,MAAM,IAAI,gBAAgB,CACxB,oCAAoC,EACpC,aAAa,CACd,CAAC;YACJ,CAAC;YAED,GAAG,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;YACpC,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;YACrE,IAAI,aAAa,EAAE,CAAC;gBAClB,MAAM,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACjD,CAAC;YAED,wEAAwE;YACxE,0EAA0E;YAC1E,uEAAuE;YACvE,MAAM,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;YAEnC,MAAM,gBAAgB,GAAG,wCAAwC,CAAC;YAClE,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;YACrE,IAAI,aAAa,EAAE,CAAC;gBAClB,MAAM,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YACjD,CAAC;YAED,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC;YACxE,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,YAAY,CAAC,KAAK,EAAE,CAAC;YAC7B,CAAC;iBAAM,CAAC;gBACN,iDAAiD;gBACjD,MAAM,aAAa,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;YACtC,CAAC;YAED,MAAM,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC;QAC7C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,MAAM,EAAE,oEAAoE,EAAE,KAAK,CAAC,CAAC;YACzF,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACK,KAAK,CAAC,WAAW,CACvB,IAAU,EACV,QAAgB;QAEhB,KAAK,MAAM,MAAM,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC7C,IAAI,MAAM,MAAM,CAAC,SAAS,EAAE;gBAAE,OAAO,MAAM,CAAC;QAC9C,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;;;;OAQG;IACK,KAAK,CAAC,iBAAiB,CAAC,IAAU;QACxC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC;QAClE,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;YAAE,OAAO;QAElE,GAAG,CAAC,MAAM,EAAE,sDAAsD,CAAC,CAAC;QACpE,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QAErB,oEAAoE;QACpE,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,EAAE,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;YAC/B,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC;YACnE,IAAI,OAAO,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC;gBAAE,OAAO;QAChF,CAAC;QACD,GAAG,CAAC,MAAM,EAAE,+DAA+D,CAAC,CAAC;IAC/E,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,IAAU;QAChC,0EAA0E;QAC1E,yDAAyD;QACzD,MAAM,OAAO,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QAChC,IAAI,OAAO,GAAe,GAAG,EAAE,GAAE,CAAC,CAAC;QACnC,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YAC7C,OAAO,GAAG,OAAO,CAAC;QACpB,CAAC,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;QAE/D,IAAI,CAAC;YACH,GAAG,CAAC,MAAM,EAAE,sDAAsD,CAAC,CAAC;YACpE,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;YAClC,GAAG,CAAC,MAAM,EAAE,oGAAoG,CAAC,CAAC;YAElH,+DAA+D;YAC/D,oEAAoE;YACpE,qEAAqE;YACrE,qEAAqE;YACrE,MAAM,IAAI,CAAC,UAAU,CACnB,CAAC,GAAG,EAAE,EAAE;gBACN,MAAM,IAAI,GAAG,GAAG,CAAC,QAAQ,EAAE,CAAC;gBAC5B,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;oBACtB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;oBACrB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;oBACtB,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;YACvC,CAAC,EACD,EAAE,OAAO,EAAE,cAAc,EAAE,CAC5B,CAAC;YACF,GAAG,CAAC,MAAM,EAAE,kCAAkC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,gBAAgB,CACxB,wCAAwC,EACxC,cAAc,EACd,KAAc,CACf,CAAC;QACJ,CAAC;gBAAS,CAAC;YACT,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,MAAM,OAAO,CAAC;QAChB,CAAC;IACH,CAAC;IAED;;;;;;OAMG;IACK,KAAK,CAAC,gBAAgB,CAC5B,IAAU,EACV,OAA0B,EAC1B,QAAuB;QAEvB,IAAI,IAAI,GAAkB,IAAI,CAAC;QAC/B,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YACrB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YAChD,IAAI,MAAM,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBAC9B,IAAI,GAAG,MAAM,CAAC;gBACd,GAAG,CAAC,MAAM,EAAE,iBAAiB,MAAM,wCAAwC,CAAC,CAAC;YAC/E,CAAC;YACD,uEAAuE;YACvE,MAAM,OAAO,CAAC,IAAI,CAAC;gBACjB,IAAI,CAAC,cAAc,CAAC,oBAAoB,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC;gBACzD,QAAQ;aACT,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,mEAAmE;IAC3D,KAAK,CAAC,eAAe,CAAC,IAAU;QACtC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC,KAAK,EAAE,CAAC;QACzD,0EAA0E;QAC1E,wEAAwE;QACxE,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC;YAAE,OAAO,IAAI,CAAC;QAC9D,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACxD,OAAO,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC;IAC9B,CAAC;IAEO,KAAK,CAAC,kBAAkB,CAAC,IAAU;QACzC,IAAI,CAAC;YACH,GAAG,CAAC,OAAO,EAAE,uCAAuC,CAAC,CAAC;YACtD,MAAM,kBAAkB,GAAG,MAAM,IAAI,CAAC,eAAe,CACnD,SAAS,CAAC,eAAe,EACzB,EAAE,OAAO,EAAE,KAAK,EAAE,CACnB,CAAC;YACF,IAAI,kBAAkB,EAAE,CAAC;gBACvB,GAAG,CAAC,MAAM,EAAE,4CAA4C,CAAC,CAAC;gBAC1D,MAAM,kBAAkB,CAAC,KAAK,EAAE,CAAC;gBACjC,MAAM,IAAI,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,yCAAyC;YACzC,GAAG,CAAC,OAAO,EAAE,oDAAoD,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;CACF"}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Purdue Brightspace MCP Server
3
3
  * Copyright (c) 2026 Rohan Muppa. All rights reserved.
4
- * Licensed under AGPL-3.0 — see LICENSE file for details.
4
+ * Licensed under MIT — see LICENSE file for details.
5
5
  */
6
6
  import type { TokenData } from "../types/index.js";
7
7
  /**
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Purdue Brightspace MCP Server
3
3
  * Copyright (c) 2026 Rohan Muppa. All rights reserved.
4
- * Licensed under AGPL-3.0 — see LICENSE file for details.
4
+ * Licensed under MIT — see LICENSE file for details.
5
5
  */
6
6
  import * as crypto from "node:crypto";
7
7
  import * as fs from "node:fs/promises";
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Brightspace MCP Server
3
+ * Copyright (c) 2026 Rohan Muppa. All rights reserved.
4
+ * Licensed under MIT — see LICENSE file for details.
5
+ */
6
+ import type { Page } from "playwright";
7
+ import type { AppConfig } from "../types/index.js";
8
+ /** The browser login sequence for one institution's identity provider. */
9
+ export interface SSOFlow {
10
+ /** True when saved credentials allow an automated sign-in attempt. */
11
+ hasCredentials(): boolean;
12
+ /** Drive the sign-in form. Resolves false on timeout so the caller can fall back. */
13
+ login(page: Page): Promise<boolean>;
14
+ /** Wait for the user to sign in themselves in a visible browser. */
15
+ manualLogin(page: Page): Promise<boolean>;
16
+ }
17
+ /**
18
+ * Pick the login sequence for the configured Brightspace host. Schools whose
19
+ * identity provider needs extra steps get their own handler here; everything
20
+ * else uses the default flow, which already covers the common Shibboleth,
21
+ * CAS, and Microsoft Entra forms.
22
+ */
23
+ export declare function createSSOFlow(config: AppConfig): SSOFlow;
24
+ //# sourceMappingURL=sso-flow.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sso-flow.d.ts","sourceRoot":"","sources":["../../src/auth/sso-flow.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAInD,0EAA0E;AAC1E,MAAM,WAAW,OAAO;IACtB,sEAAsE;IACtE,cAAc,IAAI,OAAO,CAAC;IAC1B,qFAAqF;IACrF,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC,oEAAoE;IACpE,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3C;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAQxD"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Brightspace MCP Server
3
+ * Copyright (c) 2026 Rohan Muppa. All rights reserved.
4
+ * Licensed under MIT — see LICENSE file for details.
5
+ */
6
+ import { PurdueSSOFlow } from "./purdue-sso.js";
7
+ import { SunySSOFlow, isSunyBrightspace } from "./suny-sso.js";
8
+ /**
9
+ * Pick the login sequence for the configured Brightspace host. Schools whose
10
+ * identity provider needs extra steps get their own handler here; everything
11
+ * else uses the default flow, which already covers the common Shibboleth,
12
+ * CAS, and Microsoft Entra forms.
13
+ */
14
+ export function createSSOFlow(config) {
15
+ const credentials = { username: config.username, password: config.password };
16
+ if (isSunyBrightspace(config.baseUrl)) {
17
+ return new SunySSOFlow({ ...credentials, campus: config.campus });
18
+ }
19
+ return new PurdueSSOFlow(credentials);
20
+ }
21
+ //# sourceMappingURL=sso-flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sso-flow.js","sourceRoot":"","sources":["../../src/auth/sso-flow.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAY/D;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,MAAiB;IAC7C,MAAM,WAAW,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC;IAE7E,IAAI,iBAAiB,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;QACtC,OAAO,IAAI,WAAW,CAAC,EAAE,GAAG,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;IACpE,CAAC;IAED,OAAO,IAAI,aAAa,CAAC,WAAW,CAAC,CAAC;AACxC,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Brightspace MCP Server
3
+ * Copyright (c) 2026 Rohan Muppa. All rights reserved.
4
+ * Licensed under MIT — see LICENSE file for details.
5
+ */
6
+ import type { Page } from "playwright";
7
+ interface SunySSOConfig {
8
+ username?: string;
9
+ password?: string;
10
+ /** Campus name or numeric code, matched against SUNY's own dropdown. */
11
+ campus?: string;
12
+ }
13
+ /** True for the shared SUNY Brightspace instance. */
14
+ export declare function isSunyBrightspace(baseUrl: string): boolean;
15
+ /**
16
+ * Login flow for the shared SUNY Brightspace instance.
17
+ *
18
+ * SUNY puts two extra pages in front of the campus identity provider: the
19
+ * Brightspace campus selector, whose buttons sit in a shadow DOM, and SUNY's
20
+ * own campus dropdown at idm.suny.edu. This handler clears both, then hands
21
+ * off to the default flow, which already knows the Shibboleth, CAS, and
22
+ * Microsoft Entra sign-in forms the individual campuses use.
23
+ */
24
+ export declare class SunySSOFlow {
25
+ private config;
26
+ private defaultFlow;
27
+ constructor(config: SunySSOConfig);
28
+ hasCredentials(): boolean;
29
+ login(page: Page): Promise<boolean>;
30
+ manualLogin(page: Page): Promise<boolean>;
31
+ /**
32
+ * Brightspace's own campus selector renders its buttons in a shadow DOM, so
33
+ * go straight to the SAML endpoint that selector would have reached.
34
+ */
35
+ private startSamlLogin;
36
+ /**
37
+ * Answer SUNY's "Select Campus" dropdown. Without a configured campus the
38
+ * page is left for the user, who is already at the browser for MFA.
39
+ */
40
+ private selectCampus;
41
+ /**
42
+ * Resolve the configured campus against SUNY's live option list, so no copy
43
+ * of the campus table has to be kept in this repo. Matches a numeric code or
44
+ * a campus name, exactly first and then as a prefix.
45
+ */
46
+ private findCampus;
47
+ }
48
+ export {};
49
+ //# sourceMappingURL=suny-sso.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suny-sso.d.ts","sourceRoot":"","sources":["../../src/auth/suny-sso.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAcvC,UAAU,aAAa;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAOD,qDAAqD;AACrD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAM1D;AAcD;;;;;;;;GAQG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,WAAW,CAAgB;gBAEvB,MAAM,EAAE,aAAa;IAQjC,cAAc,IAAI,OAAO;IAInB,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;IAWnC,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC;IAY/C;;;OAGG;YACW,cAAc;IAY5B;;;OAGG;YACW,YAAY;IAwC1B;;;;OAIG;IACH,OAAO,CAAC,UAAU;CAUnB"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Brightspace MCP Server
3
+ * Copyright (c) 2026 Rohan Muppa. All rights reserved.
4
+ * Licensed under MIT — see LICENSE file for details.
5
+ */
6
+ import { PurdueSSOFlow } from "./purdue-sso.js";
7
+ import { log } from "../utils/logger.js";
8
+ /** SUNY campuses share one Brightspace tenant behind one Shibboleth IdP. */
9
+ const SUNY_BRIGHTSPACE_HOST = "mylearning.suny.edu";
10
+ const SUNY_IDP_ENTITY_ID = "https://idm.suny.edu/shibboleth/idp/";
11
+ const SUNY_IDM_HOST = "idm.suny.edu";
12
+ const SELECTORS = {
13
+ campusSelect: "select#campus",
14
+ campusSubmit: '#selectionForm button[type="submit"]',
15
+ };
16
+ /** True for the shared SUNY Brightspace instance. */
17
+ export function isSunyBrightspace(baseUrl) {
18
+ try {
19
+ return new URL(baseUrl).hostname.toLowerCase() === SUNY_BRIGHTSPACE_HOST;
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ }
25
+ /**
26
+ * SUNY carries its own hostname inside the redirect parameters it round-trips,
27
+ * so compare the host rather than searching the whole URL.
28
+ */
29
+ function isSunyIdp(url) {
30
+ try {
31
+ return new URL(url).hostname.toLowerCase() === SUNY_IDM_HOST;
32
+ }
33
+ catch {
34
+ return false;
35
+ }
36
+ }
37
+ /**
38
+ * Login flow for the shared SUNY Brightspace instance.
39
+ *
40
+ * SUNY puts two extra pages in front of the campus identity provider: the
41
+ * Brightspace campus selector, whose buttons sit in a shadow DOM, and SUNY's
42
+ * own campus dropdown at idm.suny.edu. This handler clears both, then hands
43
+ * off to the default flow, which already knows the Shibboleth, CAS, and
44
+ * Microsoft Entra sign-in forms the individual campuses use.
45
+ */
46
+ export class SunySSOFlow {
47
+ config;
48
+ defaultFlow;
49
+ constructor(config) {
50
+ this.config = config;
51
+ this.defaultFlow = new PurdueSSOFlow({
52
+ username: config.username,
53
+ password: config.password,
54
+ });
55
+ }
56
+ hasCredentials() {
57
+ return this.defaultFlow.hasCredentials();
58
+ }
59
+ async login(page) {
60
+ try {
61
+ await this.startSamlLogin(page);
62
+ await this.selectCampus(page);
63
+ }
64
+ catch (error) {
65
+ log("ERROR", "SUNY campus selection failed", error);
66
+ return false;
67
+ }
68
+ return this.defaultFlow.login(page);
69
+ }
70
+ async manualLogin(page) {
71
+ try {
72
+ // Clear the shadow-DOM selector and, when configured, the campus
73
+ // dropdown, so the user lands directly on their campus sign-in page.
74
+ await this.startSamlLogin(page);
75
+ await this.selectCampus(page);
76
+ }
77
+ catch (error) {
78
+ log("DEBUG", "Could not pre-fill SUNY campus selection", error);
79
+ }
80
+ return this.defaultFlow.manualLogin(page);
81
+ }
82
+ /**
83
+ * Brightspace's own campus selector renders its buttons in a shadow DOM, so
84
+ * go straight to the SAML endpoint that selector would have reached.
85
+ */
86
+ async startSamlLogin(page) {
87
+ const currentUrl = page.url();
88
+ if (!currentUrl.includes("/d2l/login"))
89
+ return;
90
+ const origin = new URL(currentUrl).origin;
91
+ log("INFO", "Campus selector detected — navigating directly to SUNY's SAML endpoint");
92
+ await page.goto(`${origin}/d2l/lp/auth/saml/initiate-login?entityId=${SUNY_IDP_ENTITY_ID}`, { waitUntil: "domcontentloaded", timeout: 30000 });
93
+ }
94
+ /**
95
+ * Answer SUNY's "Select Campus" dropdown. Without a configured campus the
96
+ * page is left for the user, who is already at the browser for MFA.
97
+ */
98
+ async selectCampus(page) {
99
+ if (!isSunyIdp(page.url()))
100
+ return;
101
+ try {
102
+ // idm.suny.edu sits behind a bot check, so the form can take a few
103
+ // seconds to appear even on a fast connection.
104
+ await page.waitForSelector(SELECTORS.campusSelect, { timeout: 45000 });
105
+ }
106
+ catch {
107
+ log("DEBUG", "No SUNY campus dropdown found — continuing to the sign-in form");
108
+ return;
109
+ }
110
+ const options = await page.$$eval(`${SELECTORS.campusSelect} option`, (nodes) => nodes
111
+ .map((node) => ({
112
+ value: node.value,
113
+ label: (node.textContent ?? "").trim(),
114
+ }))
115
+ .filter((option) => option.value !== ""));
116
+ if (!this.config.campus) {
117
+ log("WARN", "No campus configured — choose your campus in the browser window.");
118
+ log("INFO", "Set one with: brightspace-mcp-server setup --suny");
119
+ return;
120
+ }
121
+ const match = this.findCampus(options);
122
+ if (!match) {
123
+ log("WARN", `Campus "${this.config.campus}" did not match any SUNY campus.`);
124
+ log("INFO", `Available: ${options.map((o) => o.label).join(", ")}`);
125
+ log("WARN", "Choose your campus in the browser window to continue.");
126
+ return;
127
+ }
128
+ log("INFO", `Selecting campus ${match.label} (${match.value})`);
129
+ await page.selectOption(SELECTORS.campusSelect, match.value);
130
+ await page.click(SELECTORS.campusSubmit);
131
+ }
132
+ /**
133
+ * Resolve the configured campus against SUNY's live option list, so no copy
134
+ * of the campus table has to be kept in this repo. Matches a numeric code or
135
+ * a campus name, exactly first and then as a prefix.
136
+ */
137
+ findCampus(options) {
138
+ const wanted = this.config.campus?.trim().toLowerCase();
139
+ if (!wanted)
140
+ return undefined;
141
+ return (options.find((option) => option.value.toLowerCase() === wanted) ??
142
+ options.find((option) => option.label.toLowerCase() === wanted) ??
143
+ options.find((option) => option.label.toLowerCase().startsWith(wanted)));
144
+ }
145
+ }
146
+ //# sourceMappingURL=suny-sso.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suny-sso.js","sourceRoot":"","sources":["../../src/auth/suny-sso.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAEzC,4EAA4E;AAC5E,MAAM,qBAAqB,GAAG,qBAAqB,CAAC;AACpD,MAAM,kBAAkB,GAAG,sCAAsC,CAAC;AAClE,MAAM,aAAa,GAAG,cAAc,CAAC;AAErC,MAAM,SAAS,GAAG;IAChB,YAAY,EAAE,eAAe;IAC7B,YAAY,EAAE,sCAAsC;CAC5C,CAAC;AAcX,qDAAqD;AACrD,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,qBAAqB,CAAC;IAC3E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,SAAS,SAAS,CAAC,GAAW;IAC5B,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,aAAa,CAAC;IAC/D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,WAAW;IACd,MAAM,CAAgB;IACtB,WAAW,CAAgB;IAEnC,YAAY,MAAqB;QAC/B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,WAAW,GAAG,IAAI,aAAa,CAAC;YACnC,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,QAAQ,EAAE,MAAM,CAAC,QAAQ;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,cAAc;QACZ,OAAO,IAAI,CAAC,WAAW,CAAC,cAAc,EAAE,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,IAAU;QACpB,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;YAChC,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,OAAO,EAAE,8BAA8B,EAAE,KAAK,CAAC,CAAC;YACpD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,IAAU;QAC1B,IAAI,CAAC;YACH,iEAAiE;YACjE,qEAAqE;YACrE,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;YAChC,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,GAAG,CAAC,OAAO,EAAE,0CAA0C,EAAE,KAAK,CAAC,CAAC;QAClE,CAAC;QACD,OAAO,IAAI,CAAC,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAC5C,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,cAAc,CAAC,IAAU;QACrC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC9B,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,YAAY,CAAC;YAAE,OAAO;QAE/C,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC;QAC1C,GAAG,CAAC,MAAM,EAAE,wEAAwE,CAAC,CAAC;QACtF,MAAM,IAAI,CAAC,IAAI,CACb,GAAG,MAAM,6CAA6C,kBAAkB,EAAE,EAC1E,EAAE,SAAS,EAAE,kBAAkB,EAAE,OAAO,EAAE,KAAK,EAAE,CAClD,CAAC;IACJ,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,YAAY,CAAC,IAAU;QACnC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YAAE,OAAO;QAEnC,IAAI,CAAC;YACH,mEAAmE;YACnE,+CAA+C;YAC/C,MAAM,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,YAAY,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QACzE,CAAC;QAAC,MAAM,CAAC;YACP,GAAG,CAAC,OAAO,EAAE,gEAAgE,CAAC,CAAC;YAC/E,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC,YAAY,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAC9E,KAAK;aACF,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACd,KAAK,EAAG,IAA0B,CAAC,KAAK;YACxC,KAAK,EAAE,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;SACvC,CAAC,CAAC;aACF,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,KAAK,EAAE,CAAC,CAC3C,CAAC;QAEF,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;YACxB,GAAG,CAAC,MAAM,EAAE,kEAAkE,CAAC,CAAC;YAChF,GAAG,CAAC,MAAM,EAAE,mDAAmD,CAAC,CAAC;YACjE,OAAO;QACT,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,GAAG,CAAC,MAAM,EAAE,WAAW,IAAI,CAAC,MAAM,CAAC,MAAM,kCAAkC,CAAC,CAAC;YAC7E,GAAG,CAAC,MAAM,EAAE,cAAc,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACpE,GAAG,CAAC,MAAM,EAAE,uDAAuD,CAAC,CAAC;YACrE,OAAO;QACT,CAAC;QAED,GAAG,CAAC,MAAM,EAAE,oBAAoB,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;QAChE,MAAM,IAAI,CAAC,YAAY,CAAC,SAAS,CAAC,YAAY,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QAC7D,MAAM,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IAC3C,CAAC;IAED;;;;OAIG;IACK,UAAU,CAAC,OAAuB;QACxC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACxD,IAAI,CAAC,MAAM;YAAE,OAAO,SAAS,CAAC;QAE9B,OAAO,CACL,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC;YAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC;YAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CACxE,CAAC;IACJ,CAAC;CACF"}
@@ -1,9 +1,19 @@
1
1
  /**
2
2
  * Purdue Brightspace MCP Server
3
- * Copyright (c) 2025 Rohan Muppa. All rights reserved.
4
- * Licensed under AGPL-3.0 — see LICENSE file for details.
3
+ * Copyright (c) 2026 Rohan Muppa. All rights reserved.
4
+ * Licensed under MIT — see LICENSE file for details.
5
5
  */
6
6
  import type { TokenData } from "../types/index.js";
7
+ import { mintAccessToken } from "./token-mint.js";
8
+ export interface TokenManagerOptions {
9
+ sessionDir?: string;
10
+ /** Tenant base URL. Without it the cookie mint is not attempted. */
11
+ baseUrl?: string;
12
+ /** Lifetime in seconds stamped on a minted token. */
13
+ tokenTtl?: number;
14
+ /** Injection seam for tests. */
15
+ mint?: typeof mintAccessToken;
16
+ }
7
17
  /**
8
18
  * TokenManager manages token lifecycle with in-memory caching and disk persistence.
9
19
  * Handles expiry detection with a configurable refresh buffer.
@@ -11,13 +21,30 @@ import type { TokenData } from "../types/index.js";
11
21
  export declare class TokenManager {
12
22
  private cachedToken;
13
23
  private readonly sessionStore;
24
+ private readonly baseUrl?;
25
+ private readonly tokenTtl;
26
+ private readonly mint;
27
+ /** Single in-flight mint, so concurrent callers share one request. */
28
+ private mintInFlight;
14
29
  constructor(sessionDir?: string);
30
+ constructor(options: TokenManagerOptions);
15
31
  /**
16
32
  * Get the current token if valid, otherwise null.
17
33
  * Checks memory cache first, then loads from disk if needed.
18
34
  * Returns null if token is expired or within refresh buffer.
19
35
  */
20
36
  getToken(): Promise<TokenData | null>;
37
+ /**
38
+ * First candidate that carries both the cookie header and the XSRF token,
39
+ * or null when neither can be used to mint.
40
+ */
41
+ private pickMintable;
42
+ /**
43
+ * Mint a fresh token from the stale one's session material, collapsing
44
+ * concurrent callers onto a single request.
45
+ */
46
+ private mintFromSession;
47
+ private runMint;
21
48
  /**
22
49
  * Set a new token, caching in memory and persisting to disk.
23
50
  */
@@ -1 +1 @@
1
- {"version":3,"file":"token-manager.d.ts","sourceRoot":"","sources":["../../src/auth/token-manager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAUnD;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;gBAEhC,UAAU,CAAC,EAAE,MAAM;IAI/B;;;;OAIG;IACG,QAAQ,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAmB3C;;OAEG;IACG,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAM/C;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC;;;OAGG;IACH,OAAO,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO;IAiBlC;;;OAGG;IACG,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;CAIvC"}
1
+ {"version":3,"file":"token-manager.d.ts","sourceRoot":"","sources":["../../src/auth/token-manager.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAYlD,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gCAAgC;IAChC,IAAI,CAAC,EAAE,OAAO,eAAe,CAAC;CAC/B;AAED;;;GAGG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAe;IAC5C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAyB;IAC9C,sEAAsE;IACtE,OAAO,CAAC,YAAY,CAA0C;gBAElD,UAAU,CAAC,EAAE,MAAM;gBACnB,OAAO,EAAE,mBAAmB;IAaxC;;;;OAIG;IACG,QAAQ,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IA2B3C;;;OAGG;IACH,OAAO,CAAC,YAAY;IAUpB;;;OAGG;YACW,eAAe;YAaf,OAAO;IAkCrB;;OAEG;IACG,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAM/C;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAMjC;;;OAGG;IACH,OAAO,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO;IAiBlC;;;OAGG;IACG,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;CAIvC"}