urllib 2.44.0 → 2.44.1
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/lib/urllib.js +83 -0
- package/package.json +1 -1
package/lib/urllib.js
CHANGED
|
@@ -66,6 +66,71 @@ var TEXT_DATA_TYPES = [
|
|
|
66
66
|
|
|
67
67
|
var PROTO_RE = /^https?:\/\//i;
|
|
68
68
|
|
|
69
|
+
// Credential-bearing headers that must not be forwarded across an origin
|
|
70
|
+
// boundary when following a redirect, to avoid leaking them to a third party.
|
|
71
|
+
var CROSS_ORIGIN_SENSITIVE_HEADERS = [ 'authorization', 'cookie', 'proxy-authorization' ];
|
|
72
|
+
|
|
73
|
+
// Build an absolute href good enough to compute the origin. `currentUrl` may be
|
|
74
|
+
// a parsed URL object (with href) or an http options-style object built from
|
|
75
|
+
// { host/hostname, port, path }, which has no href.
|
|
76
|
+
function resolveOriginHref(currentUrl) {
|
|
77
|
+
if (currentUrl.href) {
|
|
78
|
+
return currentUrl.href;
|
|
79
|
+
}
|
|
80
|
+
var host = currentUrl.host || currentUrl.hostname;
|
|
81
|
+
if (!host) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
var protocol = currentUrl.protocol || 'http:';
|
|
85
|
+
if (protocol.charAt(protocol.length - 1) !== ':') {
|
|
86
|
+
protocol += ':';
|
|
87
|
+
}
|
|
88
|
+
if (currentUrl.port && String(host).indexOf(':') === -1) {
|
|
89
|
+
host += ':' + currentUrl.port;
|
|
90
|
+
}
|
|
91
|
+
return protocol + '//' + host + (currentUrl.path || currentUrl.pathname || '/');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function isCrossOriginRedirect(currentUrl, toUrl) {
|
|
95
|
+
try {
|
|
96
|
+
var fromHref = resolveOriginHref(currentUrl);
|
|
97
|
+
if (!fromHref) {
|
|
98
|
+
// origin cannot be determined: fail closed
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
if (URL) {
|
|
102
|
+
return new URL(fromHref).origin !== new URL(toUrl, fromHref).origin;
|
|
103
|
+
}
|
|
104
|
+
// Fallback for runtimes without the WHATWG URL global.
|
|
105
|
+
// urlutil.parse does not normalize default ports, so compare protocol +
|
|
106
|
+
// hostname + normalized port instead of the raw `host`.
|
|
107
|
+
var from = urlutil.parse(fromHref);
|
|
108
|
+
var to = urlutil.parse(urlutil.resolve(fromHref, toUrl));
|
|
109
|
+
var fromPort = from.port || (from.protocol === 'https:' ? '443' : '80');
|
|
110
|
+
var toPort = to.port || (to.protocol === 'https:' ? '443' : '80');
|
|
111
|
+
return from.protocol !== to.protocol || from.hostname !== to.hostname || fromPort !== toPort;
|
|
112
|
+
} catch (err) {
|
|
113
|
+
// Fail closed: if the origin cannot be determined, treat it as cross-origin
|
|
114
|
+
// so credentials are stripped rather than leaked.
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function cleanCrossOriginHeaders(headers, sensitive) {
|
|
120
|
+
var list = sensitive || CROSS_ORIGIN_SENSITIVE_HEADERS;
|
|
121
|
+
var cleaned = {};
|
|
122
|
+
if (headers) {
|
|
123
|
+
var names = utility.getOwnEnumerables(headers, true);
|
|
124
|
+
for (var i = 0; i < names.length; i++) {
|
|
125
|
+
var name = names[i];
|
|
126
|
+
if (list.indexOf(name.toLowerCase()) === -1) {
|
|
127
|
+
cleaned[name] = headers[name];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return cleaned;
|
|
132
|
+
}
|
|
133
|
+
|
|
69
134
|
// Keep-Alive: timeout=5, max=100
|
|
70
135
|
var KEEP_ALIVE_RE = /^timeout=(\d+)/i;
|
|
71
136
|
|
|
@@ -688,6 +753,24 @@ function requestWithCallback(url, args, callback) {
|
|
|
688
753
|
options.headers.host = null;
|
|
689
754
|
args.headers = options.headers;
|
|
690
755
|
}
|
|
756
|
+
// do not forward credential-bearing headers / auth to a different origin
|
|
757
|
+
if (isCrossOriginRedirect(parsedUrl, newUrl)) {
|
|
758
|
+
// Clone so this redirect-specific sanitization never corrupts the
|
|
759
|
+
// caller's reusable options object.
|
|
760
|
+
var redirectArgs = Object.assign({}, args);
|
|
761
|
+
var sensitiveHeaders = CROSS_ORIGIN_SENSITIVE_HEADERS;
|
|
762
|
+
if (proxyTunnelAgent) {
|
|
763
|
+
// Proxy-Authorization authenticates the (unchanged) proxy hop, not
|
|
764
|
+
// the redirected origin, so keep it when the request is proxied.
|
|
765
|
+
sensitiveHeaders = sensitiveHeaders.filter(function (name) {
|
|
766
|
+
return name !== 'proxy-authorization';
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
redirectArgs.headers = cleanCrossOriginHeaders(args.headers || options.headers, sensitiveHeaders);
|
|
770
|
+
redirectArgs.auth = null;
|
|
771
|
+
redirectArgs.digestAuth = null;
|
|
772
|
+
args = redirectArgs;
|
|
773
|
+
}
|
|
691
774
|
// avoid done will be execute in the future change.
|
|
692
775
|
var cb = callback;
|
|
693
776
|
callback = null;
|