How to build your own dVPN desktop client based on Electron + React
Making client application
In this tutorial we will show how to build the simplest desktop dVPN application based on the Electron framework and will cover the main parts of the dVPN client, to give you an understanding of how they interact.
The code that is used through this tutorial can be found: here
- NodeJs: >=v16.9.1
- npm: >=7.21.1
- yarn: >= 1.22.5
- Electron: >= 14.0.1
- Typescript: >= 4.4.3
- webpack: == 4.46.0 // we can't use Webpack 5, because of limitation in electron-webpack
- electron-webpack: >= 2.8.2
- React: >= 17.0.2
- @mysteriumnetwork/node: > 0.64.0 // Client Mysterium Node
- mysterium-vpn-js: > 15.1.0 // Tequila API client
- electron-builder: > 22.11.7
Client application workflow
Every client application consists of these four parts:
- Application - your client application
- Mysterium Node - client node to interact with Mysterium Network
- Supervisor - a service which allows our application to interact with node without the need for privilege escalation. Supervisor used only for client applications.
- Wireguard - VPN tunnel
Typical application startup:
- Start the Node.
- Install & Start Supervisor service(if it has not been installed yet).
- Setup connection to the Node Tequila API through the localhost.
- Setup connection to the Supervisor through the socket.
- Do some application logic...
Each Mysterium client Node is running Tequila API on localhost:44050 which is used for communication and control. To interact with this API we will use the package mysterium-vpn-js. You can see docs for API by opening localhost:44050/docs in your browser(when Node working) and by visiting mysterium-vpn-js client
Let's build some simple Electron App
Clone our demo repository to your local machine
- git clone email@example.com:mysteriumnetwork/tequilapi-webapp-tutorial.git
- yarn install
- yarn dev - to see how it looks like
Structure & main modules
Usually, people build react apps using the create-react-app tool which separates Source code from Electron. But this approach has some negative consequences if we want that all our code to be written on TypeScript. That's why we will be using webkit & electron-webkit wrapper.
From this point our project structure will look like this:
In electronWebpack part of package.json we set location of our app parts like electron and app, also adding webpack config for renderer process.
We use postinstall directive to copy Node binaries to our static folder so we could get access to them later from the application.
Setting up Electron
The first entry point of our application is src/electron/main.ts which will run our Electron. To create an Electron window we use:
Besides typical stuff, we need to setup IPC channels for our Node and Supervisor. And stop Node and disconnect from Supervisor before quit
Mysterium Node & Supervisor
In the src/electron/node/ we have mysteriumNode.ts and supervisor.ts. This is our IPC listeners that runs in the Electron thread, and which will give our App the possibility to run Node and Supervisor. We need this because our renderer process with our app has no access to the system, but the electron process has.
We will communicate with them using IPC clients in src/shared/ipc folder.
In mysteriumNode.ts we have 3 IPC methods: start, stop and kill. If you need Import/Export identity methods you can find them here.
In supervisor.ts we have 4 IPC methods: install, upgrade, connect, disconnect. During Supervisor installation user will need to enter Admin password as it will be run with system privileges.
Our application is very simple and consists of a few views components and API to work with Node Tequila API.
Let's discuss the process of interaction with Node and creating VPN tunnel with some exit nodes:
- We need to create an identity, which looks something like this 0x142362c0a179da288903f21adcba24686c01e654 and which is basically user id in Mysterium Network
- To use identity we need to unlock it(with a password) and register in the Registry service of Mysterium Network.
- Get a list of proposals using some filtration by country, connection type, price, speed, etc. The proposal is information about the provider(exit node) to which you are able to connect.
- Connect to one of the providers and all traffic will be routed through him.
- Disconnect from the provider to stop route traffic through him.
We will not be using any redux, mobx, etc. Instead, we will store state in the api.ts to make the app simpler.
We use steps here instead of a router to just update the App view on State update in the API. On startup, we calling Startup() and Preload() to start the Node and the Supervisor and preload identities list with current connection status(if we reload the app during work)
After that, all pretty simple -> User select identity(or create new), unlock it, and connect to random Node.
As you can see building dVPN application for Mysterium Network is simple enough. Just a few files for Node and Supervisor integration, Tequila API to control the Node and that's all.