From df322ebadcd2718c703e05354c525b44ebb74073 Mon Sep 17 00:00:00 2001 From: Leafus Date: Mon, 19 May 2025 16:33:28 +0000 Subject: [PATCH] feat: require a special registration word in registration reason (#2) A crude way to prune out people who don't read the rules. The hint is in the bottom of the rules generally. --- locales/en-US.yml | 1 + .../1743894419864-AddRegWordFieldsToMeta.js | 20 ++ .../src/core/entities/MetaEntityService.ts | 2 + packages/backend/src/models/Meta.ts | 17 +- .../backend/src/models/json-schema/meta.ts | 8 + .../src/server/api/endpoints/admin/meta.ts | 10 + .../server/api/endpoints/admin/update-meta.ts | 10 + .../src/components/MkSignupDialog.form.vue | 8 +- .../frontend/src/pages/admin/security.vue | 189 +++++++++++------- 9 files changed, 185 insertions(+), 80 deletions(-) create mode 100644 packages/backend/migration/1743894419864-AddRegWordFieldsToMeta.js diff --git a/locales/en-US.yml b/locales/en-US.yml index 230717f372..c4c4e844d3 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -1982,6 +1982,7 @@ _signup: almostThere: "Almost there" emailAddressInfo: "Please enter your email address. It will not be made public." emailSent: "A confirmation email has been sent to your email address ({email}). Please click the included link to complete account creation." + registrationWordRequired: "Please include the required registration word in your reason" _accountDelete: accountDelete: "Delete account" mayTakeTime: "As account deletion is a resource-heavy process, it may take some time to complete depending on how much content you have created and how many files you have uploaded." diff --git a/packages/backend/migration/1743894419864-AddRegWordFieldsToMeta.js b/packages/backend/migration/1743894419864-AddRegWordFieldsToMeta.js new file mode 100644 index 0000000000..89bbe21783 --- /dev/null +++ b/packages/backend/migration/1743894419864-AddRegWordFieldsToMeta.js @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class AddRegWordFieldsToMeta1743894419864 implements MigrationInterface { + name = 'AddRegWordFieldsToMeta1743894419864' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "meta" ADD "regWordRequired" boolean NOT NULL DEFAULT false`); + await queryRunner.query(`ALTER TABLE "meta" ADD "registrationWord" character varying(1024)`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "registrationWord"`); + await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "regWordRequired"`); + } +} diff --git a/packages/backend/src/core/entities/MetaEntityService.ts b/packages/backend/src/core/entities/MetaEntityService.ts index 294187feba..8ca33a0b58 100644 --- a/packages/backend/src/core/entities/MetaEntityService.ts +++ b/packages/backend/src/core/entities/MetaEntityService.ts @@ -86,6 +86,8 @@ export class MetaEntityService { disableRegistration: instance.disableRegistration, emailRequiredForSignup: instance.emailRequiredForSignup, approvalRequiredForSignup: instance.approvalRequiredForSignup, + regWordRequired: instance.regWordRequired, + registrationWord: instance.registrationWord, enableHcaptcha: instance.enableHcaptcha, hcaptchaSiteKey: instance.hcaptchaSiteKey, enableMcaptcha: instance.enableMcaptcha, diff --git a/packages/backend/src/models/Meta.ts b/packages/backend/src/models/Meta.ts index b032c6b459..d9b9d2f81f 100644 --- a/packages/backend/src/models/Meta.ts +++ b/packages/backend/src/models/Meta.ts @@ -139,9 +139,8 @@ export class MiMeta { }) public logoImageUrl: string | null; - @Column('varchar', { - length: 1024, - nullable: true, + @Column('boolean', { + default: false, }) public iconUrl: string | null; @@ -204,6 +203,18 @@ export class MiMeta { @Column('boolean', { default: false, }) + public regWordRequired: boolean; + + @Column('varchar', { + length: 1024, + nullable: true, + }) + public registrationWord: string | null; + + @Column('varchar', { + length: 1024, + nullable: true, + }) public enableHcaptcha: boolean; @Column('varchar', { diff --git a/packages/backend/src/models/json-schema/meta.ts b/packages/backend/src/models/json-schema/meta.ts index 8cc1686ac6..10334f1b78 100644 --- a/packages/backend/src/models/json-schema/meta.ts +++ b/packages/backend/src/models/json-schema/meta.ts @@ -313,6 +313,14 @@ export const packedMetaLiteSchema = { type: 'string', optional: false, nullable: true, }, + regWordRequired: { + type: 'boolean', + optional: false, nullable: false, + }, + registrationWord: { + type: 'string', + optional: false, nullable: true, + }, privacyPolicyUrl: { type: 'string', optional: false, nullable: true, diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index fe8ca012b2..c85e72779b 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -39,6 +39,14 @@ export const meta = { type: 'boolean', optional: false, nullable: false, }, + registrationWord: { + type: 'string', + optional: false, nullable: true, + }, + regWordRequired: { + type: 'boolean', + optional: false, nullable: false, + }, enableHcaptcha: { type: 'boolean', optional: false, nullable: false, @@ -657,6 +665,8 @@ export default class extends Endpoint { // eslint- disableRegistration: instance.disableRegistration, emailRequiredForSignup: instance.emailRequiredForSignup, approvalRequiredForSignup: instance.approvalRequiredForSignup, + registrationWord: instance.registrationWord, + regWordRequired: instance.regWordRequired, enableHcaptcha: instance.enableHcaptcha, hcaptchaSiteKey: instance.hcaptchaSiteKey, enableMcaptcha: instance.enableMcaptcha, 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 4970d28cfa..7d07d4a3b5 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -74,6 +74,8 @@ export const paramDef = { cacheRemoteSensitiveFiles: { type: 'boolean' }, emailRequiredForSignup: { type: 'boolean' }, approvalRequiredForSignup: { type: 'boolean' }, + regWordRequired: { type: 'boolean', nullable: false }, + registrationWord: { type: 'string', nullable: true }, enableHcaptcha: { type: 'boolean' }, hcaptchaSiteKey: { type: 'string', nullable: true }, hcaptchaSecretKey: { type: 'string', nullable: true }, @@ -357,6 +359,14 @@ export default class extends Endpoint { // eslint- set.approvalRequiredForSignup = ps.approvalRequiredForSignup; } + if (ps.registrationWord !== undefined) { + set.registrationWord = ps.registrationWord; + } + + if (ps.regWordRequired !== undefined) { + set.regWordRequired = ps.regWordRequired; + } + if (ps.enableHcaptcha !== undefined) { set.enableHcaptcha = ps.enableHcaptcha; } diff --git a/packages/frontend/src/components/MkSignupDialog.form.vue b/packages/frontend/src/components/MkSignupDialog.form.vue index 003c68309d..b96eb64c7c 100644 --- a/packages/frontend/src/components/MkSignupDialog.form.vue +++ b/packages/frontend/src/components/MkSignupDialog.form.vue @@ -65,6 +65,11 @@ SPDX-License-Identifier: AGPL-3.0-only + @@ -149,7 +154,8 @@ const shouldDisableSubmitting = computed((): boolean => { instance.enableTestcaptcha && !testcaptchaResponse.value || instance.emailRequiredForSignup && emailState.value !== 'ok' || usernameState.value !== 'ok' || - passwordRetypeState.value !== 'match'; + passwordRetypeState.value !== 'match' || + (instance.regWordRequired && !reason.value.includes(instance.registrationWord)); }); function getPasswordStrength(source: string): number { diff --git a/packages/frontend/src/pages/admin/security.vue b/packages/frontend/src/pages/admin/security.vue index 414dc145ff..6dcef97cae 100644 --- a/packages/frontend/src/pages/admin/security.vue +++ b/packages/frontend/src/pages/admin/security.vue @@ -4,91 +4,117 @@ SPDX-License-Identifier: AGPL-3.0-only -->