enhance(backend): headタグ内にrel=alternateの指定のあるlinkタグがある場合、記述されたURLを参照して照会できるように (#14371)
* signedGet時にhttpかつalternate属性のlinkがある場合に一回だけfollowして照会する * Fix: validation position * Fix import * Fix tagname * Update CHANGELOG * Fix code style --------- Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
This commit is contained in:
parent
fd744f44c1
commit
9fbc1b7f7b
|
@ -17,6 +17,7 @@
|
||||||
- Fix: 特定の条件下でノートの削除ボタンが出ないのを修正
|
- Fix: 特定の条件下でノートの削除ボタンが出ないのを修正
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
|
- enhance: 照会時にURLがhtmlかつheadタグ内に`rel="alternate"`, `type="application/activity+json"`の`link`タグがある場合に追ってリンク先を照会できるように
|
||||||
- Enhance: 凍結されたアカウントのフォローリクエストを表示しないように
|
- Enhance: 凍結されたアカウントのフォローリクエストを表示しないように
|
||||||
- Fix: WSの`readAllNotifications` メッセージが `body` を持たない場合に動作しない問題 #14374
|
- Fix: WSの`readAllNotifications` メッセージが `body` を持たない場合に動作しない問題 #14374
|
||||||
- 通知ページや通知カラム(デッキ)を開いている状態において、新たに発生した通知が既読されない問題が修正されます。
|
- 通知ページや通知カラム(デッキ)を開いている状態において、新たに発生した通知が既読されない問題が修正されます。
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
import * as crypto from 'node:crypto';
|
import * as crypto from 'node:crypto';
|
||||||
import { URL } from 'node:url';
|
import { URL } from 'node:url';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
|
import { Window } from 'happy-dom';
|
||||||
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 { MiUser } from '@/models/User.js';
|
import type { MiUser } from '@/models/User.js';
|
||||||
|
@ -180,7 +181,8 @@ export class ApRequestService {
|
||||||
* @param url URL to fetch
|
* @param url URL to fetch
|
||||||
*/
|
*/
|
||||||
@bindThis
|
@bindThis
|
||||||
public async signedGet(url: string, user: { id: MiUser['id'] }): Promise<unknown> {
|
public async signedGet(url: string, user: { id: MiUser['id'] }, followAlternate?: boolean): Promise<unknown> {
|
||||||
|
const _followAlternate = followAlternate ?? true;
|
||||||
const keypair = await this.userKeypairService.getUserKeypair(user.id);
|
const keypair = await this.userKeypairService.getUserKeypair(user.id);
|
||||||
|
|
||||||
const req = ApRequestCreator.createSignedGet({
|
const req = ApRequestCreator.createSignedGet({
|
||||||
|
@ -198,9 +200,27 @@ export class ApRequestService {
|
||||||
headers: req.request.headers,
|
headers: req.request.headers,
|
||||||
}, {
|
}, {
|
||||||
throwErrorWhenResponseNotOk: true,
|
throwErrorWhenResponseNotOk: true,
|
||||||
validators: [validateContentTypeSetAsActivityPub],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//#region リクエスト先がhtmlかつactivity+jsonへのalternate linkタグがあるとき
|
||||||
|
if (res.headers.get('Content-type')?.startsWith('text/html;') && _followAlternate === true) {
|
||||||
|
const html = await res.text();
|
||||||
|
const window = new Window();
|
||||||
|
const document = window.document;
|
||||||
|
document.documentElement.innerHTML = html;
|
||||||
|
|
||||||
|
const alternate = document.querySelector('head > link[rel="alternate"][type="application/activity+json"]');
|
||||||
|
if (alternate) {
|
||||||
|
const href = alternate.getAttribute('href');
|
||||||
|
if (href) {
|
||||||
|
return await this.signedGet(href, user, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
validateContentTypeSetAsActivityPub(res);
|
||||||
|
|
||||||
return await res.json();
|
return await res.json();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue