プロキシの除外ホスト (#6244)
* プロキシの除外ホスト * オブジェクトストレージとの通信にProxyを使うかを選択できるように * fix lint * コメント Co-authored-by: rinsuki <428rinsuki+git@gmail.com>
This commit is contained in:
parent
e7da10ae58
commit
36b9a0d42f
12 changed files with 89 additions and 16 deletions
|
@ -142,6 +142,11 @@ id: 'aid'
|
||||||
# Proxy for HTTP/HTTPS
|
# Proxy for HTTP/HTTPS
|
||||||
#proxy: http://127.0.0.1:3128
|
#proxy: http://127.0.0.1:3128
|
||||||
|
|
||||||
|
#proxyBypassHosts: [
|
||||||
|
# 'example.com',
|
||||||
|
# '192.0.2.8'
|
||||||
|
#]
|
||||||
|
|
||||||
# Proxy for SMTP/SMTPS
|
# Proxy for SMTP/SMTPS
|
||||||
#proxySmtp: http://127.0.0.1:3128 # use HTTP/1.1 CONNECT
|
#proxySmtp: http://127.0.0.1:3128 # use HTTP/1.1 CONNECT
|
||||||
#proxySmtp: socks4://127.0.0.1:1080 # use SOCKS4
|
#proxySmtp: socks4://127.0.0.1:1080 # use SOCKS4
|
||||||
|
|
|
@ -454,6 +454,8 @@ objectStorageRegion: "Region"
|
||||||
objectStorageRegionDesc: "'xx-east-1'のようなregionを指定してください。使用サービスにregionの概念がない場合は、空または'us-east-1'にしてください。"
|
objectStorageRegionDesc: "'xx-east-1'のようなregionを指定してください。使用サービスにregionの概念がない場合は、空または'us-east-1'にしてください。"
|
||||||
objectStorageUseSSL: "SSLを使用する"
|
objectStorageUseSSL: "SSLを使用する"
|
||||||
objectStorageUseSSLDesc: "API接続にhttpsを使用しない場合はオフにしてください"
|
objectStorageUseSSLDesc: "API接続にhttpsを使用しない場合はオフにしてください"
|
||||||
|
objectStorageUseProxy: "Proxyを利用する"
|
||||||
|
objectStorageUseProxyDesc: "API接続にproxyを利用しない場合はオフにしてください"
|
||||||
serverLogs: "サーバーログ"
|
serverLogs: "サーバーログ"
|
||||||
deleteAll: "全て削除"
|
deleteAll: "全て削除"
|
||||||
showFixedPostForm: "タイムライン上部に投稿フォームを表示する"
|
showFixedPostForm: "タイムライン上部に投稿フォームを表示する"
|
||||||
|
|
14
migration/1586624197029-AddObjectStorageUseProxy.ts
Normal file
14
migration/1586624197029-AddObjectStorageUseProxy.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import {MigrationInterface, QueryRunner} from 'typeorm';
|
||||||
|
|
||||||
|
export class AddObjectStorageUseProxy1586624197029 implements MigrationInterface {
|
||||||
|
name = 'AddObjectStorageUseProxy1586624197029'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" ADD "objectStorageUseProxy" boolean NOT NULL DEFAULT true`, undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "meta" DROP COLUMN "objectStorageUseProxy"`, undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -116,6 +116,7 @@
|
||||||
<mk-input v-model="objectStorageSecretKey" :disabled="!useObjectStorage"><template #icon><fa :icon="faKey"/></template>Secret key</mk-input>
|
<mk-input v-model="objectStorageSecretKey" :disabled="!useObjectStorage"><template #icon><fa :icon="faKey"/></template>Secret key</mk-input>
|
||||||
</div>
|
</div>
|
||||||
<mk-switch v-model="objectStorageUseSSL" :disabled="!useObjectStorage">{{ $t('objectStorageUseSSL') }}<template #desc>{{ $t('objectStorageUseSSLDesc') }}</template></mk-switch>
|
<mk-switch v-model="objectStorageUseSSL" :disabled="!useObjectStorage">{{ $t('objectStorageUseSSL') }}<template #desc>{{ $t('objectStorageUseSSLDesc') }}</template></mk-switch>
|
||||||
|
<mk-switch v-model="objectStorageUseProxy" :disabled="!useObjectStorage">{{ $t('objectStorageUseProxy') }}<template #desc>{{ $t('objectStorageUseProxyDesc') }}</template></mk-switch>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div class="_footer">
|
<div class="_footer">
|
||||||
|
@ -249,6 +250,7 @@ export default Vue.extend({
|
||||||
objectStorageAccessKey: null,
|
objectStorageAccessKey: null,
|
||||||
objectStorageSecretKey: null,
|
objectStorageSecretKey: null,
|
||||||
objectStorageUseSSL: false,
|
objectStorageUseSSL: false,
|
||||||
|
objectStorageUseProxy: false,
|
||||||
enableTwitterIntegration: false,
|
enableTwitterIntegration: false,
|
||||||
twitterConsumerKey: null,
|
twitterConsumerKey: null,
|
||||||
twitterConsumerSecret: null,
|
twitterConsumerSecret: null,
|
||||||
|
@ -303,6 +305,7 @@ export default Vue.extend({
|
||||||
this.objectStorageAccessKey = this.meta.objectStorageAccessKey;
|
this.objectStorageAccessKey = this.meta.objectStorageAccessKey;
|
||||||
this.objectStorageSecretKey = this.meta.objectStorageSecretKey;
|
this.objectStorageSecretKey = this.meta.objectStorageSecretKey;
|
||||||
this.objectStorageUseSSL = this.meta.objectStorageUseSSL;
|
this.objectStorageUseSSL = this.meta.objectStorageUseSSL;
|
||||||
|
this.objectStorageUseProxy = this.meta.objectStorageUseProxy;
|
||||||
this.enableTwitterIntegration = this.meta.enableTwitterIntegration;
|
this.enableTwitterIntegration = this.meta.enableTwitterIntegration;
|
||||||
this.twitterConsumerKey = this.meta.twitterConsumerKey;
|
this.twitterConsumerKey = this.meta.twitterConsumerKey;
|
||||||
this.twitterConsumerSecret = this.meta.twitterConsumerSecret;
|
this.twitterConsumerSecret = this.meta.twitterConsumerSecret;
|
||||||
|
@ -411,6 +414,7 @@ export default Vue.extend({
|
||||||
objectStorageAccessKey: this.objectStorageAccessKey ? this.objectStorageAccessKey : null,
|
objectStorageAccessKey: this.objectStorageAccessKey ? this.objectStorageAccessKey : null,
|
||||||
objectStorageSecretKey: this.objectStorageSecretKey ? this.objectStorageSecretKey : null,
|
objectStorageSecretKey: this.objectStorageSecretKey ? this.objectStorageSecretKey : null,
|
||||||
objectStorageUseSSL: this.objectStorageUseSSL,
|
objectStorageUseSSL: this.objectStorageUseSSL,
|
||||||
|
objectStorageUseProxy: this.objectStorageUseProxy,
|
||||||
enableTwitterIntegration: this.enableTwitterIntegration,
|
enableTwitterIntegration: this.enableTwitterIntegration,
|
||||||
twitterConsumerKey: this.twitterConsumerKey,
|
twitterConsumerKey: this.twitterConsumerKey,
|
||||||
twitterConsumerSecret: this.twitterConsumerSecret,
|
twitterConsumerSecret: this.twitterConsumerSecret,
|
||||||
|
|
|
@ -35,6 +35,7 @@ export type Source = {
|
||||||
|
|
||||||
proxy?: string;
|
proxy?: string;
|
||||||
proxySmtp?: string;
|
proxySmtp?: string;
|
||||||
|
proxyBypassHosts?: string[];
|
||||||
|
|
||||||
accesslog?: string;
|
accesslog?: string;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import * as fs from 'fs';
|
||||||
import * as stream from 'stream';
|
import * as stream from 'stream';
|
||||||
import * as util from 'util';
|
import * as util from 'util';
|
||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
import { httpAgent, httpsAgent } from './fetch';
|
import { getAgentByUrl } from './fetch';
|
||||||
import { AbortController } from 'abort-controller';
|
import { AbortController } from 'abort-controller';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import * as chalk from 'chalk';
|
import * as chalk from 'chalk';
|
||||||
|
@ -25,7 +25,7 @@ export async function downloadUrl(url: string, path: string) {
|
||||||
},
|
},
|
||||||
timeout: 10 * 1000,
|
timeout: 10 * 1000,
|
||||||
signal: controller.signal,
|
signal: controller.signal,
|
||||||
agent: u => u.protocol == 'http:' ? httpAgent : httpsAgent,
|
agent: getAgentByUrl,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ export async function getJson(url: string, accept = 'application/json, */*', tim
|
||||||
Accept: accept
|
Accept: accept
|
||||||
}, headers || {}),
|
}, headers || {}),
|
||||||
timeout,
|
timeout,
|
||||||
agent: u => u.protocol == 'http:' ? httpAgent : httpsAgent,
|
agent: getAgentByUrl,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
|
@ -27,17 +27,46 @@ export async function getJson(url: string, accept = 'application/json, */*', tim
|
||||||
return await res.json();
|
return await res.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get http non-proxy agent
|
||||||
|
*/
|
||||||
|
const _http = new http.Agent({
|
||||||
|
keepAlive: true,
|
||||||
|
keepAliveMsecs: 30 * 1000,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get https non-proxy agent
|
||||||
|
*/
|
||||||
|
const _https = new https.Agent({
|
||||||
|
keepAlive: true,
|
||||||
|
keepAliveMsecs: 30 * 1000,
|
||||||
|
lookup: cache.lookup,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get http proxy or non-proxy agent
|
||||||
|
*/
|
||||||
export const httpAgent = config.proxy
|
export const httpAgent = config.proxy
|
||||||
? new HttpProxyAgent(config.proxy)
|
? new HttpProxyAgent(config.proxy)
|
||||||
: new http.Agent({
|
: _http;
|
||||||
keepAlive: true,
|
|
||||||
keepAliveMsecs: 30 * 1000,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get https proxy or non-proxy agent
|
||||||
|
*/
|
||||||
export const httpsAgent = config.proxy
|
export const httpsAgent = config.proxy
|
||||||
? new HttpsProxyAgent(config.proxy)
|
? new HttpsProxyAgent(config.proxy)
|
||||||
: new https.Agent({
|
: _https;
|
||||||
keepAlive: true,
|
|
||||||
keepAliveMsecs: 30 * 1000,
|
/**
|
||||||
lookup: cache.lookup,
|
* Get agent by URL
|
||||||
});
|
* @param url URL
|
||||||
|
* @param bypassProxy Allways bypass proxy
|
||||||
|
*/
|
||||||
|
export function getAgentByUrl(url: URL, bypassProxy = false) {
|
||||||
|
if (bypassProxy || (config.proxyBypassHosts || []).includes(url.hostname)) {
|
||||||
|
return url.protocol == 'http:' ? _http : _https;
|
||||||
|
} else {
|
||||||
|
return url.protocol == 'http:' ? httpAgent : httpsAgent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -348,4 +348,9 @@ export class Meta {
|
||||||
default: true,
|
default: true,
|
||||||
})
|
})
|
||||||
public objectStorageUseSSL: boolean;
|
public objectStorageUseSSL: boolean;
|
||||||
|
|
||||||
|
@Column('boolean', {
|
||||||
|
default: true,
|
||||||
|
})
|
||||||
|
public objectStorageUseProxy: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import config from '../../config';
|
||||||
import { ILocalUser } from '../../models/entities/user';
|
import { ILocalUser } from '../../models/entities/user';
|
||||||
import { UserKeypairs } from '../../models';
|
import { UserKeypairs } from '../../models';
|
||||||
import { ensure } from '../../prelude/ensure';
|
import { ensure } from '../../prelude/ensure';
|
||||||
import { httpsAgent } from '../../misc/fetch';
|
import { getAgentByUrl } from '../../misc/fetch';
|
||||||
|
|
||||||
export default async (user: ILocalUser, url: string, object: any) => {
|
export default async (user: ILocalUser, url: string, object: any) => {
|
||||||
const timeout = 10 * 1000;
|
const timeout = 10 * 1000;
|
||||||
|
@ -25,7 +25,7 @@ export default async (user: ILocalUser, url: string, object: any) => {
|
||||||
|
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
const req = https.request({
|
const req = https.request({
|
||||||
agent: httpsAgent,
|
agent: getAgentByUrl(new URL(`https://example.net`)),
|
||||||
protocol,
|
protocol,
|
||||||
hostname,
|
hostname,
|
||||||
port,
|
port,
|
||||||
|
|
|
@ -394,6 +394,10 @@ export const meta = {
|
||||||
objectStorageUseSSL: {
|
objectStorageUseSSL: {
|
||||||
validator: $.optional.bool
|
validator: $.optional.bool
|
||||||
},
|
},
|
||||||
|
|
||||||
|
objectStorageUseProxy: {
|
||||||
|
validator: $.optional.bool
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -632,6 +636,10 @@ export default define(meta, async (ps, me) => {
|
||||||
set.objectStorageUseSSL = ps.objectStorageUseSSL;
|
set.objectStorageUseSSL = ps.objectStorageUseSSL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ps.objectStorageUseProxy !== undefined) {
|
||||||
|
set.objectStorageUseProxy = ps.objectStorageUseProxy;
|
||||||
|
}
|
||||||
|
|
||||||
await getConnection().transaction(async transactionalEntityManager => {
|
await getConnection().transaction(async transactionalEntityManager => {
|
||||||
const meta = await transactionalEntityManager.findOne(Meta, {
|
const meta = await transactionalEntityManager.findOne(Meta, {
|
||||||
order: {
|
order: {
|
||||||
|
|
|
@ -190,6 +190,7 @@ export default define(meta, async (ps, me) => {
|
||||||
response.objectStorageAccessKey = instance.objectStorageAccessKey;
|
response.objectStorageAccessKey = instance.objectStorageAccessKey;
|
||||||
response.objectStorageSecretKey = instance.objectStorageSecretKey;
|
response.objectStorageSecretKey = instance.objectStorageSecretKey;
|
||||||
response.objectStorageUseSSL = instance.objectStorageUseSSL;
|
response.objectStorageUseSSL = instance.objectStorageUseSSL;
|
||||||
|
response.objectStorageUseProxy = instance.objectStorageUseProxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
import * as S3 from 'aws-sdk/clients/s3';
|
import * as S3 from 'aws-sdk/clients/s3';
|
||||||
import { Meta } from '../../models/entities/meta';
|
import { Meta } from '../../models/entities/meta';
|
||||||
import { httpsAgent, httpAgent } from '../../misc/fetch';
|
import { getAgentByUrl } from '../../misc/fetch';
|
||||||
|
|
||||||
export function getS3(meta: Meta) {
|
export function getS3(meta: Meta) {
|
||||||
|
const u = meta.objectStorageEndpoint != null
|
||||||
|
? `${meta.objectStorageUseSSL ? 'https://' : 'http://'}${meta.objectStorageEndpoint}`
|
||||||
|
: `${meta.objectStorageUseSSL ? 'https://' : 'http://'}example.net`;
|
||||||
|
|
||||||
return new S3({
|
return new S3({
|
||||||
endpoint: meta.objectStorageEndpoint || undefined,
|
endpoint: meta.objectStorageEndpoint || undefined,
|
||||||
accessKeyId: meta.objectStorageAccessKey!,
|
accessKeyId: meta.objectStorageAccessKey!,
|
||||||
|
@ -11,7 +15,7 @@ export function getS3(meta: Meta) {
|
||||||
sslEnabled: meta.objectStorageUseSSL,
|
sslEnabled: meta.objectStorageUseSSL,
|
||||||
s3ForcePathStyle: !!meta.objectStorageEndpoint,
|
s3ForcePathStyle: !!meta.objectStorageEndpoint,
|
||||||
httpOptions: {
|
httpOptions: {
|
||||||
agent: meta.objectStorageUseSSL ? httpsAgent : httpAgent
|
agent: getAgentByUrl(new URL(u), !meta.objectStorageUseProxy)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue