AzuraCast/frontend/src/components/Login.vue

183 lines
6.4 KiB
Vue

<template>
<div class="public-page">
<div class="card p-2">
<div class="card-body">
<div class="row mb-4">
<div class="col-sm">
<h2
v-if="hideProductName"
class="card-title text-center"
>
{{ $gettext('Welcome!') }}
</h2>
<h2
v-else
class="card-title text-center"
>
{{ $gettext('Welcome to AzuraCast!') }}
</h2>
<h3
v-if="instanceName"
class="card-subtitle text-center text-muted"
>
{{ instanceName }}
</h3>
</div>
</div>
<form
id="login-form"
action=""
method="post"
>
<div class="form-group">
<label
for="username"
class="mb-2 d-flex align-items-center gap-2"
>
<icon :icon="IconMail" />
<strong>
{{ $gettext('E-mail Address') }}
</strong>
</label>
<input
id="username"
type="email"
name="username"
class="form-control"
:placeholder="$gettext('name@example.com')"
:aria-label="$gettext('E-mail Address')"
required
autofocus
>
</div>
<div class="form-group mt-3">
<label
for="password"
class="mb-2 d-flex align-items-center gap-2"
>
<icon :icon="IconVpnKey" />
<strong>{{ $gettext('Password') }}</strong>
</label>
<input
id="password"
type="password"
name="password"
class="form-control"
:placeholder="$gettext('Enter your password')"
:aria-label="$gettext('Password')"
required
>
</div>
<div class="form-group mt-4">
<div class="custom-control custom-checkbox">
<input
id="frm_remember_me"
type="checkbox"
name="remember"
value="1"
class="toggle-switch custom-control-input"
>
<label
for="frm_remember_me"
class="custom-control-label"
>
{{ $gettext('Remember me') }}
</label>
</div>
</div>
<div class="block-buttons mt-3 mb-3">
<button
type="submit"
role="button"
:title="$gettext('Sign In')"
class="btn btn-login btn-primary"
>
{{ $gettext('Sign In') }}
</button>
</div>
</form>
<form
v-if="passkeySupported"
id="webauthn-form"
ref="$webAuthnForm"
:action="webAuthnUrl"
method="post"
>
<input
type="hidden"
name="validateData"
:value="validateData"
>
<div class="block-buttons mb-3">
<button
type="button"
role="button"
:title="$gettext('Sign In with Passkey')"
class="btn btn-sm btn-secondary"
@click="logInWithPasskey"
>
{{ $gettext('Sign In with Passkey') }}
</button>
</div>
</form>
<p class="text-center m-0">
{{ $gettext('Please log in to continue.') }}
<a :href="forgotPasswordUrl">
{{ $gettext('Forgot your password?') }}
</a>
</p>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import Icon from "~/components/Common/Icon.vue";
import {IconMail, IconVpnKey} from "~/components/Common/icons.ts";
import useWebAuthn from "~/functions/useWebAuthn.ts";
import {useAxios} from "~/vendor/axios.ts";
import {nextTick, ref} from "vue";
const props = defineProps({
hideProductName: {
type: Boolean,
default: true
},
instanceName: {
type: String,
default: null
},
forgotPasswordUrl: {
type: String,
default: null
},
webAuthnUrl: {
type: String,
default: null
}
});
const {isSupported: passkeySupported, processServerArgs, processValidateResponse} = useWebAuthn();
const {axios} = useAxios();
const $webAuthnForm = ref<HTMLFormElement | null>(null);
const validateData = ref<string | null>(null);
const logInWithPasskey = async () => {
const validateArgs = await axios.get(props.webAuthnUrl).then(r => processServerArgs(r.data));
const attResp = await navigator.credentials.get(validateArgs);
validateData.value = JSON.stringify(processValidateResponse(attResp));
await nextTick();
$webAuthnForm.value?.submit();
};
</script>