Compare commits
1 Commits
safari-adm
...
static-con
Author | SHA1 | Date | |
---|---|---|---|
86c1d60093 |
@ -1,6 +1,6 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { VERSION } from "@goauthentik/common/constants";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { BrandConfig, ServerConfig } from "@goauthentik/common/global";
|
||||
import "@goauthentik/elements/EmptyState";
|
||||
import { WithBrandConfig } from "@goauthentik/elements/Interface/brandProvider";
|
||||
import { WithLicenseSummary } from "@goauthentik/elements/Interface/licenseSummaryProvider";
|
||||
@ -33,7 +33,7 @@ export class AboutModal extends WithLicenseSummary(WithBrandConfig(ModalButton))
|
||||
const status = await new AdminApi(DEFAULT_CONFIG).adminSystemRetrieve();
|
||||
const version = await new AdminApi(DEFAULT_CONFIG).adminVersionRetrieve();
|
||||
let build: string | TemplateResult = msg("Release");
|
||||
if (globalAK().config.capabilities.includes(CapabilitiesEnum.CanDebug)) {
|
||||
if (ServerConfig.capabilities.includes(CapabilitiesEnum.CanDebug)) {
|
||||
build = msg("Development");
|
||||
} else if (version.buildHash !== "") {
|
||||
build = html`<a
|
||||
@ -58,7 +58,7 @@ export class AboutModal extends WithLicenseSummary(WithBrandConfig(ModalButton))
|
||||
}
|
||||
|
||||
renderModal() {
|
||||
let product = globalAK().brand.brandingTitle || DefaultBrand.brandingTitle;
|
||||
let product = BrandConfig.brandingTitle || DefaultBrand.brandingTitle;
|
||||
if (this.licenseSummary.status != LicenseSummaryStatusEnum.Unlicensed) {
|
||||
product += ` ${msg("Enterprise")}`;
|
||||
}
|
||||
|
@ -5,7 +5,8 @@ import {
|
||||
GroupMatchingModeToLabel,
|
||||
UserMatchingModeToLabel,
|
||||
} from "@goauthentik/admin/sources/oauth/utils";
|
||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { ServerConfig } from "@goauthentik/common/global";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/components/ak-switch-input";
|
||||
import "@goauthentik/components/ak-text-input";
|
||||
@ -61,8 +62,7 @@ export class KerberosSourceForm extends WithCapabilitiesConfig(BaseSourceForm<Ke
|
||||
kerberosSourceRequest: data as unknown as KerberosSourceRequest,
|
||||
});
|
||||
}
|
||||
const c = await config();
|
||||
if (c.capabilities.includes(CapabilitiesEnum.CanSaveMedia)) {
|
||||
if (ServerConfig.capabilities.includes(CapabilitiesEnum.CanSaveMedia)) {
|
||||
const icon = this.getFormFiles()["icon"];
|
||||
if (icon || this.clearIcon) {
|
||||
await new SourcesApi(DEFAULT_CONFIG).sourcesAllSetIconCreate({
|
||||
|
@ -5,7 +5,8 @@ import {
|
||||
GroupMatchingModeToLabel,
|
||||
UserMatchingModeToLabel,
|
||||
} from "@goauthentik/admin/sources/oauth/utils";
|
||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { ServerConfig } from "@goauthentik/common/global";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/CodeMirror";
|
||||
import { CodeMirrorMode } from "@goauthentik/elements/CodeMirror";
|
||||
@ -71,8 +72,7 @@ export class OAuthSourceForm extends WithCapabilitiesConfig(BaseSourceForm<OAuth
|
||||
oAuthSourceRequest: data as unknown as OAuthSourceRequest,
|
||||
});
|
||||
}
|
||||
const c = await config();
|
||||
if (c.capabilities.includes(CapabilitiesEnum.CanSaveMedia)) {
|
||||
if (ServerConfig.capabilities.includes(CapabilitiesEnum.CanSaveMedia)) {
|
||||
const icon = this.getFormFiles()["icon"];
|
||||
if (icon || this.clearIcon) {
|
||||
await new SourcesApi(DEFAULT_CONFIG).sourcesAllSetIconCreate({
|
||||
|
@ -6,7 +6,8 @@ import {
|
||||
GroupMatchingModeToLabel,
|
||||
UserMatchingModeToLabel,
|
||||
} from "@goauthentik/admin/sources/oauth/utils";
|
||||
import { DEFAULT_CONFIG, config } from "@goauthentik/common/api/config";
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { ServerConfig } from "@goauthentik/common/global";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import {
|
||||
CapabilitiesEnum,
|
||||
@ -62,8 +63,7 @@ export class SAMLSourceForm extends WithCapabilitiesConfig(BaseSourceForm<SAMLSo
|
||||
sAMLSourceRequest: data,
|
||||
});
|
||||
}
|
||||
const c = await config();
|
||||
if (c.capabilities.includes(CapabilitiesEnum.CanSaveMedia)) {
|
||||
if (ServerConfig.capabilities.includes(CapabilitiesEnum.CanSaveMedia)) {
|
||||
const icon = this.getFormFiles()["icon"];
|
||||
if (icon || this.clearIcon) {
|
||||
await new SourcesApi(DEFAULT_CONFIG).sourcesAllSetIconCreate({
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { APIConfig } from "@goauthentik/common/global";
|
||||
import "@goauthentik/components/ak-text-input";
|
||||
import { Form } from "@goauthentik/elements/forms/Form";
|
||||
|
||||
@ -21,7 +21,7 @@ export class UserImpersonateForm extends Form<ImpersonationRequest> {
|
||||
impersonationRequest: data,
|
||||
})
|
||||
.then(() => {
|
||||
window.location.href = globalAK().api.base;
|
||||
window.location.href = APIConfig.base;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -3,79 +3,40 @@ import {
|
||||
EventMiddleware,
|
||||
LoggingMiddleware,
|
||||
} from "@goauthentik/common/api/middleware";
|
||||
import { EVENT_LOCALE_REQUEST, VERSION } from "@goauthentik/common/constants";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { VERSION } from "@goauthentik/common/constants";
|
||||
import { APIConfig, BrandConfig } from "@goauthentik/common/global";
|
||||
|
||||
import { Config, Configuration, CoreApi, CurrentBrand, RootApi } from "@goauthentik/api";
|
||||
import { Configuration as ApiConfiguration } from "@goauthentik/api";
|
||||
|
||||
let globalConfigPromise: Promise<Config> | undefined = Promise.resolve(globalAK().config);
|
||||
export function config(): Promise<Config> {
|
||||
if (!globalConfigPromise) {
|
||||
globalConfigPromise = new RootApi(DEFAULT_CONFIG).rootConfigRetrieve();
|
||||
}
|
||||
return globalConfigPromise;
|
||||
}
|
||||
/**
|
||||
* Extract the content of a meta tag by name.
|
||||
*
|
||||
* @todo Can we memoize this?
|
||||
*/
|
||||
function extractMetaContent(name: string): string {
|
||||
const metaEl = document.querySelector<HTMLMetaElement>(`meta[name=${name}]`);
|
||||
|
||||
export function brandSetFavicon(brand: CurrentBrand) {
|
||||
/**
|
||||
* <link rel="icon" href="/static/dist/assets/icons/icon.png">
|
||||
* <link rel="shortcut icon" href="/static/dist/assets/icons/icon.png">
|
||||
*/
|
||||
const rels = ["icon", "shortcut icon"];
|
||||
rels.forEach((rel) => {
|
||||
let relIcon = document.head.querySelector<HTMLLinkElement>(`link[rel='${rel}']`);
|
||||
if (!relIcon) {
|
||||
relIcon = document.createElement("link");
|
||||
relIcon.rel = rel;
|
||||
document.getElementsByTagName("head")[0].appendChild(relIcon);
|
||||
}
|
||||
relIcon.href = brand.brandingFavicon;
|
||||
});
|
||||
}
|
||||
|
||||
export function brandSetLocale(brand: CurrentBrand) {
|
||||
if (brand.defaultLocale === "") {
|
||||
return;
|
||||
}
|
||||
console.debug("authentik/locale: setting locale from brand default");
|
||||
window.dispatchEvent(
|
||||
new CustomEvent(EVENT_LOCALE_REQUEST, {
|
||||
composed: true,
|
||||
bubbles: true,
|
||||
detail: { locale: brand.defaultLocale },
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
let globalBrandPromise: Promise<CurrentBrand> | undefined = Promise.resolve(globalAK().brand);
|
||||
export function brand(): Promise<CurrentBrand> {
|
||||
if (!globalBrandPromise) {
|
||||
globalBrandPromise = new CoreApi(DEFAULT_CONFIG)
|
||||
.coreBrandsCurrentRetrieve()
|
||||
.then((brand) => {
|
||||
brandSetFavicon(brand);
|
||||
brandSetLocale(brand);
|
||||
return brand;
|
||||
});
|
||||
}
|
||||
return globalBrandPromise;
|
||||
}
|
||||
|
||||
export function getMetaContent(key: string): string {
|
||||
const metaEl = document.querySelector<HTMLMetaElement>(`meta[name=${key}]`);
|
||||
if (!metaEl) return "";
|
||||
|
||||
return metaEl.content;
|
||||
}
|
||||
|
||||
export const DEFAULT_CONFIG = new Configuration({
|
||||
basePath: `${globalAK().api.base}api/v3`,
|
||||
/**
|
||||
* Default API Configuration.
|
||||
*
|
||||
* @todo This is a frequent source of duplication when working with the API.
|
||||
* We should consider moving this to a more central location.
|
||||
*/
|
||||
export const DEFAULT_CONFIG = new ApiConfiguration({
|
||||
basePath: `${APIConfig.base}api/v3`,
|
||||
headers: {
|
||||
"sentry-trace": getMetaContent("sentry-trace"),
|
||||
"sentry-trace": extractMetaContent("sentry-trace"),
|
||||
},
|
||||
middleware: [
|
||||
// ---
|
||||
new CSRFMiddleware(),
|
||||
new EventMiddleware(),
|
||||
new LoggingMiddleware(globalAK().brand),
|
||||
new LoggingMiddleware(BrandConfig),
|
||||
],
|
||||
});
|
||||
|
||||
|
@ -1,59 +1,142 @@
|
||||
import { Config, ConfigFromJSON, CurrentBrand, CurrentBrandFromJSON } from "@goauthentik/api";
|
||||
|
||||
export interface GlobalAuthentik {
|
||||
_converted?: boolean;
|
||||
export interface APIConfig {
|
||||
/**
|
||||
* Absolute base path to the API.
|
||||
*/
|
||||
base: string;
|
||||
/**
|
||||
* Relative base path to the API.
|
||||
*/
|
||||
relBase: string;
|
||||
}
|
||||
|
||||
export interface FlowConfig {
|
||||
/**
|
||||
* The current flow ID.
|
||||
*/
|
||||
layout: string;
|
||||
}
|
||||
|
||||
export interface SerializedClientState {
|
||||
/**
|
||||
* The BCP47 language tag.
|
||||
*/
|
||||
locale?: string;
|
||||
flow?: {
|
||||
layout: string;
|
||||
};
|
||||
config: Config;
|
||||
brand: CurrentBrand;
|
||||
/**
|
||||
* Current flow state.
|
||||
*/
|
||||
flow?: FlowConfig;
|
||||
/**
|
||||
* Server configuration.
|
||||
*/
|
||||
config: unknown;
|
||||
/**
|
||||
* Branding information.
|
||||
*/
|
||||
brand: unknown;
|
||||
/**
|
||||
* The major and minor components of the current version.
|
||||
*/
|
||||
versionFamily: string;
|
||||
/**
|
||||
* A subdomain compatible SemVer.
|
||||
*/
|
||||
versionSubdomain: string;
|
||||
/**
|
||||
* The current build hash.
|
||||
*/
|
||||
build: string;
|
||||
api: {
|
||||
base: string;
|
||||
relBase: string;
|
||||
|
||||
/**
|
||||
* The API configuration.
|
||||
*/
|
||||
api: APIConfig;
|
||||
}
|
||||
|
||||
type ClientConfigRealm<T> = T & {
|
||||
readonly authentik: Readonly<SerializedClientState>;
|
||||
};
|
||||
|
||||
function isClientConfigRealm<T>(namespace: object): namespace is ClientConfigRealm<T> {
|
||||
return typeof namespace === "object" && "authentik" in namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* The current locale as defined by the server.
|
||||
*
|
||||
* @format BCP47
|
||||
*/
|
||||
export let ServerLocale = "";
|
||||
|
||||
export let FlowConfig: FlowConfig | undefined;
|
||||
|
||||
/**
|
||||
* The current build hash.
|
||||
*/
|
||||
export let BuildHash = "";
|
||||
|
||||
/**
|
||||
* The major and minor components of the SemVer.
|
||||
*/
|
||||
export let VersionFamily = "";
|
||||
|
||||
/**
|
||||
* A subdomain compatible SemVer.
|
||||
*/
|
||||
export let VersionSubdomain = "";
|
||||
|
||||
/**
|
||||
* The parsed API configuration extracted from the global scope.
|
||||
*/
|
||||
export let APIConfig: Readonly<APIConfig>;
|
||||
|
||||
/**
|
||||
* The parsed server configuration extracted from the global scope.
|
||||
*/
|
||||
export let ServerConfig: Readonly<Config>;
|
||||
|
||||
/**
|
||||
* The parsed brand configuration extracted from the global scope.
|
||||
*/
|
||||
export let BrandConfig: Readonly<CurrentBrand>;
|
||||
|
||||
if (!isClientConfigRealm(self)) {
|
||||
const apiOrigin = new URL(process.env.AK_API_BASE_PATH || window.location.origin);
|
||||
|
||||
APIConfig = {
|
||||
base: apiOrigin.toString(),
|
||||
relBase: apiOrigin.pathname,
|
||||
};
|
||||
|
||||
BrandConfig = CurrentBrandFromJSON({
|
||||
ui_footer_links: [],
|
||||
});
|
||||
} else {
|
||||
ServerLocale = self.authentik.locale || "";
|
||||
FlowConfig = self.authentik.flow;
|
||||
|
||||
BuildHash = self.authentik.build;
|
||||
|
||||
VersionFamily = self.authentik.versionFamily;
|
||||
VersionSubdomain = self.authentik.versionSubdomain;
|
||||
|
||||
ServerConfig = ConfigFromJSON(self.authentik.config);
|
||||
BrandConfig = CurrentBrandFromJSON(self.authentik.brand);
|
||||
APIConfig = self.authentik.api;
|
||||
}
|
||||
|
||||
export interface AuthentikWindow {
|
||||
authentik: GlobalAuthentik;
|
||||
}
|
||||
/**
|
||||
* Generate a link to the documentation.
|
||||
*/
|
||||
export function docLink(documentationPath: string): string {
|
||||
const origin =
|
||||
// Default case or beta build which should always point to latest
|
||||
BuildHash || !VersionSubdomain
|
||||
? "https://goauthentik.io"
|
||||
: `https://${VersionSubdomain}.goauthentik.io`;
|
||||
|
||||
export function globalAK(): GlobalAuthentik {
|
||||
const ak = (window as unknown as AuthentikWindow).authentik;
|
||||
if (ak && !ak._converted) {
|
||||
ak._converted = true;
|
||||
ak.brand = CurrentBrandFromJSON(ak.brand);
|
||||
ak.config = ConfigFromJSON(ak.config);
|
||||
}
|
||||
const apiBase = new URL(process.env.AK_API_BASE_PATH || window.location.origin);
|
||||
if (!ak) {
|
||||
return {
|
||||
config: ConfigFromJSON({
|
||||
capabilities: [],
|
||||
}),
|
||||
brand: CurrentBrandFromJSON({
|
||||
ui_footer_links: [],
|
||||
}),
|
||||
versionFamily: "",
|
||||
versionSubdomain: "",
|
||||
build: "",
|
||||
api: {
|
||||
base: apiBase.toString(),
|
||||
relBase: apiBase.pathname,
|
||||
},
|
||||
};
|
||||
}
|
||||
return ak;
|
||||
}
|
||||
const docsURL = new URL(documentationPath, origin);
|
||||
|
||||
export function docLink(path: string): string {
|
||||
const ak = globalAK();
|
||||
// Default case or beta build which should always point to latest
|
||||
if (!ak || ak.build !== "") {
|
||||
return `https://goauthentik.io${path}`;
|
||||
}
|
||||
return `https://${ak.versionSubdomain}.goauthentik.io${path}`;
|
||||
return docsURL.toString();
|
||||
}
|
||||
|
@ -1,98 +1,106 @@
|
||||
import { config } from "@goauthentik/common/api/config";
|
||||
import { VERSION } from "@goauthentik/common/constants";
|
||||
import { SentryIgnoredError } from "@goauthentik/common/errors";
|
||||
import { ServerConfig } from "@goauthentik/common/global";
|
||||
import { me } from "@goauthentik/common/users";
|
||||
import {
|
||||
ErrorEvent,
|
||||
EventHint,
|
||||
browserTracingIntegration,
|
||||
init,
|
||||
setTag,
|
||||
setUser,
|
||||
} from "@sentry/browser";
|
||||
import { browserTracingIntegration, init, setTag, setUser } from "@sentry/browser";
|
||||
|
||||
import { CapabilitiesEnum, Config, ResponseError } from "@goauthentik/api";
|
||||
|
||||
/**
|
||||
* A generic error that can be thrown without triggering Sentry's reporting.
|
||||
*/
|
||||
export class SentryIgnoredError extends Error {}
|
||||
import { CapabilitiesEnum, ResponseError } from "@goauthentik/api";
|
||||
|
||||
export const TAG_SENTRY_COMPONENT = "authentik.component";
|
||||
export const TAG_SENTRY_CAPABILITIES = "authentik.capabilities";
|
||||
|
||||
export async function configureSentry(canDoPpi = false): Promise<Config> {
|
||||
const cfg = await config();
|
||||
/**
|
||||
* Configure Sentry with the given configuration.
|
||||
*
|
||||
* @param canSendPII Whether the user can send personally identifiable information.
|
||||
*/
|
||||
export async function configureSentry(canSendPII?: boolean): Promise<void> {
|
||||
if (!ServerConfig.errorReporting.enabled) return;
|
||||
const { capabilities, errorReporting } = ServerConfig;
|
||||
|
||||
if (cfg.errorReporting.enabled) {
|
||||
init({
|
||||
dsn: cfg.errorReporting.sentryDsn,
|
||||
ignoreErrors: [
|
||||
/network/gi,
|
||||
/fetch/gi,
|
||||
/module/gi,
|
||||
// Error on edge on ios,
|
||||
// https://stackoverflow.com/questions/69261499/what-is-instantsearchsdkjsbridgeclearhighlight
|
||||
/instantSearchSDKJSBridgeClearHighlight/gi,
|
||||
// Seems to be an issue in Safari and Firefox
|
||||
/MutationObserver.observe/gi,
|
||||
/NS_ERROR_FAILURE/gi,
|
||||
],
|
||||
release: `authentik@${VERSION}`,
|
||||
integrations: [
|
||||
browserTracingIntegration({
|
||||
shouldCreateSpanForRequest: (url: string) => {
|
||||
return url.startsWith(window.location.host);
|
||||
},
|
||||
}),
|
||||
],
|
||||
tracesSampleRate: cfg.errorReporting.tracesSampleRate,
|
||||
environment: cfg.errorReporting.environment,
|
||||
beforeSend: (
|
||||
event: ErrorEvent,
|
||||
hint: EventHint,
|
||||
): ErrorEvent | PromiseLike<ErrorEvent | null> | null => {
|
||||
if (!hint) {
|
||||
return event;
|
||||
}
|
||||
if (hint.originalException instanceof SentryIgnoredError) {
|
||||
return null;
|
||||
}
|
||||
if (
|
||||
hint.originalException instanceof ResponseError ||
|
||||
hint.originalException instanceof DOMException
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return event;
|
||||
},
|
||||
});
|
||||
setTag(TAG_SENTRY_CAPABILITIES, cfg.capabilities.join(","));
|
||||
if (window.location.pathname.includes("if/")) {
|
||||
setTag(TAG_SENTRY_COMPONENT, `web/${currentInterface()}`);
|
||||
}
|
||||
if (cfg.capabilities.includes(CapabilitiesEnum.CanDebug)) {
|
||||
const Spotlight = await import("@spotlightjs/spotlight");
|
||||
init({
|
||||
dsn: errorReporting.sentryDsn,
|
||||
ignoreErrors: [
|
||||
/network/gi,
|
||||
/fetch/gi,
|
||||
/module/gi,
|
||||
// Error on edge on ios,
|
||||
// https://stackoverflow.com/questions/69261499/what-is-instantsearchsdkjsbridgeclearhighlight
|
||||
/instantSearchSDKJSBridgeClearHighlight/gi,
|
||||
// Seems to be an issue in Safari and Firefox
|
||||
/MutationObserver.observe/gi,
|
||||
/NS_ERROR_FAILURE/gi,
|
||||
],
|
||||
release: `authentik@${VERSION}`,
|
||||
integrations: [
|
||||
browserTracingIntegration({
|
||||
shouldCreateSpanForRequest: (url: string) => {
|
||||
return url.startsWith(window.location.host);
|
||||
},
|
||||
}),
|
||||
],
|
||||
tracesSampleRate: errorReporting.tracesSampleRate,
|
||||
environment: errorReporting.environment,
|
||||
beforeSend: (event, hint) => {
|
||||
if (!hint) return event;
|
||||
|
||||
Spotlight.init({ injectImmediately: true });
|
||||
}
|
||||
if (cfg.errorReporting.sendPii && canDoPpi) {
|
||||
me().then((user) => {
|
||||
setUser({ email: user.user.email });
|
||||
console.debug("authentik/config: Sentry with PII enabled.");
|
||||
const { originalException } = hint;
|
||||
|
||||
if (originalException instanceof SentryIgnoredError) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (originalException instanceof ResponseError) return null;
|
||||
if (originalException instanceof DOMException) return null;
|
||||
|
||||
return event;
|
||||
},
|
||||
});
|
||||
|
||||
setTag(TAG_SENTRY_CAPABILITIES, capabilities.join(","));
|
||||
|
||||
if (window.location.pathname.includes("if/")) {
|
||||
setTag(TAG_SENTRY_COMPONENT, `web/${currentInterface()}`);
|
||||
}
|
||||
|
||||
if (
|
||||
// Retain this predicate order to allow ESBuild to tree-shake the import in production.
|
||||
process.env.NODE_ENV === "development" &&
|
||||
capabilities.includes(CapabilitiesEnum.CanDebug)
|
||||
) {
|
||||
await import("@spotlightjs/spotlight")
|
||||
.then((Spotlight) => {
|
||||
return Spotlight.init({
|
||||
injectImmediately: true,
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Failed to init Spotlight", error);
|
||||
});
|
||||
} else {
|
||||
console.debug("authentik/config: Sentry enabled.");
|
||||
}
|
||||
|
||||
if (errorReporting.sendPii && canSendPII) {
|
||||
const session = await me().catch(() => null);
|
||||
|
||||
if (session) {
|
||||
setUser({ email: session.user.email });
|
||||
console.debug("authentik/config: Sentry PII enabled.");
|
||||
}
|
||||
}
|
||||
return cfg;
|
||||
|
||||
console.debug("authentik/config: Sentry enabled.");
|
||||
}
|
||||
|
||||
// Get the interface name from URL
|
||||
/**
|
||||
* Get the current interface from the URL.
|
||||
*/
|
||||
export function currentInterface(): string {
|
||||
const pathMatches = window.location.pathname.match(/.+if\/(\w+)\//);
|
||||
let currentInterface = "unknown";
|
||||
|
||||
if (pathMatches && pathMatches.length >= 2) {
|
||||
currentInterface = pathMatches[1];
|
||||
}
|
||||
|
||||
return currentInterface.toLowerCase();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { EVENT_MESSAGE, EVENT_WS_MESSAGE } from "@goauthentik/common/constants";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { APIConfig } from "@goauthentik/common/global";
|
||||
import { MessageLevel } from "@goauthentik/common/messages";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
@ -22,7 +22,8 @@ export class WebsocketClient {
|
||||
|
||||
connect(): void {
|
||||
if (navigator.webdriver) return;
|
||||
const apiURL = new URL(globalAK().api.base);
|
||||
|
||||
const apiURL = new URL(APIConfig.base);
|
||||
const wsUrl = `${window.location.protocol.replace("http", "ws")}//${apiURL.host}${apiURL.pathname}ws/client/`;
|
||||
this.messageSocket = new WebSocket(wsUrl);
|
||||
this.messageSocket.addEventListener("open", () => {
|
||||
|
@ -3,7 +3,7 @@ import {
|
||||
EVENT_API_DRAWER_TOGGLE,
|
||||
EVENT_NOTIFICATION_DRAWER_TOGGLE,
|
||||
} from "@goauthentik/common/constants";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { APIConfig } from "@goauthentik/common/global";
|
||||
import { UIConfig, UserDisplay, uiConfig } from "@goauthentik/common/ui/config";
|
||||
import { me } from "@goauthentik/common/users";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
@ -146,7 +146,7 @@ export class NavigationButtons extends AKElement {
|
||||
<a
|
||||
class="pf-c-button pf-m-plain"
|
||||
type="button"
|
||||
href="${globalAK().api.base}if/user/#/settings"
|
||||
href="${APIConfig.base}if/user/#/settings"
|
||||
>
|
||||
<pf-tooltip position="top" content=${msg("Settings")}>
|
||||
<i class="fas fa-cog" aria-hidden="true"></i>
|
||||
@ -194,7 +194,7 @@ export class NavigationButtons extends AKElement {
|
||||
${this.renderSettings()}
|
||||
<div class="pf-c-page__header-tools-item">
|
||||
<a
|
||||
href="${globalAK().api.base}flows/-/default/invalidation/"
|
||||
href="${APIConfig.base}flows/-/default/invalidation/"
|
||||
class="pf-c-button pf-m-plain"
|
||||
>
|
||||
<pf-tooltip position="top" content=${msg("Sign out")}>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { EVENT_THEME_CHANGE } from "@goauthentik/common/constants";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { BrandConfig } from "@goauthentik/common/global";
|
||||
import { UIConfig } from "@goauthentik/common/ui/config";
|
||||
import { adaptCSS } from "@goauthentik/common/utils";
|
||||
import { ensureCSSStyleSheet } from "@goauthentik/elements/utils/ensureCSSStyleSheet";
|
||||
@ -78,7 +78,7 @@ export class AKElement extends LitElement {
|
||||
async _initTheme(root: DocumentOrShadowRoot): Promise<void> {
|
||||
// Early activate theme based on media query to prevent light flash
|
||||
// when dark is preferred
|
||||
this._applyTheme(root, globalAK().brand.uiTheme);
|
||||
this._applyTheme(root, BrandConfig.uiTheme);
|
||||
this._applyTheme(root, await this.getTheme());
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { EVENT_REFRESH } from "@goauthentik/common/constants";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { ServerConfig } from "@goauthentik/common/global";
|
||||
import { authentikConfigContext } from "@goauthentik/elements/AuthentikContexts";
|
||||
import type { ReactiveElementHost } from "@goauthentik/elements/types.js";
|
||||
|
||||
@ -24,8 +24,8 @@ export class ConfigContextController implements ReactiveController {
|
||||
initialValue: undefined,
|
||||
});
|
||||
// Pre-hydrate from template-embedded config
|
||||
this.context.setValue(globalAK().config);
|
||||
this.host.config = globalAK().config;
|
||||
this.context.setValue(ServerConfig);
|
||||
this.host.config = ServerConfig;
|
||||
this.fetch = this.fetch.bind(this);
|
||||
this.fetch();
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import {
|
||||
EVENT_WS_MESSAGE,
|
||||
TITLE_DEFAULT,
|
||||
} from "@goauthentik/common/constants";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { APIConfig } from "@goauthentik/common/global";
|
||||
import { currentInterface } from "@goauthentik/common/sentry";
|
||||
import { UIConfig, UserDisplay, uiConfig } from "@goauthentik/common/ui/config";
|
||||
import { me } from "@goauthentik/common/users";
|
||||
@ -186,7 +186,7 @@ export class PageHeader extends WithBrandConfig(AKElement) {
|
||||
<ak-nav-buttons .uiConfig=${this.uiConfig} .me=${this.me}>
|
||||
<a
|
||||
class="pf-c-button pf-m-secondary pf-m-small pf-u-display-none pf-u-display-block-on-md"
|
||||
href="${globalAK().api.base}if/user/"
|
||||
href="${APIConfig.base}if/user/"
|
||||
slot="extra"
|
||||
>
|
||||
${msg("User interface")}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { ServerLocale } from "@goauthentik/common/global";
|
||||
|
||||
import { LOCALES as RAW_LOCALES, enLocale } from "./definitions";
|
||||
import { AkLocale } from "./types";
|
||||
@ -51,7 +51,7 @@ export function autoDetectLanguage(userReq = TOMBSTONE, brandReq = TOMBSTONE): s
|
||||
userReq,
|
||||
window.navigator?.language ?? TOMBSTONE,
|
||||
brandReq,
|
||||
globalAK()?.locale ?? TOMBSTONE,
|
||||
ServerLocale ?? TOMBSTONE,
|
||||
DEFAULT_LOCALE,
|
||||
].filter(isLocaleCandidate);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { APIConfig } from "@goauthentik/common/global";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import { WithLicenseSummary } from "@goauthentik/elements/Interface/licenseSummaryProvider";
|
||||
|
||||
@ -76,7 +76,7 @@ export class EnterpriseStatusBanner extends WithLicenseSummary(AKElement) {
|
||||
: "pf-m-gold"}"
|
||||
>
|
||||
${message}
|
||||
<a href="${globalAK().api.base}if/admin/#/enterprise/licenses"
|
||||
<a href="${APIConfig.base}if/admin/#/enterprise/licenses"
|
||||
>${msg("Click here for more info.")}</a
|
||||
>
|
||||
</div>`;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { RequestInfo } from "@goauthentik/common/api/middleware";
|
||||
import { EVENT_API_DRAWER_TOGGLE, EVENT_REQUEST_POST } from "@goauthentik/common/constants";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { APIConfig } from "@goauthentik/common/global";
|
||||
import { formatElapsedTime } from "@goauthentik/common/temporal";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
|
||||
@ -92,7 +92,7 @@ export class APIDrawer extends AKElement {
|
||||
<h1 class="pf-c-notification-drawer__header-title">
|
||||
${msg("API Requests")}
|
||||
</h1>
|
||||
<a href="${globalAK().api.base}api/v3/" target="_blank"
|
||||
<a href="${APIConfig.base}api/v3/" target="_blank"
|
||||
>${msg("Open API Browser")}</a
|
||||
>
|
||||
</div>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { EVENT_NOTIFICATION_DRAWER_TOGGLE, EVENT_REFRESH } from "@goauthentik/common/constants";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { APIConfig } from "@goauthentik/common/global";
|
||||
import { actionToLabel } from "@goauthentik/common/labels";
|
||||
import { MessageLevel } from "@goauthentik/common/messages";
|
||||
import { formatElapsedTime } from "@goauthentik/common/temporal";
|
||||
@ -99,7 +99,7 @@ export class NotificationDrawer extends AKElement {
|
||||
html`
|
||||
<a
|
||||
class="pf-c-dropdown__toggle pf-m-plain"
|
||||
href="${globalAK().api.base}if/admin/#/events/log/${item.event?.pk}"
|
||||
href="${APIConfig.base}if/admin/#/events/log/${item.event?.pk}"
|
||||
>
|
||||
<pf-tooltip position="top" content=${msg("Show details")}>
|
||||
<i class="fas fa-share-square"></i>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import type { AdminInterface } from "@goauthentik/admin/AdminInterface/AdminInterface";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { BrandConfig } from "@goauthentik/common/global";
|
||||
import { AKElement, rootInterface } from "@goauthentik/elements/Base";
|
||||
import { WithLicenseSummary } from "@goauthentik/elements/Interface/licenseSummaryProvider";
|
||||
import { WithVersion } from "@goauthentik/elements/Interface/versionProvider";
|
||||
@ -45,7 +45,7 @@ export class SidebarVersion extends WithLicenseSummary(WithVersion(AKElement)) {
|
||||
if (!this.version || !this.licenseSummary) {
|
||||
return nothing;
|
||||
}
|
||||
let product = globalAK().brand.brandingTitle || DefaultBrand.brandingTitle;
|
||||
let product = BrandConfig.brandingTitle || DefaultBrand.brandingTitle;
|
||||
if (this.licenseSummary.status != LicenseSummaryStatusEnum.Unlicensed) {
|
||||
product += ` ${msg("Enterprise")}`;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
EVENT_FLOW_INSPECTOR_TOGGLE,
|
||||
TITLE_DEFAULT,
|
||||
} from "@goauthentik/common/constants";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { BrandConfig, FlowConfig } from "@goauthentik/common/global";
|
||||
import { configureSentry } from "@goauthentik/common/sentry";
|
||||
import { first } from "@goauthentik/common/utils";
|
||||
import { WebsocketClient } from "@goauthentik/common/ws";
|
||||
@ -201,7 +201,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
}
|
||||
|
||||
async getTheme(): Promise<UiThemeEnum> {
|
||||
return globalAK()?.brand.uiTheme || UiThemeEnum.Automatic;
|
||||
return BrandConfig.uiTheme || UiThemeEnum.Automatic;
|
||||
}
|
||||
|
||||
async submit(
|
||||
@ -487,7 +487,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
}
|
||||
|
||||
getLayout(): string {
|
||||
const prefilledFlow = globalAK()?.flow?.layout || FlowLayoutEnum.Stacked;
|
||||
const prefilledFlow = FlowConfig?.layout || FlowLayoutEnum.Stacked;
|
||||
if (this.challenge) {
|
||||
return this.challenge?.flowInfo?.layout || prefilledFlow;
|
||||
}
|
||||
@ -528,7 +528,7 @@ export class FlowExecutor extends Interface implements StageHost {
|
||||
src="${themeImage(
|
||||
first(
|
||||
this.brand?.brandingLogo,
|
||||
globalAK()?.brand.brandingLogo,
|
||||
BrandConfig.brandingLogo,
|
||||
DefaultBrand.brandingLogo,
|
||||
),
|
||||
)}"
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { APIConfig } from "@goauthentik/common/global";
|
||||
import "@goauthentik/flow/FormStatic";
|
||||
import { BaseStage } from "@goauthentik/flow/stages/base";
|
||||
|
||||
@ -48,7 +48,7 @@ export class SessionEnd extends BaseStage<SessionEndChallenge, unknown> {
|
||||
str`You've logged out of ${this.challenge.applicationName}. You can go back to the overview to launch another application, or log out of your authentik account.`,
|
||||
)}
|
||||
</p>
|
||||
<a href="${globalAK().api.base}" class="pf-c-button pf-m-primary">
|
||||
<a href="${APIConfig.base}" class="pf-c-button pf-m-primary">
|
||||
${msg("Go back to overview")}
|
||||
</a>
|
||||
${this.challenge.invalidationFlowUrl
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { CSRFHeaderName } from "@goauthentik/common/api/middleware";
|
||||
import { EVENT_THEME_CHANGE } from "@goauthentik/common/constants";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { BrandConfig } from "@goauthentik/common/global";
|
||||
import { first, getCookie } from "@goauthentik/common/utils";
|
||||
import { Interface } from "@goauthentik/elements/Interface";
|
||||
import "@goauthentik/elements/ak-locale-context";
|
||||
@ -61,7 +61,7 @@ export class APIBrowser extends Interface {
|
||||
}
|
||||
|
||||
async getTheme(): Promise<UiThemeEnum> {
|
||||
return globalAK()?.brand.uiTheme || UiThemeEnum.Automatic;
|
||||
return BrandConfig.uiTheme || UiThemeEnum.Automatic;
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { BrandConfig } from "@goauthentik/common/global";
|
||||
import { Interface } from "@goauthentik/elements/Interface";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
@ -39,7 +39,7 @@ export class Loading extends Interface {
|
||||
}
|
||||
|
||||
async getTheme(): Promise<UiThemeEnum> {
|
||||
return globalAK()?.brand.uiTheme || UiThemeEnum.Automatic;
|
||||
return BrandConfig.uiTheme || UiThemeEnum.Automatic;
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { PFSize } from "@goauthentik/common/enums.js";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { APIConfig } from "@goauthentik/common/global";
|
||||
import { truncateWords } from "@goauthentik/common/utils";
|
||||
import "@goauthentik/elements/AppIcon";
|
||||
import { AKElement, rootInterface } from "@goauthentik/elements/Base";
|
||||
@ -82,8 +82,7 @@ export class LibraryApplication extends AKElement {
|
||||
? html`
|
||||
<a
|
||||
class="pf-c-button pf-m-control pf-m-small pf-m-block"
|
||||
href="${globalAK().api
|
||||
.base}if/admin/#/core/applications/${application?.slug}"
|
||||
href="${APIConfig.base}if/admin/#/core/applications/${application?.slug}"
|
||||
>
|
||||
<i class="fas fa-edit"></i> ${msg("Edit")}
|
||||
</a>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { docLink, globalAK } from "@goauthentik/common/global";
|
||||
import { APIConfig, docLink } from "@goauthentik/common/global";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
import { paramURL } from "@goauthentik/elements/router/RouterOutlet";
|
||||
|
||||
@ -49,7 +49,7 @@ export class LibraryPageApplicationEmptyList extends AKElement {
|
||||
<a
|
||||
aria-disabled="false"
|
||||
class="cta pf-c-button pf-m-secondary"
|
||||
href="${globalAK().api.base}if/admin/${href}"
|
||||
href="${APIConfig.base}if/admin/${href}"
|
||||
>${msg("Create a new application")}</a
|
||||
>
|
||||
</div>
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
EVENT_NOTIFICATION_DRAWER_TOGGLE,
|
||||
EVENT_WS_MESSAGE,
|
||||
} from "@goauthentik/common/constants";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { APIConfig } from "@goauthentik/common/global";
|
||||
import { configureSentry } from "@goauthentik/common/sentry";
|
||||
import { UIConfig } from "@goauthentik/common/ui/config";
|
||||
import { me } from "@goauthentik/common/users";
|
||||
@ -166,14 +166,14 @@ class UserInterfacePresentation extends AKElement {
|
||||
|
||||
return html`<a
|
||||
class="pf-c-button pf-m-secondary pf-m-small pf-u-display-none pf-u-display-block-on-md"
|
||||
href="${globalAK().api.base}if/admin/"
|
||||
href="${APIConfig.base}if/admin/"
|
||||
slot="extra"
|
||||
>
|
||||
${msg("Admin interface")}
|
||||
</a>
|
||||
<a
|
||||
class="pf-c-button pf-m-secondary pf-m-small pf-u-display-none-on-md pf-u-display-block"
|
||||
href="${globalAK().api.base}if/admin/"
|
||||
href="${APIConfig.base}if/admin/"
|
||||
slot="extra"
|
||||
>
|
||||
${msg("Admin")}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { AndNext } from "@goauthentik/common/api/config";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { APIConfig } from "@goauthentik/common/global";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
@ -32,7 +32,7 @@ export class UserSettingsPassword extends AKElement {
|
||||
<div class="pf-c-card__body">
|
||||
<a
|
||||
href="${ifDefined(this.configureUrl)}${AndNext(
|
||||
`${globalAK().api.relBase}if/user/#/settings;${JSON.stringify({ page: "page-details" })}`,
|
||||
`${APIConfig.relBase}if/user/#/settings;${JSON.stringify({ page: "page-details" })}`,
|
||||
)}"
|
||||
class="pf-c-button pf-m-primary"
|
||||
>
|
||||
|
@ -5,7 +5,7 @@ import {
|
||||
parseAPIResponseError,
|
||||
pluckErrorDetail,
|
||||
} from "@goauthentik/common/errors/network";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { APIConfig } from "@goauthentik/common/global";
|
||||
import { MessageLevel } from "@goauthentik/common/messages";
|
||||
import { refreshMe } from "@goauthentik/common/users";
|
||||
import { AKElement } from "@goauthentik/elements/Base";
|
||||
@ -181,7 +181,7 @@ export class UserSettingsFlowExecutor
|
||||
);
|
||||
return html`
|
||||
<a
|
||||
href="${globalAK().api.base}if/flow/${this.flowSlug}/"
|
||||
href="${APIConfig.base}if/flow/${this.flowSlug}/"
|
||||
class="pf-c-button pf-m-primary"
|
||||
>
|
||||
${msg("Open settings")}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { APIConfig } from "@goauthentik/common/global";
|
||||
import "@goauthentik/elements/forms/HorizontalFormElement";
|
||||
import { PromptStage } from "@goauthentik/flow/stages/prompt/PromptStage";
|
||||
|
||||
@ -51,8 +51,7 @@ export class UserSettingsPromptStage extends PromptStage {
|
||||
${this.host.brand?.flowUnenrollment
|
||||
? html` <a
|
||||
class="pf-c-button pf-m-danger"
|
||||
href="${globalAK().api.base}if/flow/${this.host.brand
|
||||
.flowUnenrollment}/"
|
||||
href="${APIConfig.base}if/flow/${this.host.brand.flowUnenrollment}/"
|
||||
>
|
||||
${msg("Delete account")}
|
||||
</a>`
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { AndNext, DEFAULT_CONFIG } from "@goauthentik/common/api/config";
|
||||
import { globalAK } from "@goauthentik/common/global";
|
||||
import { SentryIgnoredError } from "@goauthentik/common/errors";
|
||||
import { APIConfig } from "@goauthentik/common/global";
|
||||
import { deviceTypeName } from "@goauthentik/common/labels";
|
||||
import { SentryIgnoredError } from "@goauthentik/common/sentry";
|
||||
import { formatElapsedTime } from "@goauthentik/common/temporal";
|
||||
import "@goauthentik/elements/buttons/Dropdown";
|
||||
import "@goauthentik/elements/buttons/ModalButton";
|
||||
@ -74,7 +74,7 @@ export class MFADevicesPage extends Table<Device> {
|
||||
return html`<li>
|
||||
<a
|
||||
href="${ifDefined(stage.configureUrl)}${AndNext(
|
||||
`${globalAK().api.relBase}if/user/#/settings;${JSON.stringify({
|
||||
`${APIConfig.relBase}if/user/#/settings;${JSON.stringify({
|
||||
page: "page-mfa",
|
||||
})}`,
|
||||
)}"
|
||||
|
Reference in New Issue
Block a user