Merge pull request #1155 from BrandonGillis/feat/custom-ca-certificate

feat: add custom CA Certificate preference
This commit is contained in:
Anoop M D 2024-01-04 22:54:29 +05:30 committed by GitHub
commit 2608ec035e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 109 additions and 2 deletions

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useRef } from 'react';
import get from 'lodash/get';
import { useFormik } from 'formik';
import { useSelector, useDispatch } from 'react-redux';
@ -6,13 +6,21 @@ import { savePreferences } from 'providers/ReduxStore/slices/app';
import StyledWrapper from './StyledWrapper';
import * as Yup from 'yup';
import toast from 'react-hot-toast';
import path from 'path';
import slash from 'utils/common/slash';
import { IconTrash } from '@tabler/icons';
const General = ({ close }) => {
const preferences = useSelector((state) => state.app.preferences);
const dispatch = useDispatch();
const inputFileCaCertificateRef = useRef();
const preferencesSchema = Yup.object().shape({
sslVerification: Yup.boolean(),
customCaCertificate: Yup.object({
enabled: Yup.boolean(),
filePath: Yup.string().nullable()
}),
storeCookies: Yup.boolean(),
sendCookies: Yup.boolean(),
timeout: Yup.mixed()
@ -31,6 +39,10 @@ const General = ({ close }) => {
const formik = useFormik({
initialValues: {
sslVerification: preferences.request.sslVerification,
customCaCertificate: {
enabled: get(preferences, 'request.customCaCertificate.enabled', false),
filePath: get(preferences, 'request.customCaCertificate.filePath', null)
},
timeout: preferences.request.timeout,
storeCookies: get(preferences, 'request.storeCookies', true),
sendCookies: get(preferences, 'request.sendCookies', true)
@ -52,6 +64,10 @@ const General = ({ close }) => {
...preferences,
request: {
sslVerification: newPreferences.sslVerification,
customCaCertificate: {
enabled: newPreferences.customCaCertificate.enabled,
filePath: newPreferences.customCaCertificate.filePath
},
timeout: newPreferences.timeout,
storeCookies: newPreferences.storeCookies,
sendCookies: newPreferences.sendCookies
@ -64,6 +80,14 @@ const General = ({ close }) => {
.catch((err) => console.log(err) && toast.error('Failed to update preferences'));
};
const addCaCertificate = (e) => {
formik.setFieldValue('customCaCertificate.filePath', e.target.files[0]?.path);
};
const deleteCaCertificate = () => {
formik.setFieldValue('customCaCertificate.filePath', null);
};
return (
<StyledWrapper>
<form className="bruno-form" onSubmit={formik.handleSubmit}>
@ -80,6 +104,60 @@ const General = ({ close }) => {
SSL/TLS Certificate Verification
</label>
</div>
<div className="flex items-center mt-2">
<input
id="customCaCertificateEnabled"
type="checkbox"
name="customCaCertificate.enabled"
checked={formik.values.customCaCertificate.enabled}
onChange={formik.handleChange}
className="mousetrap mr-0"
/>
<label className="block ml-2 select-none" htmlFor="customCaCertificateEnabled">
Use custom CA Certificate
</label>
</div>
{formik.values.customCaCertificate.filePath ? (
<div
className={`flex items-center mt-2 pl-6 ${formik.values.customCaCertificate.enabled ? '' : 'opacity-25'}`}
>
<span className="flex items-center border px-2 rounded-md">
{path.basename(slash(formik.values.customCaCertificate.filePath))}
<button
type="button"
tabIndex="-1"
className="pl-1"
disabled={formik.values.customCaCertificate.enabled ? false : true}
onClick={deleteCaCertificate}
>
<IconTrash strokeWidth={1.5} size={14} />
</button>
</span>
</div>
) : (
<div
className={`flex items-center mt-2 pl-6 ${formik.values.customCaCertificate.enabled ? '' : 'opacity-25'}`}
>
<button
type="button"
tabIndex="-1"
className="flex items-center border px-2 rounded-md"
disabled={formik.values.customCaCertificate.enabled ? false : true}
onClick={() => inputFileCaCertificateRef.current.click()}
>
select file
<input
id="caCertFilePath"
type="file"
name="customCaCertificate.filePath"
className="hidden"
ref={inputFileCaCertificateRef}
disabled={formik.values.customCaCertificate.enabled ? false : true}
onChange={addCaCertificate}
/>
</button>
</div>
)}
<div className="flex items-center mt-2">
<input
id="storeCookies"

View File

@ -11,6 +11,10 @@ const initialState = {
preferences: {
request: {
sslVerification: true,
customCaCertificate: {
enabled: false,
filePath: null
},
timeout: 0
},
font: {

View File

@ -86,11 +86,22 @@ const configureRequest = async (
request.url = `http://${request.url}`;
}
const httpsAgentRequestFields = {};
/**
* @see https://github.com/usebruno/bruno/issues/211 set keepAlive to true, this should fix socket hang up errors
* @see https://github.com/nodejs/node/pull/43522 keepAlive was changed to true globally on Node v19+
*/
const httpsAgentRequestFields = { keepAlive: true };
if (!preferencesUtil.shouldVerifyTls()) {
httpsAgentRequestFields['rejectUnauthorized'] = false;
}
if (preferencesUtil.shouldUseCustomCaCertificate()) {
const caCertFilePath = preferencesUtil.getCustomCaCertificateFilePath();
if (caCertFilePath) {
httpsAgentRequestFields['ca'] = fs.readFileSync(caCertFilePath);
}
}
const brunoConfig = getBrunoConfig(collectionUid);
const interpolationOptions = {
envVars,

View File

@ -11,6 +11,10 @@ const { get } = require('lodash');
const defaultPreferences = {
request: {
sslVerification: true,
customCaCertificate: {
enabled: false,
filePath: null
},
storeCookies: true,
sendCookies: true,
timeout: 0
@ -35,6 +39,10 @@ const defaultPreferences = {
const preferencesSchema = Yup.object().shape({
request: Yup.object().shape({
sslVerification: Yup.boolean(),
customCaCertificate: Yup.object({
enabled: Yup.boolean(),
filePath: Yup.string().nullable()
}),
storeCookies: Yup.boolean(),
sendCookies: Yup.boolean(),
timeout: Yup.number()
@ -100,6 +108,12 @@ const preferencesUtil = {
shouldVerifyTls: () => {
return get(getPreferences(), 'request.sslVerification', true);
},
shouldUseCustomCaCertificate: () => {
return get(getPreferences(), 'request.customCaCertificate.enabled', false);
},
getCustomCaCertificateFilePath: () => {
return get(getPreferences(), 'request.customCaCertificate.filePath', null);
},
getRequestTimeout: () => {
return get(getPreferences(), 'request.timeout', 0);
},