mirror of
https://github.com/usebruno/bruno.git
synced 2024-11-25 09:23:17 +01:00
feat: update proxy implementation in preferences (#2977)
This commit is contained in:
parent
c1ec95dc29
commit
c5c343c543
@ -6,28 +6,14 @@ import * as Yup from 'yup';
|
|||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
import { IconEye, IconEyeOff } from '@tabler/icons';
|
import { IconEye, IconEyeOff } from '@tabler/icons';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { cloneDeep } from 'lodash';
|
|
||||||
|
|
||||||
const ProxySettings = ({ proxyConfig: _proxyConfig, onUpdate }) => {
|
|
||||||
const proxyConfig = useMemo(() => {
|
|
||||||
const proxyConfigCopy = cloneDeep(_proxyConfig);
|
|
||||||
// backward compatibility check
|
|
||||||
if (proxyConfigCopy?.enabled == 'true') proxyConfigCopy.enabled = true;
|
|
||||||
if (proxyConfigCopy?.enabled == 'false') proxyConfigCopy.enabled = false;
|
|
||||||
|
|
||||||
proxyConfigCopy.enabled = ['string', 'boolean'].includes(typeof proxyConfigCopy?.enabled)
|
|
||||||
? proxyConfigCopy?.enabled
|
|
||||||
: 'global';
|
|
||||||
return proxyConfigCopy;
|
|
||||||
}, [_proxyConfig]);
|
|
||||||
|
|
||||||
|
const ProxySettings = ({ proxyConfig, onUpdate }) => {
|
||||||
const proxySchema = Yup.object({
|
const proxySchema = Yup.object({
|
||||||
enabled: Yup.mixed().oneOf([false, true, 'global']),
|
enabled: Yup.string().oneOf(['global', 'true', 'false']),
|
||||||
protocol: Yup.string().oneOf(['http', 'https', 'socks4', 'socks5']),
|
protocol: Yup.string().oneOf(['http', 'https', 'socks4', 'socks5']),
|
||||||
hostname: Yup.string()
|
hostname: Yup.string()
|
||||||
.when('enabled', {
|
.when('enabled', {
|
||||||
is: true,
|
is: 'true',
|
||||||
then: (hostname) => hostname.required('Specify the hostname for your proxy.'),
|
then: (hostname) => hostname.required('Specify the hostname for your proxy.'),
|
||||||
otherwise: (hostname) => hostname.nullable()
|
otherwise: (hostname) => hostname.nullable()
|
||||||
})
|
})
|
||||||
@ -40,7 +26,7 @@ const ProxySettings = ({ proxyConfig: _proxyConfig, onUpdate }) => {
|
|||||||
.transform((_, val) => (val ? Number(val) : null)),
|
.transform((_, val) => (val ? Number(val) : null)),
|
||||||
auth: Yup.object()
|
auth: Yup.object()
|
||||||
.when('enabled', {
|
.when('enabled', {
|
||||||
is: true,
|
is: 'true',
|
||||||
then: Yup.object({
|
then: Yup.object({
|
||||||
enabled: Yup.boolean(),
|
enabled: Yup.boolean(),
|
||||||
username: Yup.string()
|
username: Yup.string()
|
||||||
@ -63,7 +49,7 @@ const ProxySettings = ({ proxyConfig: _proxyConfig, onUpdate }) => {
|
|||||||
|
|
||||||
const formik = useFormik({
|
const formik = useFormik({
|
||||||
initialValues: {
|
initialValues: {
|
||||||
enabled: proxyConfig.enabled,
|
enabled: proxyConfig.enabled || 'global',
|
||||||
protocol: proxyConfig.protocol || 'http',
|
protocol: proxyConfig.protocol || 'http',
|
||||||
hostname: proxyConfig.hostname || '',
|
hostname: proxyConfig.hostname || '',
|
||||||
port: proxyConfig.port || '',
|
port: proxyConfig.port || '',
|
||||||
@ -79,6 +65,13 @@ const ProxySettings = ({ proxyConfig: _proxyConfig, onUpdate }) => {
|
|||||||
proxySchema
|
proxySchema
|
||||||
.validate(values, { abortEarly: true })
|
.validate(values, { abortEarly: true })
|
||||||
.then((validatedProxy) => {
|
.then((validatedProxy) => {
|
||||||
|
// serialize 'enabled' to boolean
|
||||||
|
if (validatedProxy.enabled === 'true') {
|
||||||
|
validatedProxy.enabled = true;
|
||||||
|
} else if (validatedProxy.enabled === 'false') {
|
||||||
|
validatedProxy.enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
onUpdate(validatedProxy);
|
onUpdate(validatedProxy);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -91,7 +84,7 @@ const ProxySettings = ({ proxyConfig: _proxyConfig, onUpdate }) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
formik.setValues({
|
formik.setValues({
|
||||||
enabled: proxyConfig.enabled,
|
enabled: proxyConfig.enabled === true ? 'true' : proxyConfig.enabled === false ? 'false' : 'global',
|
||||||
protocol: proxyConfig.protocol || 'http',
|
protocol: proxyConfig.protocol || 'http',
|
||||||
hostname: proxyConfig.hostname || '',
|
hostname: proxyConfig.hostname || '',
|
||||||
port: proxyConfig.port || '',
|
port: proxyConfig.port || '',
|
||||||
@ -125,50 +118,41 @@ const ProxySettings = ({ proxyConfig: _proxyConfig, onUpdate }) => {
|
|||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<label className="flex items-center cursor-pointer">
|
<label className="flex items-center">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
name="enabled"
|
name="enabled"
|
||||||
value="global"
|
value="global"
|
||||||
checked={formik.values.enabled === 'global'}
|
checked={formik.values.enabled === 'global'}
|
||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
className="mr-1 cursor-pointer"
|
className="mr-1"
|
||||||
/>
|
/>
|
||||||
global
|
global
|
||||||
</label>
|
</label>
|
||||||
<label className="flex items-center ml-4 cursor-pointer">
|
<label className="flex items-center ml-4">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
name="enabled"
|
name="enabled"
|
||||||
value={'true'}
|
value={'true'}
|
||||||
checked={formik.values.enabled === true}
|
checked={formik.values.enabled === 'true'}
|
||||||
onChange={(e) => {
|
onChange={formik.handleChange}
|
||||||
formik.setFieldValue('enabled', true);
|
className="mr-1"
|
||||||
}}
|
|
||||||
className="mr-1 cursor-pointer"
|
|
||||||
/>
|
/>
|
||||||
enabled
|
enabled
|
||||||
</label>
|
</label>
|
||||||
<label className="flex items-center ml-4 cursor-pointer">
|
<label className="flex items-center ml-4">
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
name="enabled"
|
name="enabled"
|
||||||
value={'false'}
|
value={'false'}
|
||||||
checked={formik.values.enabled === false}
|
checked={formik.values.enabled === 'false'}
|
||||||
onChange={(e) => {
|
onChange={formik.handleChange}
|
||||||
formik.setFieldValue('enabled', false);
|
className="mr-1"
|
||||||
}}
|
|
||||||
className="mr-1 cursor-pointer"
|
|
||||||
/>
|
/>
|
||||||
disabled
|
disabled
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{formik.values.enabled === 'global' ? (
|
|
||||||
<div className="opacity-50">Global proxy can be configured in the app preferences.</div>
|
|
||||||
) : null}
|
|
||||||
{formik.values.enabled === true ? (
|
|
||||||
<>
|
|
||||||
<div className="mb-3 flex items-center">
|
<div className="mb-3 flex items-center">
|
||||||
<label className="settings-label" htmlFor="protocol">
|
<label className="settings-label" htmlFor="protocol">
|
||||||
Protocol
|
Protocol
|
||||||
@ -314,11 +298,7 @@ const ProxySettings = ({ proxyConfig: _proxyConfig, onUpdate }) => {
|
|||||||
className="btn btn-sm absolute right-0"
|
className="btn btn-sm absolute right-0"
|
||||||
onClick={() => setPasswordVisible(!passwordVisible)}
|
onClick={() => setPasswordVisible(!passwordVisible)}
|
||||||
>
|
>
|
||||||
{passwordVisible ? (
|
{passwordVisible ? <IconEyeOff size={18} strokeWidth={1.5} /> : <IconEye size={18} strokeWidth={1.5} />}
|
||||||
<IconEyeOff size={18} strokeWidth={1.5} />
|
|
||||||
) : (
|
|
||||||
<IconEye size={18} strokeWidth={1.5} />
|
|
||||||
)}
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{formik.touched.auth?.password && formik.errors.auth?.password ? (
|
{formik.touched.auth?.password && formik.errors.auth?.password ? (
|
||||||
@ -346,8 +326,6 @@ const ProxySettings = ({ proxyConfig: _proxyConfig, onUpdate }) => {
|
|||||||
<div className="ml-3 text-red-500">{formik.errors.bypassProxy}</div>
|
<div className="ml-3 text-red-500">{formik.errors.bypassProxy}</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
<div className="mt-6">
|
<div className="mt-6">
|
||||||
<button type="submit" className="submit btn btn-sm btn-secondary">
|
<button type="submit" className="submit btn btn-sm btn-secondary">
|
||||||
Save
|
Save
|
||||||
|
@ -20,6 +20,12 @@ const StyledWrapper = styled.div`
|
|||||||
outline: none !important;
|
outline: none !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.system-proxy-settings {
|
||||||
|
label {
|
||||||
|
color: ${(props) => props.theme.colors.text.yellow};
|
||||||
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default StyledWrapper;
|
export default StyledWrapper;
|
||||||
|
@ -8,26 +8,13 @@ import StyledWrapper from './StyledWrapper';
|
|||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { IconEye, IconEyeOff } from '@tabler/icons';
|
import { IconEye, IconEyeOff } from '@tabler/icons';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { cloneDeep } from 'lodash';
|
|
||||||
|
|
||||||
const ProxySettings = ({ close }) => {
|
const ProxySettings = ({ close }) => {
|
||||||
const _preferences = useSelector((state) => state.app.preferences);
|
const preferences = useSelector((state) => state.app.preferences);
|
||||||
const systemProxyEnvVariables = useSelector((state) => state.app.systemProxyEnvVariables);
|
const systemProxyEnvVariables = useSelector((state) => state.app.systemProxyEnvVariables);
|
||||||
const { http_proxy, https_proxy, no_proxy } = systemProxyEnvVariables || {};
|
const { http_proxy, https_proxy, no_proxy } = systemProxyEnvVariables || {};
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
console.log(preferences);
|
||||||
const preferences = useMemo(() => {
|
|
||||||
const preferencesCopy = cloneDeep(_preferences);
|
|
||||||
// backward compatibility check
|
|
||||||
if (typeof preferencesCopy?.proxy?.enabled === 'boolean') {
|
|
||||||
preferencesCopy.proxy.mode = preferencesCopy?.proxy?.enabled ? 'on' : 'off';
|
|
||||||
} else {
|
|
||||||
preferencesCopy.proxy.mode =
|
|
||||||
typeof preferencesCopy?.proxy?.mode === 'string' ? preferencesCopy?.proxy?.mode : 'off';
|
|
||||||
}
|
|
||||||
return preferencesCopy;
|
|
||||||
}, [_preferences]);
|
|
||||||
|
|
||||||
const proxySchema = Yup.object({
|
const proxySchema = Yup.object({
|
||||||
mode: Yup.string().oneOf(['off', 'on', 'system']),
|
mode: Yup.string().oneOf(['off', 'on', 'system']),
|
||||||
@ -142,7 +129,7 @@ const ProxySettings = ({ close }) => {
|
|||||||
}}
|
}}
|
||||||
className="mr-1 cursor-pointer"
|
className="mr-1 cursor-pointer"
|
||||||
/>
|
/>
|
||||||
off
|
Off
|
||||||
</label>
|
</label>
|
||||||
<label className="flex items-center ml-4 cursor-pointer">
|
<label className="flex items-center ml-4 cursor-pointer">
|
||||||
<input
|
<input
|
||||||
@ -155,7 +142,7 @@ const ProxySettings = ({ close }) => {
|
|||||||
}}
|
}}
|
||||||
className="mr-1 cursor-pointer"
|
className="mr-1 cursor-pointer"
|
||||||
/>
|
/>
|
||||||
on
|
On
|
||||||
</label>
|
</label>
|
||||||
<label className="flex items-center ml-4 cursor-pointer">
|
<label className="flex items-center ml-4 cursor-pointer">
|
||||||
<input
|
<input
|
||||||
@ -166,26 +153,30 @@ const ProxySettings = ({ close }) => {
|
|||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
className="mr-1 cursor-pointer"
|
className="mr-1 cursor-pointer"
|
||||||
/>
|
/>
|
||||||
system
|
System Proxy
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{formik?.values?.mode === 'system' ? (
|
{formik?.values?.mode === 'system' ? (
|
||||||
<div className="mb-3 flex items-start pb-3">
|
<div className="mb-3 pt-1 text-muted system-proxy-settings">
|
||||||
<div className="flex flex-col gap-2 justify-start items-start">
|
<small>
|
||||||
<div className="mb-3 flex items-center">
|
Below values are sourced from your system environment variables and cannot be directly updated in Bruno.<br/>
|
||||||
|
Please refer to your OS documentation to change these values.
|
||||||
|
</small>
|
||||||
|
<div className="flex flex-col justify-start items-start pt-2">
|
||||||
|
<div className="mb-1 flex items-center">
|
||||||
<label className="settings-label" htmlFor="http_proxy">
|
<label className="settings-label" htmlFor="http_proxy">
|
||||||
http_proxy
|
http_proxy
|
||||||
</label>
|
</label>
|
||||||
<div className="opacity-80">{http_proxy || '-'}</div>
|
<div className="opacity-80">{http_proxy || '-'}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-3 flex items-center">
|
<div className="mb-1 flex items-center">
|
||||||
<label className="settings-label" htmlFor="https_proxy">
|
<label className="settings-label" htmlFor="https_proxy">
|
||||||
https_proxy
|
https_proxy
|
||||||
</label>
|
</label>
|
||||||
<div className="opacity-80">{https_proxy || '-'}</div>
|
<div className="opacity-80">{https_proxy || '-'}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-3 flex items-center">
|
<div className="mb-1 flex items-center">
|
||||||
<label className="settings-label" htmlFor="no_proxy">
|
<label className="settings-label" htmlFor="no_proxy">
|
||||||
no_proxy
|
no_proxy
|
||||||
</label>
|
</label>
|
||||||
|
@ -8,9 +8,7 @@ const axios = require('axios');
|
|||||||
*/
|
*/
|
||||||
function makeAxiosInstance() {
|
function makeAxiosInstance() {
|
||||||
/** @type {axios.AxiosInstance} */
|
/** @type {axios.AxiosInstance} */
|
||||||
const instance = axios.create({
|
const instance = axios.create();
|
||||||
proxy: false
|
|
||||||
});
|
|
||||||
|
|
||||||
instance.interceptors.request.use((config) => {
|
instance.interceptors.request.use((config) => {
|
||||||
config.headers['request-start-time'] = Date.now();
|
config.headers['request-start-time'] = Date.now();
|
||||||
|
@ -165,17 +165,32 @@ const configureRequest = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// proxy configuration
|
/**
|
||||||
let proxyConfig = get(brunoConfig, 'proxy', {});
|
* Proxy configuration
|
||||||
let proxyMode = get(proxyConfig, 'enabled', 'global');
|
*
|
||||||
if (proxyMode === 'global') {
|
* Preferences proxyMode has three possible values: on, off, system
|
||||||
|
* Collection proxyMode has three possible values: true, false, global
|
||||||
|
*
|
||||||
|
* When collection proxyMode is true, it overrides the app-level proxy settings
|
||||||
|
* When collection proxyMode is false, it ignores the app-level proxy settings
|
||||||
|
* When collection proxyMode is global, it uses the app-level proxy settings
|
||||||
|
*
|
||||||
|
* Below logic calculates the proxyMode and proxyConfig to be used for the request
|
||||||
|
*/
|
||||||
|
let proxyMode = 'off';
|
||||||
|
let proxyConfig = {};
|
||||||
|
|
||||||
|
const collectionProxyConfig = get(brunoConfig, 'proxy', {});
|
||||||
|
const collectionProxyEnabled = get(collectionProxyConfig, 'enabled', 'global');
|
||||||
|
if (collectionProxyEnabled === true) {
|
||||||
|
proxyConfig = collectionProxyConfig;
|
||||||
|
proxyMode = 'on';
|
||||||
|
} else if (collectionProxyEnabled === 'global') {
|
||||||
proxyConfig = preferencesUtil.getGlobalProxyConfig();
|
proxyConfig = preferencesUtil.getGlobalProxyConfig();
|
||||||
proxyMode = get(proxyConfig, 'mode', false);
|
proxyMode = get(proxyConfig, 'mode', 'off');
|
||||||
}
|
}
|
||||||
|
|
||||||
// proxyMode is true, if the collection-level proxy is enabled.
|
if (proxyMode === 'on') {
|
||||||
// proxyMode is 'on', if the app-level proxy mode is turned on.
|
|
||||||
if (proxyMode === true || proxyMode === 'on') {
|
|
||||||
const shouldProxy = shouldUseProxy(request.url, get(proxyConfig, 'bypassProxy', ''));
|
const shouldProxy = shouldUseProxy(request.url, get(proxyConfig, 'bypassProxy', ''));
|
||||||
if (shouldProxy) {
|
if (shouldProxy) {
|
||||||
const proxyProtocol = interpolateString(get(proxyConfig, 'protocol'), interpolationOptions);
|
const proxyProtocol = interpolateString(get(proxyConfig, 'protocol'), interpolationOptions);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const Yup = require('yup');
|
const Yup = require('yup');
|
||||||
const Store = require('electron-store');
|
const Store = require('electron-store');
|
||||||
const { get } = require('lodash');
|
const { get, merge } = require('lodash');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The preferences are stored in the electron store 'preferences.json'.
|
* The preferences are stored in the electron store 'preferences.json'.
|
||||||
@ -81,10 +81,22 @@ class PreferencesStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getPreferences() {
|
getPreferences() {
|
||||||
return {
|
let preferences = this.store.get('preferences', {});
|
||||||
...defaultPreferences,
|
|
||||||
...this.store.get('preferences')
|
// This to support the old preferences format
|
||||||
};
|
// In the old format, we had a proxy.enabled flag
|
||||||
|
// In the new format, this maps to proxy.mode = 'on'
|
||||||
|
if (preferences?.proxy?.enabled) {
|
||||||
|
preferences.proxy.mode = 'on';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the proxy.enabled property if it exists, regardless of its value
|
||||||
|
// This is a part of migration to the new preferences format
|
||||||
|
if (preferences?.proxy && 'enabled' in preferences.proxy) {
|
||||||
|
delete preferences.proxy.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
return merge({}, defaultPreferences, preferences);
|
||||||
}
|
}
|
||||||
|
|
||||||
savePreferences(newPreferences) {
|
savePreferences(newPreferences) {
|
||||||
|
Loading…
Reference in New Issue
Block a user