This commit is contained in:
parent
d4bbde7deb
commit
b1e4b648ee
5 changed files with 124 additions and 53 deletions
|
|
@ -24,6 +24,9 @@
|
|||
"email_auth_enabled": "Email authentication is enabled and ready to use.",
|
||||
"email_auth_smtp_note": "To use email-based authentication, you need to enable and configure SMTP in the SMTP tab first.",
|
||||
"enable_email_auth": "Enable Email Authentication",
|
||||
"enable_local_auth": "Enable Username and Password",
|
||||
"local_auth": "Username and Password",
|
||||
"local_auth_description": "Enable or disable local username and password authentication for your users.",
|
||||
"smtp_required": "SMTP must be enabled and configured to use email based authentication."
|
||||
},
|
||||
"configs": {
|
||||
|
|
@ -36,6 +39,7 @@
|
|||
"description": "Configure authentication providers for your server",
|
||||
"email": "Email",
|
||||
"github_enterprise": "Enable Github Enterprise",
|
||||
"local": "Username and Password",
|
||||
"oauth": "OAuth",
|
||||
"oauth_providers": "OAuth Providers",
|
||||
"provider_not_specified": "Please enable at least one authentication provider",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,14 @@
|
|||
{
|
||||
"auth": {
|
||||
"enable_local_auth": "Activer identifiant et mot de passe",
|
||||
"local_auth": "Identifiant et mot de passe",
|
||||
"local_auth_description": "Activer ou désactiver l’authentification locale par identifiant et mot de passe pour les utilisateurs."
|
||||
},
|
||||
"configs": {
|
||||
"auth_providers": {
|
||||
"local": "Identifiant et mot de passe"
|
||||
}
|
||||
},
|
||||
"onboarding": {
|
||||
"local": {
|
||||
"confirm_password": "Confirmer le mot de passe",
|
||||
|
|
|
|||
|
|
@ -62,6 +62,36 @@
|
|||
</div>
|
||||
</HoppSmartTab>
|
||||
|
||||
<HoppSmartTab id="local-auth" :label="t('configs.auth_providers.local')">
|
||||
<div class="pb-8 px-4 grid md:grid-cols-3 gap-4 md:gap-4 pt-8">
|
||||
<div class="md:col-span-1">
|
||||
<h3 class="heading">{{ t('auth.local_auth') }}</h3>
|
||||
<p class="my-1 text-secondaryLight">
|
||||
{{ t('auth.local_auth_description') }}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="sm:px-8 md:col-span-2">
|
||||
<section>
|
||||
<h4 class="font-semibold text-secondaryDark">
|
||||
{{ t('auth.local_auth') }}
|
||||
</h4>
|
||||
|
||||
<div class="space-y-4 py-4">
|
||||
<div class="flex justify-between">
|
||||
<HoppSmartToggle
|
||||
:on="isLocalAuthEnabled"
|
||||
@change="toggleLocalAuth"
|
||||
>
|
||||
{{ t('auth.enable_local_auth') }}
|
||||
</HoppSmartToggle>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</HoppSmartTab>
|
||||
|
||||
<HoppSmartTab id="token" :label="t('configs.auth_providers.token.title')">
|
||||
<div class="pb-8 px-4">
|
||||
<SettingsAuthToken v-model:config="workingConfigs" />
|
||||
|
|
@ -88,14 +118,14 @@ const emit = defineEmits<{
|
|||
}>();
|
||||
|
||||
// Auth Sub Tabs
|
||||
type AuthSubTabs = 'auth-providers' | 'email-auth' | 'token';
|
||||
type AuthSubTabs = 'auth-providers' | 'email-auth' | 'local-auth' | 'token';
|
||||
const selectedAuthSubTab = ref<AuthSubTabs>('auth-providers');
|
||||
|
||||
const workingConfigs = useVModel(props, 'config', emit);
|
||||
|
||||
// Check if SMTP is activated but not saved yet. Used to track if SMTP was enabled after the last save.
|
||||
const isSMTPActivated = computed(
|
||||
() => workingConfigs.value?.mailConfigs.enabled ?? false
|
||||
() => workingConfigs.value?.mailConfigs.enabled ?? false,
|
||||
);
|
||||
|
||||
// Check if Email authentication is enabled
|
||||
|
|
@ -111,6 +141,15 @@ const toggleEmailAuth = () => {
|
|||
}
|
||||
};
|
||||
|
||||
const isLocalAuthEnabled = computed(() => {
|
||||
return workingConfigs.value?.localAuth.enabled ?? false;
|
||||
});
|
||||
|
||||
const toggleLocalAuth = () => {
|
||||
workingConfigs.value.localAuth.enabled =
|
||||
!workingConfigs.value.localAuth.enabled;
|
||||
};
|
||||
|
||||
// Check if SMTP is enabled on mount
|
||||
const isSMTPEnabled = ref(false);
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ import { useClientHandler } from './useClientHandler';
|
|||
const COOKIE_NAME_REGEX = /^[A-Za-z0-9_-]+$/;
|
||||
|
||||
const OPTIONAL_TOKEN_FIELD_KEYS = new Set(
|
||||
TOKEN_VALIDATION_CONFIGS.filter((cfg) => cfg.optional).map((cfg) => cfg.key)
|
||||
TOKEN_VALIDATION_CONFIGS.filter((cfg) => cfg.optional).map((cfg) => cfg.key),
|
||||
);
|
||||
|
||||
/** Composable that handles all operations related to server configurations
|
||||
|
|
@ -58,10 +58,10 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
InfraConfigsDocument,
|
||||
{
|
||||
configNames: ALL_CONFIGS.flat().map(
|
||||
({ name }) => name
|
||||
({ name }) => name,
|
||||
) as InfraConfigEnum[],
|
||||
},
|
||||
(x) => x.infraConfigs
|
||||
(x) => x.infraConfigs,
|
||||
);
|
||||
|
||||
// Fetching allowed auth providers
|
||||
|
|
@ -73,7 +73,7 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
} = useClientHandler(
|
||||
AllowedAuthProvidersDocument,
|
||||
{},
|
||||
(x) => x.allowedAuthProviders
|
||||
(x) => x.allowedAuthProviders,
|
||||
);
|
||||
|
||||
// Current and working configs
|
||||
|
|
@ -133,7 +133,7 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
mailer_smtp_port: getFieldValue(InfraConfigEnum.MailerSmtpPort),
|
||||
mailer_smtp_user: getFieldValue(InfraConfigEnum.MailerSmtpUser),
|
||||
mailer_smtp_password: getFieldValue(
|
||||
InfraConfigEnum.MailerSmtpPassword
|
||||
InfraConfigEnum.MailerSmtpPassword,
|
||||
),
|
||||
mailer_smtp_secure:
|
||||
getFieldValue(InfraConfigEnum.MailerSmtpSecure) === 'true',
|
||||
|
|
@ -147,37 +147,42 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
mailer_smtp_auth_type:
|
||||
getFieldValue(InfraConfigEnum.MailerSmtpAuthType) || 'login',
|
||||
mailer_smtp_oauth2_user: getFieldValue(
|
||||
InfraConfigEnum.MailerSmtpOauth2User
|
||||
InfraConfigEnum.MailerSmtpOauth2User,
|
||||
),
|
||||
mailer_smtp_oauth2_client_id: getFieldValue(
|
||||
InfraConfigEnum.MailerSmtpOauth2ClientId
|
||||
InfraConfigEnum.MailerSmtpOauth2ClientId,
|
||||
),
|
||||
mailer_smtp_oauth2_client_secret: getFieldValue(
|
||||
InfraConfigEnum.MailerSmtpOauth2ClientSecret
|
||||
InfraConfigEnum.MailerSmtpOauth2ClientSecret,
|
||||
),
|
||||
mailer_smtp_oauth2_refresh_token: getFieldValue(
|
||||
InfraConfigEnum.MailerSmtpOauth2RefreshToken
|
||||
InfraConfigEnum.MailerSmtpOauth2RefreshToken,
|
||||
),
|
||||
mailer_smtp_oauth2_access_url: getFieldValue(
|
||||
InfraConfigEnum.MailerSmtpOauth2AccessUrl
|
||||
InfraConfigEnum.MailerSmtpOauth2AccessUrl,
|
||||
),
|
||||
},
|
||||
},
|
||||
localAuth: {
|
||||
name: 'local',
|
||||
enabled: allowedAuthProviders.value.includes(AuthProvider.Local),
|
||||
fields: {},
|
||||
},
|
||||
tokenConfigs: {
|
||||
name: 'token',
|
||||
fields: {
|
||||
jwt_secret: getFieldValue(InfraConfigEnum.JwtSecret),
|
||||
token_salt_complexity: getFieldValue(
|
||||
InfraConfigEnum.TokenSaltComplexity
|
||||
InfraConfigEnum.TokenSaltComplexity,
|
||||
),
|
||||
magic_link_token_validity: getFieldValue(
|
||||
InfraConfigEnum.MagicLinkTokenValidity
|
||||
InfraConfigEnum.MagicLinkTokenValidity,
|
||||
),
|
||||
refresh_token_validity: getFieldValue(
|
||||
InfraConfigEnum.RefreshTokenValidity
|
||||
InfraConfigEnum.RefreshTokenValidity,
|
||||
),
|
||||
access_token_validity: getFieldValue(
|
||||
InfraConfigEnum.AccessTokenValidity
|
||||
InfraConfigEnum.AccessTokenValidity,
|
||||
),
|
||||
session_secret: getFieldValue(InfraConfigEnum.SessionSecret),
|
||||
session_cookie_name: getFieldValue(InfraConfigEnum.SessionCookieName),
|
||||
|
|
@ -186,7 +191,7 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
dataSharingConfigs: {
|
||||
name: 'data_sharing',
|
||||
enabled: !!infraConfigs.value.find(
|
||||
(x) => x.name === 'ALLOW_ANALYTICS_COLLECTION' && x.value === 'true'
|
||||
(x) => x.name === 'ALLOW_ANALYTICS_COLLECTION' && x.value === 'true',
|
||||
),
|
||||
},
|
||||
historyConfig: {
|
||||
|
|
@ -194,7 +199,7 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
enabled: !!infraConfigs.value.find(
|
||||
(config) =>
|
||||
config.name === 'USER_HISTORY_STORE_ENABLED' &&
|
||||
config.value === 'ENABLE'
|
||||
config.value === 'ENABLE',
|
||||
),
|
||||
},
|
||||
rateLimitConfigs: {
|
||||
|
|
@ -208,7 +213,7 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
name: 'mock_server',
|
||||
fields: {
|
||||
mock_server_wildcard_domain: getFieldValue(
|
||||
InfraConfigEnum.MockServerWildcardDomain
|
||||
InfraConfigEnum.MockServerWildcardDomain,
|
||||
),
|
||||
},
|
||||
},
|
||||
|
|
@ -316,8 +321,7 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
return (
|
||||
section.enabled &&
|
||||
Object.entries(otherFields).some(
|
||||
([key, value]) =>
|
||||
isFieldEmpty(value) && !excludeKeys.includes(key)
|
||||
([key, value]) => isFieldEmpty(value) && !excludeKeys.includes(key),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
@ -327,7 +331,7 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
if (section.name === 'token') {
|
||||
return Object.entries(section.fields).some(
|
||||
([key, value]) =>
|
||||
!OPTIONAL_TOKEN_FIELD_KEYS.has(key) && isFieldNotValid(value)
|
||||
!OPTIONAL_TOKEN_FIELD_KEYS.has(key) && isFieldNotValid(value),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -368,20 +372,20 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
(x) =>
|
||||
x.key === key &&
|
||||
key !== 'mailer_smtp_url' &&
|
||||
key !== 'mailer_smtp_enabled'
|
||||
key !== 'mailer_smtp_enabled',
|
||||
);
|
||||
} else
|
||||
return MAIL_CONFIGS.some(
|
||||
(x) => x.key === key && key !== 'mailer_smtp_enabled'
|
||||
(x) => x.key === key && key !== 'mailer_smtp_enabled',
|
||||
);
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
// Extract the custom mail config fields
|
||||
const customMailConfigFields = Object.fromEntries(
|
||||
Object.entries(updatedConfigs?.mailConfigs.fields ?? {}).filter(([key]) =>
|
||||
CUSTOM_MAIL_CONFIGS.some((x) => x.key === key)
|
||||
)
|
||||
CUSTOM_MAIL_CONFIGS.some((x) => x.key === key),
|
||||
),
|
||||
);
|
||||
|
||||
// Transforming the working configs back into the format required by the mutations
|
||||
|
|
@ -441,7 +445,7 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
const executeMutation = async <T, V>(
|
||||
mutation: UseMutationResponse<T>,
|
||||
variables: AnyVariables = undefined,
|
||||
errorMessage: string
|
||||
errorMessage: string,
|
||||
): Promise<boolean> => {
|
||||
const result = await mutation.executeMutation(variables);
|
||||
|
||||
|
|
@ -460,7 +464,7 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
|
||||
// Updating the auth provider configurations
|
||||
const updateAuthProvider = (
|
||||
updateProviderStatus: UseMutationResponse<EnableAndDisableSsoMutation>
|
||||
updateProviderStatus: UseMutationResponse<EnableAndDisableSsoMutation>,
|
||||
) => {
|
||||
const updatedAllowedAuthProviders: EnableAndDisableSsoArgs[] = [
|
||||
{
|
||||
|
|
@ -487,6 +491,12 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
? ServiceStatus.Enable
|
||||
: ServiceStatus.Disable,
|
||||
},
|
||||
{
|
||||
provider: AuthProvider.Local,
|
||||
status: updatedConfigs?.localAuth.enabled
|
||||
? ServiceStatus.Enable
|
||||
: ServiceStatus.Disable,
|
||||
},
|
||||
];
|
||||
|
||||
return executeMutation(
|
||||
|
|
@ -494,13 +504,13 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
{
|
||||
providerInfo: updatedAllowedAuthProviders,
|
||||
},
|
||||
'configs.auth_providers.update_failure'
|
||||
'configs.auth_providers.update_failure',
|
||||
);
|
||||
};
|
||||
|
||||
// Updating the infra configurations
|
||||
const updateInfraConfigs = (
|
||||
updateInfraConfigsMutation: UseMutationResponse<UpdateInfraConfigsMutation>
|
||||
updateInfraConfigsMutation: UseMutationResponse<UpdateInfraConfigsMutation>,
|
||||
) => {
|
||||
const infraConfigs: InfraConfigArgs[] = updatedConfigs
|
||||
? transformInfraConfigs()
|
||||
|
|
@ -511,23 +521,23 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
{
|
||||
infraConfigs,
|
||||
},
|
||||
'configs.update_failure'
|
||||
'configs.update_failure',
|
||||
);
|
||||
};
|
||||
|
||||
// Resetting the infra configurations
|
||||
const resetInfraConfigs = (
|
||||
resetInfraConfigsMutation: UseMutationResponse<ResetInfraConfigsMutation>
|
||||
resetInfraConfigsMutation: UseMutationResponse<ResetInfraConfigsMutation>,
|
||||
) =>
|
||||
executeMutation(
|
||||
resetInfraConfigsMutation,
|
||||
undefined,
|
||||
'configs.reset.failure'
|
||||
'configs.reset.failure',
|
||||
);
|
||||
|
||||
// Toggle Data Sharing
|
||||
const updateDataSharingConfigs = (
|
||||
toggleDataSharingMutation: UseMutationResponse<ToggleAnalyticsCollectionMutation>
|
||||
toggleDataSharingMutation: UseMutationResponse<ToggleAnalyticsCollectionMutation>,
|
||||
) =>
|
||||
executeMutation(
|
||||
toggleDataSharingMutation,
|
||||
|
|
@ -536,12 +546,12 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
? ServiceStatus.Enable
|
||||
: ServiceStatus.Disable,
|
||||
},
|
||||
'configs.data_sharing.update_failure'
|
||||
'configs.data_sharing.update_failure',
|
||||
);
|
||||
|
||||
// Toggle SMTP
|
||||
const toggleSMTPConfigs = (
|
||||
toggleSMTP: UseMutationResponse<ToggleSmtpMutation>
|
||||
toggleSMTP: UseMutationResponse<ToggleSmtpMutation>,
|
||||
) =>
|
||||
executeMutation(
|
||||
toggleSMTP,
|
||||
|
|
@ -550,12 +560,12 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
? ServiceStatus.Enable
|
||||
: ServiceStatus.Disable,
|
||||
},
|
||||
'configs.mail_configs.toggle_failure'
|
||||
'configs.mail_configs.toggle_failure',
|
||||
);
|
||||
|
||||
// Toggle User History Store
|
||||
const toggleUserHistoryStore = (
|
||||
toggleUserHistoryStore: UseMutationResponse<ToggleUserHistoryStoreMutation>
|
||||
toggleUserHistoryStore: UseMutationResponse<ToggleUserHistoryStoreMutation>,
|
||||
) =>
|
||||
executeMutation(
|
||||
toggleUserHistoryStore,
|
||||
|
|
@ -564,11 +574,11 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
? ServiceStatus.Enable
|
||||
: ServiceStatus.Disable,
|
||||
},
|
||||
'configs.user_history_store.toggle_failure'
|
||||
'configs.user_history_store.toggle_failure',
|
||||
);
|
||||
|
||||
const updateRateLimitConfigs = (
|
||||
updateRateLimitMutation: UseMutationResponse<UpdateInfraConfigsMutation>
|
||||
updateRateLimitMutation: UseMutationResponse<UpdateInfraConfigsMutation>,
|
||||
) => {
|
||||
if (!updatedConfigs?.rateLimitConfigs) {
|
||||
toast.error(t('configs.rate_limit.input_validation_error'));
|
||||
|
|
@ -576,10 +586,10 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
}
|
||||
|
||||
const rateLimitTtl = String(
|
||||
updatedConfigs?.rateLimitConfigs.fields.rate_limit_ttl
|
||||
updatedConfigs?.rateLimitConfigs.fields.rate_limit_ttl,
|
||||
);
|
||||
const rateLimitMax = String(
|
||||
updatedConfigs?.rateLimitConfigs.fields.rate_limit_max
|
||||
updatedConfigs?.rateLimitConfigs.fields.rate_limit_max,
|
||||
);
|
||||
|
||||
if (isFieldEmpty(rateLimitTtl) || isFieldEmpty(rateLimitMax)) {
|
||||
|
|
@ -603,12 +613,12 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
{
|
||||
infraConfigs: rateLimitConfigs,
|
||||
},
|
||||
'configs.rate_limit.update_failure'
|
||||
'configs.rate_limit.update_failure',
|
||||
);
|
||||
};
|
||||
|
||||
const updateAuthTokenConfigs = (
|
||||
updateAuthTokenMutation: UseMutationResponse<UpdateInfraConfigsMutation>
|
||||
updateAuthTokenMutation: UseMutationResponse<UpdateInfraConfigsMutation>,
|
||||
) => {
|
||||
if (!updatedConfigs?.tokenConfigs) {
|
||||
toast.error(t('configs.auth_providers.token.update_failure'));
|
||||
|
|
@ -617,26 +627,28 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
|
||||
const jwtSecret = String(updatedConfigs?.tokenConfigs.fields.jwt_secret);
|
||||
const tokenSaltComplexity = String(
|
||||
updatedConfigs?.tokenConfigs.fields.token_salt_complexity
|
||||
updatedConfigs?.tokenConfigs.fields.token_salt_complexity,
|
||||
);
|
||||
const magicLinkTokenValidity = String(
|
||||
updatedConfigs?.tokenConfigs.fields.magic_link_token_validity
|
||||
updatedConfigs?.tokenConfigs.fields.magic_link_token_validity,
|
||||
);
|
||||
const refreshTokenValidity = String(
|
||||
updatedConfigs?.tokenConfigs.fields.refresh_token_validity
|
||||
updatedConfigs?.tokenConfigs.fields.refresh_token_validity,
|
||||
);
|
||||
const accessTokenValidity = String(
|
||||
updatedConfigs?.tokenConfigs.fields.access_token_validity
|
||||
updatedConfigs?.tokenConfigs.fields.access_token_validity,
|
||||
);
|
||||
const sessionSecret = String(
|
||||
updatedConfigs?.tokenConfigs.fields.session_secret
|
||||
updatedConfigs?.tokenConfigs.fields.session_secret,
|
||||
);
|
||||
const sessionCookieName = String(
|
||||
updatedConfigs?.tokenConfigs.fields.session_cookie_name || ''
|
||||
updatedConfigs?.tokenConfigs.fields.session_cookie_name || '',
|
||||
);
|
||||
// Validate cookie name: allow empty (falls back to default), else enforce pattern
|
||||
if (sessionCookieName && !COOKIE_NAME_REGEX.test(sessionCookieName)) {
|
||||
toast.error(t('configs.auth_providers.token.session_cookie_name_invalid'));
|
||||
toast.error(
|
||||
t('configs.auth_providers.token.session_cookie_name_invalid'),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
|
|
@ -687,7 +699,7 @@ export function useConfigHandler(updatedConfigs?: ServerConfigs) {
|
|||
{
|
||||
infraConfigs: authTokenConfigs,
|
||||
},
|
||||
'configs.auth_providers.token.update_failure'
|
||||
'configs.auth_providers.token.update_failure',
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,12 @@ export type ServerConfigs = {
|
|||
};
|
||||
};
|
||||
|
||||
localAuth: {
|
||||
name: string;
|
||||
enabled: boolean;
|
||||
fields: Record<string, never>;
|
||||
};
|
||||
|
||||
tokenConfigs: {
|
||||
name: string;
|
||||
fields: {
|
||||
|
|
|
|||
Loading…
Reference in a new issue