mirror of
https://github.com/misskey-dev/misskey.git
synced 2024-12-23 00:29:22 +09:00
Merge b6331402da
into 3c81926f71
This commit is contained in:
commit
e656927e50
@ -1,5 +1,10 @@
|
||||
## 2024.11.1
|
||||
|
||||
### Note
|
||||
- 登録時メールアドレスドメインのブラックリストの判定方式が後方一致から完全一致に変更されました。サブドメインごとブロックする場合は先頭に`.`を付けることで後方一致になります。
|
||||
- 例: `example.com` は `example.com` をブロックしますが、`sub.example.com` をブロックしません。
|
||||
- 例: `.example.com` は `example.com` および `sub.example.com` をブロックします。
|
||||
|
||||
### General
|
||||
-
|
||||
|
||||
@ -18,7 +23,9 @@
|
||||
- Fix: ユーザーのプロフィール画面をアドレス入力などで直接表示した際に概要タブの描画に失敗する問題の修正( #15032 )
|
||||
- Fix: 起動前の疎通チェックが機能しなくなっていた問題を修正
|
||||
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/737)
|
||||
|
||||
- Enhance: 登録時メールアドレスドメインのブラックリストの判定方式を改善
|
||||
- Enhance: 登録時メールアドレスドメインのホワイトリストを追加
|
||||
- Enhance: Active Email Validationでブロックされたドメインを自動でブラックリストに追加するオプションを追加
|
||||
|
||||
## 2024.11.0
|
||||
|
||||
|
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export class AddAllowedEmailDomains1732451011177 {
|
||||
name = 'AddAllowedEmailDomains1732451011177'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "allowedEmailDomains" character varying(1024) array NOT NULL DEFAULT '{}'`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "allowedEmailDomains"`);
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export class AddAutoAddBannedEmailDomain1732535648378 {
|
||||
name = 'AddAutoAddBannedEmailDomain1732535648378'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "enableAutoAddBannedEmailDomain" boolean NOT NULL DEFAULT false`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableAutoAddBannedEmailDomain"`);
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
export class AddEnableAllowedEmailDomainOnly1732538997055 {
|
||||
name = 'AddEnableAllowedEmailDomainOnly1732538997055'
|
||||
|
||||
async up(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" ADD "enableAllowedEmailDomainsOnly" boolean NOT NULL DEFAULT false`);
|
||||
}
|
||||
|
||||
async down(queryRunner) {
|
||||
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "enableAllowedEmailDomainsOnly"`);
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@ import type { MiMeta, UserProfilesRepository } from '@/models/_.js';
|
||||
import { LoggerService } from '@/core/LoggerService.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { HttpRequestService } from '@/core/HttpRequestService.js';
|
||||
import { MetaService } from '@/core/MetaService.js';
|
||||
|
||||
@Injectable()
|
||||
export class EmailService {
|
||||
@ -34,6 +35,7 @@ export class EmailService {
|
||||
private loggerService: LoggerService,
|
||||
private utilityService: UtilityService,
|
||||
private httpRequestService: HttpRequestService,
|
||||
private metaService: MetaService,
|
||||
) {
|
||||
this.logger = this.loggerService.getLogger('email');
|
||||
}
|
||||
@ -162,8 +164,15 @@ export class EmailService {
|
||||
@bindThis
|
||||
public async validateEmailForAccount(emailAddress: string): Promise<{
|
||||
available: boolean;
|
||||
reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | 'banned' | 'network' | 'blacklist';
|
||||
reason: null | 'used' | 'format' | 'disposable' | 'mx' | 'smtp' | 'banned' | 'network' | 'blacklist' | 'allowedOnly';
|
||||
}> {
|
||||
if (!this.utilityService.validateEmailFormat(emailAddress)) {
|
||||
return {
|
||||
available: false,
|
||||
reason: 'format',
|
||||
};
|
||||
}
|
||||
|
||||
const exist = await this.userProfilesRepository.countBy({
|
||||
emailVerified: true,
|
||||
email: emailAddress,
|
||||
@ -176,6 +185,33 @@ export class EmailService {
|
||||
};
|
||||
}
|
||||
|
||||
const emailDomain: string = emailAddress.split('@')[1];
|
||||
|
||||
// ホワイトリストに含まれている場合は即座にtrueを返す
|
||||
if (this.utilityService.isAllowedHost(this.meta.allowedEmailDomains, emailDomain)) {
|
||||
return {
|
||||
available: true,
|
||||
reason: null,
|
||||
};
|
||||
}
|
||||
|
||||
// ホワイトリストのみ許可の場合は即座にfalseを返す
|
||||
if (this.meta.enableAllowedEmailDomainsOnly) {
|
||||
return {
|
||||
available: false,
|
||||
reason: 'allowedOnly',
|
||||
};
|
||||
}
|
||||
|
||||
const isBanned = this.utilityService.isBlockedHost(this.meta.bannedEmailDomains, emailDomain);
|
||||
|
||||
if (isBanned) {
|
||||
return {
|
||||
available: false,
|
||||
reason: 'banned',
|
||||
};
|
||||
}
|
||||
|
||||
let validated: {
|
||||
valid: boolean,
|
||||
reason?: string | null,
|
||||
@ -208,22 +244,17 @@ export class EmailService {
|
||||
blacklist: 'blacklist',
|
||||
};
|
||||
|
||||
// 自動追加が有効な場合はブラックリストに追加する
|
||||
if (this.meta.enableAutoAddBannedEmailDomain) {
|
||||
await this.addBlockedHost(emailDomain);
|
||||
}
|
||||
|
||||
return {
|
||||
available: false,
|
||||
reason: validated.reason ? formatReason[validated.reason] ?? null : null,
|
||||
};
|
||||
}
|
||||
|
||||
const emailDomain: string = emailAddress.split('@')[1];
|
||||
const isBanned = this.utilityService.isBlockedHost(this.meta.bannedEmailDomains, emailDomain);
|
||||
|
||||
if (isBanned) {
|
||||
return {
|
||||
available: false,
|
||||
reason: 'banned',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
available: true,
|
||||
reason: null,
|
||||
@ -363,4 +394,11 @@ export class EmailService {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private async addBlockedHost(domain: string) {
|
||||
const set = {} as Partial<MiMeta>;
|
||||
set.bannedEmailDomains = this.meta.bannedEmailDomains;
|
||||
set.bannedEmailDomains.push(domain);
|
||||
await this.metaService.update(set);
|
||||
}
|
||||
}
|
||||
|
@ -39,10 +39,30 @@ export class UtilityService {
|
||||
return this.punyHost(uri) === this.toPuny(this.config.host);
|
||||
}
|
||||
|
||||
// メールアドレスのバリデーションを行う
|
||||
// https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address
|
||||
@bindThis
|
||||
public validateEmailFormat(email: string): boolean {
|
||||
const regexp = /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
||||
return regexp.test(email);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public isBlockedHost(blockedHosts: string[], host: string | null): boolean {
|
||||
if (host == null) return false;
|
||||
return blockedHosts.some(x => `.${host.toLowerCase()}`.endsWith(`.${x}`));
|
||||
return blockedHosts.some(x => {
|
||||
if (x.startsWith('.')) return `.${host.toLowerCase()}`.endsWith(x);
|
||||
return host.toLowerCase() === x;
|
||||
});
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public isAllowedHost(allowedHosts: string[], host: string | null): boolean {
|
||||
if (host == null) return false;
|
||||
return allowedHosts.some(x => {
|
||||
if (x.startsWith('.')) return `.${host.toLowerCase()}`.endsWith(x);
|
||||
return host.toLowerCase() === x;
|
||||
});
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
@ -569,6 +569,23 @@ export class MiMeta {
|
||||
})
|
||||
public bannedEmailDomains: string[];
|
||||
|
||||
@Column('varchar', {
|
||||
length: 1024,
|
||||
array: true,
|
||||
default: '{}',
|
||||
})
|
||||
public allowedEmailDomains: string[];
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
public enableAutoAddBannedEmailDomain: boolean;
|
||||
|
||||
@Column('boolean', {
|
||||
default: false,
|
||||
})
|
||||
public enableAllowedEmailDomainsOnly: boolean;
|
||||
|
||||
@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" }',
|
||||
})
|
||||
|
@ -192,6 +192,14 @@ export const meta = {
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
allowedEmailDomains: {
|
||||
type: 'array',
|
||||
optional: true, nullable: false,
|
||||
items: {
|
||||
type: 'string',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
},
|
||||
preservedUsernames: {
|
||||
type: 'array',
|
||||
optional: false, nullable: false,
|
||||
@ -340,6 +348,14 @@ export const meta = {
|
||||
type: 'string',
|
||||
optional: false, nullable: true,
|
||||
},
|
||||
enableAutoAddBannedEmailDomain: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
enableAllowedEmailDomainsOnly: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
},
|
||||
enableChartsForRemoteUser: {
|
||||
type: 'boolean',
|
||||
optional: false, nullable: false,
|
||||
@ -637,12 +653,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
enableTruemailApi: instance.enableTruemailApi,
|
||||
truemailInstance: instance.truemailInstance,
|
||||
truemailAuthKey: instance.truemailAuthKey,
|
||||
enableAutoAddBannedEmailDomain: instance.enableAutoAddBannedEmailDomain,
|
||||
enableAllowedEmailDomainsOnly: instance.enableAllowedEmailDomainsOnly,
|
||||
enableChartsForRemoteUser: instance.enableChartsForRemoteUser,
|
||||
enableChartsForFederatedInstances: instance.enableChartsForFederatedInstances,
|
||||
enableStatsForFederatedInstances: instance.enableStatsForFederatedInstances,
|
||||
enableServerMachineStats: instance.enableServerMachineStats,
|
||||
enableIdenticonGeneration: instance.enableIdenticonGeneration,
|
||||
bannedEmailDomains: instance.bannedEmailDomains,
|
||||
allowedEmailDomains: instance.allowedEmailDomains,
|
||||
policies: { ...DEFAULT_POLICIES, ...instance.policies },
|
||||
manifestJsonOverride: instance.manifestJsonOverride,
|
||||
enableFanoutTimeline: instance.enableFanoutTimeline,
|
||||
|
@ -141,6 +141,9 @@ export const paramDef = {
|
||||
enableIdenticonGeneration: { type: 'boolean' },
|
||||
serverRules: { type: 'array', items: { type: 'string' } },
|
||||
bannedEmailDomains: { type: 'array', items: { type: 'string' } },
|
||||
allowedEmailDomains: { type: 'array', items: { type: 'string' } },
|
||||
enableAutoAddBannedEmailDomain: { type: 'boolean' },
|
||||
enableAllowedEmailDomainsOnly: { type: 'boolean' },
|
||||
preservedUsernames: { type: 'array', items: { type: 'string' } },
|
||||
manifestJsonOverride: { type: 'string' },
|
||||
enableFanoutTimeline: { type: 'boolean' },
|
||||
@ -639,6 +642,18 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||
set.bannedEmailDomains = ps.bannedEmailDomains;
|
||||
}
|
||||
|
||||
if (ps.allowedEmailDomains !== undefined) {
|
||||
set.allowedEmailDomains = ps.allowedEmailDomains;
|
||||
}
|
||||
|
||||
if (ps.enableAutoAddBannedEmailDomain !== undefined) {
|
||||
set.enableAutoAddBannedEmailDomain = ps.enableAutoAddBannedEmailDomain;
|
||||
}
|
||||
|
||||
if (ps.enableAllowedEmailDomainsOnly !== undefined) {
|
||||
set.enableAllowedEmailDomainsOnly = ps.enableAllowedEmailDomainsOnly;
|
||||
}
|
||||
|
||||
if (ps.urlPreviewEnabled !== undefined) {
|
||||
set.urlPreviewEnabled = ps.urlPreviewEnabled;
|
||||
}
|
||||
|
@ -85,6 +85,26 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||
<template #prefix><i class="ti ti-key"></i></template>
|
||||
<template #label>TrueMail API Auth Key</template>
|
||||
</MkInput>
|
||||
<MkSwitch v-model="emailValidationForm.state.enableAutoAddBannedEmailDomain">
|
||||
<template #label>Enable Auto Add Banned Email Domain</template>
|
||||
</MkSwitch>
|
||||
</div>
|
||||
</MkFolder>
|
||||
|
||||
<MkFolder>
|
||||
<template #label>Allowed Email Domains</template>
|
||||
<template v-if="allowedEmailDomainsForm.modified.value" #footer>
|
||||
<MkFormFooter :form="allowedEmailDomainsForm"/>
|
||||
</template>
|
||||
|
||||
<div class="_gaps_m">
|
||||
<MkTextarea v-model="allowedEmailDomainsForm.state.allowedEmailDomains">
|
||||
<template #label>Allowed Email Domains List</template>
|
||||
</MkTextarea>
|
||||
|
||||
<MkSwitch v-model="allowedEmailDomainsForm.state.enableAllowedEmailDomainsOnly">
|
||||
<template #label>Enable Allowed Email Domains Only</template>
|
||||
</MkSwitch>
|
||||
</div>
|
||||
</MkFolder>
|
||||
|
||||
@ -181,6 +201,7 @@ const emailValidationForm = useForm({
|
||||
enableTruemailApi: meta.enableTruemailApi,
|
||||
truemailInstance: meta.truemailInstance,
|
||||
truemailAuthKey: meta.truemailAuthKey,
|
||||
enableAutoAddBannedEmailDomain: meta.enableAutoAddBannedEmailDomain,
|
||||
}, async (state) => {
|
||||
await os.apiWithDialog('admin/update-meta', {
|
||||
enableActiveEmailValidation: state.enableActiveEmailValidation,
|
||||
@ -189,6 +210,18 @@ const emailValidationForm = useForm({
|
||||
enableTruemailApi: state.enableTruemailApi,
|
||||
truemailInstance: state.truemailInstance,
|
||||
truemailAuthKey: state.truemailAuthKey,
|
||||
enableAutoAddBannedEmailDomain: state.enableAutoAddBannedEmailDomain,
|
||||
});
|
||||
fetchInstance(true);
|
||||
});
|
||||
|
||||
const allowedEmailDomainsForm = useForm({
|
||||
allowedEmailDomains: meta.allowedEmailDomains?.join('\n') || '',
|
||||
enableAllowedEmailDomainsOnly: meta.enableAllowedEmailDomainsOnly,
|
||||
}, async (state) => {
|
||||
await os.apiWithDialog('admin/update-meta', {
|
||||
allowedEmailDomains: state.allowedEmailDomains.split('\n'),
|
||||
enableAllowedEmailDomainsOnly: state.enableAllowedEmailDomainsOnly,
|
||||
});
|
||||
fetchInstance(true);
|
||||
});
|
||||
|
@ -5138,6 +5138,7 @@ export type operations = {
|
||||
prohibitedWords: string[];
|
||||
prohibitedWordsForNameOfUser: string[];
|
||||
bannedEmailDomains?: string[];
|
||||
allowedEmailDomains?: string[];
|
||||
preservedUsernames: string[];
|
||||
hcaptchaSecretKey: string | null;
|
||||
mcaptchaSecretKey: string | null;
|
||||
@ -5175,6 +5176,8 @@ export type operations = {
|
||||
enableTruemailApi: boolean;
|
||||
truemailInstance: string | null;
|
||||
truemailAuthKey: string | null;
|
||||
enableAutoAddBannedEmailDomain: boolean;
|
||||
enableAllowedEmailDomainsOnly: boolean;
|
||||
enableChartsForRemoteUser: boolean;
|
||||
enableChartsForFederatedInstances: boolean;
|
||||
enableStatsForFederatedInstances: boolean;
|
||||
@ -9578,6 +9581,9 @@ export type operations = {
|
||||
enableIdenticonGeneration?: boolean;
|
||||
serverRules?: string[];
|
||||
bannedEmailDomains?: string[];
|
||||
allowedEmailDomains?: string[];
|
||||
enableAutoAddBannedEmailDomain?: boolean;
|
||||
enableAllowedEmailDomainsOnly?: boolean;
|
||||
preservedUsernames?: string[];
|
||||
manifestJsonOverride?: string;
|
||||
enableFanoutTimeline?: boolean;
|
||||
|
Loading…
Reference in New Issue
Block a user