mirror of
https://github.com/tenrok/axios.git
synced 2026-06-20 20:00:40 +03:00
feat(withXSRFToken): added withXSRFToken option as a workaround to achieve the old withCredentials behavior; (#6046)
This commit is contained in:
@@ -452,6 +452,9 @@ These are the available config options for making requests. Only the `url` is re
|
|||||||
|
|
||||||
// `xsrfHeaderName` is the name of the http header that carries the xsrf token value
|
// `xsrfHeaderName` is the name of the http header that carries the xsrf token value
|
||||||
xsrfHeaderName: 'X-XSRF-TOKEN', // default
|
xsrfHeaderName: 'X-XSRF-TOKEN', // default
|
||||||
|
|
||||||
|
// `undefined` (default) - set XSRF header only for the same origin requests
|
||||||
|
withXSRFToken: boolean | undefined | ((config: InternalAxiosRequestConfig) => boolean | undefined),
|
||||||
|
|
||||||
// `onUploadProgress` allows handling of progress events for uploads
|
// `onUploadProgress` allows handling of progress events for uploads
|
||||||
// browser & node.js
|
// browser & node.js
|
||||||
|
|||||||
@@ -414,6 +414,7 @@ declare namespace axios {
|
|||||||
family?: AddressFamily;
|
family?: AddressFamily;
|
||||||
lookup?: ((hostname: string, options: object, cb: (err: Error | null, address: LookupAddress | LookupAddress[], family?: AddressFamily) => void) => void) |
|
lookup?: ((hostname: string, options: object, cb: (err: Error | null, address: LookupAddress | LookupAddress[], family?: AddressFamily) => void) => void) |
|
||||||
((hostname: string, options: object) => Promise<[address: LookupAddressEntry | LookupAddressEntry[], family?: AddressFamily] | LookupAddress>);
|
((hostname: string, options: object) => Promise<[address: LookupAddressEntry | LookupAddressEntry[], family?: AddressFamily] | LookupAddress>);
|
||||||
|
withXSRFToken?: boolean | ((config: InternalAxiosRequestConfig) => boolean | undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alias
|
// Alias
|
||||||
|
|||||||
Vendored
+1
@@ -355,6 +355,7 @@ export interface AxiosRequestConfig<D = any> {
|
|||||||
family?: AddressFamily;
|
family?: AddressFamily;
|
||||||
lookup?: ((hostname: string, options: object, cb: (err: Error | null, address: LookupAddress | LookupAddress[], family?: AddressFamily) => void) => void) |
|
lookup?: ((hostname: string, options: object, cb: (err: Error | null, address: LookupAddress | LookupAddress[], family?: AddressFamily) => void) => void) |
|
||||||
((hostname: string, options: object) => Promise<[address: LookupAddressEntry | LookupAddressEntry[], family?: AddressFamily] | LookupAddress>);
|
((hostname: string, options: object) => Promise<[address: LookupAddressEntry | LookupAddressEntry[], family?: AddressFamily] | LookupAddress>);
|
||||||
|
withXSRFToken?: boolean | ((config: InternalAxiosRequestConfig) => boolean | undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alias
|
// Alias
|
||||||
|
|||||||
+10
-7
@@ -49,7 +49,7 @@ export default isXHRAdapterSupported && function (config) {
|
|||||||
return new Promise(function dispatchXhrRequest(resolve, reject) {
|
return new Promise(function dispatchXhrRequest(resolve, reject) {
|
||||||
let requestData = config.data;
|
let requestData = config.data;
|
||||||
const requestHeaders = AxiosHeaders.from(config.headers).normalize();
|
const requestHeaders = AxiosHeaders.from(config.headers).normalize();
|
||||||
const responseType = config.responseType;
|
let {responseType, withXSRFToken} = config;
|
||||||
let onCanceled;
|
let onCanceled;
|
||||||
function done() {
|
function done() {
|
||||||
if (config.cancelToken) {
|
if (config.cancelToken) {
|
||||||
@@ -185,13 +185,16 @@ export default isXHRAdapterSupported && function (config) {
|
|||||||
// Add xsrf header
|
// Add xsrf header
|
||||||
// This is only done if running in a standard browser environment.
|
// This is only done if running in a standard browser environment.
|
||||||
// Specifically not if we're in a web worker, or react-native.
|
// Specifically not if we're in a web worker, or react-native.
|
||||||
if (platform.hasStandardBrowserEnv) {
|
if(platform.hasStandardBrowserEnv) {
|
||||||
// Add xsrf header
|
withXSRFToken && utils.isFunction(withXSRFToken) && (withXSRFToken = withXSRFToken(config));
|
||||||
// regarding CVE-2023-45857 config.withCredentials condition was removed temporarily
|
|
||||||
const xsrfValue = isURLSameOrigin(fullPath) && config.xsrfCookieName && cookies.read(config.xsrfCookieName);
|
|
||||||
|
|
||||||
if (xsrfValue) {
|
if (withXSRFToken || (withXSRFToken !== false && isURLSameOrigin(fullPath))) {
|
||||||
requestHeaders.set(config.xsrfHeaderName, xsrfValue);
|
// Add xsrf header
|
||||||
|
const xsrfValue = config.xsrfHeaderName && config.xsrfCookieName && cookies.read(config.xsrfCookieName);
|
||||||
|
|
||||||
|
if (xsrfValue) {
|
||||||
|
requestHeaders.set(config.xsrfHeaderName, xsrfValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ export default function mergeConfig(config1, config2) {
|
|||||||
timeout: defaultToConfig2,
|
timeout: defaultToConfig2,
|
||||||
timeoutMessage: defaultToConfig2,
|
timeoutMessage: defaultToConfig2,
|
||||||
withCredentials: defaultToConfig2,
|
withCredentials: defaultToConfig2,
|
||||||
|
withXSRFToken: defaultToConfig2,
|
||||||
adapter: defaultToConfig2,
|
adapter: defaultToConfig2,
|
||||||
responseType: defaultToConfig2,
|
responseType: defaultToConfig2,
|
||||||
xsrfCookieName: defaultToConfig2,
|
xsrfCookieName: defaultToConfig2,
|
||||||
|
|||||||
+29
-39
@@ -1,52 +1,42 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
import utils from './../utils.js';
|
import utils from './../utils.js';
|
||||||
import platform from '../platform/index.js';
|
import platform from '../platform/index.js';
|
||||||
|
|
||||||
export default platform.hasStandardBrowserEnv ?
|
export default platform.hasStandardBrowserEnv ?
|
||||||
|
|
||||||
// Standard browser envs support document.cookie
|
// Standard browser envs support document.cookie
|
||||||
(function standardBrowserEnv() {
|
{
|
||||||
return {
|
write(name, value, expires, path, domain, secure) {
|
||||||
write: function write(name, value, expires, path, domain, secure) {
|
const cookie = [name + '=' + encodeURIComponent(value)];
|
||||||
const cookie = [];
|
|
||||||
cookie.push(name + '=' + encodeURIComponent(value));
|
|
||||||
|
|
||||||
if (utils.isNumber(expires)) {
|
utils.isNumber(expires) && cookie.push('expires=' + new Date(expires).toGMTString());
|
||||||
cookie.push('expires=' + new Date(expires).toGMTString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (utils.isString(path)) {
|
utils.isString(path) && cookie.push('path=' + path);
|
||||||
cookie.push('path=' + path);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (utils.isString(domain)) {
|
utils.isString(domain) && cookie.push('domain=' + domain);
|
||||||
cookie.push('domain=' + domain);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (secure === true) {
|
secure === true && cookie.push('secure');
|
||||||
cookie.push('secure');
|
|
||||||
}
|
|
||||||
|
|
||||||
document.cookie = cookie.join('; ');
|
document.cookie = cookie.join('; ');
|
||||||
},
|
},
|
||||||
|
|
||||||
read: function read(name) {
|
read(name) {
|
||||||
const match = document.cookie.match(new RegExp('(^|;\\s*)(' + name + ')=([^;]*)'));
|
const match = document.cookie.match(new RegExp('(^|;\\s*)(' + name + ')=([^;]*)'));
|
||||||
return (match ? decodeURIComponent(match[3]) : null);
|
return (match ? decodeURIComponent(match[3]) : null);
|
||||||
},
|
},
|
||||||
|
|
||||||
remove: function remove(name) {
|
remove(name) {
|
||||||
this.write(name, '', Date.now() - 86400000);
|
this.write(name, '', Date.now() - 86400000);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
})() :
|
|
||||||
|
:
|
||||||
|
|
||||||
|
// Non-standard browser env (web workers, react-native) lack needed support.
|
||||||
|
{
|
||||||
|
write() {},
|
||||||
|
read() {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
remove() {}
|
||||||
|
};
|
||||||
|
|
||||||
// Non standard browser env (web workers, react-native) lack needed support.
|
|
||||||
(function nonStandardBrowserEnv() {
|
|
||||||
return {
|
|
||||||
write: function write() {},
|
|
||||||
read: function read() { return null; },
|
|
||||||
remove: function remove() {}
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export default platform.hasStandardBrowserEnv ?
|
|||||||
let originURL;
|
let originURL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a URL to discover it's components
|
* Parse a URL to discover its components
|
||||||
*
|
*
|
||||||
* @param {String} url The URL to be parsed
|
* @param {String} url The URL to be parsed
|
||||||
* @returns {Object}
|
* @returns {Object}
|
||||||
|
|||||||
@@ -79,4 +79,68 @@ describe('xsrf', function () {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('withXSRFToken option', function(){
|
||||||
|
|
||||||
|
it('should set xsrf header for cross origin when withXSRFToken = true', function (done) {
|
||||||
|
const token = '12345';
|
||||||
|
|
||||||
|
document.cookie = axios.defaults.xsrfCookieName + '=' + token;
|
||||||
|
|
||||||
|
axios('http://example.com/', {
|
||||||
|
withXSRFToken: true
|
||||||
|
});
|
||||||
|
|
||||||
|
getAjaxRequest().then(function (request) {
|
||||||
|
expect(request.requestHeaders[axios.defaults.xsrfHeaderName]).toEqual(token);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set xsrf header for the same origin when withXSRFToken = false', function (done) {
|
||||||
|
const token = '12345';
|
||||||
|
|
||||||
|
document.cookie = axios.defaults.xsrfCookieName + '=' + token;
|
||||||
|
|
||||||
|
axios('/foo', {
|
||||||
|
withXSRFToken: false
|
||||||
|
});
|
||||||
|
|
||||||
|
getAjaxRequest().then(function (request) {
|
||||||
|
expect(request.requestHeaders[axios.defaults.xsrfHeaderName]).toEqual(undefined);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not set xsrf header for the same origin when withXSRFToken = false', function (done) {
|
||||||
|
const token = '12345';
|
||||||
|
|
||||||
|
document.cookie = axios.defaults.xsrfCookieName + '=' + token;
|
||||||
|
|
||||||
|
axios('/foo', {
|
||||||
|
withXSRFToken: false
|
||||||
|
});
|
||||||
|
|
||||||
|
getAjaxRequest().then(function (request) {
|
||||||
|
expect(request.requestHeaders[axios.defaults.xsrfHeaderName]).toEqual(undefined);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should support function resolver', (done) => {
|
||||||
|
const token = '12345';
|
||||||
|
|
||||||
|
document.cookie = axios.defaults.xsrfCookieName + '=' + token;
|
||||||
|
|
||||||
|
axios('/foo', {
|
||||||
|
withXSRFToken: (config) => config.userFlag === 'yes',
|
||||||
|
userFlag: 'yes'
|
||||||
|
});
|
||||||
|
|
||||||
|
getAjaxRequest().then(function (request) {
|
||||||
|
expect(request.requestHeaders[axios.defaults.xsrfHeaderName]).toEqual(token);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user