Skip to content

Commit

Permalink
πŸ”₯πŸ•Œ Firewall Proxy (#102)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gilad-Gur-Andelman authored Oct 8, 2024
1 parent 358681c commit 2cf3af9
Show file tree
Hide file tree
Showing 65 changed files with 1,033 additions and 239 deletions.
6 changes: 6 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ module.exports = {
'no-restricted-globals': 'off',
},
},
{
files: ['src/main-process/**/*.ts'],
rules: {
'react-hooks/rules-of-hooks': 'off',
},
},
{
env: {
mocha: true,
Expand Down
8 changes: 8 additions & 0 deletions forge.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,14 @@ module.exports = {
js: './src/renderer-process/agent-view/preload.ts',
},
},
{
html: './src/renderer-process/settings-view/index.html',
js: './src/renderer-process/settings-view/renderer.ts',
name: 'settings_view',
preload: {
js: './src/renderer-process/settings-view/preload.ts',
},
},
],
},
},
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "desktop-app",
"productName": "Loadmill",
"version": "3.3.23",
"version": "3.3.24",
"description": "The Loadmill desktop app",
"author": {
"name": "Loadmill Ltd.",
Expand Down Expand Up @@ -82,6 +82,7 @@
"electron-squirrel-startup": "^1.0.0",
"electron-store": "^8.1.0",
"get-port": "^6.1.2",
"hpagent": "^1.2.0",
"is-base64": "^1.1.0",
"is-html": "^3.0.0",
"loadmill-http-mitm-proxy": "0.0.10",
Expand Down
31 changes: 0 additions & 31 deletions src/inter-process-communication/main-to-agent.ts

This file was deleted.

30 changes: 0 additions & 30 deletions src/inter-process-communication/main-to-renderer.ts

This file was deleted.

31 changes: 0 additions & 31 deletions src/inter-process-communication/proxy-to-render.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ipcRenderer } from 'electron';

import log from '../log';
import { MainMessage, MainMessageTypes } from '../types/messaging';
import log from '../../log';
import { MainMessage, MainMessageTypes } from '../../types/messaging';

