Merge pull request '2025.2.0-yumechinokuni.1' (#53) from develop into master
Reviewed-on: #53
This commit is contained in:
commit
4c174910e6
7 changed files with 44 additions and 29 deletions
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -1,3 +1,8 @@
|
|||
## 2025.2.0-yumechinokuni.1
|
||||
|
||||
- Security: Revert miskey-dev/misskey#14897
|
||||
- Security: AP請求を外部ドメーンにリダイレクトしないように
|
||||
|
||||
## 2025.2.0
|
||||
|
||||
### General
|
||||
|
@ -208,12 +213,6 @@ PgroongaのCWサーチ (github.com/paricafe/misskey#d30db97b59d264450901c1dd8680
|
|||
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/712)
|
||||
- Fix: FTT無効時にユーザーリストタイムラインが使用できない問題を修正
|
||||
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/709)
|
||||
- Fix: User Webhookテスト機能のMock Payloadを修正
|
||||
- Fix: アカウント削除のモデレーションログが動作していないのを修正 (#14996)
|
||||
- Fix: リノートミュートが新規投稿通知に対して作用していなかった問題を修正
|
||||
- Fix: Inboxの処理で生じるエラーを誤ってActivityとして処理することがある問題を修正
|
||||
(Cherry-picked from https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/730)
|
||||
- Fix: セキュリティに関する修正
|
||||
|
||||
### Misskey.js
|
||||
- Fix: Stream初期化時、別途WebSocketを指定する場合の型定義を修正
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "misskey",
|
||||
"version": "2025.2.0-yumechinokuni.0",
|
||||
"version": "2025.2.0-yumechinokuni.1",
|
||||
"codename": "nasubi",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
|
@ -17,16 +17,16 @@ function getHrefFrom(one: IObject|string): string | undefined {
|
|||
}
|
||||
|
||||
export function assertActivityMatchesUrls(activity: IObject, urls: string[]) {
|
||||
const idBad = activity.id !== undefined && !urls.includes(activity.id);
|
||||
let idBad = activity.id !== undefined && !urls.includes(activity.id);
|
||||
|
||||
// technically `activity.url` could be an `ApObject = IObject |
|
||||
// string | (IObject | string)[]`, but if it's a complicated thing
|
||||
// and the `activity.id` doesn't match, I think we're fine
|
||||
// rejecting the activity
|
||||
const urlBad = typeof activity.url === 'string' && !urls.includes(activity.url);
|
||||
const urlBad = activity.url != undefined && (typeof activity.url !== 'string' || !urls.includes(activity.url));
|
||||
|
||||
// both of them have to pass checks, if present
|
||||
if (idBad || urlBad) {
|
||||
|
||||
const hosts = urls.map(u => {
|
||||
try {
|
||||
return new URL(u).host;
|
||||
|
@ -42,6 +42,7 @@ export function assertActivityMatchesUrls(activity: IObject, urls: string[]) {
|
|||
throw new Error(`bad Activity: neither id(${activity?.id}) nor url(${JSON.stringify(activity?.url)}) match location(${urls})`);
|
||||
}
|
||||
|
||||
// at least one of the key field must be present
|
||||
if (activity.id || activity.url) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js';
|
|||
import { bindThis } from '@/decorators.js';
|
||||
import { IActivity } from '@/core/activitypub/type.js';
|
||||
import { isQuote, isRenote } from '@/misc/is-renote.js';
|
||||
import * as Acct from '@/misc/acct.js';
|
||||
import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyPluginOptions, FastifyBodyParser } from 'fastify';
|
||||
import type { FindOptionsWhere } from 'typeorm';
|
||||
|
||||
|
@ -487,16 +486,6 @@ export class ActivityPubServerService {
|
|||
return;
|
||||
}
|
||||
|
||||
// リモートだったらリダイレクト
|
||||
if (user.host != null) {
|
||||
if (user.uri == null || this.utilityService.isSelfHost(user.host)) {
|
||||
reply.code(500);
|
||||
return;
|
||||
}
|
||||
reply.redirect(user.uri, 301);
|
||||
return;
|
||||
}
|
||||
|
||||
reply.header('Cache-Control', 'public, max-age=180');
|
||||
this.setResponseType(request, reply);
|
||||
return (this.apRendererService.addContext(await this.apRendererService.renderPerson(user as MiLocalUser)));
|
||||
|
@ -665,20 +654,19 @@ export class ActivityPubServerService {
|
|||
|
||||
const user = await this.usersRepository.findOneBy({
|
||||
id: userId,
|
||||
host: IsNull(),
|
||||
isSuspended: false,
|
||||
});
|
||||
|
||||
return await this.userInfo(request, reply, user);
|
||||
});
|
||||
|
||||
fastify.get<{ Params: { acct: string; } }>('/@:acct', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => {
|
||||
fastify.get<{ Params: { user: string; } }>('/@:user', { constraints: { apOrHtml: 'ap' } }, async (request, reply) => {
|
||||
vary(reply.raw, 'Accept');
|
||||
|
||||
const acct = Acct.parse(request.params.acct);
|
||||
|
||||
const user = await this.usersRepository.findOneBy({
|
||||
usernameLower: acct.username,
|
||||
host: acct.host ?? IsNull(),
|
||||
usernameLower: request.params.user.toLowerCase(),
|
||||
host: IsNull(),
|
||||
isSuspended: false,
|
||||
});
|
||||
|
||||
|
|
|
@ -290,6 +290,35 @@ export class ServerService implements OnApplicationShutdown {
|
|||
done();
|
||||
});
|
||||
|
||||
fastify.addHook('onSend', (request, reply, payload, done) => {
|
||||
if (reply.statusCode >= 300 && reply.statusCode < 400) {
|
||||
const isAp = ["application/activity+json", "application/ld+json"].some(type => request.headers.accept?.includes(type));
|
||||
|
||||
if (isAp) {
|
||||
const location = reply.getHeader('location');
|
||||
|
||||
// the only acceptable redirect is to our own domain
|
||||
if (typeof location === 'string') {
|
||||
// allow http in development
|
||||
const normalizedLocation = process.env.NODE_ENV !== 'production' ?
|
||||
location.replace(/^http:\/\//, 'https://') : location;
|
||||
|
||||
if ([`https://${this.config.host}/`, `https://${this.config.hostname}/`].some(host => normalizedLocation.startsWith(host))) {
|
||||
done(null, payload);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
reply.code(406);
|
||||
reply.removeHeader('location');
|
||||
done(null, null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
done(null, payload);
|
||||
});
|
||||
|
||||
// CSP
|
||||
if (process.env.NODE_ENV === 'production' && !this.config.browserSandboxing.csp?.disable) {
|
||||
console.debug('cspPrerenderedContent', this.config.cspPrerenderedContent);
|
||||
|
|
|
@ -230,7 +230,6 @@ describe('Webリソース', () => {
|
|||
path: path('xxxxxxxxxx'),
|
||||
type: HTML,
|
||||
}));
|
||||
test.todo('HTMLとしてGETできる。(リモートユーザーでもリダイレクトせず)');
|
||||
});
|
||||
|
||||
describe.each([
|
||||
|
@ -250,7 +249,6 @@ describe('Webリソース', () => {
|
|||
path: path('xxxxxxxxxx'),
|
||||
accept,
|
||||
}));
|
||||
test.todo('はオリジナルにリダイレクトされる。(リモートユーザー)');
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"type": "module",
|
||||
"name": "misskey-js",
|
||||
"version": "2025.2.0-yumechinokuni.0",
|
||||
"version": "2025.2.0-yumechinokuni.1",
|
||||
"description": "Misskey SDK for JavaScript",
|
||||
"license": "MIT",
|
||||
"main": "./built/index.js",
|
||||
|
|
Loading…
Add table
Reference in a new issue