Compare commits
9 Commits
docusaurus
...
web/sdk/em
Author | SHA1 | Date | |
---|---|---|---|
a407d903ab | |||
7e6f36b0b4 | |||
8dd7b0569c | |||
616be78e10 | |||
7125db1fbd | |||
8c7c7c3fee | |||
bbbd00db22 | |||
6d60c5f7c7 | |||
accf25a626 |
@ -25,3 +25,31 @@ class BrandMiddleware:
|
|||||||
if locale != "":
|
if locale != "":
|
||||||
activate(locale)
|
activate(locale)
|
||||||
return self.get_response(request)
|
return self.get_response(request)
|
||||||
|
|
||||||
|
|
||||||
|
class BrandCORSAPIMiddleware:
|
||||||
|
"""CORS for API requests depending on Brand"""
|
||||||
|
|
||||||
|
get_response: Callable[[HttpRequest], HttpResponse]
|
||||||
|
|
||||||
|
def __init__(self, get_response: Callable[[HttpRequest], HttpResponse]):
|
||||||
|
self.get_response = get_response
|
||||||
|
|
||||||
|
def set_headers(self, request: HttpRequest, response: HttpResponse):
|
||||||
|
response["Access-Control-Allow-Origin"] = "http://localhost:8080"
|
||||||
|
response["Access-Control-Allow-Credentials"] = "true"
|
||||||
|
|
||||||
|
def __call__(self, request: HttpRequest) -> HttpResponse:
|
||||||
|
if request.method == "OPTIONS":
|
||||||
|
response = HttpResponse(
|
||||||
|
status=200,
|
||||||
|
)
|
||||||
|
self.set_headers(request, response)
|
||||||
|
response["Access-Control-Allow-Headers"] = (
|
||||||
|
"authorization,sentry-trace,x-authentik-csrf,content-type"
|
||||||
|
)
|
||||||
|
response["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS"
|
||||||
|
return response
|
||||||
|
response = self.get_response(request)
|
||||||
|
self.set_headers(request, response)
|
||||||
|
return response
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
<link rel="shortcut icon" href="{{ brand.branding_favicon }}">
|
<link rel="shortcut icon" href="{{ brand.branding_favicon }}">
|
||||||
{% block head_before %}
|
{% block head_before %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
<link rel="stylesheet" type="text/css" href="{% static 'dist/patternfly-base.css' %}">
|
||||||
<link rel="stylesheet" type="text/css" href="{% static 'dist/authentik.css' %}">
|
<link rel="stylesheet" type="text/css" href="{% static 'dist/authentik.css' %}">
|
||||||
<link rel="stylesheet" type="text/css" href="{% static 'dist/custom.css' %}" data-inject>
|
<link rel="stylesheet" type="text/css" href="{% static 'dist/custom.css' %}" data-inject>
|
||||||
{% versioned_script "dist/poly-%v.js" %}
|
{% versioned_script "dist/poly-%v.js" %}
|
||||||
|
@ -16,12 +16,14 @@ from django.views.decorators.clickjacking import xframe_options_sameorigin
|
|||||||
from django.views.generic import View
|
from django.views.generic import View
|
||||||
from drf_spectacular.types import OpenApiTypes
|
from drf_spectacular.types import OpenApiTypes
|
||||||
from drf_spectacular.utils import OpenApiParameter, PolymorphicProxySerializer, extend_schema
|
from drf_spectacular.utils import OpenApiParameter, PolymorphicProxySerializer, extend_schema
|
||||||
|
from rest_framework.exceptions import AuthenticationFailed
|
||||||
from rest_framework.permissions import AllowAny
|
from rest_framework.permissions import AllowAny
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from sentry_sdk import capture_exception, start_span
|
from sentry_sdk import capture_exception, start_span
|
||||||
from sentry_sdk.api import set_tag
|
from sentry_sdk.api import set_tag
|
||||||
from structlog.stdlib import BoundLogger, get_logger
|
from structlog.stdlib import BoundLogger, get_logger
|
||||||
|
|
||||||
|
from authentik.api.authentication import bearer_auth, get_authorization_header
|
||||||
from authentik.brands.models import Brand
|
from authentik.brands.models import Brand
|
||||||
from authentik.core.models import Application
|
from authentik.core.models import Application
|
||||||
from authentik.events.models import Event, EventAction, cleanse_dict
|
from authentik.events.models import Event, EventAction, cleanse_dict
|
||||||
@ -116,6 +118,14 @@ class FlowExecutorView(APIView):
|
|||||||
super().setup(request, flow_slug=flow_slug)
|
super().setup(request, flow_slug=flow_slug)
|
||||||
self.flow = get_object_or_404(Flow.objects.select_related(), slug=flow_slug)
|
self.flow = get_object_or_404(Flow.objects.select_related(), slug=flow_slug)
|
||||||
self._logger = get_logger().bind(flow_slug=flow_slug)
|
self._logger = get_logger().bind(flow_slug=flow_slug)
|
||||||
|
# Usually flows are authenticated by session, we don't really use rest_framework's
|
||||||
|
# authentication method.
|
||||||
|
try:
|
||||||
|
user = bearer_auth(get_authorization_header(request))
|
||||||
|
if user:
|
||||||
|
request.user = user
|
||||||
|
except AuthenticationFailed:
|
||||||
|
pass
|
||||||
set_tag("authentik.flow", self.flow.slug)
|
set_tag("authentik.flow", self.flow.slug)
|
||||||
|
|
||||||
def handle_invalid_flow(self, exc: FlowNonApplicableException) -> HttpResponse:
|
def handle_invalid_flow(self, exc: FlowNonApplicableException) -> HttpResponse:
|
||||||
|
@ -248,6 +248,7 @@ MIDDLEWARE = [
|
|||||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||||
"authentik.core.middleware.RequestIDMiddleware",
|
"authentik.core.middleware.RequestIDMiddleware",
|
||||||
"authentik.brands.middleware.BrandMiddleware",
|
"authentik.brands.middleware.BrandMiddleware",
|
||||||
|
"authentik.brands.middleware.BrandCORSAPIMiddleware",
|
||||||
"authentik.events.middleware.AuditMiddleware",
|
"authentik.events.middleware.AuditMiddleware",
|
||||||
"django.middleware.security.SecurityMiddleware",
|
"django.middleware.security.SecurityMiddleware",
|
||||||
"django.middleware.common.CommonMiddleware",
|
"django.middleware.common.CommonMiddleware",
|
||||||
|
@ -41,6 +41,7 @@ const definitions = {
|
|||||||
|
|
||||||
const otherFiles = [
|
const otherFiles = [
|
||||||
["node_modules/@patternfly/patternfly/patternfly.min.css", "."],
|
["node_modules/@patternfly/patternfly/patternfly.min.css", "."],
|
||||||
|
["node_modules/@patternfly/patternfly/patternfly-base.css", "."],
|
||||||
["node_modules/@patternfly/patternfly/assets/**", ".", "node_modules/@patternfly/patternfly/"],
|
["node_modules/@patternfly/patternfly/assets/**", ".", "node_modules/@patternfly/patternfly/"],
|
||||||
["src/custom.css", "."],
|
["src/custom.css", "."],
|
||||||
["src/common/styles/**", "."],
|
["src/common/styles/**", "."],
|
||||||
@ -79,6 +80,12 @@ const interfaces = [
|
|||||||
["polyfill/poly.ts", "."],
|
["polyfill/poly.ts", "."],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const extraTargets = [
|
||||||
|
["sdk/index.ts", "sdk", { entryNames: "[dir]/[name]" }],
|
||||||
|
["sdk/user-settings.ts", "sdk/user-settings", { entryNames: "[dir]/[name]" }],
|
||||||
|
["sdk/flow.ts", "sdk/flow", { entryNames: "[dir]/[name]" }],
|
||||||
|
];
|
||||||
|
|
||||||
const baseArgs = {
|
const baseArgs = {
|
||||||
bundle: true,
|
bundle: true,
|
||||||
write: true,
|
write: true,
|
||||||
@ -101,7 +108,11 @@ function getVersion() {
|
|||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buildOneSource(source, dest) {
|
function getAllTargets() {
|
||||||
|
return [...interfaces, ...extraTargets];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buildSingleTarget(source, dest, options) {
|
||||||
const DIST = path.join(__dirname, "./dist", dest);
|
const DIST = path.join(__dirname, "./dist", dest);
|
||||||
console.log(`[${new Date(Date.now()).toISOString()}] Starting build for target ${source}`);
|
console.log(`[${new Date(Date.now()).toISOString()}] Starting build for target ${source}`);
|
||||||
|
|
||||||
@ -112,6 +123,7 @@ async function buildOneSource(source, dest) {
|
|||||||
entryPoints: [`./src/${source}`],
|
entryPoints: [`./src/${source}`],
|
||||||
entryNames: `[dir]/[name]-${getVersion()}`,
|
entryNames: `[dir]/[name]-${getVersion()}`,
|
||||||
outdir: DIST,
|
outdir: DIST,
|
||||||
|
...options,
|
||||||
});
|
});
|
||||||
const end = Date.now();
|
const end = Date.now();
|
||||||
console.log(
|
console.log(
|
||||||
@ -124,8 +136,10 @@ async function buildOneSource(source, dest) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function buildAuthentik(interfaces) {
|
async function buildTargets(targets) {
|
||||||
await Promise.allSettled(interfaces.map(([source, dest]) => buildOneSource(source, dest)));
|
await Promise.allSettled(
|
||||||
|
targets.map(([source, dest, options]) => buildSingleTarget(source, dest, options)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let timeoutId = null;
|
let timeoutId = null;
|
||||||
@ -135,7 +149,7 @@ function debouncedBuild() {
|
|||||||
}
|
}
|
||||||
timeoutId = setTimeout(() => {
|
timeoutId = setTimeout(() => {
|
||||||
console.clear();
|
console.clear();
|
||||||
buildAuthentik(interfaces);
|
buildTargets(getAllTargets());
|
||||||
}, 250);
|
}, 250);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +157,7 @@ if (process.argv.length > 2 && (process.argv[2] === "-h" || process.argv[2] ===
|
|||||||
console.log(`Build the authentikUI
|
console.log(`Build the authentikUI
|
||||||
|
|
||||||
options:
|
options:
|
||||||
-w, --watch: Build all ${interfaces.length} interfaces
|
-w, --watch: Build all ${getAllTargets().length} interfaces
|
||||||
-p, --proxy: Build only the polyfills and the loading application
|
-p, --proxy: Build only the polyfills and the loading application
|
||||||
-h, --help: This help message
|
-h, --help: This help message
|
||||||
`);
|
`);
|
||||||
@ -163,11 +177,11 @@ if (process.argv.length > 2 && (process.argv[2] === "-w" || process.argv[2] ===
|
|||||||
});
|
});
|
||||||
} else if (process.argv.length > 2 && (process.argv[2] === "-p" || process.argv[2] === "--proxy")) {
|
} else if (process.argv.length > 2 && (process.argv[2] === "-p" || process.argv[2] === "--proxy")) {
|
||||||
// There's no watch-for-proxy, sorry.
|
// There's no watch-for-proxy, sorry.
|
||||||
await buildAuthentik(
|
await buildTargets(
|
||||||
interfaces.filter(([_, dest]) => ["standalone/loading", "."].includes(dest)),
|
interfaces.filter(([_, dest]) => ["standalone/loading", "."].includes(dest)),
|
||||||
);
|
);
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
} else {
|
} else {
|
||||||
// And the fallback: just build it.
|
// And the fallback: just build it.
|
||||||
await buildAuthentik(interfaces);
|
await buildTargets(interfaces);
|
||||||
}
|
}
|
||||||
|
3057
web/sfe/package-lock.json
generated
3057
web/sfe/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -1,28 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@goauthentik/web-sfe",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"private": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@goauthentik/api": "^2024.6.3-1724414734",
|
|
||||||
"base64-js": "^1.5.1",
|
|
||||||
"bootstrap": "^4.6.1",
|
|
||||||
"formdata-polyfill": "^4.0.10",
|
|
||||||
"jquery": "^3.7.1",
|
|
||||||
"weakmap-polyfill": "^2.0.4"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "rollup -c rollup.config.js --bundleConfigAsCjs",
|
|
||||||
"watch": "rollup -w -c rollup.config.js --bundleConfigAsCjs"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@rollup/plugin-commonjs": "^26.0.1",
|
|
||||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
||||||
"@rollup/plugin-swc": "^0.3.1",
|
|
||||||
"@swc/cli": "^0.4.0",
|
|
||||||
"@swc/core": "^1.7.23",
|
|
||||||
"@types/jquery": "^3.5.30",
|
|
||||||
"rollup": "^4.21.2",
|
|
||||||
"rollup-plugin-copy": "^3.5.0"
|
|
||||||
}
|
|
||||||
}
|
|
@ -7,6 +7,9 @@ export function renderSourceIcon(name: string, iconUrl: string | undefined | nul
|
|||||||
const url = iconUrl.replaceAll("fa://", "");
|
const url = iconUrl.replaceAll("fa://", "");
|
||||||
return html`<i class="fas ${url}" title="${name}"></i>`;
|
return html`<i class="fas ${url}" title="${name}"></i>`;
|
||||||
}
|
}
|
||||||
|
if (window.authentik_sdk?.base) {
|
||||||
|
return html`<img src="${window.authentik_sdk?.base}${iconUrl}" alt="${name}" />`;
|
||||||
|
}
|
||||||
return html`<img src="${iconUrl}" alt="${name}" />`;
|
return html`<img src="${iconUrl}" alt="${name}" />`;
|
||||||
}
|
}
|
||||||
return icon;
|
return icon;
|
||||||
|
@ -2,6 +2,7 @@ import {
|
|||||||
CSRFMiddleware,
|
CSRFMiddleware,
|
||||||
EventMiddleware,
|
EventMiddleware,
|
||||||
LoggingMiddleware,
|
LoggingMiddleware,
|
||||||
|
SDKMiddleware,
|
||||||
} from "@goauthentik/common/api/middleware";
|
} from "@goauthentik/common/api/middleware";
|
||||||
import { EVENT_LOCALE_REQUEST, VERSION } from "@goauthentik/common/constants";
|
import { EVENT_LOCALE_REQUEST, VERSION } from "@goauthentik/common/constants";
|
||||||
import { globalAK } from "@goauthentik/common/global";
|
import { globalAK } from "@goauthentik/common/global";
|
||||||
@ -67,8 +68,18 @@ export function getMetaContent(key: string): string {
|
|||||||
return metaEl.content;
|
return metaEl.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function apiBase(): string {
|
||||||
|
if (process.env.AK_API_BASE_PATH) {
|
||||||
|
return process.env.AK_API_BASE_PATH;
|
||||||
|
}
|
||||||
|
if (window.authentik_sdk?.base) {
|
||||||
|
return window.authentik_sdk?.base;
|
||||||
|
}
|
||||||
|
return window.location.origin;
|
||||||
|
}
|
||||||
|
|
||||||
export const DEFAULT_CONFIG = new Configuration({
|
export const DEFAULT_CONFIG = new Configuration({
|
||||||
basePath: (process.env.AK_API_BASE_PATH || window.location.origin) + "/api/v3",
|
basePath: `${apiBase()}/api/v3`,
|
||||||
headers: {
|
headers: {
|
||||||
"sentry-trace": getMetaContent("sentry-trace"),
|
"sentry-trace": getMetaContent("sentry-trace"),
|
||||||
},
|
},
|
||||||
@ -76,6 +87,7 @@ export const DEFAULT_CONFIG = new Configuration({
|
|||||||
new CSRFMiddleware(),
|
new CSRFMiddleware(),
|
||||||
new EventMiddleware(),
|
new EventMiddleware(),
|
||||||
new LoggingMiddleware(globalAK().brand),
|
new LoggingMiddleware(globalAK().brand),
|
||||||
|
new SDKMiddleware(),
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -44,6 +44,21 @@ export class CSRFMiddleware implements Middleware {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class SDKMiddleware implements Middleware {
|
||||||
|
token?: string;
|
||||||
|
constructor() {
|
||||||
|
this.token = window.authentik_sdk?.token;
|
||||||
|
}
|
||||||
|
pre?(context: RequestContext): Promise<FetchParams | void> {
|
||||||
|
if (this.token) {
|
||||||
|
context.init.credentials = "include";
|
||||||
|
// @ts-ignore
|
||||||
|
context.init.headers["Authorization"] = `Bearer ${this.token}`;
|
||||||
|
}
|
||||||
|
return Promise.resolve(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class EventMiddleware implements Middleware {
|
export class EventMiddleware implements Middleware {
|
||||||
post?(context: ResponseContext): Promise<Response | void> {
|
post?(context: ResponseContext): Promise<Response | void> {
|
||||||
const request: RequestInfo = {
|
const request: RequestInfo = {
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
import { Config, ConfigFromJSON, CurrentBrand, CurrentBrandFromJSON } from "@goauthentik/api";
|
import {
|
||||||
|
Config,
|
||||||
|
ConfigFromJSON,
|
||||||
|
CurrentBrand,
|
||||||
|
CurrentBrandFromJSON,
|
||||||
|
ErrorReportingConfigFromJSON,
|
||||||
|
UiThemeEnum,
|
||||||
|
} from "@goauthentik/api";
|
||||||
|
|
||||||
export interface GlobalAuthentik {
|
export interface GlobalAuthentik {
|
||||||
_converted?: boolean;
|
_converted?: boolean;
|
||||||
@ -28,9 +35,12 @@ export function globalAK(): GlobalAuthentik {
|
|||||||
return {
|
return {
|
||||||
config: ConfigFromJSON({
|
config: ConfigFromJSON({
|
||||||
capabilities: [],
|
capabilities: [],
|
||||||
|
error_reporting: ErrorReportingConfigFromJSON({}),
|
||||||
}),
|
}),
|
||||||
brand: CurrentBrandFromJSON({
|
brand: CurrentBrandFromJSON({
|
||||||
|
matched_domain: window.location.host,
|
||||||
ui_footer_links: [],
|
ui_footer_links: [],
|
||||||
|
ui_theme: window.authentik_sdk?.forceTheme ?? UiThemeEnum.Automatic,
|
||||||
}),
|
}),
|
||||||
versionFamily: "",
|
versionFamily: "",
|
||||||
versionSubdomain: "",
|
versionSubdomain: "",
|
||||||
@ -40,6 +50,10 @@ export function globalAK(): GlobalAuthentik {
|
|||||||
return ak;
|
return ak;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isEmbedded() {
|
||||||
|
return !!window.authentik_sdk;
|
||||||
|
}
|
||||||
|
|
||||||
export function docLink(path: string): string {
|
export function docLink(path: string): string {
|
||||||
const ak = globalAK();
|
const ak = globalAK();
|
||||||
// Default case or beta build which should always point to latest
|
// Default case or beta build which should always point to latest
|
||||||
|
@ -21,9 +21,12 @@ export class WebsocketClient {
|
|||||||
|
|
||||||
connect(): void {
|
connect(): void {
|
||||||
if (navigator.webdriver) return;
|
if (navigator.webdriver) return;
|
||||||
const wsUrl = `${window.location.protocol.replace("http", "ws")}//${
|
let wsUrl = `${window.location.protocol.replace("http", "ws")}//${
|
||||||
window.location.host
|
window.location.host
|
||||||
}/ws/client/`;
|
}/ws/client/`;
|
||||||
|
if (window.authentik_sdk?.base) {
|
||||||
|
wsUrl = `${window.authentik_sdk?.base.replace("http", "ws")}/ws/client/`;
|
||||||
|
}
|
||||||
this.messageSocket = new WebSocket(wsUrl);
|
this.messageSocket = new WebSocket(wsUrl);
|
||||||
this.messageSocket.addEventListener("open", () => {
|
this.messageSocket.addEventListener("open", () => {
|
||||||
console.debug(`authentik/ws: connected to ${wsUrl}`);
|
console.debug(`authentik/ws: connected to ${wsUrl}`);
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
|
import { isEmbedded } from "@goauthentik/common/global";
|
||||||
import { UIConfig, uiConfig } from "@goauthentik/common/ui/config";
|
import { UIConfig, uiConfig } from "@goauthentik/common/ui/config";
|
||||||
import { ModalOrchestrationController } from "@goauthentik/elements/controllers/ModalOrchestrationController.js";
|
import { ModalOrchestrationController } from "@goauthentik/elements/controllers/ModalOrchestrationController.js";
|
||||||
import { ensureCSSStyleSheet } from "@goauthentik/elements/utils/ensureCSSStyleSheet";
|
import { ensureCSSStyleSheet } from "@goauthentik/elements/utils/ensureCSSStyleSheet";
|
||||||
|
|
||||||
import { state } from "lit/decorators.js";
|
import { state } from "lit/decorators.js";
|
||||||
|
|
||||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
import PFVariables from "@patternfly/patternfly/base/patternfly-variables.css";
|
||||||
|
|
||||||
import type { Config, CurrentBrand, LicenseSummary } from "@goauthentik/api";
|
import type { Config, CurrentBrand, LicenseSummary } from "@goauthentik/api";
|
||||||
import { UiThemeEnum } from "@goauthentik/api";
|
import { UiThemeEnum } from "@goauthentik/api";
|
||||||
@ -43,7 +44,10 @@ export class Interface extends AKElement implements AkInterface {
|
|||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
document.adoptedStyleSheets = [...document.adoptedStyleSheets, ensureCSSStyleSheet(PFBase)];
|
document.adoptedStyleSheets = [
|
||||||
|
...document.adoptedStyleSheets,
|
||||||
|
ensureCSSStyleSheet(PFVariables),
|
||||||
|
];
|
||||||
this[brandContext] = new BrandContextController(this);
|
this[brandContext] = new BrandContextController(this);
|
||||||
this[configContext] = new ConfigContextController(this);
|
this[configContext] = new ConfigContextController(this);
|
||||||
this[modalController] = new ModalOrchestrationController(this);
|
this[modalController] = new ModalOrchestrationController(this);
|
||||||
@ -61,7 +65,9 @@ export class Interface extends AKElement implements AkInterface {
|
|||||||
// Instead of calling ._activateTheme() twice, we insert the root document in the call
|
// Instead of calling ._activateTheme() twice, we insert the root document in the call
|
||||||
// since multiple calls to ._activateTheme() would not do anything after the first call
|
// since multiple calls to ._activateTheme() would not do anything after the first call
|
||||||
// as the theme is already enabled.
|
// as the theme is already enabled.
|
||||||
roots.unshift(document as unknown as DocumentOrShadowRoot);
|
if (!isEmbedded()) {
|
||||||
|
roots.unshift(document as unknown as DocumentOrShadowRoot);
|
||||||
|
}
|
||||||
super._activateTheme(theme, ...roots);
|
super._activateTheme(theme, ...roots);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import {
|
|||||||
EVENT_FLOW_INSPECTOR_TOGGLE,
|
EVENT_FLOW_INSPECTOR_TOGGLE,
|
||||||
TITLE_DEFAULT,
|
TITLE_DEFAULT,
|
||||||
} from "@goauthentik/common/constants";
|
} from "@goauthentik/common/constants";
|
||||||
import { globalAK } from "@goauthentik/common/global";
|
import { globalAK, isEmbedded } from "@goauthentik/common/global";
|
||||||
import { configureSentry } from "@goauthentik/common/sentry";
|
import { configureSentry } from "@goauthentik/common/sentry";
|
||||||
import { first } from "@goauthentik/common/utils";
|
import { first } from "@goauthentik/common/utils";
|
||||||
import { WebsocketClient } from "@goauthentik/common/ws";
|
import { WebsocketClient } from "@goauthentik/common/ws";
|
||||||
@ -84,6 +84,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
|||||||
return [PFBase, PFLogin, PFDrawer, PFButton, PFTitle, PFList, PFBackgroundImage].concat(css`
|
return [PFBase, PFLogin, PFDrawer, PFButton, PFTitle, PFList, PFBackgroundImage].concat(css`
|
||||||
:host {
|
:host {
|
||||||
--pf-c-login__main-body--PaddingBottom: var(--pf-global--spacer--2xl);
|
--pf-c-login__main-body--PaddingBottom: var(--pf-global--spacer--2xl);
|
||||||
|
position: relative;
|
||||||
}
|
}
|
||||||
.pf-c-background-image::before {
|
.pf-c-background-image::before {
|
||||||
--pf-c-background-image--BackgroundImage: var(--ak-flow-background);
|
--pf-c-background-image--BackgroundImage: var(--ak-flow-background);
|
||||||
@ -95,9 +96,6 @@ export class FlowExecutor extends Interface implements StageHost {
|
|||||||
.ak-hidden {
|
.ak-hidden {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
:host {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.pf-c-drawer__content {
|
.pf-c-drawer__content {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
@ -262,10 +260,13 @@ export class FlowExecutor extends Interface implements StageHost {
|
|||||||
this.challenge = challenge as ChallengeTypes;
|
this.challenge = challenge as ChallengeTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
setShadowStyles(value: ContextualFlowInfo) {
|
setBackgroundImage(value: ContextualFlowInfo) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (isEmbedded()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.shadowRoot
|
this.shadowRoot
|
||||||
?.querySelectorAll<HTMLDivElement>(".pf-c-background-image")
|
?.querySelectorAll<HTMLDivElement>(".pf-c-background-image")
|
||||||
.forEach((bg) => {
|
.forEach((bg) => {
|
||||||
@ -276,7 +277,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
|||||||
// DOM post-processing has to happen after the render.
|
// DOM post-processing has to happen after the render.
|
||||||
updated(changedProperties: PropertyValues<this>) {
|
updated(changedProperties: PropertyValues<this>) {
|
||||||
if (changedProperties.has("flowInfo") && this.flowInfo !== undefined) {
|
if (changedProperties.has("flowInfo") && this.flowInfo !== undefined) {
|
||||||
this.setShadowStyles(this.flowInfo);
|
this.setBackgroundImage(this.flowInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,56 +460,63 @@ export class FlowExecutor extends Interface implements StageHost {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderCard() {
|
||||||
|
return html`<div class="pf-c-login ${this.getLayout()}">
|
||||||
|
<div class="${this.getLayoutClass()}">
|
||||||
|
<div class="pf-c-login__main">
|
||||||
|
${this.loading && this.challenge
|
||||||
|
? html`<ak-loading-overlay></ak-loading-overlay>`
|
||||||
|
: nothing}
|
||||||
|
${isEmbedded()
|
||||||
|
? nothing
|
||||||
|
: html` <div class="pf-c-login__main-header pf-c-brand ak-brand">
|
||||||
|
<img
|
||||||
|
src="${themeImage(
|
||||||
|
first(
|
||||||
|
this.brand?.brandingLogo,
|
||||||
|
globalAK()?.brand.brandingLogo,
|
||||||
|
DefaultBrand.brandingLogo,
|
||||||
|
),
|
||||||
|
)}"
|
||||||
|
alt="authentik Logo"
|
||||||
|
/>
|
||||||
|
</div>`}
|
||||||
|
${until(this.renderChallenge())}
|
||||||
|
</div>
|
||||||
|
${isEmbedded()
|
||||||
|
? nothing
|
||||||
|
: html` <footer class="pf-c-login__footer">
|
||||||
|
<ul class="pf-c-list pf-m-inline">
|
||||||
|
${this.brand?.uiFooterLinks?.map((link) => {
|
||||||
|
if (link.href) {
|
||||||
|
return html`<li>
|
||||||
|
<a href="${link.href}">${link.name}</a>
|
||||||
|
</li>`;
|
||||||
|
}
|
||||||
|
return html`<li>
|
||||||
|
<span>${link.name}</span>
|
||||||
|
</li>`;
|
||||||
|
})}
|
||||||
|
<li>
|
||||||
|
<span>${msg("Powered by authentik")}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</footer>`}
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
render(): TemplateResult {
|
render(): TemplateResult {
|
||||||
|
if (isEmbedded()) {
|
||||||
|
return this.renderCard();
|
||||||
|
}
|
||||||
return html` <ak-locale-context>
|
return html` <ak-locale-context>
|
||||||
<div class="pf-c-background-image"></div>
|
<div class="pf-c-background-image"></div>
|
||||||
<div class="pf-c-page__drawer">
|
<div class="pf-c-page__drawer">
|
||||||
<div class="pf-c-drawer ${this.inspectorOpen ? "pf-m-expanded" : "pf-m-collapsed"}">
|
<div class="pf-c-drawer ${this.inspectorOpen ? "pf-m-expanded" : "pf-m-collapsed"}">
|
||||||
<div class="pf-c-drawer__main">
|
<div class="pf-c-drawer__main">
|
||||||
<div class="pf-c-drawer__content">
|
<div class="pf-c-drawer__content">
|
||||||
<div class="pf-c-drawer__body">
|
<div class="pf-c-drawer__body">${this.renderCard()}</div>
|
||||||
<div class="pf-c-login ${this.getLayout()}">
|
|
||||||
<div class="${this.getLayoutClass()}">
|
|
||||||
<div class="pf-c-login__main">
|
|
||||||
${this.loading && this.challenge
|
|
||||||
? html`<ak-loading-overlay></ak-loading-overlay>`
|
|
||||||
: nothing}
|
|
||||||
<div
|
|
||||||
class="pf-c-login__main-header pf-c-brand ak-brand"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src="${themeImage(
|
|
||||||
first(
|
|
||||||
this.brand?.brandingLogo,
|
|
||||||
globalAK()?.brand.brandingLogo,
|
|
||||||
DefaultBrand.brandingLogo,
|
|
||||||
),
|
|
||||||
)}"
|
|
||||||
alt="authentik Logo"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
${until(this.renderChallenge())}
|
|
||||||
</div>
|
|
||||||
<footer class="pf-c-login__footer">
|
|
||||||
<ul class="pf-c-list pf-m-inline">
|
|
||||||
${this.brand?.uiFooterLinks?.map((link) => {
|
|
||||||
if (link.href) {
|
|
||||||
return html`<li>
|
|
||||||
<a href="${link.href}">${link.name}</a>
|
|
||||||
</li>`;
|
|
||||||
}
|
|
||||||
return html`<li>
|
|
||||||
<span>${link.name}</span>
|
|
||||||
</li>`;
|
|
||||||
})}
|
|
||||||
<li>
|
|
||||||
<span>${msg("Powered by authentik")}</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
${until(this.renderInspector())}
|
${until(this.renderInspector())}
|
||||||
</div>
|
</div>
|
||||||
|
@ -99,6 +99,7 @@ export class IdentificationStage extends BaseStage<
|
|||||||
createHelperForm(): void {
|
createHelperForm(): void {
|
||||||
const compatMode = "ShadyDOM" in window;
|
const compatMode = "ShadyDOM" in window;
|
||||||
this.form = document.createElement("form");
|
this.form = document.createElement("form");
|
||||||
|
this.form.style.display = "none";
|
||||||
document.documentElement.appendChild(this.form);
|
document.documentElement.appendChild(this.form);
|
||||||
// Only add the additional username input if we're in a shadow dom
|
// Only add the additional username input if we're in a shadow dom
|
||||||
// otherwise it just confuses browsers
|
// otherwise it just confuses browsers
|
||||||
|
8
web/src/global.d.ts
vendored
8
web/src/global.d.ts
vendored
@ -12,3 +12,11 @@ declare namespace Intl {
|
|||||||
public format: (items: string[]) => string;
|
public format: (items: string[]) => string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare interface Window {
|
||||||
|
authentik_sdk?: {
|
||||||
|
base: string;
|
||||||
|
token?: string;
|
||||||
|
forceTheme?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
19
web/src/sdk/common.ts
Normal file
19
web/src/sdk/common.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { Interface } from "@goauthentik/elements/Interface/Interface";
|
||||||
|
|
||||||
|
import { html } from "lit";
|
||||||
|
import { customElement } from "lit/decorators.js";
|
||||||
|
|
||||||
|
import { UiThemeEnum, UiThemeEnumFromJSON } from "@goauthentik/api";
|
||||||
|
|
||||||
|
@customElement("ak-sdk-interface")
|
||||||
|
export class SDKInterface extends Interface {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return html`<slot></slot>`;
|
||||||
|
}
|
||||||
|
async getTheme(): Promise<UiThemeEnum> {
|
||||||
|
return UiThemeEnumFromJSON(window.authentik_sdk?.forceTheme) || UiThemeEnum.Automatic;
|
||||||
|
}
|
||||||
|
}
|
34
web/src/sdk/flow.ts
Normal file
34
web/src/sdk/flow.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import "@goauthentik/elements/messages/MessageContainer";
|
||||||
|
import { FlowExecutor } from "@goauthentik/flow/FlowExecutor";
|
||||||
|
// Statically import some stages to speed up load speed
|
||||||
|
import "@goauthentik/flow/stages/access_denied/AccessDeniedStage";
|
||||||
|
// Import webauthn-related stages to prevent issues on safari
|
||||||
|
// Which is overly sensitive to allowing things only in the context of a
|
||||||
|
// user interaction
|
||||||
|
import "@goauthentik/flow/stages/authenticator_validate/AuthenticatorValidateStage";
|
||||||
|
import "@goauthentik/flow/stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage";
|
||||||
|
import "@goauthentik/flow/stages/autosubmit/AutosubmitStage";
|
||||||
|
import "@goauthentik/flow/stages/captcha/CaptchaStage";
|
||||||
|
import "@goauthentik/flow/stages/identification/IdentificationStage";
|
||||||
|
import "@goauthentik/flow/stages/password/PasswordStage";
|
||||||
|
import "@goauthentik/sdk/common";
|
||||||
|
// end of stage import
|
||||||
|
|
||||||
|
import { html, nothing } from "lit";
|
||||||
|
import { customElement } from "lit/decorators.js";
|
||||||
|
import { until } from "lit/directives/until.js";
|
||||||
|
|
||||||
|
|
||||||
|
@customElement("ak-embedded-flow-executor")
|
||||||
|
export class EmbeddedFlowExecutor extends FlowExecutor {
|
||||||
|
renderCard() {
|
||||||
|
return html`<div class="pf-c-login">
|
||||||
|
<div class="pf-c-login__main">
|
||||||
|
${this.loading && this.challenge
|
||||||
|
? html`<ak-loading-overlay></ak-loading-overlay>`
|
||||||
|
: nothing}
|
||||||
|
${until(this.renderChallenge())}
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
}
|
2
web/src/sdk/index.ts
Normal file
2
web/src/sdk/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import "@goauthentik/sdk/flow";
|
||||||
|
import "@goauthentik/sdk/user-settings";
|
3
web/src/sdk/user-settings.ts
Normal file
3
web/src/sdk/user-settings.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import "@goauthentik/elements/messages/MessageContainer";
|
||||||
|
import "@goauthentik/sdk/common";
|
||||||
|
import "@goauthentik/user/user-settings/UserSettingsPage";
|
@ -21,6 +21,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
ChallengeTypes,
|
ChallengeTypes,
|
||||||
|
CoreApi,
|
||||||
FlowChallengeResponseRequest,
|
FlowChallengeResponseRequest,
|
||||||
FlowErrorChallenge,
|
FlowErrorChallenge,
|
||||||
FlowsApi,
|
FlowsApi,
|
||||||
@ -82,8 +83,11 @@ export class UserSettingsFlowExecutor
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated(): void {
|
async firstUpdated(): Promise<void> {
|
||||||
this.flowSlug = this.brand?.flowUserSettings;
|
if (!this.brand) {
|
||||||
|
this.brand = await new CoreApi(DEFAULT_CONFIG).coreBrandsCurrentRetrieve();
|
||||||
|
}
|
||||||
|
this.flowSlug = this.brand.flowUserSettings;
|
||||||
if (!this.flowSlug) {
|
if (!this.flowSlug) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
"@goauthentik/flow/*": ["./src/flow/*"],
|
"@goauthentik/flow/*": ["./src/flow/*"],
|
||||||
"@goauthentik/locales/*": ["./src/locales/*"],
|
"@goauthentik/locales/*": ["./src/locales/*"],
|
||||||
"@goauthentik/polyfill/*": ["./src/polyfill/*"],
|
"@goauthentik/polyfill/*": ["./src/polyfill/*"],
|
||||||
|
"@goauthentik/sdk/*": ["./src/sdk/*"],
|
||||||
"@goauthentik/standalone/*": ["./src/standalone/*"],
|
"@goauthentik/standalone/*": ["./src/standalone/*"],
|
||||||
"@goauthentik/user/*": ["./src/user/*"]
|
"@goauthentik/user/*": ["./src/user/*"]
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user