export const sendToMain = (type: MainMessageTypes, data?: MainMessage['data']): void => {
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* This module provides a nice interface to send messages from main process to renderer process.
*/

import log from '../../log';
import { getMainWindow } from '../../main-process/main-window';
import { getViewByName } from '../../main-process/views';
import {
AgentRendererMessage,
MainWindowRendererMessage,
ProxyRendererMessage,
RendererMessage,
SettingsRendererMessage,
} from '../../types/messaging';
import { ViewName } from '../../types/views';

export const sendFromMainWindowToRenderer = ({ type, data }: MainWindowRendererMessage): void => {
_sendToRenderer({ data, type });
};

export const sendFromAgentViewToRenderer = ({ type, data }: AgentRendererMessage): void => {
_sendToRenderer({ data, type }, ViewName.AGENT);
};

export const sendFromProxyViewToRenderer = ({ type, data }: ProxyRendererMessage): void => {
_sendToRenderer({ data, type }, ViewName.PROXY);
};

export const sendFromSettingsViewToRenderer = ({ type, data }: SettingsRendererMessage): void => {
_sendToRenderer({ data, type }, ViewName.SETTINGS);
};

const _sendToRenderer = ({ type, data }: RendererMessage, viewName?: ViewName): void => {
try {
const viewOrWindow = viewName ? getViewByName(viewName) : getMainWindow();
const webContents = viewOrWindow?.webContents;
if (!webContents) {
throw new Error('No webContents found');
}
log.debug('Sending to renderer', { data, type, viewName });
webContents.send(type, data);
} catch (e) {
log.error('Error in send to renderer', { data, type, viewName }, e);
}
};
3 changes: 1 addition & 2 deletions src/log/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@ const setMainLogLevels = () => {
log.transports.file.level = 'info';
log.transports.console.level = 'silly';
// Now log.debug Will show in console mode (dev) but not in file mode (prod)
log.info('Main logger created. Writing to file: ', log.transports.file.getFile().path);
};

setMainLogLevels();

log.info('Main logger created. Writing to file: ', log.transports.file.getFile().path);

export const createLogger = (
logId: string,
filePath: string,
Expand Down
16 changes: 9 additions & 7 deletions src/main-process/agent-handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import path from 'path';
import '@loadmill/agent/dist/cli';
import { app } from 'electron';

import { sendFromMainToAgentRenderer } from '../inter-process-communication/main-to-agent';
import { sendToRenderer } from '../inter-process-communication/main-to-renderer';
import {
sendFromAgentViewToRenderer,
sendFromMainWindowToRenderer,
} from '../inter-process-communication/to-renderer-process/main-to-renderer';
import log from '../log';
import { AgentMessage, MainMessage } from '../types/messaging';
import { Token } from '../types/token';
Expand Down Expand Up @@ -88,7 +90,7 @@ const createAgentProcess = (): ChildProcessWithoutNullStreams => {
const addOnAgentExitEvent = () => {
agent.on('exit', (code) => {
log.info('Agent process exited with code:', code);
sendToRenderer({
sendFromMainWindowToRenderer({
data: {
isAgentConnected: isAgentConnected(),
},
Expand All @@ -101,7 +103,7 @@ const addOnAgentIsConnectedEvent = (): void => {
agent.on('message', ({ data, type }: MainMessage) => {
if (type === IS_AGENT_CONNECTED) {
log.info('Agent message received', { data, type } );
sendToRenderer({
sendFromMainWindowToRenderer({
data: {
isAgentConnected: data.isConnected,
},
Expand Down Expand Up @@ -131,7 +133,7 @@ const handleAgentStd = async (
log.info('Agent:', text);
await handleInvalidToken(text);
refreshConnectedStatus({ text });
sendFromMainToAgentRenderer({ data: { text }, type });
sendFromAgentViewToRenderer({ data: { text }, type });
agentLogger.info(text);
};

Expand Down Expand Up @@ -211,7 +213,7 @@ const handleStartAgentEvent = async () => {
}
if (isAgentConnected()) {
log.info('Agent is already connected');
sendToRenderer({
sendFromMainWindowToRenderer({
data: {
isAgentConnected: isAgentConnected(),
},
Expand All @@ -235,7 +237,7 @@ const handleStopAgentEvent = () => {
log.info(`Got ${STOP_AGENT} event`);
if (!isAgentConnected()) {
log.info('Agent is already not connected');
sendToRenderer({
sendFromMainWindowToRenderer({
data: {
isAgentConnected: isAgentConnected(),
},
Expand Down
8 changes: 5 additions & 3 deletions src/main-process/authentication.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { sendToRenderer } from '../inter-process-communication/main-to-renderer';
import {
sendFromMainWindowToRenderer,
} from '../inter-process-communication/to-renderer-process/main-to-renderer';
import log from '../log';
import {
MAGIC_TOKEN,
Expand All @@ -14,7 +16,7 @@ export const handleAuthEvent = (url: string): void => {
log.error('No magic token found in URL', { url });
return;
}
sendToRenderer({
sendFromMainWindowToRenderer({
data: { magicToken },
type: MAGIC_TOKEN,
});
Expand All @@ -27,5 +29,5 @@ const getMagicTokenFromUrl = (url: string): string => {
};

export const showAuthTokenInput = (): void => {
sendToRenderer({ type: SHOW_AUTH_TOKEN_INPUT });
sendFromMainWindowToRenderer({ type: SHOW_AUTH_TOKEN_INPUT });
};
59 changes: 59 additions & 0 deletions src/main-process/fetch/https-agent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import https from 'https';

import { HttpsProxyAgent } from 'hpagent';

import log from '../../log';

export enum HttpsProxyAgentType {
DEFAULT = 'default',
PROXY = 'proxy',
}

let agent: https.Agent | HttpsProxyAgent | null | undefined;

export const getHttpsAgent = (): https.Agent | HttpsProxyAgent | undefined => {
if (!agent) {
useDefaultHttpsAgent();
}
return agent;
};

const httpsAgentOptions = {
keepAlive: true,
keepAliveMsecs: 1000,
maxFreeSockets: 256,
maxSockets: 256,
rejectUnauthorized: false,
};

export const useProxyHttpsAgent = (proxyUrl: string): void => {
_destroyAgent();
log.info('Using proxy HTTPS agent', { proxyUrl });
agent = _createProxyHttpsAgent(proxyUrl);
};

const _createProxyHttpsAgent = (proxyUrl: string): HttpsProxyAgent => {
return new HttpsProxyAgent({
...httpsAgentOptions,
proxy: proxyUrl,
scheduling: 'lifo',
});
};

export const useDefaultHttpsAgent = (): void => {
_destroyAgent();
log.info('Using default HTTPS agent');
agent = _createDefaultHttpsAgent();
};

const _createDefaultHttpsAgent = (): https.Agent => {
return new https.Agent(httpsAgentOptions);
};

const _destroyAgent = (): void => {
if (agent) {
log.info('Destroying HTTPS agent');
agent.destroy();
agent = null;
}
};
9 changes: 2 additions & 7 deletions src/main-process/fetch/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import https from 'https';

import { app } from 'electron';
import fetch, { RequestInit, Response } from 'node-fetch';

const httpsAgent = new https.Agent({
rejectUnauthorized: false,
});
import { getHttpsAgent } from './https-agent';

const _fetch = async (path: string, reqInit: RequestInit = {}): Promise<Response> => {
const response = await fetch(path, {
agent: app.isPackaged && httpsAgent,
agent: getHttpsAgent(),
...reqInit,
});
return response;
Expand Down
Loading

0 comments on commit 2cf3af9

Please sign in to comment.