summaryrefslogtreecommitdiff
path: root/src/remote/activitypub/request.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/remote/activitypub/request.ts')
-rw-r--r--src/remote/activitypub/request.ts162
1 files changed, 32 insertions, 130 deletions
diff --git a/src/remote/activitypub/request.ts b/src/remote/activitypub/request.ts
index fe1009243c..d6ced630c1 100644
--- a/src/remote/activitypub/request.ts
+++ b/src/remote/activitypub/request.ts
@@ -1,66 +1,31 @@
-import * as http from 'http';
-import * as https from 'https';
-import { sign } from 'http-signature';
-import * as crypto from 'crypto';
-
import config from '@/config/index';
-import { User } from '@/models/entities/user';
-import { getAgentByUrl } from '@/misc/fetch';
-import { URL } from 'url';
-import got from 'got';
-import * as Got from 'got';
import { getUserKeypair } from '@/misc/keypair-store';
+import { User } from '@/models/entities/user';
+import { getResponse } from '../../misc/fetch';
+import { createSignedPost, createSignedGet } from './ap-request';
export default async (user: { id: User['id'] }, url: string, object: any) => {
- const timeout = 10 * 1000;
-
- const { protocol, hostname, port, pathname, search } = new URL(url);
-
- const data = JSON.stringify(object);
-
- const sha256 = crypto.createHash('sha256');
- sha256.update(data);
- const hash = sha256.digest('base64');
+ const body = JSON.stringify(object);
const keypair = await getUserKeypair(user.id);
- await new Promise<void>((resolve, reject) => {
- const req = https.request({
- agent: getAgentByUrl(new URL(`https://example.net`)),
- protocol,
- hostname,
- port,
- method: 'POST',
- path: pathname + search,
- timeout,
- headers: {
- 'User-Agent': config.userAgent,
- 'Content-Type': 'application/activity+json',
- 'Digest': `SHA-256=${hash}`
- }
- }, res => {
- if (res.statusCode! >= 400) {
- reject(res);
- } else {
- resolve();
- }
- });
-
- sign(req, {
- authorizationHeaderName: 'Signature',
- key: keypair.privateKey,
- keyId: `${config.url}/users/${user.id}#main-key`,
- headers: ['(request-target)', 'date', 'host', 'digest']
- });
-
- req.on('timeout', () => req.abort());
-
- req.on('error', e => {
- if (req.aborted) reject('timeout');
- reject(e);
- });
+ const req = createSignedPost({
+ key: {
+ privateKeyPem: keypair.privateKey,
+ keyId: `${config.url}/users/${user.id}#main-key`
+ },
+ url,
+ body,
+ additionalHeaders: {
+ 'User-Agent': config.userAgent,
+ }
+ });
- req.end(data);
+ await getResponse({
+ url,
+ method: req.request.method,
+ headers: req.request.headers,
+ body,
});
};
@@ -70,87 +35,24 @@ export default async (user: { id: User['id'] }, url: string, object: any) => {
* @param url URL to fetch
*/
export async function signedGet(url: string, user: { id: User['id'] }) {
- const timeout = 10 * 1000;
-
const keypair = await getUserKeypair(user.id);
- const req = got.get<any>(url, {
- headers: {
- 'Accept': 'application/activity+json, application/ld+json',
- 'User-Agent': config.userAgent,
+ const req = createSignedGet({
+ key: {
+ privateKeyPem: keypair.privateKey,
+ keyId: `${config.url}/users/${user.id}#main-key`
},
- responseType: 'json',
- timeout,
- hooks: {
- beforeRequest: [
- options => {
- options.request = (url: URL, opt: http.RequestOptions, callback?: (response: any) => void) => {
- // Select custom agent by URL
- opt.agent = getAgentByUrl(url, false);
-
- // Wrap original https?.request
- const requestFunc = url.protocol === 'http:' ? http.request : https.request;
- const clientRequest = requestFunc(url, opt, callback) as http.ClientRequest;
-
- // HTTP-Signature
- sign(clientRequest, {
- authorizationHeaderName: 'Signature',
- key: keypair.privateKey,
- keyId: `${config.url}/users/${user.id}#main-key`,
- headers: ['(request-target)', 'host', 'date', 'accept']
- });
-
- return clientRequest;
- };
- },
- ],
- },
- retry: 0,
- });
-
- const res = await receiveResponce(req, 10 * 1024 * 1024);
-
- return res.body;
-}
-
-/**
- * Receive response (with size limit)
- * @param req Request
- * @param maxSize size limit
- */
-export async function receiveResponce<T>(req: Got.CancelableRequest<Got.Response<T>>, maxSize: number) {
- // 応答ヘッダでサイズチェック
- req.on('response', (res: Got.Response) => {
- const contentLength = res.headers['content-length'];
- if (contentLength != null) {
- const size = Number(contentLength);
- if (size > maxSize) {
- req.cancel();
- }
- }
- });
-
- // 受信中のデータでサイズチェック
- req.on('downloadProgress', (progress: Got.Progress) => {
- if (progress.transferred > maxSize) {
- req.cancel();
+ url,
+ additionalHeaders: {
+ 'User-Agent': config.userAgent,
}
});
- // 応答取得 with ステータスコードエラーの整形
- const res = await req.catch(e => {
- if (e.name === 'HTTPError') {
- const statusCode = (e as Got.HTTPError).response.statusCode;
- const statusMessage = (e as Got.HTTPError).response.statusMessage;
- throw {
- name: `StatusError`,
- statusCode,
- message: `${statusCode} ${statusMessage}`,
- };
- } else {
- throw e;
- }
+ const res = await getResponse({
+ url,
+ method: req.request.method,
+ headers: req.request.headers
});
- return res;
+ return await res.json();
}