sitevision-cli 1.0.0-beta.6 → 1.0.0-beta.7
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.
|
@@ -1,15 +1,33 @@
|
|
|
1
1
|
import { getSessionCookie, setSessionCookie } from './keychain.js';
|
|
2
2
|
import { promptEnter } from './password-prompt.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
function bareDomain(domain) {
|
|
4
|
+
return domain.replace(/^\./, '');
|
|
5
|
+
}
|
|
6
|
+
/** Related if either host is the other or a subdomain of it (both directions). */
|
|
7
|
+
function domainRelated(a, b) {
|
|
8
|
+
const x = bareDomain(a);
|
|
9
|
+
const y = bareDomain(b);
|
|
10
|
+
return x === y || x.endsWith(`.${y}`) || y.endsWith(`.${x}`);
|
|
11
|
+
}
|
|
12
|
+
/** Read every cookie in the browser jar (httponly and secure included). */
|
|
13
|
+
async function readAllCookies(browser, page) {
|
|
14
|
+
// puppeteer >= 22 exposes the whole jar directly.
|
|
15
|
+
if (typeof browser.cookies === 'function') {
|
|
16
|
+
try {
|
|
17
|
+
return (await browser.cookies());
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// Fall through to CDP.
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const client = await page.createCDPSession();
|
|
24
|
+
const { cookies } = await client.send('Network.getAllCookies');
|
|
25
|
+
return cookies;
|
|
7
26
|
}
|
|
8
27
|
/**
|
|
9
28
|
* Open a real browser at the login URL, let the user complete SSO, then read
|
|
10
|
-
* the session cookies
|
|
11
|
-
*
|
|
12
|
-
* value, or null if capture failed.
|
|
29
|
+
* the session cookies via CDP — which returns httponly, secure cookies that
|
|
30
|
+
* page JavaScript can't see. Returns a `Cookie:` header value, or null.
|
|
13
31
|
*/
|
|
14
32
|
async function captureViaBrowser(loginUrl, siteDomain) {
|
|
15
33
|
let puppeteer;
|
|
@@ -27,15 +45,21 @@ async function captureViaBrowser(loginUrl, siteDomain) {
|
|
|
27
45
|
await page.goto(loginUrl, { waitUntil: 'domcontentloaded' }).catch(() => {
|
|
28
46
|
// A SAML redirect may abort the initial navigation — that's fine.
|
|
29
47
|
});
|
|
30
|
-
await promptEnter('\nLog in in the opened
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
console.log(
|
|
48
|
+
await promptEnter('\nLog in in the browser this tool opened, then press Enter here to capture the session: ');
|
|
49
|
+
const all = await readAllCookies(browser, page);
|
|
50
|
+
const sessions = all.filter(c => c.name === 'JSESSIONID');
|
|
51
|
+
if (sessions.length === 0) {
|
|
52
|
+
const domains = [...new Set(all.map(c => bareDomain(c.domain)))];
|
|
53
|
+
console.log(`\x1b[31mNo JSESSIONID among ${all.length} cookies.\x1b[0m`);
|
|
54
|
+
console.log(`Cookie domains seen: ${domains.join(', ') || '(none — was the login done in the browser this tool opened?)'}`);
|
|
55
|
+
console.log('If those are only your IdP and not the Sitevision site, open a Sitevision page/editor in that same browser (so it issues a session), then run this again.');
|
|
36
56
|
return null;
|
|
37
57
|
}
|
|
38
|
-
|
|
58
|
+
// Prefer the JSESSIONID on the deploy host; else take the only/first one.
|
|
59
|
+
const chosen = sessions.find(c => domainRelated(c.domain, siteDomain)) ?? sessions[0];
|
|
60
|
+
const cookies = all.filter(c => domainRelated(c.domain, chosen.domain));
|
|
61
|
+
console.log(`\x1b[32mCaptured session on ${bareDomain(chosen.domain)} (${cookies.length} cookies).\x1b[0m`);
|
|
62
|
+
return cookies.map(c => `${c.name}=${c.value}`).join('; ');
|
|
39
63
|
}
|
|
40
64
|
catch (error) {
|
|
41
65
|
console.log(`\x1b[31mBrowser login failed: ${error instanceof Error ? error.message : String(error)}\x1b[0m`);
|