feat(sign-in): メールアドレスログインを実装 (MisskeyIO#836)
Co-authored-by: まっちゃてぃー。 <56515516+mattyatea@users.noreply.github.com>
This commit is contained in:
parent
3ecc340168
commit
58513c1b81
14 changed files with 236 additions and 22 deletions
|
@ -5,6 +5,7 @@
|
|||
|
||||
import { defineAsyncComponent, reactive, ref } from 'vue';
|
||||
import * as Misskey from 'misskey-js';
|
||||
import { set as gtagSet, time as gtagTime } from 'vue-gtag';
|
||||
import { showSuspendedDialog } from '@/scripts/show-suspended-dialog.js';
|
||||
import { i18n } from '@/i18n.js';
|
||||
import { miLocalStorage } from '@/local-storage.js';
|
||||
|
@ -14,7 +15,6 @@ import { apiUrl } from '@/config.js';
|
|||
import { waiting, popup, popupMenu, success, alert } from '@/os.js';
|
||||
import { generateClientTransactionId, misskeyApi } from '@/scripts/misskey-api.js';
|
||||
import { unisonReload, reloadChannel } from '@/scripts/unison-reload.js';
|
||||
import { set as gtagSet, time as gtagTime } from 'vue-gtag';
|
||||
import { instance } from '@/instance.js';
|
||||
|
||||
// TODO: 他のタブと永続化されたstateを同期
|
||||
|
|
|
@ -6,24 +6,32 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
<template>
|
||||
<form :class="{ signing, totpLogin }" @submit.prevent="onSubmit">
|
||||
<div class="_gaps_m">
|
||||
<div v-show="withAvatar" :class="$style.avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : undefined, marginBottom: message ? '1.5em' : undefined }"></div>
|
||||
<div v-show="withAvatar && !loginWithEmailAddress" :class="$style.avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : undefined, marginBottom: message ? '1.5em' : undefined }"></div>
|
||||
<MkInfo v-if="message">
|
||||
{{ message }}
|
||||
</MkInfo>
|
||||
<div v-if="!totpLogin" class="normal-signin _gaps_m">
|
||||
<MkInput v-model="username" :debounce="true" :placeholder="i18n.ts.username" type="text" pattern="^[a-zA-Z0-9_]+$" :spellcheck="false" autocomplete="username webauthn" autofocus required data-cy-signin-username @update:modelValue="onUsernameChange">
|
||||
<template #prefix>@</template>
|
||||
<template #suffix>@{{ host }}</template>
|
||||
<MkInput v-model="username" :debounce="true" :placeholder="loginWithEmailAddress ? i18n.ts.emailAddress : i18n.ts.username" type="text" :pattern="loginWithEmailAddress ? '^[a-zA-Z0-9_@.]+$' : '^[a-zA-Z0-9_]+$'" :spellcheck="false" :autocomplete="loginWithEmailAddress ? 'email webauthn' : 'username webauthn'" autofocus required data-cy-signin-username @update:modelValue="onUsernameChange">
|
||||
<template #prefix>
|
||||
<i v-if="loginWithEmailAddress" class="ti ti-mail"></i>
|
||||
<span v-else>@</span>
|
||||
</template>
|
||||
<template v-if="!loginWithEmailAddress" #suffix>@{{ host }}</template>
|
||||
<template #caption>
|
||||
<button class="_textButton" type="button" tabindex="-1" @click="loginWithEmailAddress = !loginWithEmailAddress">{{ loginWithEmailAddress ? i18n.ts.usernameLogin : i18n.ts.emailAddressLogin }}</button>
|
||||
</template>
|
||||
</MkInput>
|
||||
<MkInput v-if="!user || user && !user.usePasswordLessLogin" v-model="password" :placeholder="i18n.ts.password" type="password" autocomplete="current-password webauthn" :withPasswordToggle="true" required data-cy-signin-password>
|
||||
<template #prefix><i class="ti ti-lock"></i></template>
|
||||
<template #caption><button class="_textButton" type="button" @click="resetPassword">{{ i18n.ts.forgotPassword }}</button></template>
|
||||
<template #caption>
|
||||
<button class="_textButton" type="button" tabindex="-1" @click="resetPassword">{{ i18n.ts.forgotPassword }}</button>
|
||||
</template>
|
||||
</MkInput>
|
||||
<MkCaptcha v-if="!user?.twoFactorEnabled && instance.enableHcaptcha" ref="hcaptcha" v-model="hCaptchaResponse" :class="$style.captcha" provider="hcaptcha" :sitekey="instance.hcaptchaSiteKey"/>
|
||||
<MkCaptcha v-if="!user?.twoFactorEnabled && instance.enableMcaptcha" ref="mcaptcha" v-model="mCaptchaResponse" :class="$style.captcha" provider="mcaptcha" :sitekey="instance.mcaptchaSiteKey" :instanceUrl="instance.mcaptchaInstanceUrl"/>
|
||||
<MkCaptcha v-if="!user?.twoFactorEnabled && instance.enableRecaptcha" ref="recaptcha" v-model="reCaptchaResponse" :class="$style.captcha" provider="recaptcha" :sitekey="instance.recaptchaSiteKey"/>
|
||||
<MkCaptcha v-if="!user?.twoFactorEnabled && instance.enableTurnstile" ref="turnstile" v-model="turnstileResponse" :class="$style.captcha" provider="turnstile" :sitekey="instance.turnstileSiteKey"/>
|
||||
<MkButton type="submit" large primary rounded :disabled="!user || captchaFailed || signing" style="margin: 0 auto;">{{ signing ? i18n.ts.loggingIn : i18n.ts.login }}</MkButton>
|
||||
<MkButton type="submit" large primary rounded :disabled="(!loginWithEmailAddress && !user) || captchaFailed || signing" style="margin: 0 auto;">{{ signing ? i18n.ts.loggingIn : i18n.ts.login }}</MkButton>
|
||||
</div>
|
||||
<div v-if="totpLogin" class="2fa-signin" :class="{ securityKeys: user && user.securityKeys }">
|
||||
<div v-if="user && user.securityKeys" class="twofa-group tap-group">
|
||||
|
@ -70,6 +78,7 @@ import { instance } from '@/instance.js';
|
|||
import MkCaptcha, { type Captcha } from '@/components/MkCaptcha.vue';
|
||||
|
||||
const signing = ref(false);
|
||||
const loginWithEmailAddress = ref(false);
|
||||
const userAbortController = ref<AbortController>();
|
||||
const user = ref<Misskey.entities.UserDetailed | null>(null);
|
||||
const username = ref('');
|
||||
|
@ -119,7 +128,9 @@ const props = defineProps({
|
|||
},
|
||||
});
|
||||
|
||||
function onUsernameChange(): void {
|
||||
async function onUsernameChange(): Promise<void> {
|
||||
if (loginWithEmailAddress.value) return;
|
||||
|
||||
if (userAbortController.value) {
|
||||
userAbortController.value.abort();
|
||||
}
|
||||
|
@ -168,8 +179,15 @@ async function queryKey(): Promise<void> {
|
|||
});
|
||||
}
|
||||
|
||||
function onSubmit(): void {
|
||||
async function onSubmit(): Promise<void> {
|
||||
signing.value = true;
|
||||
if (loginWithEmailAddress.value) {
|
||||
user.value = await misskeyApi('users/get-security-info', {
|
||||
email: username.value,
|
||||
password: password.value,
|
||||
});
|
||||
}
|
||||
|
||||
if (!totpLogin.value && user.value?.twoFactorEnabled) {
|
||||
if (webAuthnSupported() && user.value.securityKeys) {
|
||||
misskeyApi('signin', {
|
||||
|
|
|
@ -27,7 +27,7 @@ import { i18n } from '@/i18n.js';
|
|||
|
||||
withDefaults(defineProps<{
|
||||
autoSet?: boolean;
|
||||
message?: string,
|
||||
message?: string;
|
||||
}>(), {
|
||||
autoSet: false,
|
||||
message: '',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue