148 lines
4.3 KiB
JavaScript
148 lines
4.3 KiB
JavaScript
// Unit tests for expired-session recovery (src/session-expiry.js), run with
|
|
// `node --test` (no extra deps). Covers the pure redirect matcher and the
|
|
// onBeforeRedirect wiring against a fake webRequest.
|
|
//
|
|
// The real signal (from a live expired Databricks SSO session): every API
|
|
// call gets a 303 redirect to the gate's `login.html`. The shell reloads the
|
|
// window on that so the gate can re-challenge, since a desktop user has no
|
|
// address bar to refresh manually.
|
|
|
|
const { describe, it } = require("node:test");
|
|
const assert = require("node:assert/strict");
|
|
|
|
const { isLoginRedirect, registerSessionExpiryReload } = require("../src/session-expiry");
|
|
|
|
describe("isLoginRedirect", () => {
|
|
it("matches a 303 redirect to the login page", () => {
|
|
assert.equal(
|
|
isLoginRedirect({
|
|
statusCode: 303,
|
|
redirectURL: "https://dbc-x.cloud.databricks.com/login.html?next_url=%2Fajax-api%2F2.0",
|
|
}),
|
|
true,
|
|
);
|
|
});
|
|
|
|
it("matches other 3xx codes to the login page", () => {
|
|
assert.equal(
|
|
isLoginRedirect({ statusCode: 302, redirectURL: "https://ws.databricks.com/login.html" }),
|
|
true,
|
|
);
|
|
});
|
|
|
|
it("ignores a redirect that is not to the login page", () => {
|
|
// An ordinary same-origin API-to-API redirect must be left alone.
|
|
assert.equal(
|
|
isLoginRedirect({ statusCode: 303, redirectURL: "https://ws.databricks.com/ajax-api/2.0/x" }),
|
|
false,
|
|
);
|
|
});
|
|
|
|
it("ignores non-redirect status codes", () => {
|
|
assert.equal(
|
|
isLoginRedirect({ statusCode: 200, redirectURL: "https://ws.databricks.com/login.html" }),
|
|
false,
|
|
);
|
|
});
|
|
|
|
it("ignores a missing or unparseable redirect URL", () => {
|
|
assert.equal(isLoginRedirect({ statusCode: 303 }), false);
|
|
assert.equal(isLoginRedirect({ statusCode: 303, redirectURL: "not a url" }), false);
|
|
});
|
|
|
|
it("does not match a path that merely contains 'login.html' mid-path", () => {
|
|
// Only a pathname ending in /login.html counts, so an unrelated route
|
|
// like /docs/login.html.md or a query-only match won't trip it.
|
|
assert.equal(
|
|
isLoginRedirect({
|
|
statusCode: 303,
|
|
redirectURL: "https://ws.databricks.com/x?p=/login.html",
|
|
}),
|
|
false,
|
|
);
|
|
});
|
|
});
|
|
|
|
/** A fake session whose onBeforeRedirect listener can be driven by tests. */
|
|
function fakeSession() {
|
|
let listener = null;
|
|
return {
|
|
webRequest: {
|
|
onBeforeRedirect: (cb) => {
|
|
listener = cb;
|
|
},
|
|
},
|
|
emit: (details) => listener?.(details),
|
|
};
|
|
}
|
|
|
|
describe("registerSessionExpiryReload", () => {
|
|
const LOGIN_REDIRECT = {
|
|
url: "https://ws.databricks.com/ajax-api/2.0/omnigents/v1/sessions",
|
|
statusCode: 303,
|
|
redirectURL: "https://ws.databricks.com/login.html?next_url=%2Fajax-api",
|
|
};
|
|
|
|
it("reloads the connected origin on a login redirect", () => {
|
|
const ses = fakeSession();
|
|
const reloaded = [];
|
|
registerSessionExpiryReload(
|
|
ses,
|
|
(origin) => origin === "https://ws.databricks.com",
|
|
(origin) => reloaded.push(origin),
|
|
);
|
|
|
|
ses.emit(LOGIN_REDIRECT);
|
|
|
|
assert.deepEqual(reloaded, ["https://ws.databricks.com"]);
|
|
});
|
|
|
|
it("ignores a login redirect for an origin no window is connected to", () => {
|
|
const ses = fakeSession();
|
|
const reloaded = [];
|
|
registerSessionExpiryReload(
|
|
ses,
|
|
() => false, // nothing is a connected server
|
|
(origin) => reloaded.push(origin),
|
|
);
|
|
|
|
ses.emit(LOGIN_REDIRECT);
|
|
|
|
assert.deepEqual(reloaded, []);
|
|
});
|
|
|
|
it("ignores a non-login redirect", () => {
|
|
const ses = fakeSession();
|
|
const reloaded = [];
|
|
registerSessionExpiryReload(
|
|
ses,
|
|
() => true,
|
|
(origin) => reloaded.push(origin),
|
|
);
|
|
|
|
ses.emit({
|
|
url: "https://ws.databricks.com/ajax-api/2.0/x",
|
|
statusCode: 303,
|
|
redirectURL: "https://ws.databricks.com/ajax-api/2.0/y",
|
|
});
|
|
|
|
assert.deepEqual(reloaded, []);
|
|
});
|
|
|
|
it("ignores a login redirect whose originating URL is unparseable", () => {
|
|
// A malformed request URL must not throw out of the listener; it's
|
|
// simply skipped (no origin to attribute the reload to).
|
|
const ses = fakeSession();
|
|
const reloaded = [];
|
|
registerSessionExpiryReload(
|
|
ses,
|
|
() => true,
|
|
(origin) => reloaded.push(origin),
|
|
);
|
|
|
|
ses.emit({ ...LOGIN_REDIRECT, url: "not a url" });
|
|
|
|
assert.deepEqual(reloaded, []);
|
|
});
|
|
});
|