feat: implement attachLdSignatureForRelays to control signing of Relayed activities
				
					
				
			This commit is contained in:
		
							parent
							
								
									c344705d67
								
							
						
					
					
						commit
						32872181dd
					
				
					 6 changed files with 89 additions and 39 deletions
				
			
		| 
						 | 
					@ -106,7 +106,7 @@ redis:
 | 
				
			||||||
#   ┌───────────────────────────┐
 | 
					#   ┌───────────────────────────┐
 | 
				
			||||||
#───┘ MeiliSearch configuration └─────────────────────────────
 | 
					#───┘ MeiliSearch configuration └─────────────────────────────
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# You can set scope to local (default value) or global 
 | 
					# You can set scope to local (default value) or global
 | 
				
			||||||
# (include notes from remote).
 | 
					# (include notes from remote).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#meilisearch:
 | 
					#meilisearch:
 | 
				
			||||||
| 
						 | 
					@ -198,13 +198,15 @@ proxyRemoteFiles: true
 | 
				
			||||||
#   https://example.com/thumbnail.webp?thumbnail=1&url=https%3A%2F%2Fstorage.example.com%2Fpath%2Fto%2Fvideo.mp4
 | 
					#   https://example.com/thumbnail.webp?thumbnail=1&url=https%3A%2F%2Fstorage.example.com%2Fpath%2Fto%2Fvideo.mp4
 | 
				
			||||||
#videoThumbnailGenerator: https://example.com
 | 
					#videoThumbnailGenerator: https://example.com
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Sign to ActivityPub GET request (default: true)
 | 
					# Sign outgoing ActivityPub GET request (default: true)
 | 
				
			||||||
signToActivityPubGet: true
 | 
					signToActivityPubGet: true
 | 
				
			||||||
 | 
					# Sign outgoing ActivityPub Activities (default: true)
 | 
				
			||||||
 | 
					attachLdSignatureForRelays: true
 | 
				
			||||||
# check that inbound ActivityPub GET requests are signed ("authorized fetch")
 | 
					# check that inbound ActivityPub GET requests are signed ("authorized fetch")
 | 
				
			||||||
checkActivityPubGetSignature: false
 | 
					checkActivityPubGetSignature: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# For security reasons, uploading attachments from the intranet is prohibited,
 | 
					# For security reasons, uploading attachments from the intranet is prohibited,
 | 
				
			||||||
# but exceptions can be made from the following settings. Default value is "undefined". 
 | 
					# but exceptions can be made from the following settings. Default value is "undefined".
 | 
				
			||||||
# Read changelog to learn more (Improvements of 12.90.0 (2021/09/04)).
 | 
					# Read changelog to learn more (Improvements of 12.90.0 (2021/09/04)).
 | 
				
			||||||
#allowedPrivateNetworks: [
 | 
					#allowedPrivateNetworks: [
 | 
				
			||||||
#  '127.0.0.1/32'
 | 
					#  '127.0.0.1/32'
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -270,8 +270,10 @@ proxyRemoteFiles: true
 | 
				
			||||||
#   https://example.com/thumbnail.webp?thumbnail=1&url=https%3A%2F%2Fstorage.example.com%2Fpath%2Fto%2Fvideo.mp4
 | 
					#   https://example.com/thumbnail.webp?thumbnail=1&url=https%3A%2F%2Fstorage.example.com%2Fpath%2Fto%2Fvideo.mp4
 | 
				
			||||||
#videoThumbnailGenerator: https://example.com
 | 
					#videoThumbnailGenerator: https://example.com
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Sign to ActivityPub GET request (default: true)
 | 
					# Sign outgoing ActivityPub GET request (default: true)
 | 
				
			||||||
signToActivityPubGet: true
 | 
					signToActivityPubGet: true
 | 
				
			||||||
 | 
					# Sign outgoing ActivityPub Activities (default: true)
 | 
				
			||||||
 | 
					attachLdSignatureForRelays: true
 | 
				
			||||||
# check that inbound ActivityPub GET requests are signed ("authorized fetch")
 | 
					# check that inbound ActivityPub GET requests are signed ("authorized fetch")
 | 
				
			||||||
checkActivityPubGetSignature: false
 | 
					checkActivityPubGetSignature: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -285,8 +285,10 @@ proxyRemoteFiles: true
 | 
				
			||||||
#   https://example.com/thumbnail.webp?thumbnail=1&url=https%3A%2F%2Fstorage.example.com%2Fpath%2Fto%2Fvideo.mp4
 | 
					#   https://example.com/thumbnail.webp?thumbnail=1&url=https%3A%2F%2Fstorage.example.com%2Fpath%2Fto%2Fvideo.mp4
 | 
				
			||||||
#videoThumbnailGenerator: https://example.com
 | 
					#videoThumbnailGenerator: https://example.com
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Sign to ActivityPub GET request (default: true)
 | 
					# Sign outgoing ActivityPub GET request (default: true)
 | 
				
			||||||
signToActivityPubGet: true
 | 
					signToActivityPubGet: true
 | 
				
			||||||
 | 
					# Sign outgoing ActivityPub Activities (default: true)
 | 
				
			||||||
 | 
					attachLdSignatureForRelays: true
 | 
				
			||||||
# check that inbound ActivityPub GET requests are signed ("authorized fetch")
 | 
					# check that inbound ActivityPub GET requests are signed ("authorized fetch")
 | 
				
			||||||
checkActivityPubGetSignature: false
 | 
					checkActivityPubGetSignature: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -208,8 +208,10 @@ id: "aidx"
 | 
				
			||||||
# Media Proxy
 | 
					# Media Proxy
 | 
				
			||||||
#mediaProxy: https://example.com/proxy
 | 
					#mediaProxy: https://example.com/proxy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Sign to ActivityPub GET request (default: true)
 | 
					# Sign outgoing ActivityPub GET request (default: true)
 | 
				
			||||||
signToActivityPubGet: true
 | 
					signToActivityPubGet: true
 | 
				
			||||||
 | 
					# Sign outgoing ActivityPub Activities (default: true)
 | 
				
			||||||
 | 
					attachLdSignatureForRelays: true
 | 
				
			||||||
# check that inbound ActivityPub GET requests are signed ("authorized fetch")
 | 
					# check that inbound ActivityPub GET requests are signed ("authorized fetch")
 | 
				
			||||||
checkActivityPubGetSignature: false
 | 
					checkActivityPubGetSignature: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,12 +4,12 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import * as fs from 'node:fs';
 | 
					import * as fs from 'node:fs';
 | 
				
			||||||
import { fileURLToPath } from 'node:url';
 | 
					import {fileURLToPath} from 'node:url';
 | 
				
			||||||
import { dirname, resolve } from 'node:path';
 | 
					import {dirname, resolve} from 'node:path';
 | 
				
			||||||
import * as yaml from 'js-yaml';
 | 
					import * as yaml from 'js-yaml';
 | 
				
			||||||
import { globSync } from 'glob';
 | 
					import {globSync} from 'glob';
 | 
				
			||||||
import * as Sentry from '@sentry/node';
 | 
					import * as Sentry from '@sentry/node';
 | 
				
			||||||
import type { RedisOptions } from 'ioredis';
 | 
					import type {RedisOptions} from 'ioredis';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RedisOptionsSource = Partial<RedisOptions> & {
 | 
					type RedisOptionsSource = Partial<RedisOptions> & {
 | 
				
			||||||
	host: string;
 | 
						host: string;
 | 
				
			||||||
| 
						 | 
					@ -95,6 +95,7 @@ type Source = {
 | 
				
			||||||
	customMOTD?: string[];
 | 
						customMOTD?: string[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	signToActivityPubGet?: boolean;
 | 
						signToActivityPubGet?: boolean;
 | 
				
			||||||
 | 
						attachLdSignatureForRelays?: boolean;
 | 
				
			||||||
	checkActivityPubGetSignature?: boolean;
 | 
						checkActivityPubGetSignature?: boolean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	perChannelMaxNoteCacheCount?: number;
 | 
						perChannelMaxNoteCacheCount?: number;
 | 
				
			||||||
| 
						 | 
					@ -161,6 +162,7 @@ export type Config = {
 | 
				
			||||||
	proxyRemoteFiles: boolean | undefined;
 | 
						proxyRemoteFiles: boolean | undefined;
 | 
				
			||||||
	customMOTD: string[] | undefined;
 | 
						customMOTD: string[] | undefined;
 | 
				
			||||||
	signToActivityPubGet: boolean;
 | 
						signToActivityPubGet: boolean;
 | 
				
			||||||
 | 
						attachLdSignatureForRelays: boolean;
 | 
				
			||||||
	checkActivityPubGetSignature: boolean | undefined;
 | 
						checkActivityPubGetSignature: boolean | undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	version: string;
 | 
						version: string;
 | 
				
			||||||
| 
						 | 
					@ -291,6 +293,7 @@ export function loadConfig(): Config {
 | 
				
			||||||
		proxyRemoteFiles: config.proxyRemoteFiles,
 | 
							proxyRemoteFiles: config.proxyRemoteFiles,
 | 
				
			||||||
		customMOTD: config.customMOTD,
 | 
							customMOTD: config.customMOTD,
 | 
				
			||||||
		signToActivityPubGet: config.signToActivityPubGet ?? true,
 | 
							signToActivityPubGet: config.signToActivityPubGet ?? true,
 | 
				
			||||||
 | 
							attachLdSignatureForRelays: config.attachLdSignatureForRelays ?? true,
 | 
				
			||||||
		checkActivityPubGetSignature: config.checkActivityPubGetSignature,
 | 
							checkActivityPubGetSignature: config.checkActivityPubGetSignature,
 | 
				
			||||||
		mediaProxy: externalMediaProxy ?? internalMediaProxy,
 | 
							mediaProxy: externalMediaProxy ?? internalMediaProxy,
 | 
				
			||||||
		externalMediaProxyEnabled: externalMediaProxy !== null && externalMediaProxy !== internalMediaProxy,
 | 
							externalMediaProxyEnabled: externalMediaProxy !== null && externalMediaProxy !== internalMediaProxy,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,36 +3,69 @@
 | 
				
			||||||
 * SPDX-License-Identifier: AGPL-3.0-only
 | 
					 * SPDX-License-Identifier: AGPL-3.0-only
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { createPublicKey, randomUUID } from 'node:crypto';
 | 
					import {createPublicKey, randomUUID} from 'node:crypto';
 | 
				
			||||||
import { Inject, Injectable } from '@nestjs/common';
 | 
					import {Inject, Injectable} from '@nestjs/common';
 | 
				
			||||||
import { In } from 'typeorm';
 | 
					import {In} from 'typeorm';
 | 
				
			||||||
import * as mfm from '@transfem-org/sfm-js';
 | 
					import * as mfm from '@transfem-org/sfm-js';
 | 
				
			||||||
import { DI } from '@/di-symbols.js';
 | 
					import {DI} from '@/di-symbols.js';
 | 
				
			||||||
import type { Config } from '@/config.js';
 | 
					import type {Config} from '@/config.js';
 | 
				
			||||||
import type { MiPartialLocalUser, MiLocalUser, MiPartialRemoteUser, MiRemoteUser, MiUser } from '@/models/User.js';
 | 
					import type {MiLocalUser, MiPartialLocalUser, MiPartialRemoteUser, MiRemoteUser, MiUser} from '@/models/User.js';
 | 
				
			||||||
import type { IMentionedRemoteUsers, MiNote } from '@/models/Note.js';
 | 
					import type {IMentionedRemoteUsers, MiNote} from '@/models/Note.js';
 | 
				
			||||||
import type { MiBlocking } from '@/models/Blocking.js';
 | 
					import type {MiBlocking} from '@/models/Blocking.js';
 | 
				
			||||||
import type { MiRelay } from '@/models/Relay.js';
 | 
					import type {MiRelay} from '@/models/Relay.js';
 | 
				
			||||||
import type { MiDriveFile } from '@/models/DriveFile.js';
 | 
					import type {MiDriveFile} from '@/models/DriveFile.js';
 | 
				
			||||||
import type { MiNoteReaction } from '@/models/NoteReaction.js';
 | 
					import type {MiNoteReaction} from '@/models/NoteReaction.js';
 | 
				
			||||||
import type { MiEmoji } from '@/models/Emoji.js';
 | 
					import type {MiEmoji} from '@/models/Emoji.js';
 | 
				
			||||||
import type { MiPoll } from '@/models/Poll.js';
 | 
					import type {MiPoll} from '@/models/Poll.js';
 | 
				
			||||||
import type { MiPollVote } from '@/models/PollVote.js';
 | 
					import type {MiPollVote} from '@/models/PollVote.js';
 | 
				
			||||||
import { UserKeypairService } from '@/core/UserKeypairService.js';
 | 
					import {UserKeypairService} from '@/core/UserKeypairService.js';
 | 
				
			||||||
import { MfmService } from '@/core/MfmService.js';
 | 
					import {MfmService} from '@/core/MfmService.js';
 | 
				
			||||||
import { UserEntityService } from '@/core/entities/UserEntityService.js';
 | 
					import {UserEntityService} from '@/core/entities/UserEntityService.js';
 | 
				
			||||||
import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.js';
 | 
					import {DriveFileEntityService} from '@/core/entities/DriveFileEntityService.js';
 | 
				
			||||||
import type { MiUserKeypair } from '@/models/UserKeypair.js';
 | 
					import type {MiUserKeypair} from '@/models/UserKeypair.js';
 | 
				
			||||||
import type { UsersRepository, UserProfilesRepository, NotesRepository, DriveFilesRepository, PollsRepository, InstancesRepository } from '@/models/_.js';
 | 
					import type {
 | 
				
			||||||
import { bindThis } from '@/decorators.js';
 | 
						DriveFilesRepository,
 | 
				
			||||||
import { CustomEmojiService } from '@/core/CustomEmojiService.js';
 | 
						InstancesRepository,
 | 
				
			||||||
import { isNotNull } from '@/misc/is-not-null.js';
 | 
						NotesRepository,
 | 
				
			||||||
import { IdService } from '@/core/IdService.js';
 | 
						PollsRepository,
 | 
				
			||||||
import { MetaService } from '../MetaService.js';
 | 
						UserProfilesRepository,
 | 
				
			||||||
import { JsonLdService } from './JsonLdService.js';
 | 
						UsersRepository
 | 
				
			||||||
import { ApMfmService } from './ApMfmService.js';
 | 
					} from '@/models/_.js';
 | 
				
			||||||
import { CONTEXT } from './misc/contexts.js';
 | 
					import {bindThis} from '@/decorators.js';
 | 
				
			||||||
import type { IAccept, IActivity, IAdd, IAnnounce, IApDocument, IApEmoji, IApHashtag, IApImage, IApMention, IBlock, ICreate, IDelete, IFlag, IFollow, IKey, ILike, IMove, IObject, IPost, IQuestion, IReject, IRemove, ITombstone, IUndo, IUpdate } from './type.js';
 | 
					import {CustomEmojiService} from '@/core/CustomEmojiService.js';
 | 
				
			||||||
 | 
					import {isNotNull} from '@/misc/is-not-null.js';
 | 
				
			||||||
 | 
					import {IdService} from '@/core/IdService.js';
 | 
				
			||||||
 | 
					import {MetaService} from '../MetaService.js';
 | 
				
			||||||
 | 
					import {JsonLdService} from './JsonLdService.js';
 | 
				
			||||||
 | 
					import {ApMfmService} from './ApMfmService.js';
 | 
				
			||||||
 | 
					import {CONTEXT} from './misc/contexts.js';
 | 
				
			||||||
 | 
					import type {
 | 
				
			||||||
 | 
						IAccept,
 | 
				
			||||||
 | 
						IActivity,
 | 
				
			||||||
 | 
						IAdd,
 | 
				
			||||||
 | 
						IAnnounce,
 | 
				
			||||||
 | 
						IApDocument,
 | 
				
			||||||
 | 
						IApEmoji,
 | 
				
			||||||
 | 
						IApHashtag,
 | 
				
			||||||
 | 
						IApImage,
 | 
				
			||||||
 | 
						IApMention,
 | 
				
			||||||
 | 
						IBlock,
 | 
				
			||||||
 | 
						ICreate,
 | 
				
			||||||
 | 
						IDelete,
 | 
				
			||||||
 | 
						IFlag,
 | 
				
			||||||
 | 
						IFollow,
 | 
				
			||||||
 | 
						IKey,
 | 
				
			||||||
 | 
						ILike,
 | 
				
			||||||
 | 
						IMove,
 | 
				
			||||||
 | 
						IObject,
 | 
				
			||||||
 | 
						IPost,
 | 
				
			||||||
 | 
						IQuestion,
 | 
				
			||||||
 | 
						IReject,
 | 
				
			||||||
 | 
						IRemove,
 | 
				
			||||||
 | 
						ITombstone,
 | 
				
			||||||
 | 
						IUndo,
 | 
				
			||||||
 | 
						IUpdate
 | 
				
			||||||
 | 
					} from './type.js';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Injectable()
 | 
					@Injectable()
 | 
				
			||||||
export class ApRendererService {
 | 
					export class ApRendererService {
 | 
				
			||||||
| 
						 | 
					@ -793,6 +826,12 @@ export class ApRendererService {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	@bindThis
 | 
						@bindThis
 | 
				
			||||||
	public async attachLdSignature(activity: any, user: { id: MiUser['id']; host: null; }): Promise<IActivity> {
 | 
						public async attachLdSignature(activity: any, user: { id: MiUser['id']; host: null; }): Promise<IActivity> {
 | 
				
			||||||
 | 
							// When using authorized fetch, Linked Data signatures are often undesired (as it can allow blocked instances to bypass the check).
 | 
				
			||||||
 | 
							// We allow admins to disable LD signatures for increased privacy, at the expense of increased incoming fetch (GET) requests.
 | 
				
			||||||
 | 
							if (!this.config.attachLdSignatureForRelays) {
 | 
				
			||||||
 | 
								return activity;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const keypair = await this.userKeypairService.getUserKeypair(user.id);
 | 
							const keypair = await this.userKeypairService.getUserKeypair(user.id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		const jsonLd = this.jsonLdService.use();
 | 
							const jsonLd = this.jsonLdService.use();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue