Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ulixee
GitHub Repository: ulixee/secret-agent
Path: blob/main/plugins/default-browser-emulator/lib/helpers/lookupPublicIp.ts
1030 views
1
import * as http from 'http';
2
import { RequestOptions } from 'http';
3
import IHttpSocketAgent from '@secret-agent/interfaces/IHttpSocketAgent';
4
import * as https from 'https';
5
import * as url from 'url';
6
import IHttpSocketWrapper from '@secret-agent/interfaces/IHttpSocketWrapper';
7
8
export default async function lookupPublicIp(
9
ipLookupServiceUrl: string = IpLookupServices.ipify,
10
agent?: IHttpSocketAgent,
11
proxyUrl?: string,
12
): Promise<string> {
13
if (!ipLookupServiceUrl.startsWith('http')) ipLookupServiceUrl = `https://${ipLookupServiceUrl}`;
14
if (proxyUrl && proxyUrl.startsWith('http')) {
15
// require https for lookup services over http proxies
16
ipLookupServiceUrl.replace('http://', 'https://');
17
}
18
const lookupService = parse(ipLookupServiceUrl);
19
const port = lookupService.port ?? lookupService.protocol === 'https:' ? 443 : 80;
20
21
const requestOptions: http.RequestOptions = {
22
method: 'GET',
23
};
24
25
let socketWrapper: IHttpSocketWrapper;
26
if (agent) {
27
socketWrapper = await agent.createSocketConnection({
28
host: lookupService.host,
29
port: String(port),
30
servername: lookupService.host,
31
keepAlive: false,
32
isSsl: ipLookupServiceUrl.startsWith('https'),
33
proxyUrl,
34
});
35
36
requestOptions.createConnection = () => socketWrapper.socket;
37
requestOptions.agent = null;
38
}
39
40
try {
41
return await httpGet(ipLookupServiceUrl, requestOptions);
42
} finally {
43
if (socketWrapper) socketWrapper.close();
44
}
45
}
46
47
export function httpGet(requestUrl: string, requestOptions: RequestOptions): Promise<string> {
48
const httpModule = requestUrl.startsWith('https') ? https : http;
49
50
return new Promise<string>((resolve, reject) => {
51
const request = httpModule.request(requestUrl, requestOptions, async res => {
52
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
53
resolve(httpGet(res.headers.location, requestOptions));
54
return;
55
}
56
57
res.on('error', reject);
58
res.setEncoding('utf8');
59
let result = '';
60
for await (const chunk of res) {
61
result += chunk;
62
}
63
resolve(result);
64
});
65
request.on('error', reject);
66
request.end();
67
});
68
}
69
70
const parsedLookupServicesByUrl = new Map<string, RequestOptions>();
71
function parse(requestUrl: string): RequestOptions {
72
if (!parsedLookupServicesByUrl.has(requestUrl)) {
73
const options = url.parse(requestUrl);
74
options.port ||= requestUrl.startsWith('https') ? '443' : '80';
75
76
parsedLookupServicesByUrl.set(requestUrl, options);
77
}
78
return parsedLookupServicesByUrl.get(requestUrl);
79
}
80
81
export const IpLookupServices = {
82
ipify: 'api.ipify.org',
83
icanhazip: 'icanhazip.com', // warn: using cloudflare as of 11/19/21
84
aws: 'checkip.amazonaws.com',
85
identMe: 'ident.me',
86
ifconfigMe: 'ifconfig.me/ip',
87
ipecho: 'ipecho.net/plain',
88
ipinfo: 'ipinfo.io/ip',
89
opendns: 'diagnostic.opendns.com/myip',
90
};
91
92