request-filtering-agent
Advanced tools
Comparing version 2.0.0 to 2.0.1
/// <reference types="node" /> | ||
/// <reference types="node" /> | ||
/// <reference types="node" /> | ||
import * as net from "net"; | ||
import { TcpNetConnectOpts } from "net"; | ||
@@ -22,3 +21,3 @@ import * as http from "http"; | ||
constructor(options?: http.AgentOptions & RequestFilteringAgentOptions); | ||
createConnection(options: TcpNetConnectOpts, connectionListener?: (error: Error | null, socket: Socket) => void): net.Socket; | ||
createConnection(options: TcpNetConnectOpts, connectionListener?: (error: Error | null, socket: Socket) => void): any; | ||
} | ||
@@ -31,3 +30,3 @@ /** | ||
constructor(options?: https.AgentOptions & RequestFilteringAgentOptions); | ||
createConnection(options: TcpNetConnectOpts, connectionListener?: (error: Error | null, socket: Socket) => void): net.Socket; | ||
createConnection(options: TcpNetConnectOpts, connectionListener?: (error: Error | null, socket: Socket) => void): any; | ||
} | ||
@@ -34,0 +33,0 @@ export declare const globalHttpAgent: RequestFilteringHttpAgent; |
@@ -34,2 +34,3 @@ "use strict"; | ||
const ipaddr_js_1 = __importDefault(require("ipaddr.js")); | ||
const dns = __importStar(require("dns")); | ||
exports.DefaultRequestFilteringAgentOptions = { | ||
@@ -79,2 +80,41 @@ allowPrivateIPAddress: false, | ||
}; | ||
const makeLookup = (createConnectionOptions, requestFilterOptions) => { | ||
// @ts-expect-error - @types/node has a poor definition of this callback | ||
return (hostname, options, cb) => { | ||
const lookup = createConnectionOptions.lookup || dns.lookup; | ||
let lookupCb; | ||
if (options.all) { | ||
lookupCb = ((err, addresses) => { | ||
if (err) { | ||
cb(err); | ||
return; | ||
} | ||
for (const { address, family } of addresses) { | ||
const validationError = validateIPAddress({ address, family, host: hostname }, requestFilterOptions); | ||
if (validationError) { | ||
cb(validationError); | ||
return; | ||
} | ||
} | ||
cb(null, addresses); | ||
}); | ||
} | ||
else { | ||
lookupCb = ((err, address, family) => { | ||
if (err) { | ||
cb(err); | ||
return; | ||
} | ||
const validationError = validateIPAddress({ address: address, family: family, host: hostname }, requestFilterOptions); | ||
if (validationError) { | ||
cb(validationError); | ||
return; | ||
} | ||
cb(null, address, family); | ||
}); | ||
} | ||
// @ts-expect-error - @types/node has a poor definition of this callback | ||
lookup(hostname, options, lookupCb); | ||
}; | ||
}; | ||
/** | ||
@@ -118,21 +158,3 @@ * A subclass of http.Agent with request filtering | ||
// @ts-expect-error - @types/node does not defined createConnection | ||
const socket = super.createConnection(options, connectionListener); | ||
// Request with domain name | ||
// Example: http://127.0.0.1.nip.io/ | ||
const onLookup = (err, address, family, host) => { | ||
if (err) { | ||
return; | ||
} | ||
const validationError = validateIPAddress({ address, family, host }, this.requestFilterOptions); | ||
if (validationError) { | ||
socket.removeListener("lookup", onLookup); | ||
// When just call destroy without end, Node.js 20 throws INTERNAL error. | ||
// https://github.com/azu/request-filtering-agent/pull/16#discussion_r1367669822 | ||
socket.end(() => { | ||
socket.destroy(validationError); | ||
}); | ||
} | ||
}; | ||
socket.addListener("lookup", onLookup); | ||
return socket; | ||
return super.createConnection({ ...options, lookup: makeLookup(options, this.requestFilterOptions) }, connectionListener); | ||
} | ||
@@ -171,21 +193,3 @@ } | ||
// @ts-expect-error - @types/node does not defined createConnection | ||
const socket = super.createConnection(options, connectionListener); | ||
// Request with domain name | ||
// Example: http://127.0.0.1.nip.io/ | ||
const onLookup = (err, address, family, host) => { | ||
if (err) { | ||
return; | ||
} | ||
const validationError = validateIPAddress({ address, family, host }, this.requestFilterOptions); | ||
if (validationError) { | ||
socket.removeListener("lookup", onLookup); | ||
// When just call destroy without end, Node.js 20 throws INTERNAL error. | ||
// https://github.com/azu/request-filtering-agent/pull/16#discussion_r1367669822 | ||
socket.end(() => { | ||
socket.destroy(validationError); | ||
}); | ||
} | ||
}; | ||
socket.addListener("lookup", onLookup); | ||
return socket; | ||
return super.createConnection({ ...options, lookup: makeLookup(options, this.requestFilterOptions) }, connectionListener); | ||
} | ||
@@ -192,0 +196,0 @@ } |
{ | ||
"name": "request-filtering-agent", | ||
"version": "2.0.0", | ||
"version": "2.0.1", | ||
"description": "An http(s).Agent implementation that block request Private IP address.", | ||
@@ -5,0 +5,0 @@ "homepage": "https://github.com/azu/request-filtering-agent", |
@@ -9,4 +9,4 @@ # request-filtering-agent [![Actions Status](https://github.com/azu/request-filtering-agent/workflows/ci/badge.svg)](https://github.com/azu/request-filtering-agent/actions) | ||
This library depended on [ipaddr.js](https://github.com/whitequark/ipaddr.js) definitions. | ||
This library block the request to these IP addresses by default. | ||
This library depends on [ipaddr.js](https://github.com/whitequark/ipaddr.js) definitions. | ||
This library blocks the request to these IP addresses by default. | ||
@@ -47,2 +47,9 @@ - [Private IPv4 addresses](https://en.wikipedia.org/wiki/Private_network#Private_IPv4_addresses) | ||
### Support Node.js version | ||
| Version | Node.js 12 | Node.js 14 | Node.js 16 | Node.js 18 | Node.js 20 | | ||
| :------ | :--------- | :--------- | :--------- | :--------- | :---------- | | ||
| v1.x.x | Support | Support | Support | Support | Not Support | | ||
| v2.0.0 | No Support | No Support | No Support | Support | Support | | ||
## Usage | ||
@@ -60,3 +67,3 @@ | ||
// use http or https agent for url | ||
agent: useAgent(url, { stopPortScanningByUrlRedirection: true }) | ||
agent: useAgent(url) | ||
}).catch(err => { | ||
@@ -86,3 +93,3 @@ console.err(err); // DNS lookup 127.0.0.1(family:4, host:127.0.0.1.nip.io) is not allowed. Because, It is private IP address. | ||
fetch(url, { | ||
agent: useAgent(url) | ||
agent: useAgent(url) // use http or https agent for url | ||
}).catch(err => { | ||
@@ -118,13 +125,5 @@ console.err(err); // DNS lookup 127.0.0.1(family:4, host:127.0.0.1.nip.io) is not allowed. Because, It is private IP address. | ||
// Default: [] | ||
denyIPAddressList?: string[] | ||
// prevent url redirection attack | ||
// connection not made to private IP adresses where the port is closed | ||
// Default: false | ||
stopPortScanningByUrlRedirection?: boolean; | ||
denyIPAddressList?: string[]; | ||
} | ||
/** | ||
* Apply request filter to http(s).Agent instance | ||
*/ | ||
export declare function applyRequestFilter<T extends http.Agent | https.Agent>(agent: T, options?: RequestFilteringAgentOptions): T; | ||
/** | ||
* A subclass of http.Agent with request filtering | ||
@@ -173,30 +172,2 @@ */ | ||
### Example: Apply request filtering to excising `http.Agent` | ||
You can apply request filtering to `http.Agent` or `https.Agent` using `applyRequestFilter` method. | ||
```js | ||
const http = require("http") | ||
const fetch = require("node-fetch"); | ||
const { applyRequestFilter } = require("request-filtering-agent"); | ||
// Create http agent with keepAlive option | ||
const agent = new http.Agent({ | ||
keepAlive: true, | ||
}); | ||
// Apply request filtering to http.Agent | ||
const agentWithFiltering = applyRequestFilter(agent, { | ||
allowPrivateIPAddress: false // Default: false | ||
}); | ||
// 169.254.169.254 is private ip address aka. link-local addresses | ||
// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-retrieval.html | ||
// https://serverfault.com/questions/427018/what-is-this-ip-address-169-254-169-254 | ||
const url = 'http://169.254.169.254/'; | ||
fetch(url, { | ||
agent: agentWithFiltering | ||
}).catch(error => { | ||
console.error(error); // Dis-allowed | ||
}); | ||
``` | ||
## Related | ||
@@ -203,0 +174,0 @@ |
@@ -7,2 +7,3 @@ import * as net from "net"; | ||
import { Socket } from "net"; | ||
import * as dns from "dns"; | ||
@@ -86,2 +87,55 @@ export interface RequestFilteringAgentOptions { | ||
// @types/node has a poor definition of this callback (uses "addresses" version if option.all = true) | ||
type LookupOneCallback = (err: NodeJS.ErrnoException | null, address?: string, family?: number) => void; | ||
type LookupAllCallback = (err: NodeJS.ErrnoException | null, addresses?: dns.LookupAddress[]) => void; | ||
type LookupCallback = LookupOneCallback | LookupAllCallback; | ||
const makeLookup = ( | ||
createConnectionOptions: TcpNetConnectOpts, | ||
requestFilterOptions: Required<RequestFilteringAgentOptions> | ||
): Required<net.TcpSocketConnectOpts>["lookup"] => { | ||
// @ts-expect-error - @types/node has a poor definition of this callback | ||
return (hostname, options, cb: LookupCallback) => { | ||
const lookup = createConnectionOptions.lookup || dns.lookup; | ||
let lookupCb: LookupCallback; | ||
if (options.all) { | ||
lookupCb = ((err, addresses) => { | ||
if (err) { | ||
cb(err); | ||
return; | ||
} | ||
for (const { address, family } of addresses!) { | ||
const validationError = validateIPAddress( | ||
{ address, family, host: hostname }, | ||
requestFilterOptions | ||
); | ||
if (validationError) { | ||
cb(validationError); | ||
return; | ||
} | ||
} | ||
(cb as LookupAllCallback)(null, addresses); | ||
}) as LookupAllCallback; | ||
} else { | ||
lookupCb = ((err, address, family) => { | ||
if (err) { | ||
cb(err); | ||
return; | ||
} | ||
const validationError = validateIPAddress( | ||
{ address: address!, family: family!, host: hostname }, | ||
requestFilterOptions | ||
); | ||
if (validationError) { | ||
cb(validationError); | ||
return; | ||
} | ||
(cb as LookupOneCallback)(null, address!, family!); | ||
}) as LookupOneCallback; | ||
} | ||
// @ts-expect-error - @types/node has a poor definition of this callback | ||
lookup(hostname, options, lookupCb); | ||
}; | ||
}; | ||
/** | ||
@@ -131,21 +185,6 @@ * A subclass of http.Agent with request filtering | ||
// @ts-expect-error - @types/node does not defined createConnection | ||
const socket: Socket = super.createConnection(options, connectionListener); | ||
// Request with domain name | ||
// Example: http://127.0.0.1.nip.io/ | ||
const onLookup = (err: Error, address: string, family: string | number, host: string): void => { | ||
if (err) { | ||
return; | ||
} | ||
const validationError = validateIPAddress({ address, family, host }, this.requestFilterOptions); | ||
if (validationError) { | ||
socket.removeListener("lookup", onLookup); | ||
// When just call destroy without end, Node.js 20 throws INTERNAL error. | ||
// https://github.com/azu/request-filtering-agent/pull/16#discussion_r1367669822 | ||
socket.end(() => { | ||
socket.destroy(validationError); | ||
}); | ||
} | ||
}; | ||
socket.addListener("lookup", onLookup); | ||
return socket; | ||
return super.createConnection( | ||
{ ...options, lookup: makeLookup(options, this.requestFilterOptions) }, | ||
connectionListener | ||
); | ||
} | ||
@@ -188,21 +227,6 @@ } | ||
// @ts-expect-error - @types/node does not defined createConnection | ||
const socket: Socket = super.createConnection(options, connectionListener); | ||
// Request with domain name | ||
// Example: http://127.0.0.1.nip.io/ | ||
const onLookup = (err: Error, address: string, family: string | number, host: string): void => { | ||
if (err) { | ||
return; | ||
} | ||
const validationError = validateIPAddress({ address, family, host }, this.requestFilterOptions); | ||
if (validationError) { | ||
socket.removeListener("lookup", onLookup); | ||
// When just call destroy without end, Node.js 20 throws INTERNAL error. | ||
// https://github.com/azu/request-filtering-agent/pull/16#discussion_r1367669822 | ||
socket.end(() => { | ||
socket.destroy(validationError); | ||
}); | ||
} | ||
}; | ||
socket.addListener("lookup", onLookup); | ||
return socket; | ||
return super.createConnection( | ||
{ ...options, lookup: makeLookup(options, this.requestFilterOptions) }, | ||
connectionListener | ||
); | ||
} | ||
@@ -209,0 +233,0 @@ } |
Sorry, the diff of this file is not supported yet
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
37177
479
211