summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2023-04-29 17:03:14 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2023-04-29 17:03:14 +0900
commit0ad7869249c8594277afc0aa707c05ac2ed633cf (patch)
tree8a889e6c4a764df00ac0ce4c0d8e11c62856387a
parentMerge branch 'develop' of https://github.com/misskey-dev/misskey into develop (diff)
downloadsharkey-0ad7869249c8594277afc0aa707c05ac2ed633cf.tar.gz
sharkey-0ad7869249c8594277afc0aa707c05ac2ed633cf.tar.bz2
sharkey-0ad7869249c8594277afc0aa707c05ac2ed633cf.zip
feat: preserved usernames
Resolve #10704
-rw-r--r--CHANGELOG.md1
-rw-r--r--locales/ja-JP.yml2
-rw-r--r--packages/backend/migration/1682754135458-preservedUsernames.js11
-rw-r--r--packages/backend/src/core/SignupService.ts15
-rw-r--r--packages/backend/src/models/entities/Meta.ts5
-rw-r--r--packages/backend/src/server/api/SignupApiService.ts7
-rw-r--r--packages/backend/src/server/api/endpoints/admin/accounts/create.ts1
-rw-r--r--packages/backend/src/server/api/endpoints/admin/meta.ts9
-rw-r--r--packages/backend/src/server/api/endpoints/admin/update-meta.ts5
-rw-r--r--packages/backend/src/server/api/endpoints/username/available.ts9
-rw-r--r--packages/frontend/src/pages/admin/moderation.vue9
11 files changed, 68 insertions, 6 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 210b1ed5fe..4704c8050f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,6 +26,7 @@
- ロールタイムラインをロールごとに表示するかどうかの選択できるようになりました。
* デフォルトがオフになるので、ロールタイムラインを表示する場合はオンにしてください。
- カスタム絵文字のライセンスを複数でセットできるようになりました。
+- 管理者が予約ユーザー名を設定できるようになりました。
### Client
- 通知の表示をカスタマイズできるように
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 1e2019b8f0..5e2e83fb19 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1022,6 +1022,8 @@ serverRules: "サーバールール"
pleaseConfirmBelowBeforeSignup: "このサーバーに登録する前に、以下を確認してください。"
pleaseAgreeAllToContinue: "続けるには、全ての「同意する」にチェックが入っている必要があります。"
continue: "続ける"
+preservedUsernames: "予約ユーザー名"
+preservedUsernamesDescription: "予約するユーザー名を改行で列挙します。ここで指定されたユーザー名はアカウント作成時に使えなくなりますが、管理者によるアカウント作成自はこの制限を受けません。また、既に存在するアカウントも影響を受けません。"
_serverRules:
description: "新規登録前に表示する、サーバーの簡潔なルールを設定します。内容は利用規約の要約とすることを推奨します。"
diff --git a/packages/backend/migration/1682754135458-preservedUsernames.js b/packages/backend/migration/1682754135458-preservedUsernames.js
new file mode 100644
index 0000000000..46a0826f43
--- /dev/null
+++ b/packages/backend/migration/1682754135458-preservedUsernames.js
@@ -0,0 +1,11 @@
+export class PreservedUsernames1682754135458 {
+ name = 'PreservedUsernames1682754135458'
+
+ async up(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "meta" ADD "preservedUsernames" character varying(1024) array NOT NULL DEFAULT '{ "admin", "administrator", "root", "system", "maintainer", "host", "mod", "moderator", "owner", "superuser", "staff", "auth", "i", "me", "everyone", "all", "mention", "mentions", "example", "user", "users", "account", "accounts", "official", "help", "helps", "support", "supports", "info", "information", "informations", "announce", "announces", "announcement", "announcements", "notice", "notification", "notifications", "dev", "developer", "developers", "tech", "misskey" }'`);
+ }
+
+ async down(queryRunner) {
+ await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "preservedUsernames"`);
+ }
+}
diff --git a/packages/backend/src/core/SignupService.ts b/packages/backend/src/core/SignupService.ts
index d7bc05b8bd..2b8387f89c 100644
--- a/packages/backend/src/core/SignupService.ts
+++ b/packages/backend/src/core/SignupService.ts
@@ -13,8 +13,9 @@ import { UsedUsername } from '@/models/entities/UsedUsername.js';
import generateUserToken from '@/misc/generate-native-user-token.js';
import { UserEntityService } from '@/core/entities/UserEntityService.js';
import { bindThis } from '@/decorators.js';
-import UsersChart from './chart/charts/users.js';
-import { UtilityService } from './UtilityService.js';
+import UsersChart from '@/core/chart/charts/users.js';
+import { UtilityService } from '@/core/UtilityService.js';
+import { MetaService } from '@/core/MetaService.js';
@Injectable()
export class SignupService {
@@ -34,6 +35,7 @@ export class SignupService {
private utilityService: UtilityService,
private userEntityService: UserEntityService,
private idService: IdService,
+ private metaService: MetaService,
private usersChart: UsersChart,
) {
}
@@ -44,6 +46,7 @@ export class SignupService {
password?: string | null;
passwordHash?: UserProfile['password'] | null;
host?: string | null;
+ ignorePreservedUsernames?: boolean;
}) {
const { username, password, passwordHash, host } = opts;
let hash = passwordHash;
@@ -76,6 +79,14 @@ export class SignupService {
if (await this.usedUsernamesRepository.findOneBy({ username: username.toLowerCase() })) {
throw new Error('USED_USERNAME');
}
+
+ if (!opts.ignorePreservedUsernames) {
+ const instance = await this.metaService.fetch(true);
+ const isPreserved = instance.preservedUsernames.map(x => x.toLowerCase()).includes(username.toLowerCase());
+ if (isPreserved) {
+ throw new Error('USED_USERNAME');
+ }
+ }
const keyPair = await new Promise<string[]>((res, rej) =>
generateKeyPair('rsa', {
diff --git a/packages/backend/src/models/entities/Meta.ts b/packages/backend/src/models/entities/Meta.ts
index c8df141a0b..6d44e4edc7 100644
--- a/packages/backend/src/models/entities/Meta.ts
+++ b/packages/backend/src/models/entities/Meta.ts
@@ -412,4 +412,9 @@ export class Meta {
default: '{}',
})
public serverRules: string[];
+
+ @Column('varchar', {
+ length: 1024, array: true, default: '{ "admin", "administrator", "root", "system", "maintainer", "host", "mod", "moderator", "owner", "superuser", "staff", "auth", "i", "me", "everyone", "all", "mention", "mentions", "example", "user", "users", "account", "accounts", "official", "help", "helps", "support", "supports", "info", "information", "informations", "announce", "announces", "announcement", "announcements", "notice", "notification", "notifications", "dev", "developer", "developers", "tech", "misskey" }',
+ })
+ public preservedUsernames: string[];
}
diff --git a/packages/backend/src/server/api/SignupApiService.ts b/packages/backend/src/server/api/SignupApiService.ts
index fbabf47aff..f44e71771c 100644
--- a/packages/backend/src/server/api/SignupApiService.ts
+++ b/packages/backend/src/server/api/SignupApiService.ts
@@ -1,6 +1,7 @@
import { Inject, Injectable } from '@nestjs/common';
import rndstr from 'rndstr';
import bcrypt from 'bcryptjs';
+import { IsNull } from 'typeorm';
import { DI } from '@/di-symbols.js';
import type { RegistrationTicketsRepository, UsedUsernamesRepository, UserPendingsRepository, UserProfilesRepository, UsersRepository } from '@/models/index.js';
import type { Config } from '@/config.js';
@@ -15,7 +16,6 @@ import { FastifyReplyError } from '@/misc/fastify-reply-error.js';
import { bindThis } from '@/decorators.js';
import { SigninService } from './SigninService.js';
import type { FastifyRequest, FastifyReply } from 'fastify';
-import { IsNull } from 'typeorm';
@Injectable()
export class SignupApiService {
@@ -137,6 +137,11 @@ export class SignupApiService {
throw new FastifyReplyError(400, 'USED_USERNAME');
}
+ const isPreserved = instance.preservedUsernames.map(x => x.toLowerCase()).includes(username.toLowerCase());
+ if (isPreserved) {
+ throw new FastifyReplyError(400, 'USED_USERNAME');
+ }
+
const code = rndstr('a-z0-9', 16);
// Generate hash of password
diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts
index bac8ae16e5..8a3541dffe 100644
--- a/packages/backend/src/server/api/endpoints/admin/accounts/create.ts
+++ b/packages/backend/src/server/api/endpoints/admin/accounts/create.ts
@@ -52,6 +52,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
const { account, secret } = await this.signupService.signup({
username: ps.username,
password: ps.password,
+ ignorePreservedUsernames: true,
});
const res = await this.userEntityService.pack(account, account, {
diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts
index fc318a621a..87a2d22ac2 100644
--- a/packages/backend/src/server/api/endpoints/admin/meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/meta.ts
@@ -118,6 +118,14 @@ export const meta = {
optional: false, nullable: false,
},
},
+ preservedUsernames: {
+ type: 'array',
+ optional: false, nullable: false,
+ items: {
+ type: 'string',
+ optional: false, nullable: false,
+ },
+ },
hcaptchaSecretKey: {
type: 'string',
optional: true, nullable: true,
@@ -311,6 +319,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
hiddenTags: instance.hiddenTags,
blockedHosts: instance.blockedHosts,
sensitiveWords: instance.sensitiveWords,
+ preservedUsernames: instance.preservedUsernames,
hcaptchaSecretKey: instance.hcaptchaSecretKey,
recaptchaSecretKey: instance.recaptchaSecretKey,
turnstileSecretKey: instance.turnstileSecretKey,
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 ae2fc84b50..0e94f56cfd 100644
--- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts
+++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts
@@ -95,6 +95,7 @@ export const paramDef = {
enableChartsForRemoteUser: { type: 'boolean' },
enableChartsForFederatedInstances: { type: 'boolean' },
serverRules: { type: 'array', items: { type: 'string' } },
+ preservedUsernames: { type: 'array', items: { type: 'string' } },
},
required: [],
} as const;
@@ -392,6 +393,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
set.serverRules = ps.serverRules;
}
+ if (ps.preservedUsernames !== undefined) {
+ set.preservedUsernames = ps.preservedUsernames;
+ }
+
await this.metaService.update(set);
this.moderationLogService.insertModerationLog(me, 'updateMeta');
});
diff --git a/packages/backend/src/server/api/endpoints/username/available.ts b/packages/backend/src/server/api/endpoints/username/available.ts
index c80b6efdcd..6293c5cb50 100644
--- a/packages/backend/src/server/api/endpoints/username/available.ts
+++ b/packages/backend/src/server/api/endpoints/username/available.ts
@@ -4,6 +4,7 @@ import type { UsedUsernamesRepository, UsersRepository } from '@/models/index.js
import { Endpoint } from '@/server/api/endpoint-base.js';
import { localUsernameSchema } from '@/models/entities/User.js';
import { DI } from '@/di-symbols.js';
+import { MetaService } from '@/core/MetaService.js';
export const meta = {
tags: ['users'],
@@ -39,9 +40,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
@Inject(DI.usedUsernamesRepository)
private usedUsernamesRepository: UsedUsernamesRepository,
+
+ private metaService: MetaService,
) {
super(meta, paramDef, async (ps, me) => {
- // Get exist
const exist = await this.usersRepository.countBy({
host: IsNull(),
usernameLower: ps.username.toLowerCase(),
@@ -49,8 +51,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
const exist2 = await this.usedUsernamesRepository.countBy({ username: ps.username.toLowerCase() });
+ const meta = await this.metaService.fetch();
+ const isPreserved = meta.preservedUsernames.map(x => x.toLowerCase()).includes(ps.username.toLowerCase());
+
return {
- available: exist === 0 && exist2 === 0,
+ available: exist === 0 && exist2 === 0 && !isPreserved,
};
});
}
diff --git a/packages/frontend/src/pages/admin/moderation.vue b/packages/frontend/src/pages/admin/moderation.vue
index e7e3cb5368..1ee07d383e 100644
--- a/packages/frontend/src/pages/admin/moderation.vue
+++ b/packages/frontend/src/pages/admin/moderation.vue
@@ -12,6 +12,10 @@
<template #prefix><i class="ti ti-link"></i></template>
<template #label>{{ i18n.ts.tosUrl }}</template>
</MkInput>
+ <MkTextarea v-model="preservedUsernames">
+ <template #label>{{ i18n.ts.preservedUsernames }}</template>
+ <template #caption>{{ i18n.ts.preservedUsernamesDescription }}</template>
+ </MkTextarea>
<MkTextarea v-model="sensitiveWords">
<template #label>{{ i18n.ts.sensitiveWords }}</template>
<template #caption>{{ i18n.ts.sensitiveWordsDescription }}</template>
@@ -46,14 +50,16 @@ import { fetchInstance } from '@/instance';
import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata';
import MkButton from '@/components/MkButton.vue';
-import FormLink from "@/components/form/link.vue";
+import FormLink from '@/components/form/link.vue';
let sensitiveWords: string = $ref('');
+let preservedUsernames: string = $ref('');
let tosUrl: string | null = $ref(null);
async function init() {
const meta = await os.api('admin/meta');
sensitiveWords = meta.sensitiveWords.join('\n');
+ preservedUsernames = meta.preservedUsernames.join('\n');
tosUrl = meta.tosUrl;
}
@@ -61,6 +67,7 @@ function save() {
os.apiWithDialog('admin/update-meta', {
tosUrl,
sensitiveWords: sensitiveWords.split('\n'),
+ preservedUsernames: preservedUsernames.split('\n'),
}).then(() => {
fetchInstance();
});