Skip to content

Commit

Permalink
:electron: Desktop app to work with self signed certificates (#3308)
Browse files Browse the repository at this point in the history
* solves the problem but creates a vulnerability

* sake...

* working but need to specify rootca.pem

* works

* being flexible on the cert names, as long as its a crt or pem

* remove console logs

* initial setup for adding cert

* caps

* comments

* fix ts strict

* rewrote it

* release notes

* remove unneeded

* https no polyfill

* removing the cert reference if it is not found

* moving full stop
  • Loading branch information
MikesGlitch authored Aug 28, 2024
1 parent ae608f0 commit 8e077e0
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 11 deletions.
69 changes: 59 additions & 10 deletions packages/desktop-client/src/components/manager/ConfigServer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import {
} from 'loot-core/src/shared/environment';

import { useActions } from '../../hooks/useActions';
import { useGlobalPref } from '../../hooks/useGlobalPref';
import { useNavigate } from '../../hooks/useNavigate';
import { useSetThemeColor } from '../../hooks/useSetThemeColor';
import { theme } from '../../style';
import { Button, ButtonWithLoading } from '../common/Button2';
import { BigInput } from '../common/Input';
import { Link } from '../common/Link';
import { Text } from '../common/Text';
import { View } from '../common/View';
import { useServerURL, useSetServerURL } from '../ServerContext';
Expand All @@ -32,6 +34,9 @@ export function ConfigServer() {
}, [currentUrl]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [_serverSelfSignedCert, setServerSelfSignedCert] = useGlobalPref(
'serverSelfSignedCert',
);

function getErrorMessage(error: string) {
switch (error) {
Expand Down Expand Up @@ -83,6 +88,23 @@ export function ConfigServer() {
setUrl(window.location.origin);
}

async function onSelectSelfSignedCertificate() {
const selfSignedCertificateLocation = await window.Actual?.openFileDialog({
properties: ['openFile'],
filters: [
{
name: 'Self Signed Certificate',
extensions: ['crt', 'pem'],
},
],
});

if (selfSignedCertificateLocation) {
setServerSelfSignedCert(selfSignedCertificateLocation[0]);
globalThis.window.Actual.relaunch(); // relaunch to use the certificate
}
}

async function onSkip() {
await setServerUrl(null);
await loggedIn();
Expand Down Expand Up @@ -121,16 +143,43 @@ export function ConfigServer() {
</Text>

{error && (
<Text
style={{
marginTop: 20,
color: theme.errorText,
borderRadius: 4,
fontSize: 15,
}}
>
{getErrorMessage(error)}
</Text>
<>
<Text
style={{
marginTop: 20,
color: theme.errorText,
borderRadius: 4,
fontSize: 15,
}}
>
{getErrorMessage(error)}
</Text>
{isElectron() && (
<View
style={{ display: 'flex', flexDirection: 'row', marginTop: 20 }}
>
<Text
style={{
color: theme.errorText,
borderRadius: 4,
fontSize: 15,
}}
>
<Trans>
If the server is using a self-signed certificate{' '}
<Link
variant="text"
style={{ fontSize: 15 }}
onClick={onSelectSelfSignedCertificate}
>
select it here
</Link>
.
</Trans>
</Text>
</View>
)}
</>
)}

<View style={{ display: 'flex', flexDirection: 'row', marginTop: 30 }}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// // @ts-strict-ignore
// @ts-strict-ignore
import nodeFetch from 'node-fetch';

export const fetch = (input: RequestInfo | URL, options?: RequestInit) => {
Expand Down
26 changes: 26 additions & 0 deletions packages/loot-core/src/server/main.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
// @ts-strict-ignore
import './polyfills';
import https from 'https';
import tls from 'tls';

import * as injectAPI from '@actual-app/api/injected';
import * as CRDT from '@actual-app/crdt';
import { v4 as uuidv4 } from 'uuid';
Expand Down Expand Up @@ -1253,6 +1256,12 @@ handlers['save-global-prefs'] = async function (prefs) {
if ('theme' in prefs) {
await asyncStorage.setItem('theme', prefs.theme);
}
if ('serverSelfSignedCert' in prefs) {
await asyncStorage.setItem(
'server-self-signed-cert',
prefs.serverSelfSignedCert,
);
}
return 'ok';
};

Expand Down Expand Up @@ -2126,6 +2135,23 @@ export async function initApp(isDev, socketName) {
}
}

const selfSignedCertPath = await asyncStorage.getItem(
'server-self-signed-cert',
);

if (selfSignedCertPath) {
try {
const selfSignedCert = await fs.readFile(selfSignedCertPath);
https.globalAgent.options.ca = [...tls.rootCertificates, selfSignedCert];
} catch (error) {
console.error(
'Unable to add the self signed certificate, removing its reference',
error,
);
await asyncStorage.removeItem('server-self-signed-cert');
}
}

const url = await asyncStorage.getItem('server-url');

if (!url) {
Expand Down
1 change: 1 addition & 0 deletions packages/loot-core/src/types/prefs.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,5 @@ export type GlobalPrefs = Partial<{
keyId?: string;
theme: Theme;
documentDir: string; // Electron only
serverSelfSignedCert: string; // Electron only
}>;
1 change: 1 addition & 0 deletions packages/loot-core/webpack/webpack.browser.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ module.exports = {
process: require.resolve('process/browser'),
stream: require.resolve('stream-browserify'),
tls: false,
https: false,
// used by memfs in a check which we can ignore I think
url: false,
zlib: require.resolve('browserify-zlib'),
Expand Down
6 changes: 6 additions & 0 deletions upcoming-release-notes/3308.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
category: Maintenance
authors: [MikesGlitch]
---

Support servers with self signed certificates in the Desktop app

0 comments on commit 8e077e0

Please sign in to comment.