summaryrefslogtreecommitdiff
path: root/packages/backend/src/core/NoteCreateService.ts
diff options
context:
space:
mode:
authorJulia <julia@insertdomain.name>2025-03-02 19:54:32 +0000
committerJulia <julia@insertdomain.name>2025-03-02 19:54:32 +0000
commit9e13c375c5ef4103ad5ee87fea583b154e9e16f3 (patch)
treefe9e7b1a474e22fb0c37bd68cfd260f7ba39be74 /packages/backend/src/core/NoteCreateService.ts
parentmerge: pin corepack version (!885) (diff)
parentbump version (diff)
downloadsharkey-9e13c375c5ef4103ad5ee87fea583b154e9e16f3.tar.gz
sharkey-9e13c375c5ef4103ad5ee87fea583b154e9e16f3.tar.bz2
sharkey-9e13c375c5ef4103ad5ee87fea583b154e9e16f3.zip
merge: 2025.2.2 (!927)
View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/927 Approved-by: Marie <github@yuugi.dev> Approved-by: Julia <julia@insertdomain.name>
Diffstat (limited to 'packages/backend/src/core/NoteCreateService.ts')
-rw-r--r--packages/backend/src/core/NoteCreateService.ts81
1 files changed, 43 insertions, 38 deletions
diff --git a/packages/backend/src/core/NoteCreateService.ts b/packages/backend/src/core/NoteCreateService.ts
index 96bb30a0d6..df31cb4247 100644
--- a/packages/backend/src/core/NoteCreateService.ts
+++ b/packages/backend/src/core/NoteCreateService.ts
@@ -144,6 +144,7 @@ type Option = {
uri?: string | null;
url?: string | null;
app?: MiApp | null;
+ processErrors?: string[] | null;
};
export type PureRenoteOption = Option & { renote: MiNote } & ({ text?: null } | { cw?: null } | { reply?: null } | { poll?: null } | { files?: null | [] });
@@ -228,7 +229,7 @@ export class NoteCreateService implements OnApplicationShutdown {
}
@bindThis
- public async create(user: {
+ public async create(user: MiUser & {
id: MiUser['id'];
username: MiUser['username'];
host: MiUser['host'];
@@ -309,6 +310,9 @@ export class NoteCreateService implements OnApplicationShutdown {
}
}
+ // Check quote permissions
+ await this.checkQuotePermissions(data, user);
+
// Check blocking
if (this.isRenote(data) && !this.isQuote(data)) {
if (data.renote.userHost === null) {
@@ -435,7 +439,7 @@ export class NoteCreateService implements OnApplicationShutdown {
}
@bindThis
- public async import(user: {
+ public async import(user: MiUser & {
id: MiUser['id'];
username: MiUser['username'];
host: MiUser['host'];
@@ -482,14 +486,15 @@ export class NoteCreateService implements OnApplicationShutdown {
renoteUserId: data.renote ? data.renote.userId : null,
renoteUserHost: data.renote ? data.renote.userHost : null,
userHost: user.host,
+ processErrors: data.processErrors,
});
// should really not happen, but better safe than sorry
if (data.reply?.id === insert.id) {
- throw new Error("A note can't reply to itself");
+ throw new Error('A note can\'t reply to itself');
}
if (data.renote?.id === insert.id) {
- throw new Error("A note can't renote itself");
+ throw new Error('A note can\'t renote itself');
}
if (data.uri != null) insert.uri = data.uri;
@@ -552,7 +557,7 @@ export class NoteCreateService implements OnApplicationShutdown {
}
@bindThis
- private async postNoteCreated(note: MiNote, user: {
+ private async postNoteCreated(note: MiNote, user: MiUser & {
id: MiUser['id'];
username: MiUser['username'];
host: MiUser['host'];
@@ -678,14 +683,7 @@ export class NoteCreateService implements OnApplicationShutdown {
this.roleService.addNoteToRoleTimeline(noteObj);
- this.webhookService.getActiveWebhooks().then(webhooks => {
- webhooks = webhooks.filter(x => x.userId === user.id && x.on.includes('note'));
- for (const webhook of webhooks) {
- this.queueService.userWebhookDeliver(webhook, 'note', {
- note: noteObj,
- });
- }
- });
+ this.webhookService.enqueueUserWebhook(user.id, 'note', { note: noteObj });
const nm = new NotificationManager(this.mutingsRepository, this.notificationService, user, note);
@@ -717,13 +715,7 @@ export class NoteCreateService implements OnApplicationShutdown {
if (!isThreadMuted && !muted) {
nm.push(data.reply.userId, 'reply');
this.globalEventService.publishMainStream(data.reply.userId, 'reply', noteObj);
-
- const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.reply!.userId && x.on.includes('reply'));
- for (const webhook of webhooks) {
- this.queueService.userWebhookDeliver(webhook, 'reply', {
- note: noteObj,
- });
- }
+ this.webhookService.enqueueUserWebhook(data.reply.userId, 'reply', { note: noteObj });
}
}
}
@@ -757,22 +749,16 @@ export class NoteCreateService implements OnApplicationShutdown {
// Publish event
if ((user.id !== data.renote.userId) && data.renote.userHost === null) {
this.globalEventService.publishMainStream(data.renote.userId, 'renote', noteObj);
-
- const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === data.renote!.userId && x.on.includes('renote'));
- for (const webhook of webhooks) {
- this.queueService.userWebhookDeliver(webhook, 'renote', {
- note: noteObj,
- });
- }
+ this.webhookService.enqueueUserWebhook(data.renote.userId, 'renote', { note: noteObj });
}
}
nm.notify();
//#region AP deliver
- if (this.userEntityService.isLocalUser(user)) {
+ if (!data.localOnly && this.userEntityService.isLocalUser(user)) {
(async () => {
- const noteActivity = await this.renderNoteOrRenoteActivity(data, note);
+ const noteActivity = await this.renderNoteOrRenoteActivity(data, note, user);
const dm = this.apDeliverManagerService.createDeliverManager(user, noteActivity);
// メンションされたリモートユーザーに配送
@@ -905,13 +891,7 @@ export class NoteCreateService implements OnApplicationShutdown {
});
this.globalEventService.publishMainStream(u.id, 'mention', detailPackedNote);
-
- const webhooks = (await this.webhookService.getActiveWebhooks()).filter(x => x.userId === u.id && x.on.includes('mention'));
- for (const webhook of webhooks) {
- this.queueService.userWebhookDeliver(webhook, 'mention', {
- note: detailPackedNote,
- });
- }
+ this.webhookService.enqueueUserWebhook(u.id, 'mention', { note: detailPackedNote });
// Create notification
nm.push(u.id, 'mention');
@@ -924,12 +904,12 @@ export class NoteCreateService implements OnApplicationShutdown {
}
@bindThis
- private async renderNoteOrRenoteActivity(data: Option, note: MiNote) {
+ private async renderNoteOrRenoteActivity(data: Option, note: MiNote, user: MiUser) {
if (data.localOnly) return null;
const content = this.isRenote(data) && !this.isQuote(data)
? this.apRendererService.renderAnnounce(data.renote.uri ? data.renote.uri : `${this.config.url}/notes/${data.renote.id}`, note)
- : this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, false), note);
+ : this.apRendererService.renderCreate(await this.apRendererService.renderNote(note, user, false), note);
return this.apRendererService.addContext(content);
}
@@ -1172,4 +1152,29 @@ export class NoteCreateService implements OnApplicationShutdown {
public async onApplicationShutdown(signal?: string | undefined): Promise<void> {
await this.dispose();
}
+
+ @bindThis
+ public async checkQuotePermissions(data: Option, user: MiUser): Promise<void> {
+ // Not a quote
+ if (!this.isRenote(data) || !this.isQuote(data)) return;
+
+ // User cannot quote
+ if (user.rejectQuotes) {
+ if (user.host == null) {
+ throw new IdentifiableError('1c0ea108-d1e3-4e8e-aa3f-4d2487626153', 'QUOTE_DISABLED_FOR_USER');
+ } else {
+ (data as Option).renote = null;
+ (data.processErrors ??= []).push('quoteUnavailable');
+ }
+ }
+
+ // Instance cannot quote
+ if (user.host) {
+ const instance = await this.federatedInstanceService.fetch(user.host);
+ if (instance?.rejectQuotes) {
+ (data as Option).renote = null;
+ (data.processErrors ??= []).push('quoteUnavailable');
+ }
+ }
+ }
}