Some checks are pending
E2E / Playwright e2e (push) Waiting to run
- Updated login and signup components to utilize AuthCard for better user experience during redirection. - Introduced AuthentikEmbedDialog for seamless integration of Authentik's identity portal within the application. - Enhanced password recovery and signup flows with dynamic theme handling and improved loading states. - Refactored existing components to streamline authentication processes and improve maintainability.
81 lines
2.7 KiB
JavaScript
81 lines
2.7 KiB
JavaScript
// Headless dump of Authentik flow shadow DOM + screenshot.
|
|
// Usage: node scripts/authentik-dom-dump.mjs <url> <outName> [theme]
|
|
import { chromium } from "@playwright/test"
|
|
import { writeFileSync } from "node:fs"
|
|
|
|
const url = process.argv[2] ?? "http://localhost/auth/if/flow/default-authentication-flow/"
|
|
const outName = process.argv[3] ?? "login"
|
|
const theme = process.argv[4] ?? "light" // light | dark
|
|
|
|
const outDir = "/tmp/authentik-dom"
|
|
await import("node:fs").then((fs) => fs.mkdirSync(outDir, { recursive: true }))
|
|
|
|
const browser = await chromium.launch()
|
|
const ctx = await browser.newContext({
|
|
viewport: { width: 1280, height: 900 },
|
|
colorScheme: theme === "dark" ? "dark" : "light",
|
|
ignoreHTTPSErrors: true,
|
|
})
|
|
const page = await ctx.newPage()
|
|
|
|
// Authentik advertises api.base as https://localhost (X-Forwarded-Proto), but nginx is http-only
|
|
// here. Rewrite api.base to a same-origin relative URL before the flow bundle reads it.
|
|
await page.addInitScript(() => {
|
|
Object.defineProperty(window, "authentik", {
|
|
configurable: true,
|
|
set(v) {
|
|
try {
|
|
if (v && v.api) {
|
|
v.api.base = location.origin + "/auth/"
|
|
v.api.relBase = "/auth/"
|
|
}
|
|
} catch {}
|
|
Object.defineProperty(window, "authentik", {
|
|
value: v,
|
|
writable: true,
|
|
configurable: true,
|
|
})
|
|
},
|
|
get() {
|
|
return undefined
|
|
},
|
|
})
|
|
})
|
|
|
|
await page.goto(url, { waitUntil: "networkidle", timeout: 30000 })
|
|
// Give Lit components time to render the stage.
|
|
await page.waitForTimeout(2500)
|
|
|
|
// Recursively serialize light + shadow DOM into an indented outline.
|
|
const outline = await page.evaluate(() => {
|
|
function attrs(el) {
|
|
return [...el.attributes]
|
|
.filter((a) => !["style"].includes(a.name))
|
|
.map((a) => (a.value ? `${a.name}="${a.value}"` : a.name))
|
|
.join(" ")
|
|
}
|
|
function walk(node, depth, lines) {
|
|
const pad = " ".repeat(depth)
|
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
const tag = node.tagName.toLowerCase()
|
|
const a = attrs(node)
|
|
lines.push(`${pad}<${tag}${a ? " " + a : ""}>`)
|
|
if (node.shadowRoot) {
|
|
lines.push(`${pad} #shadow-root`)
|
|
for (const c of node.shadowRoot.children) walk(c, depth + 2, lines)
|
|
}
|
|
for (const c of node.children) walk(c, depth + 1, lines)
|
|
}
|
|
return lines
|
|
}
|
|
const lines = []
|
|
walk(document.documentElement, 0, lines)
|
|
// Cap to keep output readable.
|
|
return lines.slice(0, 1200).join("\n")
|
|
})
|
|
|
|
writeFileSync(`${outDir}/${outName}-${theme}.dom.txt`, outline)
|
|
await page.screenshot({ path: `${outDir}/${outName}-${theme}.png`, fullPage: true })
|
|
console.log(`wrote ${outDir}/${outName}-${theme}.dom.txt (+ .png)`)
|
|
await browser.close()
|