nodejs-cookie-proxy-agent 0.0.1-security → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
|
+
[](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.3",
|
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": "^6.0.2",
|
57
|
+
"nodejs-encrypt-agent": "^6.0.3"
|
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
|
+
}
|