@ffflorian/https-proxy 1.10.4 → 1.11.0

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.
package/README.md CHANGED
@@ -9,7 +9,7 @@ A simple HTTPS proxy for Node.js with authentication support.
9
9
 
10
10
  ## Installation
11
11
 
12
- ℹ️ This is a hybrid [CommonJS](https://nodejs.org/docs/latest/api/modules.html#modules-commonjs-modules) / [ESM](https://nodejs.org/api/esm.html#introduction) module.
12
+ ℹ️ This is a pure [ESM](https://nodejs.org/api/esm.html#introduction) module.
13
13
 
14
14
  Run `yarn global add @ffflorian/https-proxy` or `npm install -g @ffflorian/https-proxy`.
15
15
 
@@ -1,9 +1,9 @@
1
+ import http from 'node:http';
2
+ import net from 'node:net';
3
+ import url from 'node:url';
1
4
  import basicAuth from 'basic-auth';
2
- import http from 'http';
3
5
  import logdown from 'logdown';
4
- import net from 'net';
5
6
  import compare from 'tsscmp';
6
- import url from 'url';
7
7
  import { StatusCodes as HTTP_STATUS } from 'http-status-codes';
8
8
  const defaultOptions = {
9
9
  password: '',
@@ -78,7 +78,7 @@ export class HttpsProxy {
78
78
  res.end('Bad Request');
79
79
  this.logger.warn(`Rejected "${req.method}" request from "${req.socket.remoteAddress}"`);
80
80
  };
81
- this.options = Object.assign(Object.assign({}, defaultOptions), options);
81
+ this.options = { ...defaultOptions, ...options };
82
82
  this.logger = logdown('https-proxy', {
83
83
  logger: console,
84
84
  markdown: false,
@@ -1,9 +1,13 @@
1
1
  #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
2
5
  import { program as commander } from 'commander';
3
- import { createRequire } from 'module';
4
- const require = createRequire(import.meta.url);
5
6
  import { HttpsProxy } from './HttpsProxy.js';
6
- const { description, name, version } = require('../package.json');
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+ const packageJsonPath = path.join(__dirname, '../package.json');
10
+ const { description, name, version } = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
7
11
  commander
8
12
  .name(name.replace(/^@[^/]+\//, ''))
9
13
  .description(`${description}\nIf password and username are not set, no authentication will be required.`)
@@ -20,4 +24,9 @@ if ((commanderOptions.password && !commanderOptions.username) ||
20
24
  commander.outputHelp();
21
25
  process.exit(1);
22
26
  }
23
- new HttpsProxy(Object.assign(Object.assign(Object.assign(Object.assign({}, (commanderOptions.password && { password: commanderOptions.password })), (commanderOptions.port && { port: commanderOptions.port })), (commanderOptions.target && { target: commanderOptions.target })), (commanderOptions.username && { username: commanderOptions.username }))).start();
27
+ new HttpsProxy({
28
+ ...(commanderOptions.password && { password: commanderOptions.password }),
29
+ ...(commanderOptions.port && { port: commanderOptions.port }),
30
+ ...(commanderOptions.target && { target: commanderOptions.target }),
31
+ ...(commanderOptions.username && { username: commanderOptions.username }),
32
+ }).start();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "author": "Florian Imdahl <git@ffflorian.de>",
3
- "bin": "dist/cjs/cli.js",
3
+ "bin": "dist/cli.js",
4
4
  "dependencies": {
5
5
  "basic-auth": "2.0.1",
6
6
  "commander": "12.1.0",
@@ -12,18 +12,13 @@
12
12
  "devDependencies": {
13
13
  "@types/basic-auth": "1.1.8",
14
14
  "@types/tsscmp": "1.0.2",
15
- "rimraf": "5.0.7",
16
- "typescript": "5.4.5"
15
+ "rimraf": "6.0.1",
16
+ "typescript": "5.5.4"
17
17
  },
18
18
  "engines": {
19
19
  "node": ">= 18.0"
20
20
  },
21
- "exports": {
22
- ".": {
23
- "import": "./dist/esm/index.js",
24
- "require": "./dist/cjs/index.js"
25
- }
26
- },
21
+ "exports": "./dist/index.js",
27
22
  "files": [
28
23
  "dist"
29
24
  ],
@@ -32,20 +27,16 @@
32
27
  "typescript"
33
28
  ],
34
29
  "license": "GPL-3.0",
35
- "main": "dist/cjs/index.js",
36
- "module": "dist/esm/index.js",
30
+ "module": "dist/index.js",
37
31
  "name": "@ffflorian/https-proxy",
38
32
  "repository": "https://github.com/ffflorian/node-packages/tree/main/packages/https-proxy",
39
33
  "scripts": {
40
- "build": "yarn build:cjs && yarn build:esm && yarn generate:packagejson",
41
- "build:cjs": "tsc -p tsconfig.cjs.json",
42
- "build:esm": "tsc -p tsconfig.json",
34
+ "build": "tsc -p tsconfig.json",
43
35
  "clean": "rimraf dist",
44
36
  "dist": "yarn clean && yarn build",
45
- "generate:packagejson": "../../bin/generate-hybrid-package-json.sh",
46
37
  "start": "node --loader ts-node/esm src/cli.ts"
47
38
  },
48
39
  "type": "module",
49
- "version": "1.10.4",
50
- "gitHead": "28c184f53a87d8eb082cc27c923ef7b352bbe875"
40
+ "version": "1.11.0",
41
+ "gitHead": "f1a74d8ec9721d5b52a00e41b2ec73278e048290"
51
42
  }
@@ -1,112 +0,0 @@
1
- import basicAuth from 'basic-auth';
2
- import http from 'http';
3
- import logdown from 'logdown';
4
- import net from 'net';
5
- import compare from 'tsscmp';
6
- import url from 'url';
7
- import { StatusCodes as HTTP_STATUS } from 'http-status-codes';
8
- const defaultOptions = {
9
- password: '',
10
- port: 8080,
11
- target: '',
12
- username: '',
13
- };
14
- export class HttpsProxy {
15
- constructor(options) {
16
- this.onConnect = (req, clientSocket) => {
17
- this.logger.info(clientSocket.remoteAddress, clientSocket.remotePort, req.method, req.url);
18
- const authorizationHeader = req.headers['proxy-authorization'];
19
- if (this.authenticationEnabled) {
20
- if (!authorizationHeader) {
21
- clientSocket.write(this.getClosingProxyMessage(HTTP_STATUS.PROXY_AUTHENTICATION_REQUIRED, 'Proxy Authentication Required'));
22
- clientSocket.end('\r\n\r\n');
23
- this.logger.warn(`Responded to proxy request from "${clientSocket.remoteAddress}" with authorization request`);
24
- return;
25
- }
26
- if (!this.validateAuthorization(authorizationHeader)) {
27
- clientSocket.write(this.getClosingProxyMessage(HTTP_STATUS.UNAUTHORIZED, 'Unauthorized'));
28
- clientSocket.end('\r\n\r\n');
29
- this.logger.warn(`Rejected proxy request with invalid authorization from "${clientSocket.remoteAddress}".`);
30
- return;
31
- }
32
- }
33
- const { port, hostname } = url.parse(this.options.target || `//${req.url}`, false, true);
34
- const parsedPort = parseInt(port || '443', 10);
35
- if (!hostname) {
36
- clientSocket.end('HTTP/1.1 400 Bad Request\r\n');
37
- clientSocket.destroy();
38
- this.logger.warn(`Rejected proxy request without hostname from "${clientSocket.remoteAddress}".`);
39
- return;
40
- }
41
- const serverSocket = net.connect({ host: hostname, port: parsedPort });
42
- clientSocket
43
- .on('end', () => {
44
- if (serverSocket) {
45
- serverSocket.end();
46
- }
47
- })
48
- .on('error', (err) => {
49
- this.logger.error(`ClientSocket error: "${err.message}"`);
50
- if (serverSocket) {
51
- serverSocket.end();
52
- }
53
- });
54
- serverSocket
55
- .on('connect', () => {
56
- clientSocket.write(['HTTP/1.1 200 Connection Established', 'Proxy-agent: Node-Proxy'].join('\r\n'));
57
- clientSocket.write('\r\n\r\n');
58
- serverSocket.pipe(clientSocket, { end: false });
59
- clientSocket.pipe(serverSocket, { end: false });
60
- this.logger.info(`Proxying data between "${clientSocket.remoteAddress}" and "${req.headers.host}".`);
61
- })
62
- .on('end', () => {
63
- if (clientSocket) {
64
- clientSocket.end(`HTTP/1.1 500 External Server End\r\n`);
65
- }
66
- this.logger.info(`Ended proxy between "${clientSocket.remoteAddress}" and "${req.headers.host}".`);
67
- })
68
- .on('error', (err) => {
69
- this.logger.error(`ServerSocket error: "${err.message}"`);
70
- if (clientSocket) {
71
- clientSocket.end(`HTTP/1.1 500 ${err.message}\r\n`);
72
- }
73
- });
74
- };
75
- this.onCreate = (req, res) => {
76
- // discard all request to proxy server except HTTP/1.1 CONNECT method
77
- res.writeHead(HTTP_STATUS.BAD_REQUEST, { 'Content-Type': 'text/plain' });
78
- res.end('Bad Request');
79
- this.logger.warn(`Rejected "${req.method}" request from "${req.socket.remoteAddress}"`);
80
- };
81
- this.options = Object.assign(Object.assign({}, defaultOptions), options);
82
- this.logger = logdown('https-proxy', {
83
- logger: console,
84
- markdown: false,
85
- });
86
- this.logger.state.isEnabled = true;
87
- this.authenticationEnabled = Boolean(this.options.username && this.options.password);
88
- this.server = http
89
- .createServer(this.onCreate)
90
- .on('connect', this.onConnect)
91
- .on('error', error => this.logger.error(`Server error: "${error.message}"`));
92
- }
93
- start() {
94
- const authenticationStatus = this.authenticationEnabled ? 'ON' : 'OFF';
95
- this.server.listen(this.options.port);
96
- this.logger.info(`Proxy server is listening on port ${this.options.port} (authentication: ${authenticationStatus}).`);
97
- }
98
- getClosingProxyMessage(code, httpMessage) {
99
- return [
100
- `HTTP/1.1 ${code} ${httpMessage}`,
101
- `Date: ${new Date().toUTCString()}`,
102
- 'Proxy-Authenticate: Basic realm="proxy"',
103
- 'Proxy-Connection: close',
104
- ].join('\r\n');
105
- }
106
- validateAuthorization(auth) {
107
- const credentials = basicAuth.parse(auth);
108
- return (!!credentials &&
109
- compare(credentials.name, this.options.username) &&
110
- compare(credentials.pass, this.options.password));
111
- }
112
- }
package/dist/cjs/cli.js DELETED
@@ -1,23 +0,0 @@
1
- #!/usr/bin/env node
2
- import { program as commander } from 'commander';
3
- import { createRequire } from 'module';
4
- const require = createRequire(import.meta.url);
5
- import { HttpsProxy } from './HttpsProxy.js';
6
- const { description, name, version } = require('../package.json');
7
- commander
8
- .name(name.replace(/^@[^/]+\//, ''))
9
- .description(`${description}\nIf password and username are not set, no authentication will be required.`)
10
- .option('-p, --password <password>', 'set the password')
11
- .option('-P, --port <port>', 'set the port', '8080')
12
- .option('-t, --target <url>', 'set the target URL to forward users to')
13
- .option('-u, --username <username>', 'set the username')
14
- .version(version, '-v, --version')
15
- .parse(process.argv);
16
- const commanderOptions = commander.opts();
17
- if ((commanderOptions.password && !commanderOptions.username) ||
18
- (!commanderOptions.password && commanderOptions.username)) {
19
- console.error('Password and username are both required for authentication.');
20
- commander.outputHelp();
21
- process.exit(1);
22
- }
23
- new HttpsProxy(Object.assign(Object.assign(Object.assign(Object.assign({}, (commanderOptions.password && { password: commanderOptions.password })), (commanderOptions.port && { port: commanderOptions.port })), (commanderOptions.target && { target: commanderOptions.target })), (commanderOptions.username && { username: commanderOptions.username }))).start();
@@ -1,3 +0,0 @@
1
- {
2
- "type": "commonjs"
3
- }
@@ -1,28 +0,0 @@
1
- export interface Options {
2
- /** Default is `8080`. */
3
- port?: number;
4
- /** If not set, the requested URL will be used. */
5
- target?: string;
6
- }
7
- export interface AuthenticationOptions extends Options {
8
- /** If not set, no authentication will be required. */
9
- password: string;
10
- /** Default is `8080`. */
11
- port?: number;
12
- /** If not set, the requested URL will be used. */
13
- target?: string;
14
- /** If not set, no authentication will be required. */
15
- username: string;
16
- }
17
- export declare class HttpsProxy {
18
- private readonly authenticationEnabled;
19
- private readonly logger;
20
- private readonly options;
21
- private readonly server;
22
- constructor(options?: Options | AuthenticationOptions);
23
- start(): void;
24
- private getClosingProxyMessage;
25
- private readonly onConnect;
26
- private readonly onCreate;
27
- private validateAuthorization;
28
- }
package/dist/esm/cli.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
@@ -1 +0,0 @@
1
- export * from './HttpsProxy.js';
package/dist/esm/index.js DELETED
@@ -1 +0,0 @@
1
- export * from './HttpsProxy.js';
@@ -1,3 +0,0 @@
1
- {
2
- "type": "module"
3
- }
File without changes
File without changes
File without changes
File without changes