mirror of
https://github.com/goauthentik/authentik.git
synced 2026-06-17 19:09:11 +03:00
52674afa8a
* ## What
window.authentik.flow = {
"layout": "{{ flow.layout }}",
+ "background": "{{ flow.background }}",
+ "title": "{{ flow.title }}",
};
Amends the `flow.html` template and `GlobalAuthentik` parser to include new parameters, `background` and `title`, in the flow-specific part of the configuration written to the HTML `<head>` object, and to provide those parameters to client code.
## Why
The `layout` is start-up critical: it tells the Flow interface how the admin wants the Flow page to look, and allows the HTML and CSS to be pre-aligned to that condition. `layout` is determined on a per-Flow bases, not a per-Stage basis; Flows are derived from a tuple of `(Brand, Application?)`, where the opening policy *may* direct a user to a different flow if the user reached authentik via a redirect from a specific application, but will otherwise fall back to the default Flow for the Brand.
The `background` is a field that is required if the `Flow`’s layout is of type `frame_background`; in this case, the part of the viewport not dedicated to the FlowExecutor is reserved for an `<iframe>` that will be filled in with whatever the administrator specifies. Although this gives it the same priority as `layout` (whether it’s provided or undefined) for describing the [chrome](https://developer.mozilla.org/en-US/docs/Glossary/Chrome) around a challenge, it is currently not provided to the application in the start-up config; it is provided in the `challenge` and renders the IFrame as part of the initial challenge.
This patch fixes that; if `layout` is provided, `background` ought to be as well, even if it’s empty. The execution of a Challenge ought not have any influence over the look and feel of the Flow-defined appearance *around* that Challenge.
I have added `title` as well; with that, all of the current theme-and-appearance related configuration details are placed into `<head>` and can be removed from the FlowExecutor.
Server-side, `background` is currently specified: `background = FileField(blank=True, default="")` which is … interesting since we also appear to store URLs in it. I don’t see anything in the FlowSerializer that would change that from a client’s point of view.
This patch furthers the effort to separate flow execution from flow presentation.
- \[🐰\] The code has been formatted (`make web`)
* web/update: update `secret text` to enable password-like inputs
# What
Adds a flag to ak-secret-text-input so that most secret texts are more password-like than plain-text-with-hidden. plain-text-with-hidden can still be enabled.
# Why
Some customers were uncomfortable with fields named “password” showing input as plain text during object creation.
* web/update: update `secret text` to enable password-like inputs
# What
Adds a flag to ak-secret-text-input so that most secret texts are more password-like than plain-text-with-hidden. plain-text-with-hidden can still be enabled.
# Why
Some customers were uncomfortable with fields named “password” showing input as plain text during object creation.
127 lines
3.9 KiB
TypeScript
127 lines
3.9 KiB
TypeScript
import { HorizontalLightComponent } from "./HorizontalLightComponent.js";
|
|
|
|
import { ifPresent } from "#elements/utils/attributes";
|
|
|
|
import { msg } from "@lit/localize";
|
|
import { html, PropertyValues } from "lit";
|
|
import { customElement, property } from "lit/decorators.js";
|
|
import { classMap } from "lit/directives/class-map.js";
|
|
import { ifDefined } from "lit/directives/if-defined.js";
|
|
import { createRef, ref } from "lit/directives/ref.js";
|
|
import { styleMap } from "lit/directives/style-map.js";
|
|
|
|
@customElement("ak-secret-text-input")
|
|
export class AkSecretTextInput extends HorizontalLightComponent<string> {
|
|
@property({ type: String })
|
|
public value = "";
|
|
|
|
@property({ type: Boolean, reflect: true })
|
|
public revealed = false;
|
|
|
|
@property({ type: Boolean, reflect: true })
|
|
public plaintext = false;
|
|
|
|
@property({ type: String })
|
|
public placeholder = "";
|
|
|
|
@property({ type: Number, attribute: "maxlength" })
|
|
public maxLength?: number;
|
|
|
|
@property({ type: Number, attribute: "minlength" })
|
|
public minLength?: number;
|
|
|
|
public reveal = () => {
|
|
this.revealed = true;
|
|
};
|
|
|
|
#inputListener = (ev: InputEvent) => {
|
|
this.value = (ev.target as HTMLInputElement).value;
|
|
};
|
|
|
|
#ref = createRef<HTMLInputElement>();
|
|
|
|
public override updated(changedProperties: PropertyValues<this>): void {
|
|
super.updated(changedProperties);
|
|
|
|
if (changedProperties.has("revealed") && this.revealed) {
|
|
this.#ref.value?.focus();
|
|
}
|
|
}
|
|
|
|
#renderSecretInput() {
|
|
return html`<div
|
|
class="pf-c-form__horizontal-group"
|
|
style=${styleMap({
|
|
display: "flex",
|
|
gap: "var(--pf-global--spacer--sm)",
|
|
})}
|
|
>
|
|
<input
|
|
@click=${this.reveal}
|
|
id=${this.fieldID}
|
|
aria-describedby=${this.helpID}
|
|
class="pf-c-form-control"
|
|
type="password"
|
|
disabled
|
|
data-form-ignore="true"
|
|
value="**************"
|
|
/>
|
|
<input
|
|
type="text"
|
|
value="${ifDefined(this.value)}"
|
|
?required=${this.required}
|
|
name=${ifDefined(this.name)}
|
|
hidden
|
|
/>
|
|
<button
|
|
id=${this.helpID}
|
|
class="pf-c-button pf-m-tertiary pf-m-inline"
|
|
type="button"
|
|
@click=${this.reveal}
|
|
>
|
|
${msg("Modify", {
|
|
id: "ak-secret-text-input.actions.modify",
|
|
desc: "Help text for secret input field to indicate that clicking will allow changing the value.",
|
|
})}
|
|
</button>
|
|
</div>`;
|
|
}
|
|
|
|
protected renderVisibleInput() {
|
|
const code = this.inputHint === "code";
|
|
const classes = {
|
|
"pf-c-form-control": true,
|
|
"pf-m-monospace": code,
|
|
};
|
|
|
|
return html`<input
|
|
${ref(this.#ref)}
|
|
type=${this.plaintext ? "text" : "password"}
|
|
id=${this.fieldID}
|
|
aria-describedby=${this.helpID}
|
|
@input=${this.#inputListener}
|
|
name=${ifDefined(this.name)}
|
|
value=${ifDefined(this.value)}
|
|
class="${classMap(classes)}"
|
|
maxlength=${ifPresent(this.maxLength)}
|
|
minlength=${ifPresent(this.minLength)}
|
|
placeholder=${ifPresent(this.placeholder)}
|
|
autocomplete=${ifDefined(code ? "off" : undefined)}
|
|
spellcheck=${ifDefined(code ? "false" : undefined)}
|
|
?required=${this.required}
|
|
/>`;
|
|
}
|
|
|
|
public override renderControl() {
|
|
return this.revealed ? this.renderVisibleInput() : this.#renderSecretInput();
|
|
}
|
|
}
|
|
|
|
export default AkSecretTextInput;
|
|
|
|
declare global {
|
|
interface HTMLElementTagNameMap {
|
|
"ak-secret-text-input": AkSecretTextInput;
|
|
}
|
|
}
|