web/flow: render prompt inputs without unsafeHTML (#5404)
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
parent
af7cc8d42d
commit
a8332eced6
|
@ -50,147 +50,151 @@ export class PromptStage extends BaseStage<PromptChallenge, PromptChallengeRespo
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPromptInner(prompt: StagePrompt): string {
|
renderPromptInner(prompt: StagePrompt): TemplateResult {
|
||||||
switch (prompt.type) {
|
switch (prompt.type) {
|
||||||
case PromptTypeEnum.Text:
|
case PromptTypeEnum.Text:
|
||||||
return `<input
|
return html`<input
|
||||||
type="text"
|
type="text"
|
||||||
name="${prompt.fieldKey}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
?required=${prompt.required}
|
?required=${prompt.required}
|
||||||
value="${prompt.initialValue}">`;
|
value="${prompt.initialValue}"
|
||||||
|
/>`;
|
||||||
case PromptTypeEnum.TextArea:
|
case PromptTypeEnum.TextArea:
|
||||||
return `<textarea
|
return html`<textarea
|
||||||
type="text"
|
type="text"
|
||||||
name="${prompt.fieldKey}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
?required=${prompt.required}
|
?required=${prompt.required}
|
||||||
value="${prompt.initialValue}"">`;
|
value="${prompt.initialValue}"
|
||||||
|
></textarea>`;
|
||||||
case PromptTypeEnum.TextReadOnly:
|
case PromptTypeEnum.TextReadOnly:
|
||||||
return `<input
|
return html`<input
|
||||||
type="text"
|
type="text"
|
||||||
name="${prompt.fieldKey}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
readonly
|
readonly
|
||||||
value="${prompt.initialValue}">`;
|
value="${prompt.initialValue}"
|
||||||
|
/>`;
|
||||||
case PromptTypeEnum.TextAreaReadOnly:
|
case PromptTypeEnum.TextAreaReadOnly:
|
||||||
return `<textarea
|
return html`<textarea
|
||||||
type="text"
|
type="text"
|
||||||
name="${prompt.fieldKey}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
readonly
|
readonly
|
||||||
value="${prompt.initialValue}">`;
|
value="${prompt.initialValue}"
|
||||||
|
></textarea>`;
|
||||||
case PromptTypeEnum.Username:
|
case PromptTypeEnum.Username:
|
||||||
return `<input
|
return html`<input
|
||||||
type="text"
|
type="text"
|
||||||
name="${prompt.fieldKey}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
autocomplete="username"
|
autocomplete="username"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
?required=${prompt.required}
|
?required=${prompt.required}
|
||||||
value="${prompt.initialValue}">`;
|
value="${prompt.initialValue}"
|
||||||
|
/>`;
|
||||||
case PromptTypeEnum.Email:
|
case PromptTypeEnum.Email:
|
||||||
return `<input
|
return html`<input
|
||||||
type="email"
|
type="email"
|
||||||
name="${prompt.fieldKey}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
?required=${prompt.required}
|
?required=${prompt.required}
|
||||||
value="${prompt.initialValue}">`;
|
value="${prompt.initialValue}"
|
||||||
|
/>`;
|
||||||
case PromptTypeEnum.Password:
|
case PromptTypeEnum.Password:
|
||||||
return `<input
|
return html`<input
|
||||||
type="password"
|
type="password"
|
||||||
name="${prompt.fieldKey}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
autocomplete="new-password"
|
autocomplete="new-password"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
?required=${prompt.required}>`;
|
?required=${prompt.required}
|
||||||
|
/>`;
|
||||||
case PromptTypeEnum.Number:
|
case PromptTypeEnum.Number:
|
||||||
return `<input
|
return html`<input
|
||||||
type="number"
|
type="number"
|
||||||
name="${prompt.fieldKey}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
?required=${prompt.required}
|
?required=${prompt.required}
|
||||||
value="${prompt.initialValue}">`;
|
value="${prompt.initialValue}"
|
||||||
|
/>`;
|
||||||
case PromptTypeEnum.Date:
|
case PromptTypeEnum.Date:
|
||||||
return `<input
|
return html`<input
|
||||||
type="date"
|
type="date"
|
||||||
name="${prompt.fieldKey}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
?required=${prompt.required}
|
?required=${prompt.required}
|
||||||
value="${prompt.initialValue}">`;
|
value="${prompt.initialValue}"
|
||||||
|
/>`;
|
||||||
case PromptTypeEnum.DateTime:
|
case PromptTypeEnum.DateTime:
|
||||||
return `<input
|
return html`<input
|
||||||
type="datetime"
|
type="datetime"
|
||||||
name="${prompt.fieldKey}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
?required=${prompt.required}
|
?required=${prompt.required}
|
||||||
value="${prompt.initialValue}">`;
|
value="${prompt.initialValue}"
|
||||||
|
/>`;
|
||||||
case PromptTypeEnum.File:
|
case PromptTypeEnum.File:
|
||||||
return `<input
|
return html`<input
|
||||||
type="file"
|
type="file"
|
||||||
name="${prompt.fieldKey}"
|
name="${prompt.fieldKey}"
|
||||||
placeholder="${prompt.placeholder}"
|
placeholder="${prompt.placeholder}"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
?required=${prompt.required}
|
?required=${prompt.required}
|
||||||
value="${prompt.initialValue}">`;
|
value="${prompt.initialValue}"
|
||||||
|
/>`;
|
||||||
case PromptTypeEnum.Separator:
|
case PromptTypeEnum.Separator:
|
||||||
return `<ak-divider>${prompt.placeholder}</ak-divider>`;
|
return html`<ak-divider>${prompt.placeholder}</ak-divider>`;
|
||||||
case PromptTypeEnum.Hidden:
|
case PromptTypeEnum.Hidden:
|
||||||
return `<input
|
return html`<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
name="${prompt.fieldKey}"
|
name="${prompt.fieldKey}"
|
||||||
value="${prompt.initialValue}"
|
value="${prompt.initialValue}"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
?required=${prompt.required}>`;
|
?required=${prompt.required}
|
||||||
|
/>`;
|
||||||
case PromptTypeEnum.Static:
|
case PromptTypeEnum.Static:
|
||||||
return `<p>${prompt.initialValue}</p>`;
|
return html`<p>${unsafeHTML(prompt.initialValue)}</p>`;
|
||||||
case PromptTypeEnum.Dropdown:
|
case PromptTypeEnum.Dropdown:
|
||||||
return `<select class="pf-c-form-control" name="${prompt.fieldKey}">
|
return html`<select class="pf-c-form-control" name="${prompt.fieldKey}">
|
||||||
${prompt.choices
|
${prompt.choices?.map((choice) => {
|
||||||
?.map((choice) => {
|
return html`<option
|
||||||
return `<option
|
|
||||||
value="${choice}"
|
value="${choice}"
|
||||||
?selected=${prompt.initialValue === choice}
|
?selected=${prompt.initialValue === choice}
|
||||||
>
|
>
|
||||||
${choice}
|
${choice}
|
||||||
</option>`;
|
</option>`;
|
||||||
})
|
})}
|
||||||
.join("")}
|
|
||||||
</select>`;
|
</select>`;
|
||||||
case PromptTypeEnum.RadioButtonGroup:
|
case PromptTypeEnum.RadioButtonGroup:
|
||||||
return (
|
return html`${(prompt.choices || []).map((choice) => {
|
||||||
prompt.choices
|
const id = `${prompt.fieldKey}-${choice}`;
|
||||||
?.map((choice) => {
|
return html`<div class="pf-c-check">
|
||||||
return ` <div class="pf-c-check">
|
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
class="pf-c-check__input"
|
class="pf-c-check__input"
|
||||||
id="${prompt.fieldKey}"
|
|
||||||
name="${prompt.fieldKey}"
|
name="${prompt.fieldKey}"
|
||||||
|
id="${id}"
|
||||||
checked="${prompt.initialValue === choice}"
|
checked="${prompt.initialValue === choice}"
|
||||||
required="${prompt.required}"
|
required="${prompt.required}"
|
||||||
value="${choice}"
|
value="${choice}"
|
||||||
/>
|
/>
|
||||||
<label class="pf-c-check__label" for="${
|
<label class="pf-c-check__label" for=${id}>${choice}</label>
|
||||||
prompt.fieldKey
|
</div> `;
|
||||||
}">${choice}</label>
|
})}`;
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
})
|
|
||||||
.join("") || ""
|
|
||||||
);
|
|
||||||
case PromptTypeEnum.AkLocale:
|
case PromptTypeEnum.AkLocale:
|
||||||
return `<select class="pf-c-form-control" name="${prompt.fieldKey}">
|
return html`<select class="pf-c-form-control" name="${prompt.fieldKey}">
|
||||||
<option value="" ${prompt.initialValue === "" ? "selected" : ""}>
|
<option value="" ${prompt.initialValue === "" ? "selected" : ""}>
|
||||||
${t`Auto-detect (based on your browser)`}
|
${t`Auto-detect (based on your browser)`}
|
||||||
</option>
|
</option>
|
||||||
|
@ -202,19 +206,17 @@ export class PromptStage extends BaseStage<PromptChallenge, PromptChallengeRespo
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
})
|
}).map((locale) => {
|
||||||
.map((locale) => {
|
return html`<option
|
||||||
return `<option
|
|
||||||
value=${locale.code}
|
value=${locale.code}
|
||||||
${prompt.initialValue === locale.code ? "selected" : ""}
|
${prompt.initialValue === locale.code ? "selected" : ""}
|
||||||
>
|
>
|
||||||
${locale.code.toUpperCase()} - ${locale.label}
|
${locale.code.toUpperCase()} - ${locale.label}
|
||||||
</option>`;
|
</option>`;
|
||||||
})
|
})}
|
||||||
.join("")}
|
|
||||||
</select>`;
|
</select>`;
|
||||||
default:
|
default:
|
||||||
return `<p>invalid type '${prompt.type}'</p>`;
|
return html`<p>invalid type '${prompt.type}'</p>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,11 +265,10 @@ export class PromptStage extends BaseStage<PromptChallenge, PromptChallengeRespo
|
||||||
class="pf-c-form__group"
|
class="pf-c-form__group"
|
||||||
.errors=${(this.challenge?.responseErrors || {})[prompt.fieldKey]}
|
.errors=${(this.challenge?.responseErrors || {})[prompt.fieldKey]}
|
||||||
>
|
>
|
||||||
${unsafeHTML(this.renderPromptInner(prompt))} ${this.renderPromptHelpText(prompt)}
|
${this.renderPromptInner(prompt)} ${this.renderPromptHelpText(prompt)}
|
||||||
</ak-form-element>`;
|
</ak-form-element>`;
|
||||||
}
|
}
|
||||||
return html` ${unsafeHTML(this.renderPromptInner(prompt))}
|
return html` ${this.renderPromptInner(prompt)} ${this.renderPromptHelpText(prompt)}`;
|
||||||
${this.renderPromptHelpText(prompt)}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderContinue(): TemplateResult {
|
renderContinue(): TemplateResult {
|
||||||
|
|
|
@ -5,17 +5,16 @@ import { t } from "@lingui/macro";
|
||||||
|
|
||||||
import { TemplateResult, html } from "lit";
|
import { TemplateResult, html } from "lit";
|
||||||
import { customElement } from "lit/decorators.js";
|
import { customElement } from "lit/decorators.js";
|
||||||
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
|
||||||
|
|
||||||
import { PromptTypeEnum, StagePrompt } from "@goauthentik/api";
|
import { PromptTypeEnum, StagePrompt } from "@goauthentik/api";
|
||||||
|
|
||||||
@customElement("ak-user-stage-prompt")
|
@customElement("ak-user-stage-prompt")
|
||||||
export class UserSettingsPromptStage extends PromptStage {
|
export class UserSettingsPromptStage extends PromptStage {
|
||||||
renderPromptInner(prompt: StagePrompt): string {
|
renderPromptInner(prompt: StagePrompt): TemplateResult {
|
||||||
switch (prompt.type) {
|
switch (prompt.type) {
|
||||||
// Checkbox requires slightly different rendering here due to the use of horizontal form elements
|
// Checkbox requires slightly different rendering here due to the use of horizontal form elements
|
||||||
case PromptTypeEnum.Checkbox:
|
case PromptTypeEnum.Checkbox:
|
||||||
return `<input
|
return html`<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
class="pf-c-check__input"
|
class="pf-c-check__input"
|
||||||
name="${prompt.fieldKey}"
|
name="${prompt.fieldKey}"
|
||||||
|
@ -41,14 +40,11 @@ export class UserSettingsPromptStage extends PromptStage {
|
||||||
return error.string;
|
return error.string;
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
${unsafeHTML(this.renderPromptInner(prompt))}
|
${this.renderPromptInner(prompt)} ${this.renderPromptHelpText(prompt)}
|
||||||
${this.renderPromptHelpText(prompt)}
|
|
||||||
</ak-form-element-horizontal>
|
</ak-form-element-horizontal>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
return html`
|
return html` ${this.renderPromptInner(prompt)} ${this.renderPromptHelpText(prompt)} `;
|
||||||
${unsafeHTML(this.renderPromptInner(prompt))} ${this.renderPromptHelpText(prompt)}
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderContinue(): TemplateResult {
|
renderContinue(): TemplateResult {
|
||||||
|
|
Reference in New Issue