Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

micro-ftch

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

micro-ftch - npm Package Compare versions

Comparing version 0.2.0 to 0.3.0

9

index.d.ts

@@ -1,2 +0,2 @@

declare type FETCH_OPT = {
export declare type FETCH_OPT = {
method?: string;

@@ -12,5 +12,10 @@ type?: 'text' | 'json' | 'bytes';

referrer: boolean;
sslAllowSelfSigned: boolean;
sslPinnedCertificates?: string[];
_redirectCount: number;
};
export declare class InvalidCertError extends Error {
readonly fingerprint256: string;
constructor(msg: string, fingerprint256: string);
}
export default function fetchUrl(url: string, options?: FETCH_OPT): Promise<any>;
export {};
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InvalidCertError = void 0;
const DEFAULT_OPT = Object.freeze({

@@ -11,4 +12,12 @@ redirect: true,

referrer: false,
sslAllowSelfSigned: false,
_redirectCount: 0,
});
class InvalidCertError extends Error {
constructor(msg, fingerprint256) {
super(msg);
this.fingerprint256 = fingerprint256;
}
}
exports.InvalidCertError = InvalidCertError;
function detectType(b, type) {

@@ -36,3 +45,3 @@ if (!type || type === 'text' || type === 'json') {

}
let _httpAgent, _httpsAgent;
let agents = {};
function fetchNode(url, options = DEFAULT_OPT) {

@@ -45,7 +54,2 @@ options = { ...DEFAULT_OPT, ...options };

const { resolve: urlResolve } = require('url');
const agentOpt = { keepAlive: true, keepAliveMsecs: 30 * 1000, maxFreeSockets: 1024 };
if (!_httpAgent)
_httpAgent = new http.Agent(agentOpt);
if (!_httpsAgent)
_httpsAgent = new https.Agent(agentOpt);
const isSecure = !!/^https/.test(url);

@@ -56,4 +60,17 @@ let opts = {

};
if (options.keepAlive)
opts.agent = isSecure ? _httpsAgent : _httpAgent;
const compactFP = (s) => s.replace(/:| /g, '').toLowerCase();
if (options.keepAlive) {
const agentOpt = {
keepAlive: true,
keepAliveMsecs: 30 * 1000,
maxFreeSockets: 1024,
maxCachedSessions: 1024,
};
const agentKey = [
isSecure,
isSecure && options.sslPinnedCertificates?.map((i) => compactFP(i)).sort(),
].join();
opts.agent =
agents[agentKey] || (agents[agentKey] = new (isSecure ? https : http).Agent(agentOpt));
}
if (options.type === 'json')

@@ -67,2 +84,4 @@ opts.headers['Content-Type'] = 'application/json';

opts.headers = { ...opts.headers, ...options.headers };
if (options.sslAllowSelfSigned)
opts.rejectUnauthorized = false;
const handleRes = async (res) => {

@@ -95,4 +114,17 @@ const status = res.statusCode;

return new Promise((resolve, reject) => {
const handleError = async (err) => {
if (err && err.code === 'DEPTH_ZERO_SELF_SIGNED_CERT') {
try {
await fetchNode(url, { ...options, sslAllowSelfSigned: true, sslPinnedCertificates: [] });
}
catch (e) {
if (e && e.fingerprint256) {
err = new InvalidCertError(`Self-signed SSL certificate: ${e.fingerprint256}`, e.fingerprint256);
}
}
}
reject(err);
};
const req = (isSecure ? https : http).request(url, opts, (res) => {
res.on('error', reject);
res.on('error', handleError);
(async () => {

@@ -107,2 +139,24 @@ try {

});
req.on('error', handleError);
const pinned = options.sslPinnedCertificates?.map((i) => compactFP(i));
const mfetchSecureConnect = (socket) => {
const fp256 = compactFP(socket.getPeerCertificate()?.fingerprint256 || '');
if (!fp256 && socket.isSessionReused())
return;
if (pinned.includes(fp256))
return;
req.emit('error', new InvalidCertError(`Invalid SSL certificate: ${fp256} Expected: ${pinned}`, fp256));
return req.abort();
};
if (options.sslPinnedCertificates) {
req.on('socket', (socket) => {
const hasListeners = socket
.listeners('secureConnect')
.map((i) => (i.name || '').replace('bound ', ''))
.includes('mfetchSecureConnect');
if (hasListeners)
return;
socket.on('secureConnect', mfetchSecureConnect.bind(null, socket));
});
}
if (options.keepAlive)

@@ -124,2 +178,10 @@ req.setNoDelay(true);

headers.set('Content-Type', 'application/json');
let parsed = new URL(url);
if (parsed.username) {
const auth = btoa(`${parsed.username}:${parsed.password}`);
headers.set('Authorization', `Basic ${auth}`);
parsed.username = '';
parsed.password = '';
}
url = '' + parsed;
for (let k in options.headers) {

@@ -126,0 +188,0 @@ const name = k.toLowerCase();

{
"name": "micro-ftch",
"version": "0.2.0",
"version": "0.3.0",
"description": "Wraps nodejs built-in modules and browser fetch into one function.",

@@ -27,5 +27,5 @@ "main": "index.js",

"devDependencies": {
"@types/node": "^14.0.14",
"typescript": "^4.3.2"
"@types/node": "^16.0",
"typescript": "^4.3.5"
}
}

@@ -16,4 +16,26 @@ # micro-ftch

## Options
The list of options that can be supplied as second argument to fetch(url, opts):
```typescript
export type FETCH_OPT = {
method?: string;
type?: 'text' | 'json' | 'bytes'; // Response encoding (auto-detect if empty)
redirect: boolean; // Follow redirects
expectStatusCode?: number | false; // Expect this status code
headers: Record<string, string>;
data?: object; // POST/PUT/DELETE request data
full: boolean; // Return full request {headers, status, body}
keepAlive: boolean; // Enable keep-alive (node only)
cors: boolean; // Allow CORS safe-listed headers (browser-only)
referrer: boolean; // Send referrer (browser-only)
sslAllowSelfSigned: boolean; // Allow self-signed ssl certs (node only)
sslPinnedCertificates?: string[]; // Verify fingerprint of certificate (node only)
_redirectCount: number;
};
```
## License
MIT License (c) 2020, Paul Miller (https://paulmillr.com)
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc