diff --git a/Makefile b/Makefile index 08d2304af1..c430305513 100644 --- a/Makefile +++ b/Makefile @@ -205,7 +205,7 @@ gen: gen-build gen-client-ts web-build: web-install ## Build the Authentik UI cd web && npm run build -web: web-lint-fix web-lint web-check-compile web-test ## Automatically fix formatting issues in the Authentik UI source code, lint the code, and compile it +web: web-lint-fix web-lint web-check-compile ## Automatically fix formatting issues in the Authentik UI source code, lint the code, and compile it web-install: ## Install the necessary libraries to build the Authentik UI cd web && npm ci diff --git a/web/src/admin/applications/wizard/methods/oauth/ak-application-wizard-authentication-by-oauth.ts b/web/src/admin/applications/wizard/methods/oauth/ak-application-wizard-authentication-by-oauth.ts index 95d893110a..dd913dd3ed 100644 --- a/web/src/admin/applications/wizard/methods/oauth/ak-application-wizard-authentication-by-oauth.ts +++ b/web/src/admin/applications/wizard/methods/oauth/ak-application-wizard-authentication-by-oauth.ts @@ -11,7 +11,10 @@ import { redirectUriHelp, subjectModeOptions, } from "@goauthentik/admin/providers/oauth2/OAuth2ProviderForm"; -import { oauth2SourcesProvider } from "@goauthentik/admin/providers/oauth2/OAuth2Sources.js"; +import { + makeSourceSelector, + oauth2SourcesProvider, +} from "@goauthentik/admin/providers/oauth2/OAuth2Sources.js"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { ascii_letters, digits, first, randomString } from "@goauthentik/common/utils"; import "@goauthentik/components/ak-number-input"; @@ -263,12 +266,12 @@ export class ApplicationWizardAuthenticationByOauth extends BaseProviderPanel { name="jwksSources" .errorMessages=${errors?.jwksSources ?? []} > - + >

${msg( "JWTs signed by certificates configured in the selected sources can be used to authenticate to this provider.", diff --git a/web/src/admin/applications/wizard/methods/proxy/AuthenticationByProxyPage.ts b/web/src/admin/applications/wizard/methods/proxy/AuthenticationByProxyPage.ts index 81c9ef4057..df65e92183 100644 --- a/web/src/admin/applications/wizard/methods/proxy/AuthenticationByProxyPage.ts +++ b/web/src/admin/applications/wizard/methods/proxy/AuthenticationByProxyPage.ts @@ -1,5 +1,8 @@ import "@goauthentik/admin/applications/wizard/ak-wizard-title"; -import { oauth2SourcesProvider } from "@goauthentik/admin/providers/oauth2/OAuth2Sources.js"; +import { + makeSourceSelector, + oauth2SourcesProvider, +} from "@goauthentik/admin/providers/oauth2/OAuth2Sources.js"; import { makeProxyPropertyMappingsSelector, proxyPropertyMappingsProvider, @@ -11,7 +14,6 @@ import "@goauthentik/components/ak-text-input"; import "@goauthentik/components/ak-textarea-input"; import "@goauthentik/components/ak-toggle-group"; import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js"; -import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider.js"; import "@goauthentik/elements/forms/HorizontalFormElement"; import { msg } from "@lit/localize"; @@ -228,12 +230,12 @@ export class AkTypeProxyApplicationWizardPage extends BaseProviderPanel { name="jwksSources" .errorMessages=${errors?.jwksSources ?? []} > - + >

${msg( "JWTs signed by certificates configured in the selected sources can be used to authenticate to this provider.", diff --git a/web/src/admin/events/RuleForm.ts b/web/src/admin/events/RuleForm.ts index b26318adb1..24ec962f4d 100644 --- a/web/src/admin/events/RuleForm.ts +++ b/web/src/admin/events/RuleForm.ts @@ -1,5 +1,7 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { severityToLabel } from "@goauthentik/common/labels"; +import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js"; +import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types"; import "@goauthentik/elements/forms/HorizontalFormElement"; import { ModelForm } from "@goauthentik/elements/forms/ModelForm"; import "@goauthentik/elements/forms/Radio"; @@ -16,6 +18,7 @@ import { EventsApi, Group, NotificationRule, + NotificationTransport, PaginatedNotificationTransportList, SeverityEnum, } from "@goauthentik/api"; @@ -34,6 +37,13 @@ async function eventTransportsProvider(page = 1, search = "") { }; } +export function makeTransportSelector(instanceTransports: string[] | undefined) { + const localTransports = instanceTransports ? new Set(instanceTransports) : undefined; + + return localTransports + ? ([pk, _]: DualSelectPair) => localTransports.has(pk) + : ([_0, _1, _2, stage]: DualSelectPair) => stage !== undefined; +} @customElement("ak-event-rule-form") export class RuleForm extends ModelForm { eventTransports?: PaginatedNotificationTransportList; @@ -114,12 +124,12 @@ export class RuleForm extends ModelForm { ?required=${true} name="transports" > - + >

${msg( "Select which transports should be used to notify the user. If none are selected, the notification will only be shown in the authentik UI.", diff --git a/web/src/admin/providers/oauth2/OAuth2PropertyMappings.ts b/web/src/admin/providers/oauth2/OAuth2PropertyMappings.ts index 3134ff3f1b..2c4cc45e5b 100644 --- a/web/src/admin/providers/oauth2/OAuth2PropertyMappings.ts +++ b/web/src/admin/providers/oauth2/OAuth2PropertyMappings.ts @@ -3,6 +3,12 @@ import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js"; import { PropertymappingsApi, ScopeMapping } from "@goauthentik/api"; +export const defaultScopes = [ + "goauthentik.io/providers/oauth2/scope-openid", + "goauthentik.io/providers/oauth2/scope-email", + "goauthentik.io/providers/oauth2/scope-profile", +]; + export async function oauth2PropertyMappingsProvider(page = 1, search = "") { const propertyMappings = await new PropertymappingsApi( DEFAULT_CONFIG, @@ -23,6 +29,5 @@ export function makeOAuth2PropertyMappingsSelector(instanceMappings: string[] | return localMappings ? ([pk, _]: DualSelectPair) => localMappings.has(pk) : ([_0, _1, _2, scope]: DualSelectPair) => - scope?.managed?.startsWith("goauthentik.io/providers/oauth2/scope-") && - scope?.managed !== "goauthentik.io/providers/oauth2/scope-offline_access"; + scope?.managed && defaultScopes.includes(scope?.managed); } diff --git a/web/src/admin/providers/oauth2/OAuth2ProviderForm.ts b/web/src/admin/providers/oauth2/OAuth2ProviderForm.ts index 5cb3c417b5..d10fa8851a 100644 --- a/web/src/admin/providers/oauth2/OAuth2ProviderForm.ts +++ b/web/src/admin/providers/oauth2/OAuth2ProviderForm.ts @@ -32,7 +32,7 @@ import { makeOAuth2PropertyMappingsSelector, oauth2PropertyMappingsProvider, } from "./OAuth2PropertyMappings.js"; -import { oauth2SourcesProvider } from "./OAuth2Sources.js"; +import { makeSourceSelector, oauth2SourcesProvider } from "./OAuth2Sources.js"; export const clientTypeOptions = [ { @@ -52,12 +52,6 @@ export const clientTypeOptions = [ }, ]; -export const defaultScopes = [ - "goauthentik.io/providers/oauth2/scope-openid", - "goauthentik.io/providers/oauth2/scope-email", - "goauthentik.io/providers/oauth2/scope-profile", -]; - export const subjectModeOptions = [ { label: msg("Based on the User's hashed ID"), @@ -335,12 +329,12 @@ export class OAuth2ProviderFormPage extends BaseProviderForm { label=${msg("Trusted OIDC Sources")} name="jwksSources" > - + >

${msg( "JWTs signed by certificates configured in the selected sources can be used to authenticate to this provider.", diff --git a/web/src/admin/providers/oauth2/OAuth2Sources.ts b/web/src/admin/providers/oauth2/OAuth2Sources.ts index 4adc6dd425..f6ecde10f2 100644 --- a/web/src/admin/providers/oauth2/OAuth2Sources.ts +++ b/web/src/admin/providers/oauth2/OAuth2Sources.ts @@ -1,6 +1,7 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; +import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types"; -import { SourcesApi } from "@goauthentik/api"; +import { OAuthSource, SourcesApi } from "@goauthentik/api"; export async function oauth2SourcesProvider(page = 1, search = "") { const oauthSources = await new SourcesApi(DEFAULT_CONFIG).sourcesOauthList({ @@ -19,3 +20,11 @@ export async function oauth2SourcesProvider(page = 1, search = "") { ]), }; } + +export function makeSourceSelector(instanceSources: string[] | undefined) { + const localSources = instanceSources ? new Set(instanceSources) : undefined; + + return localSources + ? ([pk, _]: DualSelectPair) => localSources.has(pk) + : ([_0, _1, _2, prompt]: DualSelectPair) => prompt !== undefined; +} diff --git a/web/src/admin/providers/proxy/ProxyProviderForm.ts b/web/src/admin/providers/proxy/ProxyProviderForm.ts index 1e741fb1c8..60ea064708 100644 --- a/web/src/admin/providers/proxy/ProxyProviderForm.ts +++ b/web/src/admin/providers/proxy/ProxyProviderForm.ts @@ -1,12 +1,14 @@ import "@goauthentik/admin/common/ak-crypto-certificate-search"; import "@goauthentik/admin/common/ak-flow-search/ak-flow-search"; import { BaseProviderForm } from "@goauthentik/admin/providers/BaseProviderForm"; -import { oauth2SourcesProvider } from "@goauthentik/admin/providers/oauth2/OAuth2Sources.js"; +import { + makeSourceSelector, + oauth2SourcesProvider, +} from "@goauthentik/admin/providers/oauth2/OAuth2Sources.js"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { first } from "@goauthentik/common/utils"; import "@goauthentik/components/ak-toggle-group"; import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js"; -import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider.js"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/SearchSelect"; @@ -403,12 +405,12 @@ ${this.instance?.skipPathRegex} - + >

${msg( "JWTs signed by certificates configured in the selected sources can be used to authenticate to this provider.", diff --git a/web/src/admin/stages/authenticator_validate/AuthenticatorValidateStageForm.ts b/web/src/admin/stages/authenticator_validate/AuthenticatorValidateStageForm.ts index ff438f6963..16c9411973 100644 --- a/web/src/admin/stages/authenticator_validate/AuthenticatorValidateStageForm.ts +++ b/web/src/admin/stages/authenticator_validate/AuthenticatorValidateStageForm.ts @@ -2,7 +2,9 @@ import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm"; import { deviceTypeRestrictionPair } from "@goauthentik/admin/stages/authenticator_webauthn/utils"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import "@goauthentik/elements/Alert"; +import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js"; import "@goauthentik/elements/ak-dual-select/ak-dual-select-provider"; +import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/Radio"; @@ -18,6 +20,7 @@ import { DeviceClassesEnum, NotConfiguredActionEnum, PaginatedStageList, + Stage, StagesApi, UserVerificationEnum, } from "@goauthentik/api"; @@ -36,6 +39,14 @@ async function stagesProvider(page = 1, search = "") { }; } +export function makeStageSelector(instanceStages: string[] | undefined) { + const localStages = instanceStages ? new Set(instanceStages) : undefined; + + return localStages + ? ([pk, _]: DualSelectPair) => localStages.has(pk) + : ([_0, _1, _2, stage]: DualSelectPair) => stage !== undefined; +} + async function authenticatorWebauthnDeviceTypesListProvider(page = 1, search = "") { const devicetypes = await new StagesApi( DEFAULT_CONFIG, @@ -205,14 +216,14 @@ export class AuthenticatorValidateStageForm extends BaseStageForm - + >

${msg( "Stages used to configure Authenticator when user doesn't have any compatible devices. After this configuration Stage passes, the user is not prompted again.", diff --git a/web/src/admin/stages/identification/IdentificationStageForm.ts b/web/src/admin/stages/identification/IdentificationStageForm.ts index 6b541d08c8..9123fba71a 100644 --- a/web/src/admin/stages/identification/IdentificationStageForm.ts +++ b/web/src/admin/stages/identification/IdentificationStageForm.ts @@ -41,7 +41,7 @@ async function sourcesProvider(page = 1, search = "") { }; } -async function makeSourcesSelector(instanceSources: string[] | undefined) { +function makeSourcesSelector(instanceSources: string[] | undefined) { const localSources = instanceSources ? new Set(instanceSources) : undefined; return localSources diff --git a/web/src/admin/stages/prompt/PromptStageForm.ts b/web/src/admin/stages/prompt/PromptStageForm.ts index 6c2fe87256..2fb9e6e2b6 100644 --- a/web/src/admin/stages/prompt/PromptStageForm.ts +++ b/web/src/admin/stages/prompt/PromptStageForm.ts @@ -2,6 +2,8 @@ import { BaseStageForm } from "@goauthentik/admin/stages/BaseStageForm"; import "@goauthentik/admin/stages/prompt/PromptForm"; import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { PFSize } from "@goauthentik/common/enums"; +import "@goauthentik/elements/ak-dual-select/ak-dual-select-dynamic-selected-provider.js"; +import { DualSelectPair } from "@goauthentik/elements/ak-dual-select/types.js"; import "@goauthentik/elements/forms/FormGroup"; import "@goauthentik/elements/forms/HorizontalFormElement"; import "@goauthentik/elements/forms/ModalForm"; @@ -11,9 +13,9 @@ import { TemplateResult, html, nothing } from "lit"; import { customElement } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; -import { PoliciesApi, PromptStage, StagesApi } from "@goauthentik/api"; +import { PoliciesApi, Policy, Prompt, PromptStage, StagesApi } from "@goauthentik/api"; -async function promptsProvider(page = 1, search = "") { +async function promptFieldsProvider(page = 1, search = "") { const prompts = await new StagesApi(DEFAULT_CONFIG).stagesPromptPromptsList({ ordering: "field_name", pageSize: 20, @@ -25,11 +27,19 @@ async function promptsProvider(page = 1, search = "") { pagination: prompts.pagination, options: prompts.results.map((prompt) => [ prompt.pk, - str`${prompt.name} ("${prompt.fieldKey}", of type ${prompt.type})`, + msg(str`${prompt.name} ("${prompt.fieldKey}", of type ${prompt.type})`), ]), }; } +function makeFieldSelector(instanceFields: string[] | undefined) { + const localFields = instanceFields ? new Set(instanceFields) : undefined; + + return localFields + ? ([pk, _]: DualSelectPair) => localFields.has(pk) + : ([_0, _1, _2, prompt]: DualSelectPair) => prompt !== undefined; +} + async function policiesProvider(page = 1, search = "") { const policies = await new PoliciesApi(DEFAULT_CONFIG).policiesAllList({ ordering: "name", @@ -47,6 +57,14 @@ async function policiesProvider(page = 1, search = "") { }; } +function makePoliciesSelector(instancePolicies: string[] | undefined) { + const localPolicies = instancePolicies ? new Set(instancePolicies) : undefined; + + return localPolicies + ? ([pk, _]: DualSelectPair) => localPolicies.has(pk) + : ([_0, _1, _2, policy]: DualSelectPair) => policy !== undefined; +} + @customElement("ak-stage-prompt-form") export class PromptStageForm extends BaseStageForm { loadInstance(pk: string): Promise { @@ -90,12 +108,12 @@ export class PromptStageForm extends BaseStageForm { ?required=${true} name="fields" > - + > ${this.instance ? html` ${msg("Create")} @@ -115,12 +133,12 @@ export class PromptStageForm extends BaseStageForm { label=${msg("Validation Policies")} name="validationPolicies" > - + >

${msg( "Selected policies are executed when the stage is submitted to validate the data.",