From 8729a87024fc837f7dd6f13afeec90cf6dda1c06 Mon Sep 17 00:00:00 2001 From: smilekison <24309222+smilekison@users.noreply.github.com> Date: Wed, 25 Aug 2021 06:08:37 -0700 Subject: Support proxies for PeerTube (#4346) * Updated with latest code * Updated Support proxies for PeerTube * Support Proxies for PeerTube (Updated with change request) * Cleanup proxy PR Co-authored-by: Chocobozzz --- server/helpers/proxy.ts | 14 ++++++++ server/helpers/requests.ts | 32 ++++++++++++++++-- server/tests/api/server/index.ts | 1 + server/tests/api/server/proxy.ts | 72 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 server/helpers/proxy.ts create mode 100644 server/tests/api/server/proxy.ts (limited to 'server') diff --git a/server/helpers/proxy.ts b/server/helpers/proxy.ts new file mode 100644 index 000000000..8b82ccae0 --- /dev/null +++ b/server/helpers/proxy.ts @@ -0,0 +1,14 @@ +function getProxy () { + return process.env.HTTPS_PROXY || + process.env.HTTP_PROXY || + undefined +} + +function isProxyEnabled () { + return !!getProxy() +} + +export { + getProxy, + isProxyEnabled +} diff --git a/server/helpers/requests.ts b/server/helpers/requests.ts index 36e69458e..e09e23086 100644 --- a/server/helpers/requests.ts +++ b/server/helpers/requests.ts @@ -1,19 +1,21 @@ import { createWriteStream, remove } from 'fs-extra' import got, { CancelableRequest, Options as GotOptions, RequestError } from 'got' +import { HttpProxyAgent, HttpsProxyAgent } from 'hpagent' import { join } from 'path' import { CONFIG } from '../initializers/config' import { ACTIVITY_PUB, PEERTUBE_VERSION, REQUEST_TIMEOUT, WEBSERVER } from '../initializers/constants' import { pipelinePromise } from './core-utils' import { processImage } from './image-utils' import { logger } from './logger' +import { getProxy, isProxyEnabled } from './proxy' + +const httpSignature = require('http-signature') export interface PeerTubeRequestError extends Error { statusCode?: number responseBody?: any } -const httpSignature = require('http-signature') - type PeerTubeRequestOptions = { activityPub?: boolean bodyKBLimit?: number // 1MB @@ -29,6 +31,8 @@ type PeerTubeRequestOptions = { } & Pick const peertubeGot = got.extend({ + ...getAgent(), + headers: { 'user-agent': getUserAgent() }, @@ -153,6 +157,30 @@ async function downloadImage (url: string, destDir: string, destName: string, si } } +function getAgent () { + if (!isProxyEnabled()) return {} + + const proxy = getProxy() + + logger.info('Using proxy %s.', proxy) + + const proxyAgentOptions = { + keepAlive: true, + keepAliveMsecs: 1000, + maxSockets: 256, + maxFreeSockets: 256, + scheduling: 'lifo' as 'lifo', + proxy + } + + return { + agent: { + http: new HttpProxyAgent(proxyAgentOptions), + https: new HttpsProxyAgent(proxyAgentOptions) + } + } +} + function getUserAgent () { return `PeerTube/${PEERTUBE_VERSION} (+${WEBSERVER.URL})` } diff --git a/server/tests/api/server/index.ts b/server/tests/api/server/index.ts index 56e6eb5da..b16a22ee7 100644 --- a/server/tests/api/server/index.ts +++ b/server/tests/api/server/index.ts @@ -15,3 +15,4 @@ import './stats' import './tracker' import './no-client' import './plugins' +import './proxy' diff --git a/server/tests/api/server/proxy.ts b/server/tests/api/server/proxy.ts new file mode 100644 index 000000000..d5042ef27 --- /dev/null +++ b/server/tests/api/server/proxy.ts @@ -0,0 +1,72 @@ +/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ + +import 'mocha' +import * as chai from 'chai' +import { cleanupTests, createMultipleServers, doubleFollow, PeerTubeServer, setAccessTokensToServers, waitJobs } from '@shared/extra-utils' +import { MockProxy } from '@shared/extra-utils/mock-servers/mock-proxy' + +const expect = chai.expect + +describe('Test proxy', function () { + let servers: PeerTubeServer[] = [] + let proxy: MockProxy + + const goodEnv = { HTTP_PROXY: '' } + const badEnv = { HTTP_PROXY: 'http://localhost:9000' } + + before(async function () { + this.timeout(120000) + + proxy = new MockProxy() + + const proxyPort = await proxy.initialize() + servers = await createMultipleServers(2) + + goodEnv.HTTP_PROXY = 'http://localhost:' + proxyPort + + await setAccessTokensToServers(servers) + await doubleFollow(servers[0], servers[1]) + }) + + it('Should succeed federation with the appropriate proxy config', async function () { + await servers[0].kill() + await servers[0].run({}, { env: goodEnv }) + + await servers[0].videos.quickUpload({ name: 'video 1' }) + + await waitJobs(servers) + + for (const server of servers) { + const { total, data } = await server.videos.list() + expect(total).to.equal(1) + expect(data).to.have.lengthOf(1) + } + }) + + it('Should fail federation with a wrong proxy config', async function () { + await servers[0].kill() + await servers[0].run({}, { env: badEnv }) + + await servers[0].videos.quickUpload({ name: 'video 2' }) + + await waitJobs(servers) + + { + const { total, data } = await servers[0].videos.list() + expect(total).to.equal(2) + expect(data).to.have.lengthOf(2) + } + + { + const { total, data } = await servers[1].videos.list() + expect(total).to.equal(1) + expect(data).to.have.lengthOf(1) + } + }) + + after(async function () { + proxy.terminate() + + await cleanupTests(servers) + }) +}) -- cgit v1.2.3