flows: make use of oneOf OpenAPI to annotate all challenge types
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
		@ -25,29 +25,16 @@ import "./stages/identification/IdentificationStage";
 | 
			
		||||
import "./stages/password/PasswordStage";
 | 
			
		||||
import "./stages/prompt/PromptStage";
 | 
			
		||||
import "./sources/plex/PlexLoginInit";
 | 
			
		||||
import { ShellChallenge, RedirectChallenge } from "../api/Flows";
 | 
			
		||||
import { IdentificationChallenge } from "./stages/identification/IdentificationStage";
 | 
			
		||||
import { PasswordChallenge } from "./stages/password/PasswordStage";
 | 
			
		||||
import { ConsentChallenge } from "./stages/consent/ConsentStage";
 | 
			
		||||
import { EmailChallenge } from "./stages/email/EmailStage";
 | 
			
		||||
import { AutosubmitChallenge } from "./stages/autosubmit/AutosubmitStage";
 | 
			
		||||
import { PromptChallenge } from "./stages/prompt/PromptStage";
 | 
			
		||||
import { AuthenticatorTOTPChallenge } from "./stages/authenticator_totp/AuthenticatorTOTPStage";
 | 
			
		||||
import { AuthenticatorStaticChallenge } from "./stages/authenticator_static/AuthenticatorStaticStage";
 | 
			
		||||
import { AuthenticatorValidateStageChallenge } from "./stages/authenticator_validate/AuthenticatorValidateStage";
 | 
			
		||||
import { WebAuthnAuthenticatorRegisterChallenge } from "./stages/authenticator_webauthn/WebAuthnAuthenticatorRegisterStage";
 | 
			
		||||
import { CaptchaChallenge } from "./stages/captcha/CaptchaStage";
 | 
			
		||||
import { StageHost } from "./stages/base";
 | 
			
		||||
import { Challenge, ChallengeChoices, Config, FlowsApi } from "authentik-api";
 | 
			
		||||
import { Challenge, ChallengeChoices, Config, FlowsApi, RedirectChallenge, ShellChallenge } from "authentik-api";
 | 
			
		||||
import { config, DEFAULT_CONFIG } from "../api/Config";
 | 
			
		||||
import { ifDefined } from "lit-html/directives/if-defined";
 | 
			
		||||
import { until } from "lit-html/directives/until";
 | 
			
		||||
import { AccessDeniedChallenge } from "./access_denied/FlowAccessDenied";
 | 
			
		||||
import { PFSize } from "../elements/Spinner";
 | 
			
		||||
import { TITLE_DEFAULT } from "../constants";
 | 
			
		||||
import { configureSentry } from "../api/Sentry";
 | 
			
		||||
import { PlexAuthenticationChallenge } from "./sources/plex/PlexLoginInit";
 | 
			
		||||
import { AuthenticatorDuoChallenge } from "./stages/authenticator_duo/AuthenticatorDuoStage";
 | 
			
		||||
import { ChallengeResponseRequest } from "authentik-api/dist/models/ChallengeResponseRequest";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@customElement("ak-flow-executor")
 | 
			
		||||
export class FlowExecutor extends LitElement implements StageHost {
 | 
			
		||||
@ -112,18 +99,18 @@ export class FlowExecutor extends LitElement implements StageHost {
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    submit<T>(formData?: T): Promise<void> {
 | 
			
		||||
    submit(payload: ChallengeResponseRequest): Promise<void> {
 | 
			
		||||
        payload.component = this.challenge.component;
 | 
			
		||||
        this.loading = true;
 | 
			
		||||
        return new FlowsApi(DEFAULT_CONFIG).flowsExecutorSolveRaw({
 | 
			
		||||
        return new FlowsApi(DEFAULT_CONFIG).flowsExecutorSolve({
 | 
			
		||||
            flowSlug: this.flowSlug,
 | 
			
		||||
            requestBody: formData || {},
 | 
			
		||||
            query: window.location.search.substring(1),
 | 
			
		||||
        }).then((challengeRaw) => {
 | 
			
		||||
            return challengeRaw.raw.json();
 | 
			
		||||
            challengeResponseRequest: payload,
 | 
			
		||||
        }).then((data) => {
 | 
			
		||||
            this.challenge = data;
 | 
			
		||||
            this.postUpdate();
 | 
			
		||||
        }).catch((e: Response) => {
 | 
			
		||||
            console.debug(e);
 | 
			
		||||
            this.errorMessage(e.statusText);
 | 
			
		||||
        }).finally(() => {
 | 
			
		||||
            this.loading = false;
 | 
			
		||||
@ -135,19 +122,18 @@ export class FlowExecutor extends LitElement implements StageHost {
 | 
			
		||||
            this.config = config;
 | 
			
		||||
        });
 | 
			
		||||
        this.loading = true;
 | 
			
		||||
        new FlowsApi(DEFAULT_CONFIG).flowsExecutorGetRaw({
 | 
			
		||||
        new FlowsApi(DEFAULT_CONFIG).flowsExecutorGet({
 | 
			
		||||
            flowSlug: this.flowSlug,
 | 
			
		||||
            query: window.location.search.substring(1),
 | 
			
		||||
        }).then((challengeRaw) => {
 | 
			
		||||
            return challengeRaw.raw.json();
 | 
			
		||||
        }).then((challenge) => {
 | 
			
		||||
            this.challenge = challenge as Challenge;
 | 
			
		||||
            this.challenge = challenge;
 | 
			
		||||
            // Only set background on first update, flow won't change throughout execution
 | 
			
		||||
            if (this.challenge?.background) {
 | 
			
		||||
                this.setBackground(this.challenge.background);
 | 
			
		||||
            }
 | 
			
		||||
            this.postUpdate();
 | 
			
		||||
        }).catch((e: Response) => {
 | 
			
		||||
            console.debug(e);
 | 
			
		||||
            // Catch JSON or Update errors
 | 
			
		||||
            this.errorMessage(e.statusText);
 | 
			
		||||
        }).finally(() => {
 | 
			
		||||
@ -202,35 +188,35 @@ export class FlowExecutor extends LitElement implements StageHost {
 | 
			
		||||
            case ChallengeChoices.Native:
 | 
			
		||||
                switch (this.challenge.component) {
 | 
			
		||||
                    case "ak-stage-access-denied":
 | 
			
		||||
                        return html`<ak-stage-access-denied .host=${this} .challenge=${this.challenge as AccessDeniedChallenge}></ak-stage-access-denied>`;
 | 
			
		||||
                        return html`<ak-stage-access-denied .host=${this} .challenge=${this.challenge}></ak-stage-access-denied>`;
 | 
			
		||||
                    case "ak-stage-identification":
 | 
			
		||||
                        return html`<ak-stage-identification .host=${this} .challenge=${this.challenge as IdentificationChallenge}></ak-stage-identification>`;
 | 
			
		||||
                        return html`<ak-stage-identification .host=${this} .challenge=${this.challenge}></ak-stage-identification>`;
 | 
			
		||||
                    case "ak-stage-password":
 | 
			
		||||
                        return html`<ak-stage-password .host=${this} .challenge=${this.challenge as PasswordChallenge}></ak-stage-password>`;
 | 
			
		||||
                        return html`<ak-stage-password .host=${this} .challenge=${this.challenge}></ak-stage-password>`;
 | 
			
		||||
                    case "ak-stage-captcha":
 | 
			
		||||
                        return html`<ak-stage-captcha .host=${this} .challenge=${this.challenge as CaptchaChallenge}></ak-stage-captcha>`;
 | 
			
		||||
                        return html`<ak-stage-captcha .host=${this} .challenge=${this.challenge}></ak-stage-captcha>`;
 | 
			
		||||
                    case "ak-stage-consent":
 | 
			
		||||
                        return html`<ak-stage-consent .host=${this} .challenge=${this.challenge as ConsentChallenge}></ak-stage-consent>`;
 | 
			
		||||
                        return html`<ak-stage-consent .host=${this} .challenge=${this.challenge}></ak-stage-consent>`;
 | 
			
		||||
                    case "ak-stage-dummy":
 | 
			
		||||
                        return html`<ak-stage-dummy .host=${this} .challenge=${this.challenge as Challenge}></ak-stage-dummy>`;
 | 
			
		||||
                        return html`<ak-stage-dummy .host=${this} .challenge=${this.challenge}></ak-stage-dummy>`;
 | 
			
		||||
                    case "ak-stage-email":
 | 
			
		||||
                        return html`<ak-stage-email .host=${this} .challenge=${this.challenge as EmailChallenge}></ak-stage-email>`;
 | 
			
		||||
                        return html`<ak-stage-email .host=${this} .challenge=${this.challenge}></ak-stage-email>`;
 | 
			
		||||
                    case "ak-stage-autosubmit":
 | 
			
		||||
                        return html`<ak-stage-autosubmit .host=${this} .challenge=${this.challenge as AutosubmitChallenge}></ak-stage-autosubmit>`;
 | 
			
		||||
                        return html`<ak-stage-autosubmit .host=${this} .challenge=${this.challenge}></ak-stage-autosubmit>`;
 | 
			
		||||
                    case "ak-stage-prompt":
 | 
			
		||||
                        return html`<ak-stage-prompt .host=${this} .challenge=${this.challenge as PromptChallenge}></ak-stage-prompt>`;
 | 
			
		||||
                        return html`<ak-stage-prompt .host=${this} .challenge=${this.challenge}></ak-stage-prompt>`;
 | 
			
		||||
                    case "ak-stage-authenticator-totp":
 | 
			
		||||
                        return html`<ak-stage-authenticator-totp .host=${this} .challenge=${this.challenge as AuthenticatorTOTPChallenge}></ak-stage-authenticator-totp>`;
 | 
			
		||||
                        return html`<ak-stage-authenticator-totp .host=${this} .challenge=${this.challenge}></ak-stage-authenticator-totp>`;
 | 
			
		||||
                    case "ak-stage-authenticator-duo":
 | 
			
		||||
                        return html`<ak-stage-authenticator-duo .host=${this} .challenge=${this.challenge as AuthenticatorDuoChallenge}></ak-stage-authenticator-duo>`;
 | 
			
		||||
                        return html`<ak-stage-authenticator-duo .host=${this} .challenge=${this.challenge}></ak-stage-authenticator-duo>`;
 | 
			
		||||
                    case "ak-stage-authenticator-static":
 | 
			
		||||
                        return html`<ak-stage-authenticator-static .host=${this} .challenge=${this.challenge as AuthenticatorStaticChallenge}></ak-stage-authenticator-static>`;
 | 
			
		||||
                        return html`<ak-stage-authenticator-static .host=${this} .challenge=${this.challenge}></ak-stage-authenticator-static>`;
 | 
			
		||||
                    case "ak-stage-authenticator-webauthn":
 | 
			
		||||
                        return html`<ak-stage-authenticator-webauthn .host=${this} .challenge=${this.challenge as WebAuthnAuthenticatorRegisterChallenge}></ak-stage-authenticator-webauthn>`;
 | 
			
		||||
                        return html`<ak-stage-authenticator-webauthn .host=${this} .challenge=${this.challenge}></ak-stage-authenticator-webauthn>`;
 | 
			
		||||
                    case "ak-stage-authenticator-validate":
 | 
			
		||||
                        return html`<ak-stage-authenticator-validate .host=${this} .challenge=${this.challenge as AuthenticatorValidateStageChallenge}></ak-stage-authenticator-validate>`;
 | 
			
		||||
                        return html`<ak-stage-authenticator-validate .host=${this} .challenge=${this.challenge}></ak-stage-authenticator-validate>`;
 | 
			
		||||
                    case "ak-flow-sources-plex":
 | 
			
		||||
                        return html`<ak-flow-sources-plex .host=${this} .challenge=${this.challenge as PlexAuthenticationChallenge}></ak-flow-sources-plex>`;
 | 
			
		||||
                        return html`<ak-flow-sources-plex .host=${this} .challenge=${this.challenge}></ak-flow-sources-plex>`;
 | 
			
		||||
                    default:
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
@ -288,8 +274,7 @@ export class FlowExecutor extends LitElement implements StageHost {
 | 
			
		||||
                            </li>`;
 | 
			
		||||
                        }))}
 | 
			
		||||
                        ${this.config?.brandingTitle != "authentik" ? html`
 | 
			
		||||
                        <li><a href="https://goauthentik.io">${t`Powered by authentik`}</a></li>
 | 
			
		||||
                        ` : html``}
 | 
			
		||||
                        <li><a href="https://goauthentik.io">${t`Powered by authentik`}</a></li>` : html``}
 | 
			
		||||
                    </ul>
 | 
			
		||||
                </footer>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
import { Challenge } from "authentik-api";
 | 
			
		||||
import { AccessDeniedChallenge } from "authentik-api";
 | 
			
		||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
 | 
			
		||||
import { BaseStage } from "../stages/base";
 | 
			
		||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
 | 
			
		||||
@ -12,10 +12,6 @@ import { t } from "@lingui/macro";
 | 
			
		||||
 | 
			
		||||
import "../../elements/EmptyState";
 | 
			
		||||
 | 
			
		||||
export interface AccessDeniedChallenge extends Challenge {
 | 
			
		||||
    error_message?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@customElement("ak-stage-access-denied")
 | 
			
		||||
export class FlowAccessDenied extends BaseStage {
 | 
			
		||||
 | 
			
		||||
@ -45,9 +41,9 @@ export class FlowAccessDenied extends BaseStage {
 | 
			
		||||
                            <i class="pf-icon pf-icon-error-circle-o"></i>
 | 
			
		||||
                            ${t`Request has been denied.`}
 | 
			
		||||
                        </p>
 | 
			
		||||
                        ${this.challenge?.error_message &&
 | 
			
		||||
                        ${this.challenge?.errorMessage &&
 | 
			
		||||
                            html`<hr>
 | 
			
		||||
                            <p>${this.challenge.error_message}</p>`}
 | 
			
		||||
                            <p>${this.challenge.errorMessage}</p>`}
 | 
			
		||||
                    </div>
 | 
			
		||||
                </form>
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { Challenge } from "authentik-api";
 | 
			
		||||
import { PlexAuthenticationChallenge } from "authentik-api";
 | 
			
		||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
 | 
			
		||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
 | 
			
		||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
 | 
			
		||||
@ -16,12 +16,6 @@ import { SourcesApi } from "authentik-api";
 | 
			
		||||
import { showMessage } from "../../../elements/messages/MessageContainer";
 | 
			
		||||
import { MessageLevel } from "../../../elements/messages/Message";
 | 
			
		||||
 | 
			
		||||
export interface PlexAuthenticationChallenge extends Challenge {
 | 
			
		||||
 | 
			
		||||
    client_id: string;
 | 
			
		||||
    slug: string;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@customElement("ak-flow-sources-plex")
 | 
			
		||||
export class PlexLoginInit extends BaseStage {
 | 
			
		||||
@ -34,9 +28,9 @@ export class PlexLoginInit extends BaseStage {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async firstUpdated(): Promise<void> {
 | 
			
		||||
        const authInfo = await PlexAPIClient.getPin(this.challenge?.client_id || "");
 | 
			
		||||
        const authInfo = await PlexAPIClient.getPin(this.challenge?.clientId || "");
 | 
			
		||||
        const authWindow = popupCenterScreen(authInfo.authUrl, "plex auth", 550, 700);
 | 
			
		||||
        PlexAPIClient.pinPoll(this.challenge?.client_id || "", authInfo.pin.id).then(token => {
 | 
			
		||||
        PlexAPIClient.pinPoll(this.challenge?.clientId || "", authInfo.pin.id).then(token => {
 | 
			
		||||
            authWindow?.close();
 | 
			
		||||
            new SourcesApi(DEFAULT_CONFIG).sourcesPlexRedeemTokenCreate({
 | 
			
		||||
                plexTokenRedeemRequest: {
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
 | 
			
		||||
import { WithUserInfoChallenge } from "../../../api/Flows";
 | 
			
		||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
 | 
			
		||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
 | 
			
		||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
 | 
			
		||||
@ -13,15 +12,9 @@ import "../../../elements/forms/FormElement";
 | 
			
		||||
import "../../../elements/EmptyState";
 | 
			
		||||
import "../../FormStatic";
 | 
			
		||||
import { FlowURLManager } from "../../../api/legacy";
 | 
			
		||||
import { StagesApi } from "authentik-api";
 | 
			
		||||
import { AuthenticatorDuoChallenge, StagesApi } from "authentik-api";
 | 
			
		||||
import { DEFAULT_CONFIG } from "../../../api/Config";
 | 
			
		||||
 | 
			
		||||
export interface AuthenticatorDuoChallenge extends WithUserInfoChallenge {
 | 
			
		||||
    activation_barcode: string;
 | 
			
		||||
    activation_code: string;
 | 
			
		||||
    stage_uuid: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@customElement("ak-stage-authenticator-duo")
 | 
			
		||||
export class AuthenticatorDuoStage extends BaseStage {
 | 
			
		||||
 | 
			
		||||
@ -42,10 +35,11 @@ export class AuthenticatorDuoStage extends BaseStage {
 | 
			
		||||
 | 
			
		||||
    checkEnrollStatus(): Promise<void> {
 | 
			
		||||
        return new StagesApi(DEFAULT_CONFIG).stagesAuthenticatorDuoEnrollmentStatusCreate({
 | 
			
		||||
            stageUuid: this.challenge?.stage_uuid || "",
 | 
			
		||||
        }).then(r => {
 | 
			
		||||
            stageUuid: this.challenge?.stageUuid || "",
 | 
			
		||||
        }).then(() => {
 | 
			
		||||
            this.host?.submit({});
 | 
			
		||||
        }).catch(e => {
 | 
			
		||||
        }).catch(() => {
 | 
			
		||||
            console.debug("authentik/flows/duo: Waiting for auth status");
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -65,17 +59,17 @@ export class AuthenticatorDuoStage extends BaseStage {
 | 
			
		||||
                <form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
 | 
			
		||||
                    <ak-form-static
 | 
			
		||||
                        class="pf-c-form__group"
 | 
			
		||||
                        userAvatar="${this.challenge.pending_user_avatar}"
 | 
			
		||||
                        user=${this.challenge.pending_user}>
 | 
			
		||||
                        userAvatar="${this.challenge.pendingUserAvatar}"
 | 
			
		||||
                        user=${this.challenge.pendingUser}>
 | 
			
		||||
                        <div slot="link">
 | 
			
		||||
                            <a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </ak-form-static>
 | 
			
		||||
                    <img src=${this.challenge.activation_barcode} />
 | 
			
		||||
                    <img src=${this.challenge.activationBarcode} />
 | 
			
		||||
                    <p>
 | 
			
		||||
                        ${t`Alternatively, if your current device has Duo installed, click on this link:`}
 | 
			
		||||
                    </p>
 | 
			
		||||
                    <a href=${this.challenge.activation_code}>${t`Duo activation`}</a>
 | 
			
		||||
                    <a href=${this.challenge.activationCode}>${t`Duo activation`}</a>
 | 
			
		||||
 | 
			
		||||
                    <div class="pf-c-form__group pf-m-action">
 | 
			
		||||
                        <button type="button" class="pf-c-button pf-m-primary pf-m-block" @click=${() => {
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { css, CSSResult, customElement, html, property, TemplateResult } from "lit-element";
 | 
			
		||||
import { WithUserInfoChallenge } from "../../../api/Flows";
 | 
			
		||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
 | 
			
		||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
 | 
			
		||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
 | 
			
		||||
@ -13,6 +12,7 @@ import "../../../elements/forms/FormElement";
 | 
			
		||||
import "../../../elements/EmptyState";
 | 
			
		||||
import "../../FormStatic";
 | 
			
		||||
import { FlowURLManager } from "../../../api/legacy";
 | 
			
		||||
import { AuthenticatorStaticChallenge } from "authentik-api";
 | 
			
		||||
 | 
			
		||||
export const STATIC_TOKEN_STYLE = css`
 | 
			
		||||
/* Static OTP Tokens */
 | 
			
		||||
@ -29,9 +29,6 @@ export const STATIC_TOKEN_STYLE = css`
 | 
			
		||||
}
 | 
			
		||||
`;
 | 
			
		||||
 | 
			
		||||
export interface AuthenticatorStaticChallenge extends WithUserInfoChallenge {
 | 
			
		||||
    codes: number[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@customElement("ak-stage-authenticator-static")
 | 
			
		||||
export class AuthenticatorStaticStage extends BaseStage {
 | 
			
		||||
@ -59,8 +56,8 @@ export class AuthenticatorStaticStage extends BaseStage {
 | 
			
		||||
                <form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
 | 
			
		||||
                    <ak-form-static
 | 
			
		||||
                        class="pf-c-form__group"
 | 
			
		||||
                        userAvatar="${this.challenge.pending_user_avatar}"
 | 
			
		||||
                        user=${this.challenge.pending_user}>
 | 
			
		||||
                        userAvatar="${this.challenge.pendingUserAvatar}"
 | 
			
		||||
                        user=${this.challenge.pendingUser}>
 | 
			
		||||
                        <div slot="link">
 | 
			
		||||
                            <a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
 | 
			
		||||
                        </div>
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
 | 
			
		||||
import { WithUserInfoChallenge } from "../../../api/Flows";
 | 
			
		||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
 | 
			
		||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
 | 
			
		||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
 | 
			
		||||
@ -16,10 +15,8 @@ import "../../../elements/EmptyState";
 | 
			
		||||
import "../../FormStatic";
 | 
			
		||||
import { MessageLevel } from "../../../elements/messages/Message";
 | 
			
		||||
import { FlowURLManager } from "../../../api/legacy";
 | 
			
		||||
import { AuthenticatorTOTPChallenge } from "authentik-api";
 | 
			
		||||
 | 
			
		||||
export interface AuthenticatorTOTPChallenge extends WithUserInfoChallenge {
 | 
			
		||||
    config_url: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@customElement("ak-stage-authenticator-totp")
 | 
			
		||||
export class AuthenticatorTOTPStage extends BaseStage {
 | 
			
		||||
@ -47,20 +44,20 @@ export class AuthenticatorTOTPStage extends BaseStage {
 | 
			
		||||
                <form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
 | 
			
		||||
                    <ak-form-static
 | 
			
		||||
                        class="pf-c-form__group"
 | 
			
		||||
                        userAvatar="${this.challenge.pending_user_avatar}"
 | 
			
		||||
                        user=${this.challenge.pending_user}>
 | 
			
		||||
                        userAvatar="${this.challenge.pendingUserAvatar}"
 | 
			
		||||
                        user=${this.challenge.pendingUser}>
 | 
			
		||||
                        <div slot="link">
 | 
			
		||||
                            <a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </ak-form-static>
 | 
			
		||||
                    <input type="hidden" name="otp_uri" value=${this.challenge.config_url} />
 | 
			
		||||
                    <input type="hidden" name="otp_uri" value=${this.challenge.configUrl} />
 | 
			
		||||
                    <ak-form-element>
 | 
			
		||||
                        <!-- @ts-ignore -->
 | 
			
		||||
                        <qr-code data="${this.challenge.config_url}"></qr-code>
 | 
			
		||||
                        <qr-code data="${this.challenge.configUrl}"></qr-code>
 | 
			
		||||
                        <button type="button" class="pf-c-button pf-m-secondary pf-m-progress pf-m-in-progress" @click=${(e: Event) => {
 | 
			
		||||
                            e.preventDefault();
 | 
			
		||||
                            if (!this.challenge?.config_url) return;
 | 
			
		||||
                            navigator.clipboard.writeText(this.challenge?.config_url).then(() => {
 | 
			
		||||
                            if (!this.challenge?.configUrl) return;
 | 
			
		||||
                            navigator.clipboard.writeText(this.challenge?.configUrl).then(() => {
 | 
			
		||||
                                showMessage({
 | 
			
		||||
                                    level: MessageLevel.success,
 | 
			
		||||
                                    message: t`Successfully copied TOTP Config.`
 | 
			
		||||
@ -75,7 +72,7 @@ export class AuthenticatorTOTPStage extends BaseStage {
 | 
			
		||||
                        label="${t`Code`}"
 | 
			
		||||
                        ?required="${true}"
 | 
			
		||||
                        class="pf-c-form__group"
 | 
			
		||||
                        .errors=${(this.challenge?.response_errors || {})["code"]}>
 | 
			
		||||
                        .errors=${(this.challenge?.responseErrors || {})["code"]}>
 | 
			
		||||
                        <!-- @ts-ignore -->
 | 
			
		||||
                        <input type="text"
 | 
			
		||||
                            name="code"
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { css, CSSResult, customElement, html, property, TemplateResult } from "lit-element";
 | 
			
		||||
import { WithUserInfoChallenge } from "../../../api/Flows";
 | 
			
		||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
 | 
			
		||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
 | 
			
		||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
 | 
			
		||||
@ -13,6 +12,9 @@ import "./AuthenticatorValidateStageWebAuthn";
 | 
			
		||||
import "./AuthenticatorValidateStageCode";
 | 
			
		||||
import "./AuthenticatorValidateStageDuo";
 | 
			
		||||
import { PasswordManagerPrefill } from "../identification/IdentificationStage";
 | 
			
		||||
import { DeviceChallenge } from "authentik-api";
 | 
			
		||||
import { AuthenticatorValidationChallenge } from "authentik-api/dist/models/AuthenticatorValidationChallenge";
 | 
			
		||||
import { ChallengeResponseRequest } from "authentik-api/dist/models/ChallengeResponseRequest";
 | 
			
		||||
 | 
			
		||||
export enum DeviceClasses {
 | 
			
		||||
    STATIC = "static",
 | 
			
		||||
@ -21,33 +23,17 @@ export enum DeviceClasses {
 | 
			
		||||
    DUO = "duo",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface DeviceChallenge {
 | 
			
		||||
    device_class: DeviceClasses;
 | 
			
		||||
    device_uid: string;
 | 
			
		||||
    challenge: unknown;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AuthenticatorValidateStageChallenge extends WithUserInfoChallenge {
 | 
			
		||||
    device_challenges: DeviceChallenge[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface AuthenticatorValidateStageChallengeResponse {
 | 
			
		||||
    code?: string;
 | 
			
		||||
    webauthn?: string;
 | 
			
		||||
    duo?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@customElement("ak-stage-authenticator-validate")
 | 
			
		||||
export class AuthenticatorValidateStage extends BaseStage implements StageHost {
 | 
			
		||||
 | 
			
		||||
    @property({ attribute: false })
 | 
			
		||||
    challenge?: AuthenticatorValidateStageChallenge;
 | 
			
		||||
    challenge?: AuthenticatorValidationChallenge;
 | 
			
		||||
 | 
			
		||||
    @property({attribute: false})
 | 
			
		||||
    selectedDeviceChallenge?: DeviceChallenge;
 | 
			
		||||
 | 
			
		||||
    submit<T>(formData?: T): Promise<void> {
 | 
			
		||||
        return this.host?.submit<T>(formData) || Promise.resolve();
 | 
			
		||||
    submit(payload: ChallengeResponseRequest): Promise<void> {
 | 
			
		||||
        return this.host?.submit(payload) || Promise.resolve();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static get styles(): CSSResult[] {
 | 
			
		||||
@ -79,7 +65,7 @@ export class AuthenticatorValidateStage extends BaseStage implements StageHost {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderDevicePickerSingle(deviceChallenge: DeviceChallenge): TemplateResult {
 | 
			
		||||
        switch (deviceChallenge.device_class) {
 | 
			
		||||
        switch (deviceChallenge.deviceClass) {
 | 
			
		||||
            case DeviceClasses.DUO:
 | 
			
		||||
                return html`<i class="fas fa-mobile-alt"></i>
 | 
			
		||||
                    <div class="right">
 | 
			
		||||
@ -124,7 +110,7 @@ export class AuthenticatorValidateStage extends BaseStage implements StageHost {
 | 
			
		||||
    renderDevicePicker(): TemplateResult {
 | 
			
		||||
        return html`
 | 
			
		||||
        <ul>
 | 
			
		||||
            ${this.challenge?.device_challenges.map((challenges) => {
 | 
			
		||||
            ${this.challenge?.deviceChallenges.map((challenges) => {
 | 
			
		||||
                return html`<li>
 | 
			
		||||
                    <button class="pf-c-button authenticator-button" type="button" @click=${() => {
 | 
			
		||||
                        this.selectedDeviceChallenge = challenges;
 | 
			
		||||
@ -140,30 +126,31 @@ export class AuthenticatorValidateStage extends BaseStage implements StageHost {
 | 
			
		||||
        if (!this.selectedDeviceChallenge) {
 | 
			
		||||
            return html``;
 | 
			
		||||
        }
 | 
			
		||||
        switch (this.selectedDeviceChallenge?.device_class) {
 | 
			
		||||
        switch (this.selectedDeviceChallenge?.deviceClass) {
 | 
			
		||||
        case DeviceClasses.STATIC:
 | 
			
		||||
        case DeviceClasses.TOTP:
 | 
			
		||||
            return html`<ak-stage-authenticator-validate-code
 | 
			
		||||
                .host=${this}
 | 
			
		||||
                .host=${this as StageHost}
 | 
			
		||||
                .challenge=${this.challenge}
 | 
			
		||||
                .deviceChallenge=${this.selectedDeviceChallenge}
 | 
			
		||||
                .showBackButton=${(this.challenge?.device_challenges.length || []) > 1}>
 | 
			
		||||
                .showBackButton=${(this.challenge?.deviceChallenges.length || []) > 1}>
 | 
			
		||||
            </ak-stage-authenticator-validate-code>`;
 | 
			
		||||
        case DeviceClasses.WEBAUTHN:
 | 
			
		||||
            return html`<ak-stage-authenticator-validate-webauthn
 | 
			
		||||
                .host=${this}
 | 
			
		||||
                .host=${this as StageHost}
 | 
			
		||||
                .challenge=${this.challenge}
 | 
			
		||||
                .deviceChallenge=${this.selectedDeviceChallenge}
 | 
			
		||||
                .showBackButton=${(this.challenge?.device_challenges.length || []) > 1}>
 | 
			
		||||
                .showBackButton=${(this.challenge?.deviceChallenges.length || []) > 1}>
 | 
			
		||||
            </ak-stage-authenticator-validate-webauthn>`;
 | 
			
		||||
        case DeviceClasses.DUO:
 | 
			
		||||
            return html`<ak-stage-authenticator-validate-duo
 | 
			
		||||
                .host=${this}
 | 
			
		||||
                .host=${this as StageHost}
 | 
			
		||||
                .challenge=${this.challenge}
 | 
			
		||||
                .deviceChallenge=${this.selectedDeviceChallenge}
 | 
			
		||||
                .showBackButton=${(this.challenge?.device_challenges.length || []) > 1}>
 | 
			
		||||
                .showBackButton=${(this.challenge?.deviceChallenges.length || []) > 1}>
 | 
			
		||||
            </ak-stage-authenticator-validate-duo>`;
 | 
			
		||||
        }
 | 
			
		||||
        return html``;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render(): TemplateResult {
 | 
			
		||||
@ -174,8 +161,8 @@ export class AuthenticatorValidateStage extends BaseStage implements StageHost {
 | 
			
		||||
            </ak-empty-state>`;
 | 
			
		||||
        }
 | 
			
		||||
        // User only has a single device class, so we don't show a picker
 | 
			
		||||
        if (this.challenge?.device_challenges.length === 1) {
 | 
			
		||||
            this.selectedDeviceChallenge = this.challenge.device_challenges[0];
 | 
			
		||||
        if (this.challenge?.deviceChallenges.length === 1) {
 | 
			
		||||
            this.selectedDeviceChallenge = this.challenge.deviceChallenges[0];
 | 
			
		||||
        }
 | 
			
		||||
        return html`<header class="pf-c-login__main-header">
 | 
			
		||||
                <h1 class="pf-c-title pf-m-3xl">
 | 
			
		||||
 | 
			
		||||
@ -8,18 +8,20 @@ import PFButton from "@patternfly/patternfly/components/Button/button.css";
 | 
			
		||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
			
		||||
import AKGlobal from "../../../authentik.css";
 | 
			
		||||
import { BaseStage } from "../base";
 | 
			
		||||
import { AuthenticatorValidateStage, AuthenticatorValidateStageChallenge, DeviceChallenge } from "./AuthenticatorValidateStage";
 | 
			
		||||
import { AuthenticatorValidateStage } from "./AuthenticatorValidateStage";
 | 
			
		||||
import "../../../elements/forms/FormElement";
 | 
			
		||||
import "../../../elements/EmptyState";
 | 
			
		||||
import { PasswordManagerPrefill } from "../identification/IdentificationStage";
 | 
			
		||||
import "../../FormStatic";
 | 
			
		||||
import { FlowURLManager } from "../../../api/legacy";
 | 
			
		||||
import { AuthenticatorValidationChallenge } from "authentik-api/dist/models/AuthenticatorValidationChallenge";
 | 
			
		||||
import { DeviceChallenge } from "authentik-api";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-stage-authenticator-validate-code")
 | 
			
		||||
export class AuthenticatorValidateStageWebCode extends BaseStage {
 | 
			
		||||
 | 
			
		||||
    @property({ attribute: false })
 | 
			
		||||
    challenge?: AuthenticatorValidateStageChallenge;
 | 
			
		||||
    challenge?: AuthenticatorValidationChallenge;
 | 
			
		||||
 | 
			
		||||
    @property({ attribute: false })
 | 
			
		||||
    deviceChallenge?: DeviceChallenge;
 | 
			
		||||
@ -42,8 +44,8 @@ export class AuthenticatorValidateStageWebCode extends BaseStage {
 | 
			
		||||
            <form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
 | 
			
		||||
                <ak-form-static
 | 
			
		||||
                    class="pf-c-form__group"
 | 
			
		||||
                    userAvatar="${this.challenge.pending_user_avatar}"
 | 
			
		||||
                    user=${this.challenge.pending_user}>
 | 
			
		||||
                    userAvatar="${this.challenge.pendingUserAvatar}"
 | 
			
		||||
                    user=${this.challenge.pendingUser}>
 | 
			
		||||
                    <div slot="link">
 | 
			
		||||
                        <a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
 | 
			
		||||
                    </div>
 | 
			
		||||
@ -52,7 +54,7 @@ export class AuthenticatorValidateStageWebCode extends BaseStage {
 | 
			
		||||
                    label="${t`Code`}"
 | 
			
		||||
                    ?required="${true}"
 | 
			
		||||
                    class="pf-c-form__group"
 | 
			
		||||
                    .errors=${(this.challenge?.response_errors || {})["code"]}>
 | 
			
		||||
                    .errors=${(this.challenge?.responseErrors || {})["code"]}>
 | 
			
		||||
                    <!-- @ts-ignore -->
 | 
			
		||||
                    <input type="text"
 | 
			
		||||
                        name="code"
 | 
			
		||||
 | 
			
		||||
@ -8,18 +8,19 @@ import PFButton from "@patternfly/patternfly/components/Button/button.css";
 | 
			
		||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
			
		||||
import AKGlobal from "../../../authentik.css";
 | 
			
		||||
import { BaseStage } from "../base";
 | 
			
		||||
import { AuthenticatorValidateStage, AuthenticatorValidateStageChallenge, DeviceChallenge } from "./AuthenticatorValidateStage";
 | 
			
		||||
import { AuthenticatorValidateStage } from "./AuthenticatorValidateStage";
 | 
			
		||||
import "../../../elements/forms/FormElement";
 | 
			
		||||
import "../../../elements/EmptyState";
 | 
			
		||||
import { PasswordManagerPrefill } from "../identification/IdentificationStage";
 | 
			
		||||
import "../../FormStatic";
 | 
			
		||||
import { FlowURLManager } from "../../../api/legacy";
 | 
			
		||||
import { AuthenticatorValidationChallenge } from "authentik-api/dist/models/AuthenticatorValidationChallenge";
 | 
			
		||||
import { DeviceChallenge } from "authentik-api";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-stage-authenticator-validate-duo")
 | 
			
		||||
export class AuthenticatorValidateStageWebDuo extends BaseStage {
 | 
			
		||||
 | 
			
		||||
    @property({ attribute: false })
 | 
			
		||||
    challenge?: AuthenticatorValidateStageChallenge;
 | 
			
		||||
    challenge?: AuthenticatorValidationChallenge;
 | 
			
		||||
 | 
			
		||||
    @property({ attribute: false })
 | 
			
		||||
    deviceChallenge?: DeviceChallenge;
 | 
			
		||||
@ -33,7 +34,7 @@ export class AuthenticatorValidateStageWebDuo extends BaseStage {
 | 
			
		||||
 | 
			
		||||
    firstUpdated(): void {
 | 
			
		||||
        this.host?.submit({
 | 
			
		||||
            "duo": this.deviceChallenge?.device_uid
 | 
			
		||||
            "duo": this.deviceChallenge?.deviceUid
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -48,8 +49,8 @@ export class AuthenticatorValidateStageWebDuo extends BaseStage {
 | 
			
		||||
            <form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
 | 
			
		||||
                <ak-form-static
 | 
			
		||||
                    class="pf-c-form__group"
 | 
			
		||||
                    userAvatar="${this.challenge.pending_user_avatar}"
 | 
			
		||||
                    user=${this.challenge.pending_user}>
 | 
			
		||||
                    userAvatar="${this.challenge.pendingUserAvatar}"
 | 
			
		||||
                    user=${this.challenge.pendingUser}>
 | 
			
		||||
                    <div slot="link">
 | 
			
		||||
                        <a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
 | 
			
		||||
                    </div>
 | 
			
		||||
 | 
			
		||||
@ -10,13 +10,15 @@ import AKGlobal from "../../../authentik.css";
 | 
			
		||||
import { PFSize } from "../../../elements/Spinner";
 | 
			
		||||
import { transformAssertionForServer, transformCredentialRequestOptions } from "../authenticator_webauthn/utils";
 | 
			
		||||
import { BaseStage } from "../base";
 | 
			
		||||
import { AuthenticatorValidateStage, AuthenticatorValidateStageChallenge, DeviceChallenge } from "./AuthenticatorValidateStage";
 | 
			
		||||
import { AuthenticatorValidateStage } from "./AuthenticatorValidateStage";
 | 
			
		||||
import { AuthenticatorValidationChallenge } from "authentik-api/dist/models/AuthenticatorValidationChallenge";
 | 
			
		||||
import { DeviceChallenge } from "authentik-api";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-stage-authenticator-validate-webauthn")
 | 
			
		||||
export class AuthenticatorValidateStageWebAuthn extends BaseStage {
 | 
			
		||||
 | 
			
		||||
    @property({attribute: false})
 | 
			
		||||
    challenge?: AuthenticatorValidateStageChallenge;
 | 
			
		||||
    challenge?: AuthenticatorValidationChallenge;
 | 
			
		||||
 | 
			
		||||
    @property({attribute: false})
 | 
			
		||||
    deviceChallenge?: DeviceChallenge;
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
 | 
			
		||||
import { WithUserInfoChallenge } from "../../../api/Flows";
 | 
			
		||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
 | 
			
		||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
 | 
			
		||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
 | 
			
		||||
@ -11,10 +10,7 @@ import AKGlobal from "../../../authentik.css";
 | 
			
		||||
import { PFSize } from "../../../elements/Spinner";
 | 
			
		||||
import { BaseStage } from "../base";
 | 
			
		||||
import { Assertion, transformCredentialCreateOptions, transformNewAssertionForServer } from "./utils";
 | 
			
		||||
 | 
			
		||||
export interface WebAuthnAuthenticatorRegisterChallenge extends WithUserInfoChallenge {
 | 
			
		||||
    registration: PublicKeyCredentialCreationOptions;
 | 
			
		||||
}
 | 
			
		||||
import { AuthenticatorWebAuthnChallenge } from "authentik-api";
 | 
			
		||||
 | 
			
		||||
export interface WebAuthnAuthenticatorRegisterChallengeResponse {
 | 
			
		||||
    response: Assertion;
 | 
			
		||||
@ -24,7 +20,7 @@ export interface WebAuthnAuthenticatorRegisterChallengeResponse {
 | 
			
		||||
export class WebAuthnAuthenticatorRegisterStage extends BaseStage {
 | 
			
		||||
 | 
			
		||||
    @property({ attribute: false })
 | 
			
		||||
    challenge?: WebAuthnAuthenticatorRegisterChallenge;
 | 
			
		||||
    challenge?: AuthenticatorWebAuthnChallenge;
 | 
			
		||||
 | 
			
		||||
    @property({type: Boolean})
 | 
			
		||||
    registerRunning = false;
 | 
			
		||||
@ -42,7 +38,7 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage {
 | 
			
		||||
        }
 | 
			
		||||
        // convert certain members of the PublicKeyCredentialCreateOptions into
 | 
			
		||||
        // byte arrays as expected by the spec.
 | 
			
		||||
        const publicKeyCredentialCreateOptions = transformCredentialCreateOptions(this.challenge?.registration);
 | 
			
		||||
        const publicKeyCredentialCreateOptions = transformCredentialCreateOptions(this.challenge?.registration as PublicKeyCredentialCreationOptions);
 | 
			
		||||
 | 
			
		||||
        // request the authenticator(s) to create a new credential keypair.
 | 
			
		||||
        let credential;
 | 
			
		||||
@ -106,8 +102,8 @@ export class WebAuthnAuthenticatorRegisterStage extends BaseStage {
 | 
			
		||||
                        </div>`:
 | 
			
		||||
                    html`
 | 
			
		||||
                    <div class="pf-c-form__group pf-m-action">
 | 
			
		||||
                        ${this.challenge?.response_errors ?
 | 
			
		||||
                            html`<p class="pf-m-block">${this.challenge.response_errors["response"][0].string}</p>`:
 | 
			
		||||
                        ${this.challenge?.responseErrors ?
 | 
			
		||||
                            html`<p class="pf-m-block">${this.challenge.responseErrors["response"][0].string}</p>`:
 | 
			
		||||
                            html``}
 | 
			
		||||
                        <p class="pf-m-block">${this.registerMessage}</p>
 | 
			
		||||
                        <button class="pf-c-button pf-m-primary pf-m-block" @click=${() => {
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
 | 
			
		||||
import { WithUserInfoChallenge } from "../../../api/Flows";
 | 
			
		||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
 | 
			
		||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
 | 
			
		||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
 | 
			
		||||
@ -10,11 +9,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
			
		||||
import AKGlobal from "../../../authentik.css";
 | 
			
		||||
import { BaseStage } from "../base";
 | 
			
		||||
import "../../../elements/EmptyState";
 | 
			
		||||
 | 
			
		||||
export interface AutosubmitChallenge extends WithUserInfoChallenge {
 | 
			
		||||
    url: string;
 | 
			
		||||
    attrs: { [key: string]: string };
 | 
			
		||||
}
 | 
			
		||||
import { AutosubmitChallenge } from "authentik-api";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-stage-autosubmit")
 | 
			
		||||
export class AutosubmitStage extends BaseStage {
 | 
			
		||||
 | 
			
		||||
@ -1,20 +1,25 @@
 | 
			
		||||
import { Challenge } from "authentik-api";
 | 
			
		||||
import { ChallengeResponseRequest } from "authentik-api/dist/models/ChallengeResponseRequest";
 | 
			
		||||
import { LitElement } from "lit-element";
 | 
			
		||||
 | 
			
		||||
export interface StageHost {
 | 
			
		||||
    challenge?: Challenge;
 | 
			
		||||
    submit<T>(formData?: T): Promise<void>;
 | 
			
		||||
    submit(payload: ChallengeResponseRequest): Promise<void>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class BaseStage extends LitElement {
 | 
			
		||||
 | 
			
		||||
    host?: StageHost;
 | 
			
		||||
    challenge?: Challenge;
 | 
			
		||||
 | 
			
		||||
    submitForm(e: Event): void {
 | 
			
		||||
        e.preventDefault();
 | 
			
		||||
        const object: {
 | 
			
		||||
            component: string;
 | 
			
		||||
            [key: string]: unknown;
 | 
			
		||||
        } = {};
 | 
			
		||||
        } = {
 | 
			
		||||
            component: this.challenge.component,
 | 
			
		||||
        };
 | 
			
		||||
        const form = new FormData(this.shadowRoot?.querySelector("form") || undefined);
 | 
			
		||||
        form.forEach((value, key) => object[key] = value);
 | 
			
		||||
        this.host?.submit(object);
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
 | 
			
		||||
import { WithUserInfoChallenge } from "../../../api/Flows";
 | 
			
		||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
 | 
			
		||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
 | 
			
		||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
 | 
			
		||||
@ -14,10 +13,7 @@ import "../../../elements/forms/FormElement";
 | 
			
		||||
import "../../../elements/EmptyState";
 | 
			
		||||
import "../../FormStatic";
 | 
			
		||||
import { FlowURLManager } from "../../../api/legacy";
 | 
			
		||||
 | 
			
		||||
export interface CaptchaChallenge extends WithUserInfoChallenge {
 | 
			
		||||
    site_key: string;
 | 
			
		||||
}
 | 
			
		||||
import { CaptchaChallenge } from "authentik-api";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-stage-captcha")
 | 
			
		||||
export class CaptchaStage extends BaseStage {
 | 
			
		||||
@ -39,10 +35,10 @@ export class CaptchaStage extends BaseStage {
 | 
			
		||||
        script.onload = () => {
 | 
			
		||||
            console.debug("authentik/stages/captcha: script loaded");
 | 
			
		||||
            grecaptcha.ready(() => {
 | 
			
		||||
                if (!this.challenge?.site_key) return;
 | 
			
		||||
                if (!this.challenge?.siteKey) return;
 | 
			
		||||
                console.debug("authentik/stages/captcha: ready");
 | 
			
		||||
                const captchaId = grecaptcha.render(captchaContainer, {
 | 
			
		||||
                    sitekey: this.challenge.site_key,
 | 
			
		||||
                    sitekey: this.challenge.siteKey,
 | 
			
		||||
                    callback: (token) => {
 | 
			
		||||
                        this.host?.submit({
 | 
			
		||||
                            "token": token,
 | 
			
		||||
@ -72,8 +68,8 @@ export class CaptchaStage extends BaseStage {
 | 
			
		||||
                <form class="pf-c-form">
 | 
			
		||||
                    <ak-form-static
 | 
			
		||||
                        class="pf-c-form__group"
 | 
			
		||||
                        userAvatar="${this.challenge.pending_user_avatar}"
 | 
			
		||||
                        user=${this.challenge.pending_user}>
 | 
			
		||||
                        userAvatar="${this.challenge.pendingUserAvatar}"
 | 
			
		||||
                        user=${this.challenge.pendingUser}>
 | 
			
		||||
                        <div slot="link">
 | 
			
		||||
                            <a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
 | 
			
		||||
                        </div>
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
 | 
			
		||||
import { WithUserInfoChallenge } from "../../../api/Flows";
 | 
			
		||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
 | 
			
		||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
 | 
			
		||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
 | 
			
		||||
@ -12,18 +11,8 @@ import { BaseStage } from "../base";
 | 
			
		||||
import "../../../elements/EmptyState";
 | 
			
		||||
import "../../FormStatic";
 | 
			
		||||
import { FlowURLManager } from "../../../api/legacy";
 | 
			
		||||
import { ConsentChallenge } from "authentik-api";
 | 
			
		||||
 | 
			
		||||
export interface Permission {
 | 
			
		||||
    name: string;
 | 
			
		||||
    id: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ConsentChallenge extends WithUserInfoChallenge {
 | 
			
		||||
 | 
			
		||||
    header_text: string;
 | 
			
		||||
    permissions?: Permission[];
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@customElement("ak-stage-consent")
 | 
			
		||||
export class ConsentStage extends BaseStage {
 | 
			
		||||
@ -51,15 +40,15 @@ export class ConsentStage extends BaseStage {
 | 
			
		||||
                <form class="pf-c-form" @submit=${(e: Event) => { this.submitForm(e); }}>
 | 
			
		||||
                    <ak-form-static
 | 
			
		||||
                        class="pf-c-form__group"
 | 
			
		||||
                        userAvatar="${this.challenge.pending_user_avatar}"
 | 
			
		||||
                        user=${this.challenge.pending_user}>
 | 
			
		||||
                        userAvatar="${this.challenge.pendingUserAvatar}"
 | 
			
		||||
                        user=${this.challenge.pendingUser}>
 | 
			
		||||
                        <div slot="link">
 | 
			
		||||
                            <a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </ak-form-static>
 | 
			
		||||
                    <div class="pf-c-form__group">
 | 
			
		||||
                        <p id="header-text">
 | 
			
		||||
                            ${this.challenge.header_text}
 | 
			
		||||
                            ${this.challenge.headerText}
 | 
			
		||||
                        </p>
 | 
			
		||||
                        <p>${t`Application requires following permissions`}</p>
 | 
			
		||||
                        <ul class="pf-c-list" id="permmissions">
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
 | 
			
		||||
import { Challenge } from "../../../api/Flows";
 | 
			
		||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
 | 
			
		||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
 | 
			
		||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
 | 
			
		||||
@ -11,12 +10,13 @@ import AKGlobal from "../../../authentik.css";
 | 
			
		||||
import { BaseStage } from "../base";
 | 
			
		||||
import "../../../elements/EmptyState";
 | 
			
		||||
import "../../FormStatic";
 | 
			
		||||
import { DummyChallenge } from "authentik-api";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-stage-dummy")
 | 
			
		||||
export class DummyStage extends BaseStage {
 | 
			
		||||
 | 
			
		||||
    @property({ attribute: false })
 | 
			
		||||
    challenge?: Challenge;
 | 
			
		||||
    challenge?: DummyChallenge;
 | 
			
		||||
 | 
			
		||||
    static get styles(): CSSResult[] {
 | 
			
		||||
        return [PFBase, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal];
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
 | 
			
		||||
import { Challenge } from "authentik-api";
 | 
			
		||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
 | 
			
		||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
 | 
			
		||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
 | 
			
		||||
@ -10,8 +9,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
			
		||||
import AKGlobal from "../../../authentik.css";
 | 
			
		||||
import { BaseStage } from "../base";
 | 
			
		||||
import "../../../elements/EmptyState";
 | 
			
		||||
 | 
			
		||||
export type EmailChallenge = Challenge;
 | 
			
		||||
import { EmailChallenge } from "authentik-api";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-stage-email")
 | 
			
		||||
export class EmailStage extends BaseStage {
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
			
		||||
import AKGlobal from "../../../authentik.css";
 | 
			
		||||
import "../../../elements/forms/FormElement";
 | 
			
		||||
import "../../../elements/EmptyState";
 | 
			
		||||
import { Challenge } from "../../../api/Flows";
 | 
			
		||||
import { IdentificationChallenge, UILoginButton } from "authentik-api";
 | 
			
		||||
 | 
			
		||||
export const PasswordManagerPrefill: {
 | 
			
		||||
    password: string | undefined;
 | 
			
		||||
@ -20,24 +20,6 @@ export const PasswordManagerPrefill: {
 | 
			
		||||
    totp: undefined,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export interface IdentificationChallenge extends Challenge {
 | 
			
		||||
 | 
			
		||||
    user_fields?: string[];
 | 
			
		||||
    primary_action: string;
 | 
			
		||||
    sources?: UILoginButton[];
 | 
			
		||||
 | 
			
		||||
    application_pre?: string;
 | 
			
		||||
 | 
			
		||||
    enroll_url?: string;
 | 
			
		||||
    recovery_url?: string;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface UILoginButton {
 | 
			
		||||
    name: string;
 | 
			
		||||
    challenge: Challenge;
 | 
			
		||||
    icon_url?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@customElement("ak-stage-identification")
 | 
			
		||||
export class IdentificationStage extends BaseStage {
 | 
			
		||||
@ -131,8 +113,8 @@ export class IdentificationStage extends BaseStage {
 | 
			
		||||
 | 
			
		||||
    renderSource(source: UILoginButton): TemplateResult {
 | 
			
		||||
        let icon = html`<i class="fas fas fa-share-square" title="${source.name}"></i>`;
 | 
			
		||||
        if (source.icon_url) {
 | 
			
		||||
            icon = html`<img src="${source.icon_url}" alt="${source.name}">`;
 | 
			
		||||
        if (source.iconUrl) {
 | 
			
		||||
            icon = html`<img src="${source.iconUrl}" alt="${source.name}">`;
 | 
			
		||||
        }
 | 
			
		||||
        return html`<li class="pf-c-login__main-footer-links-item">
 | 
			
		||||
                <button type="button" @click=${() => {
 | 
			
		||||
@ -145,18 +127,18 @@ export class IdentificationStage extends BaseStage {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    renderFooter(): TemplateResult {
 | 
			
		||||
        if (!this.challenge?.enroll_url && !this.challenge?.recovery_url) {
 | 
			
		||||
        if (!this.challenge?.enrollUrl && !this.challenge?.recoveryUrl) {
 | 
			
		||||
            return html``;
 | 
			
		||||
        }
 | 
			
		||||
        return html`<div class="pf-c-login__main-footer-band">
 | 
			
		||||
                ${this.challenge.enroll_url ? html`
 | 
			
		||||
                ${this.challenge.enrollUrl ? html`
 | 
			
		||||
                <p class="pf-c-login__main-footer-band-item">
 | 
			
		||||
                    ${t`Need an account?`}
 | 
			
		||||
                    <a id="enroll" href="${this.challenge.enroll_url}">${t`Sign up.`}</a>
 | 
			
		||||
                    <a id="enroll" href="${this.challenge.enrollUrl}">${t`Sign up.`}</a>
 | 
			
		||||
                </p>` : html``}
 | 
			
		||||
                ${this.challenge.recovery_url ? html`
 | 
			
		||||
                ${this.challenge.recoveryUrl ? html`
 | 
			
		||||
                <p class="pf-c-login__main-footer-band-item">
 | 
			
		||||
                    <a id="recovery" href="${this.challenge.recovery_url}">${t`Forgot username or password?`}</a>
 | 
			
		||||
                    <a id="recovery" href="${this.challenge.recoveryUrl}">${t`Forgot username or password?`}</a>
 | 
			
		||||
                </p>` : html``}
 | 
			
		||||
            </div>`;
 | 
			
		||||
    }
 | 
			
		||||
@ -164,15 +146,15 @@ export class IdentificationStage extends BaseStage {
 | 
			
		||||
    renderInput(): TemplateResult {
 | 
			
		||||
        let label = "";
 | 
			
		||||
        let type = "text";
 | 
			
		||||
        if (!this.challenge?.user_fields) {
 | 
			
		||||
        if (!this.challenge?.userFields) {
 | 
			
		||||
            return html`<p>
 | 
			
		||||
                ${t`Select one of the sources below to login.`}
 | 
			
		||||
            </p>`;
 | 
			
		||||
        }
 | 
			
		||||
        if (this.challenge?.user_fields === ["email"]) {
 | 
			
		||||
        if (this.challenge?.userFields === ["email"]) {
 | 
			
		||||
            label = t`Email`;
 | 
			
		||||
            type = "email";
 | 
			
		||||
        } else if (this.challenge?.user_fields === ["username"]) {
 | 
			
		||||
        } else if (this.challenge?.userFields === ["username"]) {
 | 
			
		||||
            label = t`Username`;
 | 
			
		||||
        } else {
 | 
			
		||||
            label = t`Email or username`;
 | 
			
		||||
@ -181,10 +163,10 @@ export class IdentificationStage extends BaseStage {
 | 
			
		||||
                label=${label}
 | 
			
		||||
                ?required="${true}"
 | 
			
		||||
                class="pf-c-form__group"
 | 
			
		||||
                .errors=${(this.challenge?.response_errors || {})["uid_field"]}>
 | 
			
		||||
                .errors=${(this.challenge?.responseErrors || {})["uidField"]}>
 | 
			
		||||
                <!-- @ts-ignore -->
 | 
			
		||||
                <input type=${type}
 | 
			
		||||
                    name="uid_field"
 | 
			
		||||
                    name="uidField"
 | 
			
		||||
                    placeholder="Email or Username"
 | 
			
		||||
                    autofocus=""
 | 
			
		||||
                    autocomplete="username"
 | 
			
		||||
@ -193,7 +175,7 @@ export class IdentificationStage extends BaseStage {
 | 
			
		||||
            </ak-form-element>
 | 
			
		||||
            <div class="pf-c-form__group pf-m-action">
 | 
			
		||||
                <button type="submit" class="pf-c-button pf-m-primary pf-m-block">
 | 
			
		||||
                    ${this.challenge.primary_action}
 | 
			
		||||
                    ${this.challenge.primaryAction}
 | 
			
		||||
                </button>
 | 
			
		||||
            </div>`;
 | 
			
		||||
    }
 | 
			
		||||
@ -212,9 +194,9 @@ export class IdentificationStage extends BaseStage {
 | 
			
		||||
            </header>
 | 
			
		||||
            <div class="pf-c-login__main-body">
 | 
			
		||||
                <form class="pf-c-form" @submit=${(e: Event) => {this.submitForm(e);}}>
 | 
			
		||||
                    ${this.challenge.application_pre ?
 | 
			
		||||
                    ${this.challenge.applicationPre ?
 | 
			
		||||
                        html`<p>
 | 
			
		||||
                            ${t`Login to continue to ${this.challenge.application_pre}.`}
 | 
			
		||||
                            ${t`Login to continue to ${this.challenge.applicationPre}.`}
 | 
			
		||||
                        </p>`:
 | 
			
		||||
                        html``}
 | 
			
		||||
                    ${this.renderInput()}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,5 @@
 | 
			
		||||
import { t } from "@lingui/macro";
 | 
			
		||||
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
 | 
			
		||||
import { WithUserInfoChallenge } from "../../../api/Flows";
 | 
			
		||||
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
 | 
			
		||||
import PFForm from "@patternfly/patternfly/components/Form/form.css";
 | 
			
		||||
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
 | 
			
		||||
@ -14,10 +13,7 @@ import "../../../elements/EmptyState";
 | 
			
		||||
import { PasswordManagerPrefill } from "../identification/IdentificationStage";
 | 
			
		||||
import "../../FormStatic";
 | 
			
		||||
import { FlowURLManager } from "../../../api/legacy";
 | 
			
		||||
 | 
			
		||||
export interface PasswordChallenge extends WithUserInfoChallenge {
 | 
			
		||||
    recovery_url?: string;
 | 
			
		||||
}
 | 
			
		||||
import { PasswordChallenge } from "authentik-api";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-stage-password")
 | 
			
		||||
export class PasswordStage extends BaseStage {
 | 
			
		||||
@ -45,18 +41,18 @@ export class PasswordStage extends BaseStage {
 | 
			
		||||
                <form class="pf-c-form" @submit=${(e: Event) => {this.submitForm(e);}}>
 | 
			
		||||
                    <ak-form-static
 | 
			
		||||
                        class="pf-c-form__group"
 | 
			
		||||
                        userAvatar="${this.challenge.pending_user_avatar}"
 | 
			
		||||
                        user=${this.challenge.pending_user}>
 | 
			
		||||
                        userAvatar="${this.challenge.pendingUserAvatar}"
 | 
			
		||||
                        user=${this.challenge.pendingUser}>
 | 
			
		||||
                        <div slot="link">
 | 
			
		||||
                            <a href="${FlowURLManager.cancel()}">${t`Not you?`}</a>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </ak-form-static>
 | 
			
		||||
                    <input name="username" autocomplete="username" type="hidden" value="${this.challenge.pending_user}">
 | 
			
		||||
                    <input name="username" autocomplete="username" type="hidden" value="${this.challenge.pendingUser}">
 | 
			
		||||
                    <ak-form-element
 | 
			
		||||
                        label="${t`Password`}"
 | 
			
		||||
                        ?required="${true}"
 | 
			
		||||
                        class="pf-c-form__group"
 | 
			
		||||
                        .errors=${(this.challenge?.response_errors || {})["password"]}>
 | 
			
		||||
                        .errors=${(this.challenge?.responseErrors || {})["password"]}>
 | 
			
		||||
                        <input type="password"
 | 
			
		||||
                            name="password"
 | 
			
		||||
                            placeholder="${t`Please enter your password`}"
 | 
			
		||||
@ -67,8 +63,8 @@ export class PasswordStage extends BaseStage {
 | 
			
		||||
                            value=${PasswordManagerPrefill.password || ""}>
 | 
			
		||||
                    </ak-form-element>
 | 
			
		||||
 | 
			
		||||
                    ${this.challenge.recovery_url ?
 | 
			
		||||
                        html`<a href="${this.challenge.recovery_url}">
 | 
			
		||||
                    ${this.challenge.recoveryUrl ?
 | 
			
		||||
                        html`<a href="${this.challenge.recoveryUrl}">
 | 
			
		||||
                        ${t`Forgot password?`}</a>` : ""}
 | 
			
		||||
 | 
			
		||||
                    <div class="pf-c-form__group pf-m-action">
 | 
			
		||||
 | 
			
		||||
@ -13,20 +13,9 @@ import { BaseStage } from "../base";
 | 
			
		||||
import "../../../elements/forms/FormElement";
 | 
			
		||||
import "../../../elements/EmptyState";
 | 
			
		||||
import "../../../elements/Divider";
 | 
			
		||||
import { Challenge, Error } from "../../../api/Flows";
 | 
			
		||||
import { Error } from "../../../api/Flows";
 | 
			
		||||
import { Prompt, PromptChallenge } from "authentik-api";
 | 
			
		||||
 | 
			
		||||
export interface Prompt {
 | 
			
		||||
    field_key: string;
 | 
			
		||||
    label: string;
 | 
			
		||||
    type: string;
 | 
			
		||||
    required: boolean;
 | 
			
		||||
    placeholder: string;
 | 
			
		||||
    order: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface PromptChallenge extends Challenge {
 | 
			
		||||
    fields: Prompt[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@customElement("ak-stage-prompt")
 | 
			
		||||
export class PromptStage extends BaseStage {
 | 
			
		||||
@ -43,7 +32,7 @@ export class PromptStage extends BaseStage {
 | 
			
		||||
            case "text":
 | 
			
		||||
                return `<input
 | 
			
		||||
                    type="text"
 | 
			
		||||
                    name="${prompt.field_key}"
 | 
			
		||||
                    name="${prompt.fieldKey}"
 | 
			
		||||
                    placeholder="${prompt.placeholder}"
 | 
			
		||||
                    autocomplete="off"
 | 
			
		||||
                    class="pf-c-form-control"
 | 
			
		||||
@ -52,7 +41,7 @@ export class PromptStage extends BaseStage {
 | 
			
		||||
            case "username":
 | 
			
		||||
                return `<input
 | 
			
		||||
                    type="text"
 | 
			
		||||
                    name="${prompt.field_key}"
 | 
			
		||||
                    name="${prompt.fieldKey}"
 | 
			
		||||
                    placeholder="${prompt.placeholder}"
 | 
			
		||||
                    autocomplete="username"
 | 
			
		||||
                    class="pf-c-form-control"
 | 
			
		||||
@ -61,7 +50,7 @@ export class PromptStage extends BaseStage {
 | 
			
		||||
            case "email":
 | 
			
		||||
                return `<input
 | 
			
		||||
                    type="email"
 | 
			
		||||
                    name="${prompt.field_key}"
 | 
			
		||||
                    name="${prompt.fieldKey}"
 | 
			
		||||
                    placeholder="${prompt.placeholder}"
 | 
			
		||||
                    class="pf-c-form-control"
 | 
			
		||||
                    ?required=${prompt.required}
 | 
			
		||||
@ -69,7 +58,7 @@ export class PromptStage extends BaseStage {
 | 
			
		||||
            case "password":
 | 
			
		||||
                return `<input
 | 
			
		||||
                    type="password"
 | 
			
		||||
                    name="${prompt.field_key}"
 | 
			
		||||
                    name="${prompt.fieldKey}"
 | 
			
		||||
                    placeholder="${prompt.placeholder}"
 | 
			
		||||
                    autocomplete="new-password"
 | 
			
		||||
                    class="pf-c-form-control"
 | 
			
		||||
@ -77,28 +66,28 @@ export class PromptStage extends BaseStage {
 | 
			
		||||
            case "number":
 | 
			
		||||
                return `<input
 | 
			
		||||
                    type="number"
 | 
			
		||||
                    name="${prompt.field_key}"
 | 
			
		||||
                    name="${prompt.fieldKey}"
 | 
			
		||||
                    placeholder="${prompt.placeholder}"
 | 
			
		||||
                    class="pf-c-form-control"
 | 
			
		||||
                    ?required=${prompt.required}>`;
 | 
			
		||||
            case "checkbox":
 | 
			
		||||
                return `<input
 | 
			
		||||
                    type="checkbox"
 | 
			
		||||
                    name="${prompt.field_key}"
 | 
			
		||||
                    name="${prompt.fieldKey}"
 | 
			
		||||
                    placeholder="${prompt.placeholder}"
 | 
			
		||||
                    class="pf-c-form-control"
 | 
			
		||||
                    ?required=${prompt.required}>`;
 | 
			
		||||
            case "date":
 | 
			
		||||
                return `<input
 | 
			
		||||
                    type="date"
 | 
			
		||||
                    name="${prompt.field_key}"
 | 
			
		||||
                    name="${prompt.fieldKey}"
 | 
			
		||||
                    placeholder="${prompt.placeholder}"
 | 
			
		||||
                    class="pf-c-form-control"
 | 
			
		||||
                    ?required=${prompt.required}>`;
 | 
			
		||||
            case "date-time":
 | 
			
		||||
                return `<input
 | 
			
		||||
                    type="datetime"
 | 
			
		||||
                    name="${prompt.field_key}"
 | 
			
		||||
                    name="${prompt.fieldKey}"
 | 
			
		||||
                    placeholder="${prompt.placeholder}"
 | 
			
		||||
                    class="pf-c-form-control"
 | 
			
		||||
                    ?required=${prompt.required}>`;
 | 
			
		||||
@ -107,7 +96,7 @@ export class PromptStage extends BaseStage {
 | 
			
		||||
            case "hidden":
 | 
			
		||||
                return `<input
 | 
			
		||||
                    type="hidden"
 | 
			
		||||
                    name="${prompt.field_key}"
 | 
			
		||||
                    name="${prompt.fieldKey}"
 | 
			
		||||
                    value="${prompt.placeholder}"
 | 
			
		||||
                    class="pf-c-form-control"
 | 
			
		||||
                    ?required=${prompt.required}>`;
 | 
			
		||||
@ -158,12 +147,12 @@ export class PromptStage extends BaseStage {
 | 
			
		||||
                            label="${prompt.label}"
 | 
			
		||||
                            ?required="${prompt.required}"
 | 
			
		||||
                            class="pf-c-form__group"
 | 
			
		||||
                            .errors=${(this.challenge?.response_errors || {})[prompt.field_key]}>
 | 
			
		||||
                            .errors=${(this.challenge?.responseErrors || {})[prompt.fieldKey]}>
 | 
			
		||||
                            ${unsafeHTML(this.renderPromptInner(prompt))}
 | 
			
		||||
                        </ak-form-element>`;
 | 
			
		||||
                    })}
 | 
			
		||||
                    ${"non_field_errors" in (this.challenge?.response_errors || {}) ?
 | 
			
		||||
                        this.renderNonFieldErrors(this.challenge?.response_errors?.non_field_errors || []):
 | 
			
		||||
                    ${"non_field_errors" in (this.challenge?.responseErrors || {}) ?
 | 
			
		||||
                        this.renderNonFieldErrors(this.challenge?.responseErrors?.non_field_errors || []):
 | 
			
		||||
                        html``}
 | 
			
		||||
                    <div class="pf-c-form__group pf-m-action">
 | 
			
		||||
                        <button type="submit" class="pf-c-button pf-m-primary pf-m-block">
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user