プロキシの除外ホスト (#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(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export const httpAgent = config.proxy | /** | ||||||
| 	? new HttpProxyAgent(config.proxy) |  * Get http non-proxy agent | ||||||
| 	: new http.Agent({ |  */ | ||||||
|  | const _http = new http.Agent({ | ||||||
| 	keepAlive: true, | 	keepAlive: true, | ||||||
| 	keepAliveMsecs: 30 * 1000, | 	keepAliveMsecs: 30 * 1000, | ||||||
| 	}); | }); | ||||||
| 
 | 
 | ||||||
| export const httpsAgent = config.proxy | /** | ||||||
| 	? new HttpsProxyAgent(config.proxy) |  * Get https non-proxy agent | ||||||
| 	: new https.Agent({ |  */ | ||||||
|  | const _https = new https.Agent({ | ||||||
| 	keepAlive: true, | 	keepAlive: true, | ||||||
| 	keepAliveMsecs: 30 * 1000, | 	keepAliveMsecs: 30 * 1000, | ||||||
| 	lookup: cache.lookup, | 	lookup: cache.lookup, | ||||||
| 	}); | }); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Get http proxy or non-proxy agent | ||||||
|  |  */ | ||||||
|  | export const httpAgent = config.proxy | ||||||
|  | 	? new HttpProxyAgent(config.proxy) | ||||||
|  | 	: _http; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Get https proxy or non-proxy agent | ||||||
|  |  */ | ||||||
|  | export const httpsAgent = config.proxy | ||||||
|  | 	? new HttpsProxyAgent(config.proxy) | ||||||
|  | 	: _https; | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * 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…
	
	Add table
		Add a link
		
	
		Reference in a new issue