Compare commits

...

18 Commits

Author SHA1 Message Date
rinsuki
a5a74f4434 12.119.2 2022-12-04 00:31:01 +09:00
mei23
993110d114 Fix: forkbomb 2 2022-12-04 00:29:42 +09:00
syuilo
fccd9c32e8 12.119.1 2022-12-03 18:42:19 +09:00
syuilo
58a3a0b7d4 forkbomb DOS mitigation 2022-12-03 18:42:06 +09:00
syuilo
a2a1636c10 Merge branch 'develop' 2022-09-10 19:26:43 +09:00
syuilo
46ec0303b7 Merge branch 'develop' 2022-08-08 11:39:04 +09:00
syuilo
3b1669fb6b Merge branch 'develop' 2022-08-07 00:39:21 +09:00
syuilo
09591fa4ae Merge branch 'develop' 2022-07-19 17:22:32 +09:00
syuilo
85ce00adc0 Merge branch 'develop' 2022-07-18 05:07:12 +09:00
syuilo
f25518af91 Merge branch 'develop' 2022-07-17 05:35:36 +09:00
syuilo
b796aacf7f Merge branch 'develop' 2022-07-16 23:53:24 +09:00
syuilo
ff24811676 Merge branch 'develop' 2022-07-16 18:21:44 +09:00
syuilo
4c8a1867f0 Merge branch 'develop' 2022-07-15 22:45:13 +09:00
syuilo
bce48dfee9 Merge branch 'develop' 2022-07-13 21:59:47 +09:00
syuilo
c20311b8a7 Merge branch 'develop' 2022-07-09 18:32:55 +09:00
syuilo
fb14ac50b8 Merge branch 'develop' 2022-07-08 17:34:53 +09:00
syuilo
84d984bd31 Merge branch 'develop' 2022-07-07 21:23:03 +09:00
syuilo
1bc856c451 Merge pull request #8821 from misskey-dev/develop
Release: 12.111.1
2022-06-13 00:41:09 +09:00
8 changed files with 35 additions and 23 deletions

View File

@@ -9,6 +9,14 @@
You should also include the user name that made the change. You should also include the user name that made the change.
--> -->
## 12.119.2 (2022/12/04)
### Bugfixes
- Server: Backported versions mitigate isn't working @mei23
## 12.119.1 (2022/12/03)
### Bugfixes
- Server: Mitigate AP reference chain DoS vector @skehmatics
## 12.119.0 (2022/09/10) ## 12.119.0 (2022/09/10)
### Improvements ### Improvements

View File

@@ -1,6 +1,6 @@
{ {
"name": "misskey", "name": "misskey",
"version": "12.119.0", "version": "12.119.2",
"codename": "indigo", "codename": "indigo",
"repository": { "repository": {
"type": "git", "type": "git",

View File

@@ -10,7 +10,7 @@ import { updatePerson } from '../../models/person.js';
*/ */
export default async (actor: CacheableRemoteUser, activity: IUpdate): Promise<string> => { export default async (actor: CacheableRemoteUser, activity: IUpdate): Promise<string> => {
if ('actor' in activity && actor.uri !== activity.actor) { if ('actor' in activity && actor.uri !== activity.actor) {
return `skip: invalid actor`; return 'skip: invalid actor';
} }
apLogger.debug('Update'); apLogger.debug('Update');
@@ -24,10 +24,10 @@ export default async (actor: CacheableRemoteUser, activity: IUpdate): Promise<st
if (isActor(object)) { if (isActor(object)) {
await updatePerson(actor.uri!, resolver, object); await updatePerson(actor.uri!, resolver, object);
return `ok: Person updated`; return 'ok: Person updated';
} else if (getApType(object) === 'Question') { } else if (getApType(object) === 'Question') {
await updateQuestion(object).catch(e => console.log(e)); await updateQuestion(object, resolver).catch(e => console.log(e));
return `ok: Question updated`; return 'ok: Question updated';
} else { } else {
return `skip: Unknown type: ${getApType(object)}`; return `skip: Unknown type: ${getApType(object)}`;
} }

View File

@@ -5,11 +5,9 @@ import { IObject, isMention, IApMention } from '../type.js';
import Resolver from '../resolver.js'; import Resolver from '../resolver.js';
import { resolvePerson } from './person.js'; import { resolvePerson } from './person.js';
export async function extractApMentions(tags: IObject | IObject[] | null | undefined) { export async function extractApMentions(tags: IObject | IObject[] | null | undefined, resolver: Resolver) {
const hrefs = unique(extractApMentionObjects(tags).map(x => x.href as string)); const hrefs = unique(extractApMentionObjects(tags).map(x => x.href as string));
const resolver = new Resolver();
const limit = promiseLimit<CacheableUser | null>(2); const limit = promiseLimit<CacheableUser | null>(2);
const mentionedUsers = (await Promise.all( const mentionedUsers = (await Promise.all(
hrefs.map(x => limit(() => resolvePerson(x, resolver).catch(() => null))), hrefs.map(x => limit(() => resolvePerson(x, resolver).catch(() => null))),

View File

@@ -97,7 +97,7 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s
throw new Error('actor has been suspended'); throw new Error('actor has been suspended');
} }
const noteAudience = await parseAudience(actor, note.to, note.cc); const noteAudience = await parseAudience(actor, note.to, note.cc, resolver);
let visibility = noteAudience.visibility; let visibility = noteAudience.visibility;
const visibleUsers = noteAudience.visibleUsers; const visibleUsers = noteAudience.visibleUsers;
@@ -111,7 +111,7 @@ export async function createNote(value: string | IObject, resolver?: Resolver, s
let isTalk = note._misskey_talk && visibility === 'specified'; let isTalk = note._misskey_talk && visibility === 'specified';
const apMentions = await extractApMentions(note.tag); const apMentions = await extractApMentions(note.tag, resolver);
const apHashtags = await extractApHashtags(note.tag); const apHashtags = await extractApHashtags(note.tag);
// 添付ファイル // 添付ファイル

View File

@@ -271,7 +271,7 @@ export async function createPerson(uri: string, resolver?: Resolver): Promise<Us
}); });
//#endregion //#endregion
await updateFeatured(user!.id).catch(err => logger.error(err)); await updateFeatured(user!.id, resolver).catch(err => logger.error(err));
return user!; return user!;
} }
@@ -384,7 +384,7 @@ export async function updatePerson(uri: string, resolver?: Resolver | null, hint
followerSharedInbox: person.sharedInbox || (person.endpoints ? person.endpoints.sharedInbox : undefined), followerSharedInbox: person.sharedInbox || (person.endpoints ? person.endpoints.sharedInbox : undefined),
}); });
await updateFeatured(exist.id).catch(err => logger.error(err)); await updateFeatured(exist.id, resolver).catch(err => logger.error(err));
} }
/** /**
@@ -462,14 +462,14 @@ export function analyzeAttachments(attachments: IObject | IObject[] | undefined)
return { fields, services }; return { fields, services };
} }
export async function updateFeatured(userId: User['id']) { export async function updateFeatured(userId: User['id'], resolver?: Resolver) {
const user = await Users.findOneByOrFail({ id: userId }); const user = await Users.findOneByOrFail({ id: userId });
if (!Users.isRemoteUser(user)) return; if (!Users.isRemoteUser(user)) return;
if (!user.featured) return; if (!user.featured) return;
logger.info(`Updating the featured: ${user.uri}`); logger.info(`Updating the featured: ${user.uri}`);
const resolver = new Resolver(); if (resolver == null) resolver = new Resolver();
// Resolve to (Ordered)Collection Object // Resolve to (Ordered)Collection Object
const collection = await resolver.resolveCollection(user.featured); const collection = await resolver.resolveCollection(user.featured);

View File

@@ -1,9 +1,9 @@
import config from '@/config/index.js'; import config from '@/config/index.js';
import { Notes, Polls } from '@/models/index.js';
import { IPoll } from '@/models/entities/poll.js';
import Resolver from '../resolver.js'; import Resolver from '../resolver.js';
import { IObject, IQuestion, isQuestion } from '../type.js'; import { IObject, IQuestion, isQuestion } from '../type.js';
import { apLogger } from '../logger.js'; import { apLogger } from '../logger.js';
import { Notes, Polls } from '@/models/index.js';
import { IPoll } from '@/models/entities/poll.js';
export async function extractPollFromQuestion(source: string | IObject, resolver?: Resolver): Promise<IPoll> { export async function extractPollFromQuestion(source: string | IObject, resolver?: Resolver): Promise<IPoll> {
if (resolver == null) resolver = new Resolver(); if (resolver == null) resolver = new Resolver();
@@ -40,7 +40,7 @@ export async function extractPollFromQuestion(source: string | IObject, resolver
* @param uri URI of AP Question object * @param uri URI of AP Question object
* @returns true if updated * @returns true if updated
*/ */
export async function updateQuestion(value: any) { export async function updateQuestion(value: any, resolver?: Resolver) {
const uri = typeof value === 'string' ? value : value.id; const uri = typeof value === 'string' ? value : value.id;
// URIがこのサーバーを指しているならスキップ // URIがこのサーバーを指しているならスキップ
@@ -55,7 +55,7 @@ export async function updateQuestion(value: any) {
//#endregion //#endregion
// resolve new Question object // resolve new Question object
const resolver = new Resolver(); if (resolver == null) resolver = new Resolver();
const question = await resolver.resolve(value) as IQuestion; const question = await resolver.resolve(value) as IQuestion;
apLogger.debug(`fetched question: ${JSON.stringify(question, null, 2)}`); apLogger.debug(`fetched question: ${JSON.stringify(question, null, 2)}`);

View File

@@ -4,10 +4,7 @@ import { ILocalUser } from '@/models/entities/user.js';
import { getInstanceActor } from '@/services/instance-actor.js'; import { getInstanceActor } from '@/services/instance-actor.js';
import { fetchMeta } from '@/misc/fetch-meta.js'; import { fetchMeta } from '@/misc/fetch-meta.js';
import { extractDbHost, isSelfHost } from '@/misc/convert-host.js'; import { extractDbHost, isSelfHost } from '@/misc/convert-host.js';
import { signedGet } from './request.js';
import { IObject, isCollectionOrOrderedCollection, ICollection, IOrderedCollection } from './type.js';
import { FollowRequests, Notes, NoteReactions, Polls, Users } from '@/models/index.js'; import { FollowRequests, Notes, NoteReactions, Polls, Users } from '@/models/index.js';
import { parseUri } from './db-resolver.js';
import renderNote from '@/remote/activitypub/renderer/note.js'; import renderNote from '@/remote/activitypub/renderer/note.js';
import { renderLike } from '@/remote/activitypub/renderer/like.js'; import { renderLike } from '@/remote/activitypub/renderer/like.js';
import { renderPerson } from '@/remote/activitypub/renderer/person.js'; import { renderPerson } from '@/remote/activitypub/renderer/person.js';
@@ -15,13 +12,18 @@ import renderQuestion from '@/remote/activitypub/renderer/question.js';
import renderCreate from '@/remote/activitypub/renderer/create.js'; import renderCreate from '@/remote/activitypub/renderer/create.js';
import { renderActivity } from '@/remote/activitypub/renderer/index.js'; import { renderActivity } from '@/remote/activitypub/renderer/index.js';
import renderFollow from '@/remote/activitypub/renderer/follow.js'; import renderFollow from '@/remote/activitypub/renderer/follow.js';
import { parseUri } from './db-resolver.js';
import { IObject, isCollectionOrOrderedCollection, ICollection, IOrderedCollection } from './type.js';
import { signedGet } from './request.js';
export default class Resolver { export default class Resolver {
private history: Set<string>; private history: Set<string>;
private user?: ILocalUser; private user?: ILocalUser;
private recursionLimit?: number;
constructor() { constructor(recursionLimit = 100) {
this.history = new Set(); this.history = new Set();
this.recursionLimit = recursionLimit;
} }
public getHistory(): string[] { public getHistory(): string[] {
@@ -60,6 +62,10 @@ export default class Resolver {
throw new Error('cannot resolve already resolved one'); throw new Error('cannot resolve already resolved one');
} }
if (this.recursionLimit && this.history.size > this.recursionLimit) {
throw new Error('hit recursion limit');
}
this.history.add(value); this.history.add(value);
const host = extractDbHost(value); const host = extractDbHost(value);
@@ -123,7 +129,7 @@ export default class Resolver {
if (parsed.rest == null || !/^\w+$/.test(parsed.rest)) throw new Error('resolveLocal: invalid follow URI'); if (parsed.rest == null || !/^\w+$/.test(parsed.rest)) throw new Error('resolveLocal: invalid follow URI');
return Promise.all( return Promise.all(
[parsed.id, parsed.rest].map(id => Users.findOneByOrFail({ id })) [parsed.id, parsed.rest].map(id => Users.findOneByOrFail({ id })),
) )
.then(([follower, followee]) => renderActivity(renderFollow(follower, followee, url))); .then(([follower, followee]) => renderActivity(renderFollow(follower, followee, url)));
default: default: