ssrf-agent-guard 0.1.2 → 0.1.4
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 +4 -1
- package/dist/index.cjs.js +10 -22
- package/dist/index.esm.js +10 -22
- package/package.json +1 -1
- package/ssrf-agent-guard-0.1.3.tgz +0 -0
- package/.eslintrc.js +0 -27
- package/.prettierrc +0 -8
- package/dist/index.d.ts +0 -14
- package/dist/lib/types.d.ts +0 -27
- package/dist/lib/utils.d.ts +0 -9
- package/index.ts +0 -95
- package/lib/types.ts +0 -37
- package/lib/utils.ts +0 -46
- package/rollup.config.mjs +0 -10
- package/test/index.test.ts +0 -63
- package/tsconfig.json +0 -18
package/README.md
CHANGED
|
@@ -35,7 +35,10 @@ const isValidDomainOptions = {
|
|
|
35
35
|
subdomain: true,
|
|
36
36
|
wildcard: true
|
|
37
37
|
};
|
|
38
|
-
axios.get(
|
|
38
|
+
axios.get(
|
|
39
|
+
url, {
|
|
40
|
+
httpAgent: ssrfAgentGuard(url, isValidDomainOptions), httpsAgent: ssrfAgentGuard(url, isValidDomainOptions)
|
|
41
|
+
})
|
|
39
42
|
.then((response) => {
|
|
40
43
|
console.log(`Success`);
|
|
41
44
|
})
|
package/dist/index.cjs.js
CHANGED
|
@@ -27,25 +27,16 @@ function isIp(input) {
|
|
|
27
27
|
function isPublicIp(ip) {
|
|
28
28
|
return ipaddr.parse(ip).range() === 'unicast';
|
|
29
29
|
}
|
|
30
|
-
/**
|
|
31
|
-
* Validates whether a domain is syntactically valid.
|
|
32
|
-
*/
|
|
33
|
-
function isSafeIp(hostname) {
|
|
34
|
-
// Case 1: IP address
|
|
35
|
-
if (isIp(hostname)) {
|
|
36
|
-
return isPublicIp(hostname); // only allow public IPs
|
|
37
|
-
}
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
40
30
|
/**
|
|
41
31
|
* High-level validation for hostnames (domains + public IPs).
|
|
42
32
|
*/
|
|
43
33
|
function isSafeHost(hostname, isValidDomainOptions) {
|
|
44
34
|
// Block cloud metadata IP/domains
|
|
45
|
-
if (CLOUD_METADATA_HOSTS.indexOf(hostname))
|
|
46
|
-
return false;
|
|
47
|
-
if (!isSafeIp(hostname))
|
|
35
|
+
if (CLOUD_METADATA_HOSTS.indexOf(hostname) !== -1)
|
|
48
36
|
return false;
|
|
37
|
+
// Case 1: IP address
|
|
38
|
+
if (isIp(hostname))
|
|
39
|
+
return isPublicIp(hostname);
|
|
49
40
|
// Case 2: Domain name
|
|
50
41
|
return isValidDomain(hostname, {
|
|
51
42
|
allowUnicode: false,
|
|
@@ -90,7 +81,7 @@ const ssrfAgentGuard = function (url, isValidDomainOptions) {
|
|
|
90
81
|
// The original createConnection function from the Agent
|
|
91
82
|
const createConnection = finalAgent.createConnection;
|
|
92
83
|
// Patch the createConnection method on the agent
|
|
93
|
-
finalAgent.createConnection = (options, fn)
|
|
84
|
+
finalAgent.createConnection = function (options, fn) {
|
|
94
85
|
const { host: address } = options;
|
|
95
86
|
// --- 1. Pre-DNS Check (Host/Address Check) ---
|
|
96
87
|
// If the 'host' option is an IP address, check it immediately.
|
|
@@ -99,22 +90,19 @@ const ssrfAgentGuard = function (url, isValidDomainOptions) {
|
|
|
99
90
|
throw new Error(`DNS lookup ${address} is not allowed.`);
|
|
100
91
|
}
|
|
101
92
|
// Call the original createConnection
|
|
102
|
-
// @ts-expect-error 'this' is not assignable to type 'HttpAgent | HttpsAgent'
|
|
103
93
|
const client = createConnection.call(this, options, fn);
|
|
104
94
|
// --- 2. Post-DNS Check (Lookup Event Check) ---
|
|
105
95
|
// The 'lookup' event fires after the DNS lookup is complete
|
|
106
96
|
// and provides the resolved IP address.
|
|
107
97
|
client?.on('lookup', (err, resolvedAddress) => {
|
|
108
|
-
// If there was an error in lookup, or if the resolved IP is allowed, do nothing.
|
|
109
|
-
if (err) {
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
98
|
// Ensure resolvedAddress is a string for the check (it's typically a string for simple lookups)
|
|
113
99
|
const ipToCheck = Array.isArray(resolvedAddress) ? resolvedAddress[0] : resolvedAddress;
|
|
114
|
-
if
|
|
115
|
-
|
|
116
|
-
return
|
|
100
|
+
// If there was an error in lookup, or if the resolved IP is allowed, do nothing.
|
|
101
|
+
if (err || isSafeHost(ipToCheck, isValidDomainOptions)) {
|
|
102
|
+
return false;
|
|
117
103
|
}
|
|
104
|
+
// If the resolved IP is NOT allowed (e.g., a private IP), destroy the connection.
|
|
105
|
+
return client?.destroy(new Error(`DNS lookup ${ipToCheck} is not allowed.`));
|
|
118
106
|
});
|
|
119
107
|
return client;
|
|
120
108
|
};
|
package/dist/index.esm.js
CHANGED
|
@@ -23,25 +23,16 @@ function isIp(input) {
|
|
|
23
23
|
function isPublicIp(ip) {
|
|
24
24
|
return ipaddr.parse(ip).range() === 'unicast';
|
|
25
25
|
}
|
|
26
|
-
/**
|
|
27
|
-
* Validates whether a domain is syntactically valid.
|
|
28
|
-
*/
|
|
29
|
-
function isSafeIp(hostname) {
|
|
30
|
-
// Case 1: IP address
|
|
31
|
-
if (isIp(hostname)) {
|
|
32
|
-
return isPublicIp(hostname); // only allow public IPs
|
|
33
|
-
}
|
|
34
|
-
return true;
|
|
35
|
-
}
|
|
36
26
|
/**
|
|
37
27
|
* High-level validation for hostnames (domains + public IPs).
|
|
38
28
|
*/
|
|
39
29
|
function isSafeHost(hostname, isValidDomainOptions) {
|
|
40
30
|
// Block cloud metadata IP/domains
|
|
41
|
-
if (CLOUD_METADATA_HOSTS.indexOf(hostname))
|
|
42
|
-
return false;
|
|
43
|
-
if (!isSafeIp(hostname))
|
|
31
|
+
if (CLOUD_METADATA_HOSTS.indexOf(hostname) !== -1)
|
|
44
32
|
return false;
|
|
33
|
+
// Case 1: IP address
|
|
34
|
+
if (isIp(hostname))
|
|
35
|
+
return isPublicIp(hostname);
|
|
45
36
|
// Case 2: Domain name
|
|
46
37
|
return isValidDomain(hostname, {
|
|
47
38
|
allowUnicode: false,
|
|
@@ -86,7 +77,7 @@ const ssrfAgentGuard = function (url, isValidDomainOptions) {
|
|
|
86
77
|
// The original createConnection function from the Agent
|
|
87
78
|
const createConnection = finalAgent.createConnection;
|
|
88
79
|
// Patch the createConnection method on the agent
|
|
89
|
-
finalAgent.createConnection = (options, fn)
|
|
80
|
+
finalAgent.createConnection = function (options, fn) {
|
|
90
81
|
const { host: address } = options;
|
|
91
82
|
// --- 1. Pre-DNS Check (Host/Address Check) ---
|
|
92
83
|
// If the 'host' option is an IP address, check it immediately.
|
|
@@ -95,22 +86,19 @@ const ssrfAgentGuard = function (url, isValidDomainOptions) {
|
|
|
95
86
|
throw new Error(`DNS lookup ${address} is not allowed.`);
|
|
96
87
|
}
|
|
97
88
|
// Call the original createConnection
|
|
98
|
-
// @ts-expect-error 'this' is not assignable to type 'HttpAgent | HttpsAgent'
|
|
99
89
|
const client = createConnection.call(this, options, fn);
|
|
100
90
|
// --- 2. Post-DNS Check (Lookup Event Check) ---
|
|
101
91
|
// The 'lookup' event fires after the DNS lookup is complete
|
|
102
92
|
// and provides the resolved IP address.
|
|
103
93
|
client?.on('lookup', (err, resolvedAddress) => {
|
|
104
|
-
// If there was an error in lookup, or if the resolved IP is allowed, do nothing.
|
|
105
|
-
if (err) {
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
94
|
// Ensure resolvedAddress is a string for the check (it's typically a string for simple lookups)
|
|
109
95
|
const ipToCheck = Array.isArray(resolvedAddress) ? resolvedAddress[0] : resolvedAddress;
|
|
110
|
-
if
|
|
111
|
-
|
|
112
|
-
return
|
|
96
|
+
// If there was an error in lookup, or if the resolved IP is allowed, do nothing.
|
|
97
|
+
if (err || isSafeHost(ipToCheck, isValidDomainOptions)) {
|
|
98
|
+
return false;
|
|
113
99
|
}
|
|
100
|
+
// If the resolved IP is NOT allowed (e.g., a private IP), destroy the connection.
|
|
101
|
+
return client?.destroy(new Error(`DNS lookup ${ipToCheck} is not allowed.`));
|
|
114
102
|
});
|
|
115
103
|
return client;
|
|
116
104
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ssrf-agent-guard",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "A TypeScript SSRF protection library for Node.js (express/axios) with advanced policies, DNS rebinding detection and cloud metadata protection.",
|
|
5
5
|
"main": "dist/index.cjs.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
Binary file
|
package/.eslintrc.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
root: true,
|
|
3
|
-
parser: '@typescript-eslint/parser',
|
|
4
|
-
parserOptions: {
|
|
5
|
-
ecmaVersion: 2020,
|
|
6
|
-
sourceType: 'module',
|
|
7
|
-
},
|
|
8
|
-
env: {
|
|
9
|
-
node: true,
|
|
10
|
-
es2020: true,
|
|
11
|
-
jest: true,
|
|
12
|
-
},
|
|
13
|
-
extends: [
|
|
14
|
-
'eslint:recommended',
|
|
15
|
-
'plugin:@typescript-eslint/recommended', // TypeScript rules
|
|
16
|
-
'plugin:prettier/recommended' // Integrate Prettier
|
|
17
|
-
],
|
|
18
|
-
plugins: ['@typescript-eslint', 'prettier'],
|
|
19
|
-
rules: {
|
|
20
|
-
'prettier/prettier': 'error', // Show prettier errors as ESLint errors
|
|
21
|
-
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
22
|
-
'@typescript-eslint/no-explicit-any': 'off',
|
|
23
|
-
'@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
|
|
24
|
-
'no-console': 'warn',
|
|
25
|
-
'prefer-const': 'error',
|
|
26
|
-
},
|
|
27
|
-
};
|
package/.prettierrc
DELETED
package/dist/index.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Agent as HttpAgent } from 'http';
|
|
2
|
-
import { Agent as HttpsAgent } from 'https';
|
|
3
|
-
import { IsValidDomainOptions } from './lib/types';
|
|
4
|
-
type CustomAgent = HttpAgent | HttpsAgent;
|
|
5
|
-
/**
|
|
6
|
-
* Patches an http.Agent or https.Agent to enforce an HOST/IP check
|
|
7
|
-
* before and after a DNS lookup.
|
|
8
|
-
*
|
|
9
|
-
* @param url The URL or another input to determine the agent type.
|
|
10
|
-
* @param isValidDomainOptions Options for validating domain names.
|
|
11
|
-
* @returns The patched CustomAgent instance.
|
|
12
|
-
*/
|
|
13
|
-
declare const ssrfAgentGuard: (url: string, isValidDomainOptions?: IsValidDomainOptions) => CustomAgent;
|
|
14
|
-
export default ssrfAgentGuard;
|
package/dist/lib/types.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
export interface Options {
|
|
2
|
-
protocal?: string;
|
|
3
|
-
metadataHosts?: string[];
|
|
4
|
-
mode?: 'block' | 'report' | 'allow';
|
|
5
|
-
policy?: PolicyOptions;
|
|
6
|
-
blockCloudMetadata?: boolean;
|
|
7
|
-
detectDnsRebinding?: boolean;
|
|
8
|
-
logger?: (level: 'info' | 'warn' | 'error', msg: string, meta?: any) => void;
|
|
9
|
-
}
|
|
10
|
-
export interface PolicyOptions {
|
|
11
|
-
allowDomains?: string[];
|
|
12
|
-
denyDomains?: string[];
|
|
13
|
-
denyTLD?: string[];
|
|
14
|
-
}
|
|
15
|
-
export interface BlockEvent {
|
|
16
|
-
url: string;
|
|
17
|
-
reason: string;
|
|
18
|
-
ip?: string;
|
|
19
|
-
timestamp: number;
|
|
20
|
-
}
|
|
21
|
-
export interface IsValidDomainOptions {
|
|
22
|
-
subdomain?: boolean;
|
|
23
|
-
wildcard?: boolean;
|
|
24
|
-
allowUnicode?: boolean;
|
|
25
|
-
topLevel?: boolean;
|
|
26
|
-
}
|
|
27
|
-
export declare const CLOUD_METADATA_HOSTS: string[];
|
package/dist/lib/utils.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { IsValidDomainOptions } from './types';
|
|
2
|
-
/**
|
|
3
|
-
* Validates whether a domain is syntactically valid.
|
|
4
|
-
*/
|
|
5
|
-
export declare function isSafeIp(hostname: string): boolean;
|
|
6
|
-
/**
|
|
7
|
-
* High-level validation for hostnames (domains + public IPs).
|
|
8
|
-
*/
|
|
9
|
-
export declare function isSafeHost(hostname: string, isValidDomainOptions?: IsValidDomainOptions): boolean;
|
package/index.ts
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { Agent as HttpAgent, AgentOptions as HttpAgentOptions } from 'http';
|
|
2
|
-
import { Agent as HttpsAgent, AgentOptions as HttpsAgentOptions } from 'https';
|
|
3
|
-
import { Duplex } from 'stream';
|
|
4
|
-
|
|
5
|
-
import { isSafeHost, isSafeIp } from './lib/utils';
|
|
6
|
-
import { IsValidDomainOptions } from './lib/types';
|
|
7
|
-
|
|
8
|
-
// Define the type for the Agent that this module will modify and return.
|
|
9
|
-
// It can be either an HttpAgent or an HttpsAgent.
|
|
10
|
-
type CustomAgent = HttpAgent | HttpsAgent;
|
|
11
|
-
|
|
12
|
-
// Instantiate the default agents
|
|
13
|
-
const httpAgent = new HttpAgent();
|
|
14
|
-
const httpsAgent = new HttpsAgent();
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Determines the correct Agent instance based on the input.
|
|
18
|
-
* @param url The URL or another input to determine the agent type.
|
|
19
|
-
* @returns The appropriate HttpAgent or HttpsAgent instance.
|
|
20
|
-
*/
|
|
21
|
-
const getAgent = (url: string): CustomAgent => {
|
|
22
|
-
// If it's a string, check if it implies HTTPS
|
|
23
|
-
if (typeof url === 'string' && url.startsWith('https')) {
|
|
24
|
-
return httpsAgent;
|
|
25
|
-
}
|
|
26
|
-
// Default to HTTP agent
|
|
27
|
-
return httpAgent;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
// Define a Symbol for a unique property to prevent double-patching the agent.
|
|
31
|
-
const CREATE_CONNECTION = Symbol('createConnection');
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Patches an http.Agent or https.Agent to enforce an HOST/IP check
|
|
35
|
-
* before and after a DNS lookup.
|
|
36
|
-
*
|
|
37
|
-
* @param url The URL or another input to determine the agent type.
|
|
38
|
-
* @param isValidDomainOptions Options for validating domain names.
|
|
39
|
-
* @returns The patched CustomAgent instance.
|
|
40
|
-
*/
|
|
41
|
-
const ssrfAgentGuard = function (url: string, isValidDomainOptions?: IsValidDomainOptions): CustomAgent {
|
|
42
|
-
const finalAgent = getAgent(url);
|
|
43
|
-
|
|
44
|
-
// Prevent patching the agent multiple times
|
|
45
|
-
if ((finalAgent as any)[CREATE_CONNECTION]) {
|
|
46
|
-
return finalAgent;
|
|
47
|
-
}
|
|
48
|
-
(finalAgent as any)[CREATE_CONNECTION] = true;
|
|
49
|
-
|
|
50
|
-
// The original createConnection function from the Agent
|
|
51
|
-
const createConnection = finalAgent.createConnection;
|
|
52
|
-
|
|
53
|
-
// Patch the createConnection method on the agent
|
|
54
|
-
finalAgent.createConnection = (
|
|
55
|
-
options: HttpAgentOptions | HttpsAgentOptions,
|
|
56
|
-
fn?: (err: Error | null, stream: Duplex) => void,
|
|
57
|
-
) => {
|
|
58
|
-
const { host: address } = options;
|
|
59
|
-
// --- 1. Pre-DNS Check (Host/Address Check) ---
|
|
60
|
-
// If the 'host' option is an IP address, check it immediately.
|
|
61
|
-
// If it's a hostname, this check will usually pass (via defaultIpChecker).
|
|
62
|
-
if (address && !isSafeHost(address, isValidDomainOptions)) {
|
|
63
|
-
throw new Error(`DNS lookup ${address} is not allowed.`);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Call the original createConnection
|
|
67
|
-
// @ts-expect-error 'this' is not assignable to type 'HttpAgent | HttpsAgent'
|
|
68
|
-
const client = createConnection.call(this, options, fn);
|
|
69
|
-
|
|
70
|
-
// --- 2. Post-DNS Check (Lookup Event Check) ---
|
|
71
|
-
// The 'lookup' event fires after the DNS lookup is complete
|
|
72
|
-
// and provides the resolved IP address.
|
|
73
|
-
client?.on('lookup', (err: Error | null, resolvedAddress: string | string[]) => {
|
|
74
|
-
// If there was an error in lookup, or if the resolved IP is allowed, do nothing.
|
|
75
|
-
if (err) {
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Ensure resolvedAddress is a string for the check (it's typically a string for simple lookups)
|
|
80
|
-
const ipToCheck = Array.isArray(resolvedAddress) ? resolvedAddress[0] : resolvedAddress;
|
|
81
|
-
|
|
82
|
-
if (!isSafeHost(ipToCheck)) {
|
|
83
|
-
// If the resolved IP is NOT allowed (e.g., a private IP), destroy the connection.
|
|
84
|
-
return client?.destroy(new Error(`DNS lookup ${ipToCheck} is not allowed.`));
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
return client;
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
return finalAgent;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export default ssrfAgentGuard;
|
|
95
|
-
module.exports = ssrfAgentGuard;
|
package/lib/types.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
// lib/types.ts
|
|
2
|
-
export interface Options {
|
|
3
|
-
protocal?: string;
|
|
4
|
-
metadataHosts?: string[];
|
|
5
|
-
mode?: 'block' | 'report' | 'allow';
|
|
6
|
-
policy?: PolicyOptions;
|
|
7
|
-
blockCloudMetadata?: boolean;
|
|
8
|
-
detectDnsRebinding?: boolean;
|
|
9
|
-
logger?: (level: 'info' | 'warn' | 'error', msg: string, meta?: any) => void;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface PolicyOptions {
|
|
13
|
-
allowDomains?: string[];
|
|
14
|
-
denyDomains?: string[];
|
|
15
|
-
denyTLD?: string[];
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export interface BlockEvent {
|
|
19
|
-
url: string;
|
|
20
|
-
reason: string;
|
|
21
|
-
ip?: string;
|
|
22
|
-
timestamp: number;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface IsValidDomainOptions {
|
|
26
|
-
subdomain?: boolean;
|
|
27
|
-
wildcard?: boolean;
|
|
28
|
-
allowUnicode?: boolean;
|
|
29
|
-
topLevel?: boolean;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export const CLOUD_METADATA_HOSTS: string[] = [
|
|
33
|
-
'169.254.169.254',
|
|
34
|
-
'169.254.169.253',
|
|
35
|
-
'metadata.google.internal',
|
|
36
|
-
'169.254.170.2',
|
|
37
|
-
];
|
package/lib/utils.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
// lib/utils.ts
|
|
2
|
-
import isValidDomain from 'is-valid-domain';
|
|
3
|
-
import ipaddr from 'ipaddr.js';
|
|
4
|
-
import { IsValidDomainOptions, CLOUD_METADATA_HOSTS } from './types';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Checks if the input is an IP address (v4/v6).
|
|
8
|
-
*/
|
|
9
|
-
function isIp(input: string): boolean {
|
|
10
|
-
return ipaddr.isValid(input);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Returns true for valid public unicast IP addresses.
|
|
15
|
-
*/
|
|
16
|
-
function isPublicIp(ip: string): boolean {
|
|
17
|
-
return ipaddr.parse(ip).range() === 'unicast';
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Validates whether a domain is syntactically valid.
|
|
22
|
-
*/
|
|
23
|
-
export function isSafeIp(hostname: string): boolean {
|
|
24
|
-
// Case 1: IP address
|
|
25
|
-
if (isIp(hostname)) {
|
|
26
|
-
return isPublicIp(hostname); // only allow public IPs
|
|
27
|
-
}
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* High-level validation for hostnames (domains + public IPs).
|
|
33
|
-
*/
|
|
34
|
-
export function isSafeHost(hostname: string, isValidDomainOptions?: IsValidDomainOptions): boolean {
|
|
35
|
-
// Block cloud metadata IP/domains
|
|
36
|
-
if (CLOUD_METADATA_HOSTS.indexOf(hostname)) return false;
|
|
37
|
-
|
|
38
|
-
if (!isSafeIp(hostname)) return false;
|
|
39
|
-
|
|
40
|
-
// Case 2: Domain name
|
|
41
|
-
return isValidDomain(hostname, {
|
|
42
|
-
allowUnicode: false,
|
|
43
|
-
subdomain: true,
|
|
44
|
-
...isValidDomainOptions,
|
|
45
|
-
});
|
|
46
|
-
}
|
package/rollup.config.mjs
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import typescript from 'rollup-plugin-typescript2';
|
|
2
|
-
|
|
3
|
-
export default {
|
|
4
|
-
input: 'index.ts',
|
|
5
|
-
output: [
|
|
6
|
-
{ file: 'dist/index.esm.js', format: 'es' },
|
|
7
|
-
{ file: 'dist/index.cjs.js', format: 'cjs', exports: 'named' },
|
|
8
|
-
],
|
|
9
|
-
plugins: [typescript({ useTsconfigDeclarationDir: true })],
|
|
10
|
-
};
|
package/test/index.test.ts
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
describe('SSRF Agent Guard', () => {
|
|
2
|
-
describe('Agent Selection', () => {
|
|
3
|
-
it('should return HttpsAgent for HTTPS URLs', () => {
|
|
4
|
-
expect(true).toBe(true);
|
|
5
|
-
});
|
|
6
|
-
|
|
7
|
-
it('should return HttpAgent for HTTP URLs', () => {
|
|
8
|
-
expect(true).toBe(true);
|
|
9
|
-
});
|
|
10
|
-
|
|
11
|
-
it('should return HttpAgent by default for non-HTTPS URLs', () => {
|
|
12
|
-
expect(true).toBe(true);
|
|
13
|
-
});
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
describe('Pre-DNS Validation', () => {
|
|
17
|
-
it('should throw error if host is not safe', () => {
|
|
18
|
-
expect(true).toBe(true);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
it('should not throw if host is safe', () => {
|
|
22
|
-
expect(true).toBe(true);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('should pass options to isSafeHost', () => {
|
|
26
|
-
expect(true).toBe(true);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
it('should handle missing host option', () => {
|
|
30
|
-
expect(true).toBe(true);
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
describe('Post-DNS Validation', () => {
|
|
35
|
-
it('should destroy connection if resolved IP is not safe', () => {
|
|
36
|
-
expect(true).toBe(true);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('should not destroy connection if resolved IP is safe', () => {
|
|
40
|
-
expect(true).toBe(true);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('should handle array of resolved addresses', () => {
|
|
44
|
-
expect(true).toBe(true);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it('should ignore lookup errors', () => {
|
|
48
|
-
expect(true).toBe(true);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
describe('Patch Prevention', () => {
|
|
53
|
-
it('should not patch agent multiple times', () => {
|
|
54
|
-
expect(true).toBe(true);
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
describe('Callback Handling', () => {
|
|
59
|
-
it('should call provided callback with client', () => {
|
|
60
|
-
expect(true).toBe(true);
|
|
61
|
-
});
|
|
62
|
-
});
|
|
63
|
-
});
|
package/tsconfig.json
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2020",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"declaration": true,
|
|
6
|
-
"emitDeclarationOnly": false,
|
|
7
|
-
"declarationDir": "./dist",
|
|
8
|
-
"outDir": "dist",
|
|
9
|
-
"strict": true,
|
|
10
|
-
"esModuleInterop": true,
|
|
11
|
-
"moduleResolution": "node",
|
|
12
|
-
"skipLibCheck": true
|
|
13
|
-
},
|
|
14
|
-
"include": [
|
|
15
|
-
"lib/**/*",
|
|
16
|
-
"rollup.config.mjs"
|
|
17
|
-
]
|
|
18
|
-
}
|