convert Authorized Fetch to a setting and add support for hybrid mode (essential metadata only)

This commit is contained in:
Hazelnoot 2025-02-21 22:04:36 -05:00
parent e3d949ced6
commit a35c2f214b
28 changed files with 517 additions and 103 deletions

View file

@ -5,6 +5,7 @@
import { Inject, Injectable } from '@nestjs/common';
import * as Redis from 'ioredis';
import { IsNull } from 'typeorm';
import type { BlockingsRepository, FollowingsRepository, MutingsRepository, RenoteMutingsRepository, MiUserProfile, UserProfilesRepository, UsersRepository, MiFollowing } from '@/models/_.js';
import { MemoryKVCache, RedisKVCache } from '@/misc/cache.js';
import type { MiLocalUser, MiUser } from '@/models/User.js';
@ -179,6 +180,13 @@ export class CacheService implements OnApplicationShutdown {
return this.userByIdCache.fetch(userId, () => this.usersRepository.findOneByOrFail({ id: userId }));
}
@bindThis
public async findLocalUserById(userId: MiUser['id']): Promise<MiLocalUser | null> {
return await this.localUserByIdCache.fetchMaybe(userId, async () => {
return await this.usersRepository.findOneBy({ id: userId, host: IsNull() }) as MiLocalUser | null ?? undefined;
}) ?? null;
}
@bindThis
public dispose(): void {
this.redisForSub.off('message', this.onMessage);

View file

@ -29,7 +29,7 @@ export class CreateSystemUserService {
}
@bindThis
public async createSystemUser(username: string): Promise<MiUser> {
public async createSystemUser(username: string, data?: Partial<MiUser>): Promise<MiUser> {
const password = randomUUID();
// Generate hash of password
@ -63,6 +63,7 @@ export class CreateSystemUserService {
isExplorable: false,
approved: true,
isBot: true,
...(data ?? {}),
}).then(x => transactionalEntityManager.findOneByOrFail(MiUser, x.identifiers[0]));
await transactionalEntityManager.insert(MiUserKeypair, {

View file

@ -49,7 +49,15 @@ export class InstanceActorService {
this.cache.set(user);
return user;
} else {
const created = await this.createSystemUserService.createSystemUser(ACTOR_USERNAME) as MiLocalUser;
const created = await this.createSystemUserService.createSystemUser(ACTOR_USERNAME, {
/* we always allow requests about our instance actor, because when
a remote instance needs to check our signature on a request we
sent, it will need to fetch information about the user that
signed it (which is our instance actor), and if we try to check
their signature on *that* request, we'll fetch *their* instance
actor... leading to an infinite recursion */
allowUnsignedFetch: 'always',
}) as MiLocalUser;
this.cache.set(created);
return created;
}

View file

@ -571,6 +571,38 @@ export class ApRendererService {
return person;
}
@bindThis
public async renderPersonRedacted(user: MiLocalUser) {
const id = this.userEntityService.genLocalUserUri(user.id);
const isSystem = user.username.includes('.');
const keypair = await this.userKeypairService.getUserKeypair(user.id);
return {
// Basic federation metadata
type: isSystem ? 'Application' : user.isBot ? 'Service' : 'Person',
id,
inbox: `${id}/inbox`,
outbox: `${id}/outbox`,
sharedInbox: `${this.config.url}/inbox`,
endpoints: { sharedInbox: `${this.config.url}/inbox` },
url: `${this.config.url}/@${user.username}`,
preferredUsername: user.username,
publicKey: this.renderKey(user, keypair, '#main-key'),
// Privacy settings
_misskey_requireSigninToViewContents: user.requireSigninToViewContents,
_misskey_makeNotesFollowersOnlyBefore: user.makeNotesFollowersOnlyBefore,
_misskey_makeNotesHiddenBefore: user.makeNotesHiddenBefore,
manuallyApprovesFollowers: user.isLocked,
discoverable: user.isExplorable,
hideOnlineStatus: user.hideOnlineStatus,
noindex: user.noindex,
indexable: !user.noindex,
enableRss: user.enableRss,
};
}
@bindThis
public renderQuestion(user: { id: MiUser['id'] }, note: MiNote, poll: MiPoll): IQuestion {
return {

View file

@ -181,6 +181,7 @@ export class MetaEntityService {
serviceWorker: instance.enableServiceWorker,
miauth: true,
},
allowUnsignedFetch: instance.allowUnsignedFetch,
};
return packDetailed;

View file

@ -725,6 +725,7 @@ export class UserEntityService implements OnModuleInit {
policies: this.roleService.getUserPolicies(user.id),
defaultCW: profile!.defaultCW,
defaultCWPriority: profile!.defaultCWPriority,
allowUnsignedFetch: user.allowUnsignedFetch,
} : {}),
...(opts.includeSecrets ? {