mirror of
https://github.com/misskey-dev/misskey.git
synced 2025-03-16 09:55:16 +09:00
feat(frontend): CAPTCHAの設定変更時は実際に検証を通過しないと保存できないようにする
This commit is contained in:
parent
e8bf6285cb
commit
41d5afbffb
@ -94,6 +94,14 @@ const scriptId = computed(() => `script-${props.provider}`);
|
||||
|
||||
const captcha = computed<Captcha>(() => window[variable.value] || {} as unknown as Captcha);
|
||||
|
||||
watch(() => [props.instanceUrl, props.sitekey], async () => {
|
||||
// 変更があったときはリフレッシュと再レンダリングをしておかないと、変更後の値で再検証が出来ない
|
||||
if (available.value) {
|
||||
callback(undefined);
|
||||
await requestRender();
|
||||
}
|
||||
});
|
||||
|
||||
if (loaded || props.provider === 'mcaptcha' || props.provider === 'testcaptcha') {
|
||||
available.value = true;
|
||||
} else if (src.value !== null) {
|
||||
@ -106,20 +114,34 @@ if (loaded || props.provider === 'mcaptcha' || props.provider === 'testcaptcha')
|
||||
}
|
||||
|
||||
function reset() {
|
||||
if (captcha.value.reset) captcha.value.reset();
|
||||
if (captcha.value.reset) {
|
||||
try {
|
||||
captcha.value.reset();
|
||||
} catch (error: unknown) {
|
||||
// ignore
|
||||
if (_DEV_) console.warn(error);
|
||||
}
|
||||
}
|
||||
testcaptchaPassed.value = false;
|
||||
testcaptchaInput.value = '';
|
||||
}
|
||||
|
||||
async function requestRender() {
|
||||
if (captcha.value.render && captchaEl.value instanceof Element) {
|
||||
captcha.value.render(captchaEl.value, {
|
||||
sitekey: props.sitekey,
|
||||
theme: defaultStore.state.darkMode ? 'dark' : 'light',
|
||||
callback: callback,
|
||||
'expired-callback': () => callback(undefined),
|
||||
'error-callback': () => callback(undefined),
|
||||
});
|
||||
// 設定値の変更時などのタイミングで再レンダリングを行う際はリセットしておく必要がある
|
||||
reset();
|
||||
|
||||
if (props.sitekey && props.sitekey.length > 0) {
|
||||
captcha.value.render(captchaEl.value, {
|
||||
sitekey: props.sitekey,
|
||||
theme: defaultStore.state.darkMode ? 'dark' : 'light',
|
||||
callback: callback,
|
||||
'expired-callback': () => callback(undefined),
|
||||
'error-callback': () => callback(undefined),
|
||||
});
|
||||
} else {
|
||||
captchaEl.value.innerHTML = '';
|
||||
}
|
||||
} else if (props.provider === 'mcaptcha' && props.instanceUrl && props.sitekey) {
|
||||
const { default: Widget } = await import('@mcaptcha/vanilla-glue');
|
||||
new Widget({
|
||||
|
@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<div :class="$style.text">{{ i18n.tsx.thereAreNChanges({ n: form.modifiedCount.value }) }}</div>
|
||||
<div style="margin-left: auto;" class="_buttons">
|
||||
<MkButton danger rounded @click="form.discard"><i class="ti ti-x"></i> {{ i18n.ts.discard }}</MkButton>
|
||||
<MkButton primary rounded @click="form.save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton>
|
||||
<MkButton primary rounded :disabled="!canSaving" @click="form.save"><i class="ti ti-check"></i> {{ i18n.ts.save }}</MkButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -26,6 +26,7 @@ const props = defineProps<{
|
||||
discard: () => void;
|
||||
save: () => void;
|
||||
};
|
||||
canSaving: boolean;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self' https://newassets.hcaptcha.com/ https://challenges.cloudflare.com/ http://localhost:7493/;
|
||||
worker-src 'self';
|
||||
script-src 'self' 'unsafe-eval' https://*.hcaptcha.com https://challenges.cloudflare.com https://esm.sh;
|
||||
script-src 'self' 'unsafe-eval' https://*.hcaptcha.com https://*.recaptcha.net https://*.gstatic.com https://challenges.cloudflare.com https://esm.sh;
|
||||
style-src 'self' 'unsafe-inline';
|
||||
img-src 'self' data: blob: www.google.com xn--931a.moe localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000;
|
||||
media-src 'self' localhost:3000 localhost:5173 127.0.0.1:5173 127.0.0.1:3000;
|
||||
|
@ -14,7 +14,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<template v-else-if="botProtectionForm.savedState.provider === 'testcaptcha'" #suffix>testCaptcha</template>
|
||||
<template v-else #suffix>{{ i18n.ts.none }} ({{ i18n.ts.notRecommended }})</template>
|
||||
<template v-if="botProtectionForm.modified.value" #footer>
|
||||
<MkFormFooter :form="botProtectionForm"/>
|
||||
<MkFormFooter :canSaving="canSaving" :form="botProtectionForm"/>
|
||||
</template>
|
||||
|
||||
<div class="_gaps_m">
|
||||
@ -36,11 +36,18 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>{{ i18n.ts.hcaptchaSecretKey }}</template>
|
||||
</MkInput>
|
||||
<FormSlot>
|
||||
<FormSlot v-if="botProtectionForm.state.hcaptchaSiteKey">
|
||||
<template #label>{{ i18n.ts.preview }}</template>
|
||||
<MkCaptcha provider="hcaptcha" :sitekey="botProtectionForm.state.hcaptchaSiteKey || '10000000-ffff-ffff-ffff-000000000001'"/>
|
||||
<MkCaptcha v-model="hCaptchaResponse" provider="hcaptcha" :sitekey="botProtectionForm.state.hcaptchaSiteKey"/>
|
||||
</FormSlot>
|
||||
<MkInfo>
|
||||
<div :class="$style.captchaInfoMsg">
|
||||
<div>サイトキーに"10000000-ffff-ffff-ffff-000000000001"と入力することで動作をテスト出来ます。<br/>本番運用時には必ず正規のサイトキーを設定してください。</div>
|
||||
<div>ref: <a href="https://docs.hcaptcha.com/#integration-testing-test-keys" target="_blank">hCaptcha Developer Guide</a></div>
|
||||
</div>
|
||||
</MkInfo>
|
||||
</template>
|
||||
|
||||
<template v-else-if="botProtectionForm.state.provider === 'mcaptcha'">
|
||||
<MkInput v-model="botProtectionForm.state.mcaptchaSiteKey">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
@ -56,9 +63,10 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</MkInput>
|
||||
<FormSlot v-if="botProtectionForm.state.mcaptchaSiteKey && botProtectionForm.state.mcaptchaInstanceUrl">
|
||||
<template #label>{{ i18n.ts.preview }}</template>
|
||||
<MkCaptcha provider="mcaptcha" :sitekey="botProtectionForm.state.mcaptchaSiteKey" :instanceUrl="botProtectionForm.state.mcaptchaInstanceUrl"/>
|
||||
<MkCaptcha v-model="mCaptchaResponse" provider="mcaptcha" :sitekey="botProtectionForm.state.mcaptchaSiteKey" :instanceUrl="botProtectionForm.state.mcaptchaInstanceUrl"/>
|
||||
</FormSlot>
|
||||
</template>
|
||||
|
||||
<template v-else-if="botProtectionForm.state.provider === 'recaptcha'">
|
||||
<MkInput v-model="botProtectionForm.state.recaptchaSiteKey">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
@ -70,9 +78,16 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</MkInput>
|
||||
<FormSlot v-if="botProtectionForm.state.recaptchaSiteKey">
|
||||
<template #label>{{ i18n.ts.preview }}</template>
|
||||
<MkCaptcha provider="recaptcha" :sitekey="botProtectionForm.state.recaptchaSiteKey"/>
|
||||
<MkCaptcha v-model="reCaptchaResponse" provider="recaptcha" :sitekey="botProtectionForm.state.recaptchaSiteKey"/>
|
||||
</FormSlot>
|
||||
<MkInfo>
|
||||
<div :class="$style.captchaInfoMsg">
|
||||
<div>サイトキーに"6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI"と入力することで動作をテスト出来ます。<br/>本番運用時には必ず正規のサイトキーを設定してください。</div>
|
||||
<div>ref: <a href="https://developers.google.com/recaptcha/docs/faq?hl=ja#id-like-to-run-automated-tests-with-recaptcha.-what-should-i-do" target="_blank">reCAPTCHA FAQ</a></div>
|
||||
</div>
|
||||
</MkInfo>
|
||||
</template>
|
||||
|
||||
<template v-else-if="botProtectionForm.state.provider === 'turnstile'">
|
||||
<MkInput v-model="botProtectionForm.state.turnstileSiteKey">
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
@ -82,16 +97,23 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>{{ i18n.ts.turnstileSecretKey }}</template>
|
||||
</MkInput>
|
||||
<FormSlot>
|
||||
<FormSlot v-if="botProtectionForm.state.turnstileSiteKey">
|
||||
<template #label>{{ i18n.ts.preview }}</template>
|
||||
<MkCaptcha provider="turnstile" :sitekey="botProtectionForm.state.turnstileSiteKey || '1x00000000000000000000AA'"/>
|
||||
<MkCaptcha v-model="turnstileResponse" provider="turnstile" :sitekey="botProtectionForm.state.turnstileSiteKey"/>
|
||||
</FormSlot>
|
||||
<MkInfo>
|
||||
<div :class="$style.captchaInfoMsg">
|
||||
<div>サイトキーに"1x00000000000000000000AA"と入力することで動作をテスト出来ます。<br/>本番運用時には必ず正規のサイトキーを設定してください。</div>
|
||||
<div>ref: <a href="https://developers.cloudflare.com/turnstile/troubleshooting/testing/" target="_blank">Cloudflare Docs</a></div>
|
||||
</div>
|
||||
</MkInfo>
|
||||
</template>
|
||||
|
||||
<template v-else-if="botProtectionForm.state.provider === 'testcaptcha'">
|
||||
<MkInfo warn><span v-html="i18n.ts.testCaptchaWarning"></span></MkInfo>
|
||||
<FormSlot>
|
||||
<template #label>{{ i18n.ts.preview }}</template>
|
||||
<MkCaptcha provider="testcaptcha"/>
|
||||
<MkCaptcha v-model="testCaptchaResponse" provider="testcaptcha" :sitekey="null"/>
|
||||
</FormSlot>
|
||||
</template>
|
||||
</div>
|
||||
@ -99,7 +121,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, ref } from 'vue';
|
||||
import { computed, defineAsyncComponent, ref } from 'vue';
|
||||
import MkRadios from '@/components/MkRadios.vue';
|
||||
import MkInput from '@/components/MkInput.vue';
|
||||
import FormSlot from '@/components/form/slot.vue';
|
||||
@ -116,6 +138,20 @@ const MkCaptcha = defineAsyncComponent(() => import('@/components/MkCaptcha.vue'
|
||||
|
||||
const meta = await misskeyApi('admin/meta');
|
||||
|
||||
const hCaptchaResponse = ref<string | null>(null);
|
||||
const mCaptchaResponse = ref<string | null>(null);
|
||||
const reCaptchaResponse = ref<string | null>(null);
|
||||
const turnstileResponse = ref<string | null>(null);
|
||||
const testCaptchaResponse = ref<string | null>(null);
|
||||
|
||||
const canSaving = computed((): boolean => {
|
||||
return (botProtectionForm.state.provider === 'hcaptcha' && !!hCaptchaResponse.value) ||
|
||||
(botProtectionForm.state.provider === 'mcaptcha' && !!mCaptchaResponse.value) ||
|
||||
(botProtectionForm.state.provider === 'recaptcha' && !!reCaptchaResponse.value) ||
|
||||
(botProtectionForm.state.provider === 'turnstile' && !!turnstileResponse.value) ||
|
||||
(botProtectionForm.state.provider === 'testcaptcha' && !!testCaptchaResponse.value);
|
||||
});
|
||||
|
||||
const botProtectionForm = useForm({
|
||||
provider: meta.enableHcaptcha
|
||||
? 'hcaptcha'
|
||||
@ -157,3 +193,11 @@ const botProtectionForm = useForm({
|
||||
fetchInstance(true);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.captchaInfoMsg {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
</style>
|
||||
|
Loading…
Reference in New Issue
Block a user