Files
ppeasy_vg12/resources/js/pages/settings/Auth.vue
T
2026-10-09 08:21:06 +02:00

263 lines
14 KiB
Vue

<script setup lang="ts">
import { useForm } from '@inertiajs/vue3';
import Button from '@/components/ui/Button.vue';
import Input from '@/components/ui/Input.vue';
import Message from '@/components/ui/Message.vue';
import Tabs from '@/components/ui/Tabs.vue';
import FeatureToggleCard from '@/components/FeatureToggleCard.vue';
import SettingsCard from '@/components/SettingsCard.vue';
import ToggleField from '@/components/ToggleField.vue';
import { useTranslations } from '@/composables/useVanguard';
import AppLayout from '@/layouts/AppLayout.vue';
import { ref } from 'vue';
const props = defineProps<{
values: Record<string, string | number>;
captchaConfigured: boolean;
}>();
const { __ } = useTranslations();
const general = useForm({
remember_me: Number(props.values.remember_me ?? 0),
forgot_password: Number(props.values.forgot_password ?? 0),
login_reset_token_lifetime: String(props.values.login_reset_token_lifetime ?? 30),
max_active_sessions: String(props.values.max_active_sessions ?? 0),
});
const throttling = useForm({
throttle_enabled: Number(props.values.throttle_enabled ?? 0),
throttle_attempts: String(props.values.throttle_attempts ?? 10),
throttle_lockout_time: String(props.values.throttle_lockout_time ?? 1),
});
const registration = useForm({
reg_enabled: Number(props.values.reg_enabled ?? 0),
tos: Number(props.values.tos ?? 0),
reg_email_confirmation: Number(props.values.reg_email_confirmation ?? 0),
});
function submit(form: { post: (url: string, options: object) => void }) {
form.post(route('settings.auth.update'), { preserveScroll: true });
}
/**
* Keys containing quotes or ampersands are declared here rather than inline in
* the template, so the string handed to __() matches the language file key
* exactly and is not altered by HTML entity decoding.
*/
const labels = {
rememberMe: __('Allow "Remember Me"'),
rememberMeHint: __("Should 'Remember Me' checkbox be displayed on login form?"),
terms: __('Terms & Conditions'),
};
const activeTab = ref('auth');
const tabs = [
{ value: 'auth', label: __('Authentication'), icon: 'fa fa-lock' },
{ value: 'registration', label: __('Registration'), icon: 'fa fa-user-plus' },
];
</script>
<template>
<AppLayout
:title="__('Authentication Settings')"
:heading="__('Authentication')"
:breadcrumbs="[{ label: __('Settings') }, { label: __('Authentication') }]"
>
<Tabs v-model="activeTab" :tabs="tabs">
<template #auth>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<div class="space-y-4">
<SettingsCard :title="__('General')">
<form class="space-y-6" @submit.prevent="submit(general)">
<ToggleField
v-model="general.remember_me"
input-id="switch-remember-me"
:label="labels.rememberMe"
:description="labels.rememberMeHint"
/>
<ToggleField
v-model="general.forgot_password"
input-id="switch-forgot-pass"
:label="__('Forgot Password')"
:description="__('Enable/Disable forgot password feature.')"
/>
<div>
<label for="login_reset_token_lifetime" class="block text-slate-700">
{{ __('Reset Token Lifetime') }}
</label>
<small class="mb-1 block text-slate-500">
{{ __('Number of minutes that the reset token should be considered valid.') }}
</small>
<Input
id="login_reset_token_lifetime"
v-model="general.login_reset_token_lifetime"
class="w-full"
/>
</div>
<div>
<label for="max_active_sessions" class="block text-slate-700">
{{ __('Max Number of Active Sessions') }}
</label>
<small class="mb-1 block text-slate-500">
{{ __('Maximum number of active sessions per user. Set to 0 to allow unlimited number of active sessions.') }}
{{ __('Only applies when using database session driver.') }}
</small>
<Input
id="max_active_sessions"
v-model="general.max_active_sessions"
class="w-full"
/>
</div>
<Button
type="submit"
:label="__('Update')"
:loading="general.processing"
/>
</form>
</SettingsCard>
<FeatureToggleCard
:title="__('Two-Factor Authentication')"
:description="__('Enable/Disable Two-Factor Authentication for the application.')"
:enabled="Boolean(Number(values['2fa.enabled']))"
:enable-url="route('settings.auth.2fa.enable')"
:disable-url="route('settings.auth.2fa.disable')"
/>
</div>
<div class="space-y-4">
<SettingsCard :title="__('Authentication Throttling')">
<form class="space-y-6" @submit.prevent="submit(throttling)">
<ToggleField
v-model="throttling.throttle_enabled"
input-id="switch-throttle"
:label="__('Throttle Authentication')"
:description="__('Should the system throttle authentication attempts?')"
/>
<div>
<label for="throttle_attempts" class="block text-slate-700">
{{ __('Maximum Number of Attempts') }}
</label>
<small class="mb-1 block text-slate-500">
{{ __('Maximum number of incorrect login attempts before lockout.') }}
</small>
<Input
id="throttle_attempts"
v-model="throttling.throttle_attempts"
class="w-full"
/>
</div>
<div>
<label for="throttle_lockout_time" class="block text-slate-700">
{{ __('Lockout Time') }}
</label>
<small class="mb-1 block text-slate-500">
{{ __('Number of minutes to lock the user out for after specified maximum number of incorrect login attempts.') }}
</small>
<Input
id="throttle_lockout_time"
v-model="throttling.throttle_lockout_time"
class="w-full"
/>
</div>
<Button
type="submit"
:label="__('Update')"
:loading="throttling.processing"
/>
</form>
</SettingsCard>
<FeatureToggleCard
:title="__('User Confirmation Flow')"
:description="__('Enable/Disable the user confirmation flow for the application. When enabled, users will be set to Waiting Approval and require admin approval before becoming Active.')"
:enabled="Boolean(Number(values['approval.enabled']))"
:enable-url="route('settings.auth.approval.enable')"
:disable-url="route('settings.auth.approval.disable')"
/>
<FeatureToggleCard
:title="__('Force Password Change On Next Login')"
:description="__('Force all the users created manually by admin to reset the password on their first log in to be able to use the application.')"
:enabled="Boolean(Number(values['password-change.enabled']))"
:enable-url="route('settings.auth.password-change.enable')"
:disable-url="route('settings.auth.password-change.disable')"
/>
</div>
</div>
</template>
<template #registration>
<div class="grid grid-cols-1 gap-4 md:grid-cols-2">
<SettingsCard :title="__('General')">
<form class="space-y-6" @submit.prevent="submit(registration)">
<ToggleField
v-model="registration.reg_enabled"
input-id="switch-reg-enabled"
:label="__('Allow Registration')"
/>
<ToggleField
v-model="registration.tos"
input-id="switch-tos"
:label="labels.terms"
:description="__('The user has to confirm that he agrees with terms and conditions in order to create an account.')"
/>
<ToggleField
v-model="registration.reg_email_confirmation"
input-id="switch-reg-email-confirm"
:label="__('Email Confirmation')"
:description="__('Require email confirmation from your newly registered users.')"
/>
<Button
type="submit"
:label="__('Update')"
:loading="registration.processing"
/>
</form>
</SettingsCard>
<FeatureToggleCard
:title="__('Google reCAPTCHA')"
:description="__('Enable/Disable Google reCAPTCHA during the registration.')"
:enabled="Boolean(Number(values['registration.captcha.enabled']))"
:enable-url="route('settings.registration.captcha.enable')"
:disable-url="route('settings.registration.captcha.disable')"
>
<template v-if="!captchaConfigured" #notice>
<Message severity="info">
{{ __('To utilize Google reCAPTCHA, please get your') }}
<code>{{ __('Site Key') }}</code>
{{ __('and') }} <code>{{ __('Secret Key') }}</code>
{{ __('from') }}
<a
href="https://www.google.com/recaptcha/intro/index.html"
target="_blank"
rel="noopener"
class="font-bold underline"
>{{ __('reCAPTCHA Website') }}</a>,
{{ __('and update your') }} <code>RECAPTCHA_SITEKEY</code>
{{ __('and') }} <code>RECAPTCHA_SECRETKEY</code>
{{ __('environment variables inside') }} <code>.env</code>
{{ __('file') }}.
</Message>
</template>
</FeatureToggleCard>
</div>
</template>
</Tabs>
</AppLayout>
</template>