Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

spec(backend/NoteCreateService): ローカルユーザーがまだ誰もフォローしていないリモートユーザーによる通知を引き起こす可能性のある投稿を拒否できるように (MisskeyIO#462) (patched) #149

Merged
merged 4 commits into from
Feb 19, 2024
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,15 @@

-->

## 202x.x.x-kinel.x (unreleased)

### General

### Client

### Server
- ローカルユーザーがまだ誰もフォローしていないリモートユーザーによる、通知を引き起こす可能性のある投稿を拒否できるように

## 2024.2.0-kinel.1

### Client
Expand Down
3 changes: 3 additions & 0 deletions packages/backend/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ type Source = {
maxWebImageSize?: number;
withRepliesInHomeTL?: boolean;
withRepliesInUserList?: boolean;
blockMentionsFromUnfamiliarRemoteUsers?: boolean;
}
};

Expand Down Expand Up @@ -185,6 +186,7 @@ export type Config = {
maxWebImageSize?: number;
withRepliesInHomeTL?: boolean,
withRepliesInUserList: boolean,
blockMentionsFromUnfamiliarRemoteUsers: boolean;
}
};

Expand Down Expand Up @@ -230,6 +232,7 @@ export function loadConfig(): Config {
// to avoid merge conflict in the future, this is at top
nirila: Object.assign({
withRepliesInUserList: true,
blockMentionsFromUnfamiliarRemoteUsers: false,
}, config.nirila ?? {}),
version,
publishTarballInsteadOfProvideRepositoryUrl: !!config.publishTarballInsteadOfProvideRepositoryUrl,
Expand Down
19 changes: 18 additions & 1 deletion packages/backend/src/core/NoteCreateService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ import { UtilityService } from '@/core/UtilityService.js';
import { UserBlockingService } from '@/core/UserBlockingService.js';
import { isReply } from '@/misc/is-reply.js';
import { trackPromise } from '@/misc/promise-tracker.js';
import { IdentifiableError } from '@/misc/identifiable-error.js';
import { LoggerService } from '@/core/LoggerService.js';
import type Logger from '@/logger.js';

type NotificationType = 'reply' | 'renote' | 'quote' | 'mention';

Expand Down Expand Up @@ -149,6 +152,7 @@ type Option = {

@Injectable()
export class NoteCreateService implements OnApplicationShutdown {
private logger: Logger;
#shutdownController = new AbortController();

public static ContainsProhibitedWordsError = class extends Error {};
Expand Down Expand Up @@ -219,7 +223,10 @@ export class NoteCreateService implements OnApplicationShutdown {
private instanceChart: InstanceChart,
private utilityService: UtilityService,
private userBlockingService: UserBlockingService,
) { }
private loggerService: LoggerService,
) {
this.logger = this.loggerService.getLogger('note:create');
}

@bindThis
public async create(user: {
Expand Down Expand Up @@ -359,6 +366,16 @@ export class NoteCreateService implements OnApplicationShutdown {
mentionedUsers = data.apMentions ?? await this.extractMentionedUsers(user, combinedTokens);
}

const willCauseNotification = mentionedUsers.filter(u => u.host === null).length > 0 || data.reply?.userHost === null || data.renote?.userHost === null;

if (this.config.nirila.blockMentionsFromUnfamiliarRemoteUsers && user.host !== null && willCauseNotification) {
const userEntity = await this.usersRepository.findOneBy({ id: user.id });
if ((userEntity?.followersCount ?? 0) === 0) {
this.logger.error('Request rejected because user has no local followers', { user: user.id, note: data });
throw new IdentifiableError('e11b3a16-f543-4885-8eb1-66cad131dbfd', 'Notes including mentions, replies, or renotes from remote users are not allowed until user has at least one local follower.');
}
}

tags = tags.filter(tag => Array.from(tag).length <= 128).splice(0, 32);

if (data.reply && (user.id !== data.reply.userId) && !mentionedUsers.some(u => u.id === data.reply!.userId)) {
Expand Down
Loading