Files
authentik/web/src/admin/admin-settings/AdminSettingsForm.ts
Simonyi Gergő edf3300944 policies/reputation: limit reputation score (#14008)
* add limits to reputation score

* limit reputation score limits

Upper to non-negative, Lower to non-positive

* simplify tests

* "fix" bandit false-positives

* move magic numbers to constants

Is it too much to ask for a world in which I can just import these
straight from Python?
2025-04-14 14:18:59 +00:00

272 lines
12 KiB
TypeScript

import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { first } from "@goauthentik/common/utils";
import "@goauthentik/components/ak-number-input";
import "@goauthentik/components/ak-switch-input";
import "@goauthentik/components/ak-text-input";
import "@goauthentik/elements/ak-array-input.js";
import { Form } from "@goauthentik/elements/forms/Form";
import "@goauthentik/elements/forms/FormGroup";
import "@goauthentik/elements/forms/HorizontalFormElement";
import "@goauthentik/elements/forms/Radio";
import "@goauthentik/elements/forms/SearchSelect";
import "@goauthentik/elements/utils/TimeDeltaHelp";
import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, css, html } from "lit";
import { customElement, property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import PFList from "@patternfly/patternfly/components/List/list.css";
import { AdminApi, FooterLink, Settings, SettingsRequest } from "@goauthentik/api";
import "./AdminSettingsFooterLinks.js";
import { IFooterLinkInput, akFooterLinkInput } from "./AdminSettingsFooterLinks.js";
const DEFAULT_REPUTATION_LOWER_LIMIT = -5;
const DEFAULT_REPUTATION_UPPER_LIMIT = 5;
@customElement("ak-admin-settings-form")
export class AdminSettingsForm extends Form<SettingsRequest> {
//
// Custom property accessors in Lit 2 require a manual call to requestUpdate(). See:
// https://lit.dev/docs/v2/components/properties/#accessors-custom
//
set settings(value: Settings | undefined) {
this._settings = value;
this.requestUpdate();
}
@property({ type: Object })
get settings() {
return this._settings;
}
private _settings?: Settings;
static get styles(): CSSResult[] {
return super.styles.concat(
PFList,
css`
ak-array-input {
width: 100%;
}
`,
);
}
getSuccessMessage(): string {
return msg("Successfully updated settings.");
}
async send(data: SettingsRequest): Promise<Settings> {
const result = await new AdminApi(DEFAULT_CONFIG).adminSettingsUpdate({
settingsRequest: data,
});
this.dispatchEvent(new CustomEvent("ak-admin-setting-changed"));
return result;
}
renderForm(): TemplateResult {
return html`
<ak-text-input
name="avatars"
label=${msg("Avatars")}
value="${ifDefined(this._settings?.avatars)}"
inputHint="code"
.bighelp=${html`
<p class="pf-c-form__helper-text">
${msg(
"Configure how authentik should show avatars for users. The following values can be set:",
)}
</p>
<ul class="pf-c-list">
<li class="pf-c-form__helper-text">
<code>none</code>:
${msg(
"Disables per-user avatars and just shows a 1x1 pixel transparent picture",
)}
</li>
<li class="pf-c-form__helper-text">
<code>gravatar</code>:
${msg("Uses gravatar with the user's email address")}
</li>
<li class="pf-c-form__helper-text">
<code>initials</code>:
${msg("Generated avatars based on the user's name")}
</li>
<li class="pf-c-form__helper-text">
${msg(
"Any URL: If you want to use images hosted on another server, you can set any URL. Additionally, these placeholders can be used:",
)}
<ul class="pf-c-list">
<li class="pf-c-form__helper-text">
<code>%(username)s</code>: ${msg("The user's username")}
</li>
<li class="pf-c-form__helper-text">
<code>%(mail_hash)s</code>:
${msg("The email address, md5 hashed")}
</li>
<li class="pf-c-form__helper-text">
<code>%(upn)s</code>:
${msg("The user's UPN, if set (otherwise an empty string)")}
</li>
</ul>
</li>
<li class="pf-c-form__helper-text">
${msg(
html`An attribute path like
<code>attributes.something.avatar</code>, which can be used in
combination with the file field to allow users to upload custom
avatars for themselves.`,
)}
</li>
</ul>
<p class="pf-c-form__helper-text">
${msg(
"Multiple values can be set, comma-separated, and authentik will fallback to the next mode when no avatar could be found.",
)}
${msg(
html`For example, setting this to <code>gravatar,initials</code> will
attempt to get an avatar from Gravatar, and if the user has not
configured on there, it will fallback to a generated avatar.`,
)}
</p>
`}
required
>
</ak-text-input>
<ak-switch-input
name="defaultUserChangeName"
label=${msg("Allow users to change name")}
?checked="${this._settings?.defaultUserChangeName}"
help=${msg("Enable the ability for users to change their name.")}
>
</ak-switch-input>
<ak-switch-input
name="defaultUserChangeEmail"
label=${msg("Allow users to change email")}
?checked="${this._settings?.defaultUserChangeEmail}"
help=${msg("Enable the ability for users to change their email.")}
>
</ak-switch-input>
<ak-switch-input
name="defaultUserChangeUsername"
label=${msg("Allow users to change username")}
?checked="${this._settings?.defaultUserChangeUsername}"
help=${msg("Enable the ability for users to change their username.")}
>
</ak-switch-input>
<ak-text-input
name="eventRetention"
label=${msg("Event retention")}
inputHint="code"
required
value="${ifDefined(this._settings?.eventRetention)}"
.bighelp=${html`<p class="pf-c-form__helper-text">
${msg("Duration after which events will be deleted from the database.")}
</p>
<p class="pf-c-form__helper-text">
${msg(
html`When using an external logging solution for archiving, this can be
set to <code>minutes=5</code>.`,
)}
</p>
<p class="pf-c-form__helper-text">
${msg(
"This setting only affects new Events, as the expiration is saved per-event.",
)}
</p>
<ak-utils-time-delta-help></ak-utils-time-delta-help>`}
>
</ak-text-input>
<ak-number-input
label=${msg("Reputation: lower limit")}
required
name="reputationLowerLimit"
value="${first(
this._settings?.reputationLowerLimit,
DEFAULT_REPUTATION_LOWER_LIMIT,
)}"
help=${msg("Reputation cannot decrease lower than this value. Zero or negative.")}
></ak-number-input>
<ak-number-input
label=${msg("Reputation: upper limit")}
required
name="reputationUpperLimit"
value="${first(
this._settings?.reputationUpperLimit,
DEFAULT_REPUTATION_UPPER_LIMIT,
)}"
help=${msg("Reputation cannot increase higher than this value. Zero or positive.")}
></ak-number-input>
<ak-form-element-horizontal label=${msg("Footer links")} name="footerLinks">
<ak-array-input
.items=${this._settings?.footerLinks ?? []}
.newItem=${() => ({ name: "", href: "" })}
.row=${(f?: FooterLink) =>
akFooterLinkInput({
".footerLink": f,
"style": "width: 100%",
"name": "footer-link",
} as unknown as IFooterLinkInput)}
>
</ak-array-input>
<p class="pf-c-form__helper-text">
${msg(
"This option configures the footer links on the flow executor pages. The URL is limited to web and mail addresses. If the name is left blank, the URL will be shown.",
)}
</p>
</ak-form-element-horizontal>
<ak-switch-input
name="gdprCompliance"
label=${msg("GDPR compliance")}
?checked="${this._settings?.gdprCompliance}"
help=${msg(
"When enabled, all the events caused by a user will be deleted upon the user's deletion.",
)}
>
</ak-switch-input>
<ak-switch-input
name="impersonation"
label=${msg("Impersonation")}
?checked="${this._settings?.impersonation}"
help=${msg("Globally enable/disable impersonation.")}
>
</ak-switch-input>
<ak-switch-input
name="impersonationRequireReason"
label=${msg("Require reason for impersonation")}
?checked="${this._settings?.impersonationRequireReason}"
help=${msg("Require administrators to provide a reason for impersonating a user.")}
>
</ak-switch-input>
<ak-text-input
name="defaultTokenDuration"
label=${msg("Default token duration")}
inputHint="code"
required
value="${ifDefined(this._settings?.defaultTokenDuration)}"
.bighelp=${html`<p class="pf-c-form__helper-text">
${msg("Default duration for generated tokens")}
</p>
<ak-utils-time-delta-help></ak-utils-time-delta-help>`}
>
</ak-text-input>
<ak-number-input
label=${msg("Default token length")}
required
name="defaultTokenLength"
value="${first(this._settings?.defaultTokenLength, 60)}"
help=${msg("Default length of generated tokens")}
></ak-number-input>
`;
}
}
declare global {
interface HTMLElementTagNameMap {
"ak-admin-settings-form": AdminSettingsForm;
}
}