mirror of
https://github.com/usebruno/bruno.git
synced 2025-02-02 02:49:48 +01:00
feat(#968): cookie support
This commit is contained in:
parent
9f535aeba7
commit
e1a96e0f23
42
package-lock.json
generated
42
package-lock.json
generated
@ -17745,6 +17745,7 @@
|
|||||||
"node-machine-id": "^1.1.12",
|
"node-machine-id": "^1.1.12",
|
||||||
"qs": "^6.11.0",
|
"qs": "^6.11.0",
|
||||||
"socks-proxy-agent": "^8.0.2",
|
"socks-proxy-agent": "^8.0.2",
|
||||||
|
"tough-cookie": "^4.1.3",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"vm2": "^3.9.13",
|
"vm2": "^3.9.13",
|
||||||
"yup": "^0.32.11"
|
"yup": "^0.32.11"
|
||||||
@ -17905,6 +17906,28 @@
|
|||||||
"js-yaml": "bin/js-yaml.js"
|
"js-yaml": "bin/js-yaml.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"packages/bruno-electron/node_modules/tough-cookie": {
|
||||||
|
"version": "4.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
|
||||||
|
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
|
||||||
|
"dependencies": {
|
||||||
|
"psl": "^1.1.33",
|
||||||
|
"punycode": "^2.1.1",
|
||||||
|
"universalify": "^0.2.0",
|
||||||
|
"url-parse": "^1.5.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"packages/bruno-electron/node_modules/tough-cookie/node_modules/universalify": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"packages/bruno-electron/node_modules/uuid": {
|
"packages/bruno-electron/node_modules/uuid": {
|
||||||
"version": "9.0.0",
|
"version": "9.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
@ -22828,6 +22851,7 @@
|
|||||||
"node-machine-id": "^1.1.12",
|
"node-machine-id": "^1.1.12",
|
||||||
"qs": "^6.11.0",
|
"qs": "^6.11.0",
|
||||||
"socks-proxy-agent": "^8.0.2",
|
"socks-proxy-agent": "^8.0.2",
|
||||||
|
"tough-cookie": "*",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"vm2": "^3.9.13",
|
"vm2": "^3.9.13",
|
||||||
"yup": "^0.32.11"
|
"yup": "^0.32.11"
|
||||||
@ -22926,6 +22950,24 @@
|
|||||||
"argparse": "^2.0.1"
|
"argparse": "^2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"tough-cookie": {
|
||||||
|
"version": "4.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
|
||||||
|
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
|
||||||
|
"requires": {
|
||||||
|
"psl": "^1.1.33",
|
||||||
|
"punycode": "^2.1.1",
|
||||||
|
"universalify": "^0.2.0",
|
||||||
|
"url-parse": "^1.5.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"universalify": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"uuid": {
|
"uuid": {
|
||||||
"version": "9.0.0"
|
"version": "9.0.0"
|
||||||
}
|
}
|
||||||
|
30
packages/bruno-app/src/components/Cookies/index.js
Normal file
30
packages/bruno-app/src/components/Cookies/index.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
import Modal from 'components/Modal';
|
||||||
|
|
||||||
|
const CollectionProperties = ({ onClose }) => {
|
||||||
|
const cookies = useSelector((state) => state.app.cookies) || [];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal size="md" title="Cookies" hideFooter={true} handleCancel={onClose}>
|
||||||
|
<table className="w-full border-collapse" style={{ marginTop: '-1rem' }}>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th className="py-2 px-2 text-left">Domain</th>
|
||||||
|
<th className="py-2 px-2 text-left">Cookie</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{cookies.map((cookie) => (
|
||||||
|
<tr key={cookie.id}>
|
||||||
|
<td className="py-2 px-2">{cookie.domain}</td>
|
||||||
|
<td className="py-2 px-2 break-all">{cookie.cookieString}</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CollectionProperties;
|
@ -3,10 +3,11 @@ import Collections from './Collections';
|
|||||||
import StyledWrapper from './StyledWrapper';
|
import StyledWrapper from './StyledWrapper';
|
||||||
import GitHubButton from 'react-github-btn';
|
import GitHubButton from 'react-github-btn';
|
||||||
import Preferences from 'components/Preferences';
|
import Preferences from 'components/Preferences';
|
||||||
|
import Cookies from 'components/Cookies';
|
||||||
|
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { useSelector, useDispatch } from 'react-redux';
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
import { IconSettings } from '@tabler/icons';
|
import { IconSettings, IconCookie } from '@tabler/icons';
|
||||||
import { updateLeftSidebarWidth, updateIsDragging, showPreferences } from 'providers/ReduxStore/slices/app';
|
import { updateLeftSidebarWidth, updateIsDragging, showPreferences } from 'providers/ReduxStore/slices/app';
|
||||||
import { useTheme } from 'providers/Theme';
|
import { useTheme } from 'providers/Theme';
|
||||||
|
|
||||||
@ -18,6 +19,7 @@ const Sidebar = () => {
|
|||||||
const preferencesOpen = useSelector((state) => state.app.showPreferences);
|
const preferencesOpen = useSelector((state) => state.app.showPreferences);
|
||||||
|
|
||||||
const [asideWidth, setAsideWidth] = useState(leftSidebarWidth);
|
const [asideWidth, setAsideWidth] = useState(leftSidebarWidth);
|
||||||
|
const [cookiesOpen, setCookiesOpen] = useState(false);
|
||||||
|
|
||||||
const { storedTheme } = useTheme();
|
const { storedTheme } = useTheme();
|
||||||
|
|
||||||
@ -79,6 +81,7 @@ const Sidebar = () => {
|
|||||||
<aside>
|
<aside>
|
||||||
<div className="flex flex-row h-screen w-full">
|
<div className="flex flex-row h-screen w-full">
|
||||||
{preferencesOpen && <Preferences onClose={() => dispatch(showPreferences(false))} />}
|
{preferencesOpen && <Preferences onClose={() => dispatch(showPreferences(false))} />}
|
||||||
|
{cookiesOpen && <Cookies onClose={() => setCookiesOpen(false)} />}
|
||||||
|
|
||||||
<div className="flex flex-col w-full" style={{ width: asideWidth }}>
|
<div className="flex flex-col w-full" style={{ width: asideWidth }}>
|
||||||
<div className="flex flex-col flex-grow">
|
<div className="flex flex-col flex-grow">
|
||||||
@ -91,19 +94,26 @@ const Sidebar = () => {
|
|||||||
<IconSettings
|
<IconSettings
|
||||||
size={18}
|
size={18}
|
||||||
strokeWidth={1.5}
|
strokeWidth={1.5}
|
||||||
className="mr-2 hover:text-gray-700"
|
className="mr-2 hover:text-gray-700"
|
||||||
onClick={() => dispatch(showPreferences(true))}
|
onClick={() => dispatch(showPreferences(true))}
|
||||||
/>
|
/>
|
||||||
|
<IconCookie
|
||||||
|
size={18}
|
||||||
|
strokeWidth={1.5}
|
||||||
|
className="mr-2 hover:text-gray-700"
|
||||||
|
onClick={() => setCookiesOpen(true)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="pl-1" style={{ position: 'relative', top: '3px' }}>
|
<div className="pl-1" style={{ position: 'relative', top: '3px' }}>
|
||||||
<GitHubButton
|
{/* This will get moved to home page */}
|
||||||
|
{/* <GitHubButton
|
||||||
href="https://github.com/usebruno/bruno"
|
href="https://github.com/usebruno/bruno"
|
||||||
data-color-scheme={storedTheme}
|
data-color-scheme={storedTheme}
|
||||||
data-show-count="true"
|
data-show-count="true"
|
||||||
aria-label="Star usebruno/bruno on GitHub"
|
aria-label="Star usebruno/bruno on GitHub"
|
||||||
>
|
>
|
||||||
Star
|
Star
|
||||||
</GitHubButton>
|
</GitHubButton> */}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-grow items-center justify-end text-xs mr-2">v1.1.1</div>
|
<div className="flex flex-grow items-center justify-end text-xs mr-2">v1.1.1</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,7 +14,7 @@ import {
|
|||||||
runFolderEvent,
|
runFolderEvent,
|
||||||
brunoConfigUpdateEvent
|
brunoConfigUpdateEvent
|
||||||
} from 'providers/ReduxStore/slices/collections';
|
} from 'providers/ReduxStore/slices/collections';
|
||||||
import { showPreferences, updatePreferences } from 'providers/ReduxStore/slices/app';
|
import { showPreferences, updatePreferences, updateCookies } from 'providers/ReduxStore/slices/app';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
import { openCollectionEvent, collectionAddEnvFileEvent } from 'providers/ReduxStore/slices/collections/actions';
|
import { openCollectionEvent, collectionAddEnvFileEvent } from 'providers/ReduxStore/slices/collections/actions';
|
||||||
import { isElectron } from 'utils/common/platform';
|
import { isElectron } from 'utils/common/platform';
|
||||||
@ -135,6 +135,10 @@ const useIpcEvents = () => {
|
|||||||
dispatch(updatePreferences(val));
|
dispatch(updatePreferences(val));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const removeCookieUpdateListener = ipcRenderer.on('main:cookies-update', (val) => {
|
||||||
|
dispatch(updateCookies(val));
|
||||||
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
removeCollectionTreeUpdateListener();
|
removeCollectionTreeUpdateListener();
|
||||||
removeOpenCollectionListener();
|
removeOpenCollectionListener();
|
||||||
@ -149,6 +153,7 @@ const useIpcEvents = () => {
|
|||||||
removeConfigUpdatesListener();
|
removeConfigUpdatesListener();
|
||||||
showPreferencesListener();
|
showPreferencesListener();
|
||||||
removePreferencesUpdatesListener();
|
removePreferencesUpdatesListener();
|
||||||
|
removeCookieUpdateListener();
|
||||||
};
|
};
|
||||||
}, [isElectron]);
|
}, [isElectron]);
|
||||||
};
|
};
|
||||||
|
@ -16,7 +16,8 @@ const initialState = {
|
|||||||
font: {
|
font: {
|
||||||
codeFont: 'default'
|
codeFont: 'default'
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
cookies: []
|
||||||
};
|
};
|
||||||
|
|
||||||
export const appSlice = createSlice({
|
export const appSlice = createSlice({
|
||||||
@ -46,6 +47,10 @@ export const appSlice = createSlice({
|
|||||||
},
|
},
|
||||||
updatePreferences: (state, action) => {
|
updatePreferences: (state, action) => {
|
||||||
state.preferences = action.payload;
|
state.preferences = action.payload;
|
||||||
|
},
|
||||||
|
updateCookies: (state, action) => {
|
||||||
|
state.cookies = action.payload;
|
||||||
|
console.log(state.cookies);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -58,7 +63,8 @@ export const {
|
|||||||
showHomePage,
|
showHomePage,
|
||||||
hideHomePage,
|
hideHomePage,
|
||||||
showPreferences,
|
showPreferences,
|
||||||
updatePreferences
|
updatePreferences,
|
||||||
|
updateCookies
|
||||||
} = appSlice.actions;
|
} = appSlice.actions;
|
||||||
|
|
||||||
export const savePreferences = (preferences) => (dispatch, getState) => {
|
export const savePreferences = (preferences) => (dispatch, getState) => {
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
"node-machine-id": "^1.1.12",
|
"node-machine-id": "^1.1.12",
|
||||||
"qs": "^6.11.0",
|
"qs": "^6.11.0",
|
||||||
"socks-proxy-agent": "^8.0.2",
|
"socks-proxy-agent": "^8.0.2",
|
||||||
|
"tough-cookie": "^4.1.3",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"vm2": "^3.9.13",
|
"vm2": "^3.9.13",
|
||||||
"yup": "^0.32.11"
|
"yup": "^0.32.11"
|
||||||
|
@ -28,6 +28,7 @@ const { addAwsV4Interceptor, resolveAwsV4Credentials } = require('./awsv4auth-he
|
|||||||
const { addDigestInterceptor } = require('./digestauth-helper');
|
const { addDigestInterceptor } = require('./digestauth-helper');
|
||||||
const { shouldUseProxy, PatchedHttpsProxyAgent } = require('../../utils/proxy-util');
|
const { shouldUseProxy, PatchedHttpsProxyAgent } = require('../../utils/proxy-util');
|
||||||
const { chooseFileToSave, writeBinaryFile } = require('../../utils/filesystem');
|
const { chooseFileToSave, writeBinaryFile } = require('../../utils/filesystem');
|
||||||
|
const { getCookieStringForUrl, addCookieToJar, getDomainsWithCookies } = require('../../utils/cookies');
|
||||||
|
|
||||||
// override the default escape function to prevent escaping
|
// override the default escape function to prevent escaping
|
||||||
Mustache.escape = function (value) {
|
Mustache.escape = function (value) {
|
||||||
@ -181,6 +182,12 @@ const configureRequest = async (
|
|||||||
|
|
||||||
request.timeout = preferencesUtil.getRequestTimeout();
|
request.timeout = preferencesUtil.getRequestTimeout();
|
||||||
|
|
||||||
|
// add cookies to request
|
||||||
|
const cookieString = getCookieStringForUrl(request.url);
|
||||||
|
if (cookieString && typeof cookieString === 'string' && cookieString.length) {
|
||||||
|
request.headers['cookie'] = cookieString;
|
||||||
|
}
|
||||||
|
|
||||||
return axiosInstance;
|
return axiosInstance;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -439,6 +446,22 @@ const registerNetworkIpc = (mainWindow) => {
|
|||||||
const { data, dataBuffer } = parseDataFromResponse(response);
|
const { data, dataBuffer } = parseDataFromResponse(response);
|
||||||
response.data = data;
|
response.data = data;
|
||||||
|
|
||||||
|
// save cookies
|
||||||
|
let setCookieHeaders = [];
|
||||||
|
if (response.headers['set-cookie']) {
|
||||||
|
setCookieHeaders = Array.isArray(response.headers['set-cookie'])
|
||||||
|
? response.headers['set-cookie']
|
||||||
|
: [response.headers['set-cookie']];
|
||||||
|
|
||||||
|
for (let setCookieHeader of setCookieHeaders) {
|
||||||
|
addCookieToJar(setCookieHeader, request.url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// send domain cookies to renderer
|
||||||
|
const domainsWithCookies = await getDomainsWithCookies();
|
||||||
|
mainWindow.webContents.send('main:cookies-update', safeParseJSON(safeStringifyJSON(domainsWithCookies)));
|
||||||
|
|
||||||
await runPostResponse(
|
await runPostResponse(
|
||||||
request,
|
request,
|
||||||
response,
|
response,
|
||||||
|
70
packages/bruno-electron/src/utils/cookies.js
Normal file
70
packages/bruno-electron/src/utils/cookies.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
const { Cookie, CookieJar } = require('tough-cookie');
|
||||||
|
const each = require('lodash/each');
|
||||||
|
|
||||||
|
const cookieJar = new CookieJar();
|
||||||
|
|
||||||
|
const addCookieToJar = (setCookieHeader, requestUrl) => {
|
||||||
|
const cookie = Cookie.parse(setCookieHeader, { loose: true });
|
||||||
|
cookieJar.setCookieSync(cookie, requestUrl);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCookiesForUrl = (url) => {
|
||||||
|
return cookieJar.getCookiesSync(url);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getCookieStringForUrl = (url) => {
|
||||||
|
const cookies = getCookiesForUrl(url);
|
||||||
|
|
||||||
|
if (!Array.isArray(cookies) || !cookies.length) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
const validCookies = cookies.filter((cookie) => !cookie.expires || cookie.expires > Date.now());
|
||||||
|
|
||||||
|
return validCookies.map((cookie) => cookie.cookieString()).join('; ');
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDomainsWithCookies = () => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const domainCookieMap = {};
|
||||||
|
|
||||||
|
cookieJar.store.getAllCookies((err, cookies) => {
|
||||||
|
if (err) {
|
||||||
|
return reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
cookies.forEach((cookie) => {
|
||||||
|
if (!domainCookieMap[cookie.domain]) {
|
||||||
|
domainCookieMap[cookie.domain] = [cookie];
|
||||||
|
} else {
|
||||||
|
domainCookieMap[cookie.domain].push(cookie);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const domains = Object.keys(domainCookieMap);
|
||||||
|
const domainsWithCookies = [];
|
||||||
|
|
||||||
|
each(domains, (domain) => {
|
||||||
|
const cookies = domainCookieMap[domain];
|
||||||
|
const validCookies = cookies.filter((cookie) => !cookie.expires || cookie.expires > Date.now());
|
||||||
|
|
||||||
|
if (validCookies.length) {
|
||||||
|
domainsWithCookies.push({
|
||||||
|
domain,
|
||||||
|
cookies: validCookies,
|
||||||
|
cookieString: validCookies.map((cookie) => cookie.cookieString()).join('; ')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
resolve(domainsWithCookies);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
addCookieToJar,
|
||||||
|
getCookiesForUrl,
|
||||||
|
getCookieStringForUrl,
|
||||||
|
getDomainsWithCookies
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user