-
-
- {{ message }}
-
-
-
-
- {{ i18n.ts.continueOnRemote }}
-
-
-
-
-
-
-
- @
- @{{ host }}
-
-
-
-
-
-
-
-
-
- {{ signing ? i18n.ts.loggingIn : i18n.ts.login }}
-
-
-
-
{{ i18n.ts.useSecurityKey }}
-
- {{ i18n.ts.retry }}
-
-
-
-
-
- {{ i18n.ts.token }} ({{ i18n.ts['2fa'] }})
-
-
-
- {{ signing ? i18n.ts.loggingIn : i18n.ts.login }}
-
-
-
-
-
-
- {{ signing ? i18n.ts.loggingIn : i18n.ts.signinWithPasskey }}
-
-
{{ i18n.ts.useSecurityKey }}
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
diff --git a/packages/frontend/src/components/MkSigninDialog.vue b/packages/frontend/src/components/MkSigninDialog.vue
index d48780e9de..8351d7d5e0 100644
--- a/packages/frontend/src/components/MkSigninDialog.vue
+++ b/packages/frontend/src/components/MkSigninDialog.vue
@@ -4,26 +4,29 @@ SPDX-License-Identifier: AGPL-3.0-only
-->
-
- {{ i18n.ts.login }}
-
-
-
-
-
+
+
+
{{ i18n.ts.login }}
+
+
+
+
+
+
+
+
+
diff --git a/packages/misskey-js/etc/misskey-js.api.md b/packages/misskey-js/etc/misskey-js.api.md
index 5f4792eb74..9ad784c296 100644
--- a/packages/misskey-js/etc/misskey-js.api.md
+++ b/packages/misskey-js/etc/misskey-js.api.md
@@ -3040,7 +3040,7 @@ type Signin = components['schemas']['Signin'];
// @public (undocumented)
type SigninRequest = {
username: string;
- password: string;
+ password?: string;
token?: string;
credential?: AuthenticationResponseJSON;
'hcaptcha-response'?: string | null;
diff --git a/packages/misskey-js/src/autogen/types.ts b/packages/misskey-js/src/autogen/types.ts
index 32646d28ed..3876a0bfe5 100644
--- a/packages/misskey-js/src/autogen/types.ts
+++ b/packages/misskey-js/src/autogen/types.ts
@@ -3782,16 +3782,13 @@ export type components = {
followingVisibility: 'public' | 'followers' | 'private';
/** @enum {string} */
followersVisibility: 'public' | 'followers' | 'private';
- /** @default false */
- twoFactorEnabled: boolean;
- /** @default false */
- usePasswordLessLogin: boolean;
- /** @default false */
- securityKeys: boolean;
roles: components['schemas']['RoleLite'][];
followedMessage?: string | null;
memo: string | null;
moderationNote?: string;
+ twoFactorEnabled?: boolean;
+ usePasswordLessLogin?: boolean;
+ securityKeys?: boolean;
isFollowing?: boolean;
isFollowed?: boolean;
hasPendingFollowRequestFromYou?: boolean;
@@ -3972,6 +3969,12 @@ export type components = {
}[];
loggedInDays: number;
policies: components['schemas']['RolePolicies'];
+ /** @default false */
+ twoFactorEnabled: boolean;
+ /** @default false */
+ usePasswordLessLogin: boolean;
+ /** @default false */
+ securityKeys: boolean;
email?: string | null;
emailVerified?: boolean | null;
securityKeysList?: {
diff --git a/packages/misskey-js/src/entities.ts b/packages/misskey-js/src/entities.ts
index 36b7f5bca3..98ac50e5a1 100644
--- a/packages/misskey-js/src/entities.ts
+++ b/packages/misskey-js/src/entities.ts
@@ -269,7 +269,7 @@ export type SignupPendingResponse = {
export type SigninRequest = {
username: string;
- password: string;
+ password?: string;
token?: string;
credential?: AuthenticationResponseJSON;
'hcaptcha-response'?: string | null;
--
cgit v1.2.3-freya
From af1cbc131fc9e045692f9f9def708c0978817fff Mon Sep 17 00:00:00 2001
From: syuilo <4439005+syuilo@users.noreply.github.com>
Date: Fri, 11 Oct 2024 21:05:53 +0900
Subject: wip (#14745)
---
locales/index.d.ts | 4 +++
locales/ja-JP.yml | 1 +
.../backend/migration/1728550878802-testcaptcha.js | 16 ++++++++++++
packages/backend/src/core/CaptchaService.ts | 13 ++++++++++
.../backend/src/core/entities/MetaEntityService.ts | 1 +
packages/backend/src/models/Meta.ts | 5 ++++
packages/backend/src/models/json-schema/meta.ts | 4 +++
.../backend/src/server/api/ApiServerService.ts | 2 ++
.../backend/src/server/api/SigninApiService.ts | 7 ++++++
.../backend/src/server/api/SignupApiService.ts | 7 ++++++
.../backend/src/server/api/endpoints/admin/meta.ts | 5 ++++
.../src/server/api/endpoints/admin/update-meta.ts | 5 ++++
packages/frontend/assets/testcaptcha.png | Bin 0 -> 2634 bytes
packages/frontend/src/components/MkCaptcha.vue | 28 +++++++++++++++++++--
.../frontend/src/components/MkSignin.password.vue | 9 ++++++-
packages/frontend/src/components/MkSignin.vue | 6 ++---
.../src/components/MkSignupDialog.form.vue | 6 +++++
.../frontend/src/pages/admin/bot-protection.vue | 15 ++++++++++-
packages/misskey-js/src/autogen/types.ts | 3 +++
19 files changed, 130 insertions(+), 7 deletions(-)
create mode 100644 packages/backend/migration/1728550878802-testcaptcha.js
create mode 100644 packages/frontend/assets/testcaptcha.png
(limited to 'packages/backend/src/models/json-schema')
diff --git a/locales/index.d.ts b/locales/index.d.ts
index f0dead1245..dab8eb0361 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -5166,6 +5166,10 @@ export interface Locale extends ILocale {
* 対象
*/
"target": string;
+ /**
+ * CAPTCHAのテストを目的とした機能です。
本番環境で使用しないでください。
+ */
+ "testCaptchaWarning": string;
"_abuseUserReport": {
/**
* 転送
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 48a670ce50..440ffa9306 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1287,6 +1287,7 @@ passkeyVerificationFailed: "パスキーの検証に失敗しました。"
passkeyVerificationSucceededButPasswordlessLoginDisabled: "パスキーの検証に成功しましたが、パスワードレスログインが無効になっています。"
messageToFollower: "フォロワーへのメッセージ"
target: "対象"
+testCaptchaWarning: "CAPTCHAのテストを目的とした機能です。
本番環境で使用しないでください。"
_abuseUserReport:
forward: "転送"
diff --git a/packages/backend/migration/1728550878802-testcaptcha.js b/packages/backend/migration/1728550878802-testcaptcha.js
new file mode 100644
index 0000000000..d8d987c0c1
--- /dev/null
+++ b/packages/backend/migration/1728550878802-testcaptcha.js
@@ -0,0 +1,16 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and misskey-project
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class Testcaptcha1728550878802 {
+ name = 'Testcaptcha1728550878802'
+
+ async up(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "meta" ADD "enableTestcaptcha" boolean NOT NULL DEFAULT false`);
+ }
+
+ async down(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableTestcaptcha"`);
+ }
+}
diff --git a/packages/backend/src/core/CaptchaService.ts b/packages/backend/src/core/CaptchaService.ts
index f6b7955cd2..206d0dbe0a 100644
--- a/packages/backend/src/core/CaptchaService.ts
+++ b/packages/backend/src/core/CaptchaService.ts
@@ -119,5 +119,18 @@ export class CaptchaService {
throw new Error(`turnstile-failed: ${errorCodes}`);
}
}
+
+ @bindThis
+ public async verifyTestcaptcha(response: string | null | undefined): Promise
{
+ if (response == null) {
+ throw new Error('testcaptcha-failed: no response provided');
+ }
+
+ const success = response === 'testcaptcha-passed';
+
+ if (!success) {
+ throw new Error('testcaptcha-failed');
+ }
+ }
}
diff --git a/packages/backend/src/core/entities/MetaEntityService.ts b/packages/backend/src/core/entities/MetaEntityService.ts
index fbd982eb34..409dca3426 100644
--- a/packages/backend/src/core/entities/MetaEntityService.ts
+++ b/packages/backend/src/core/entities/MetaEntityService.ts
@@ -96,6 +96,7 @@ export class MetaEntityService {
recaptchaSiteKey: instance.recaptchaSiteKey,
enableTurnstile: instance.enableTurnstile,
turnstileSiteKey: instance.turnstileSiteKey,
+ enableTestcaptcha: instance.enableTestcaptcha,
swPublickey: instance.swPublicKey,
themeColor: instance.themeColor,
mascotImageUrl: instance.mascotImageUrl ?? '/assets/ai.png',
diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts
index d29689f907..fd007de6c6 100644
--- a/packages/backend/src/models/Meta.ts
+++ b/packages/backend/src/models/Meta.ts
@@ -258,6 +258,11 @@ export class MiMeta {
})
public turnstileSecretKey: string | null;
+ @Column('boolean', {
+ default: false,
+ })
+ public enableTestcaptcha: boolean;
+
// chaptcha系を追加した際にはnodeinfoのレスポンスに追加するのを忘れないようにすること
@Column('enum', {
diff --git a/packages/backend/src/models/json-schema/meta.ts b/packages/backend/src/models/json-schema/meta.ts
index 99feeaa7d7..e3fd63464a 100644
--- a/packages/backend/src/models/json-schema/meta.ts
+++ b/packages/backend/src/models/json-schema/meta.ts
@@ -115,6 +115,10 @@ export const packedMetaLiteSchema = {
type: 'string',
optional: false, nullable: true,
},
+ enableTestcaptcha: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
swPublickey: {
type: 'string',
optional: false, nullable: true,
diff --git a/packages/backend/src/server/api/ApiServerService.ts b/packages/backend/src/server/api/ApiServerService.ts
index be63635efe..3a8cb19f01 100644
--- a/packages/backend/src/server/api/ApiServerService.ts
+++ b/packages/backend/src/server/api/ApiServerService.ts
@@ -119,6 +119,7 @@ export class ApiServerService {
'g-recaptcha-response'?: string;
'turnstile-response'?: string;
'm-captcha-response'?: string;
+ 'testcaptcha-response'?: string;
}
}>('/signup', (request, reply) => this.signupApiService.signup(request, reply));
@@ -132,6 +133,7 @@ export class ApiServerService {
'g-recaptcha-response'?: string;
'turnstile-response'?: string;
'm-captcha-response'?: string;
+ 'testcaptcha-response'?: string;
};
}>('/signin-flow', (request, reply) => this.signinApiService.signin(request, reply));
diff --git a/packages/backend/src/server/api/SigninApiService.ts b/packages/backend/src/server/api/SigninApiService.ts
index 0d24ffa56a..1d983ca4bc 100644
--- a/packages/backend/src/server/api/SigninApiService.ts
+++ b/packages/backend/src/server/api/SigninApiService.ts
@@ -71,6 +71,7 @@ export class SigninApiService {
'g-recaptcha-response'?: string;
'turnstile-response'?: string;
'm-captcha-response'?: string;
+ 'testcaptcha-response'?: string;
};
}>,
reply: FastifyReply,
@@ -194,6 +195,12 @@ export class SigninApiService {
throw new FastifyReplyError(400, err);
});
}
+
+ if (this.meta.enableTestcaptcha) {
+ await this.captchaService.verifyTestcaptcha(body['testcaptcha-response']).catch(err => {
+ throw new FastifyReplyError(400, err);
+ });
+ }
}
if (same) {
diff --git a/packages/backend/src/server/api/SignupApiService.ts b/packages/backend/src/server/api/SignupApiService.ts
index c499638018..3ec5e5d3e6 100644
--- a/packages/backend/src/server/api/SignupApiService.ts
+++ b/packages/backend/src/server/api/SignupApiService.ts
@@ -67,6 +67,7 @@ export class SignupApiService {
'g-recaptcha-response'?: string;
'turnstile-response'?: string;
'm-captcha-response'?: string;
+ 'testcaptcha-response'?: string;
}
}>,
reply: FastifyReply,
@@ -99,6 +100,12 @@ export class SignupApiService {
throw new FastifyReplyError(400, err);
});
}
+
+ if (this.meta.enableTestcaptcha) {
+ await this.captchaService.verifyTestcaptcha(body['testcaptcha-response']).catch(err => {
+ throw new FastifyReplyError(400, err);
+ });
+ }
}
const username = body['username'];
diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts
index b76ed5c524..abb3c17be3 100644
--- a/packages/backend/src/server/api/endpoints/admin/meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/meta.ts
@@ -69,6 +69,10 @@ export const meta = {
type: 'string',
optional: false, nullable: true,
},
+ enableTestcaptcha: {
+ type: 'boolean',
+ optional: false, nullable: false,
+ },
swPublickey: {
type: 'string',
optional: false, nullable: true,
@@ -555,6 +559,7 @@ export default class extends Endpoint { // eslint-
recaptchaSiteKey: instance.recaptchaSiteKey,
enableTurnstile: instance.enableTurnstile,
turnstileSiteKey: instance.turnstileSiteKey,
+ enableTestcaptcha: instance.enableTestcaptcha,
swPublickey: instance.swPublicKey,
themeColor: instance.themeColor,
mascotImageUrl: instance.mascotImageUrl,
diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
index 9ffae840b6..e97ac4e2b9 100644
--- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
@@ -78,6 +78,7 @@ export const paramDef = {
enableTurnstile: { type: 'boolean' },
turnstileSiteKey: { type: 'string', nullable: true },
turnstileSecretKey: { type: 'string', nullable: true },
+ enableTestcaptcha: { type: 'boolean' },
sensitiveMediaDetection: { type: 'string', enum: ['none', 'all', 'local', 'remote'] },
sensitiveMediaDetectionSensitivity: { type: 'string', enum: ['medium', 'low', 'high', 'veryLow', 'veryHigh'] },
setSensitiveFlagAutomatically: { type: 'boolean' },
@@ -357,6 +358,10 @@ export default class extends Endpoint { // eslint-
set.turnstileSecretKey = ps.turnstileSecretKey;
}
+ if (ps.enableTestcaptcha !== undefined) {
+ set.enableTestcaptcha = ps.enableTestcaptcha;
+ }
+
if (ps.sensitiveMediaDetection !== undefined) {
set.sensitiveMediaDetection = ps.sensitiveMediaDetection;
}
diff --git a/packages/frontend/assets/testcaptcha.png b/packages/frontend/assets/testcaptcha.png
new file mode 100644
index 0000000000..9bfd252b51
Binary files /dev/null and b/packages/frontend/assets/testcaptcha.png differ
diff --git a/packages/frontend/src/components/MkCaptcha.vue b/packages/frontend/src/components/MkCaptcha.vue
index c5b6e0caed..82fc89e51c 100644
--- a/packages/frontend/src/components/MkCaptcha.vue
+++ b/packages/frontend/src/components/MkCaptcha.vue
@@ -10,6 +10,17 @@ SPDX-License-Identifier: AGPL-3.0-only
+