123-lang 2.1.3 → 2.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/source/electron.js +312 -0
package/package.json
CHANGED
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
app,
|
|
5
|
+
BrowserWindow,
|
|
6
|
+
shell,
|
|
7
|
+
dialog,
|
|
8
|
+
session,
|
|
9
|
+
globalShortcut,
|
|
10
|
+
} = require('electron');
|
|
11
|
+
const isDev = require('electron-is-dev');
|
|
12
|
+
// Auto updater
|
|
13
|
+
const fs = require('fs');
|
|
14
|
+
const { localStorage } = require('electron-browser-storage');
|
|
15
|
+
const { t } = require('./electron-configuration/messages');
|
|
16
|
+
const {
|
|
17
|
+
config,
|
|
18
|
+
platforms,
|
|
19
|
+
platformsNames,
|
|
20
|
+
} = require('./electron-configuration/configuration');
|
|
21
|
+
const { autoUpdater } = require('electron-updater');
|
|
22
|
+
const log = require('electron-log');
|
|
23
|
+
const forge = require('node-forge');
|
|
24
|
+
const os = require('os');
|
|
25
|
+
|
|
26
|
+
const getLang = async () => localStorage.getItem(config.storageNames.lang);
|
|
27
|
+
|
|
28
|
+
const { isEnableDevTools, isAvailableDomainInput, certificate } = config;
|
|
29
|
+
|
|
30
|
+
const rootCertificatePath = path.join(
|
|
31
|
+
__dirname,
|
|
32
|
+
certificate.dir,
|
|
33
|
+
certificate.fileName
|
|
34
|
+
);
|
|
35
|
+
const rootCertificatePathSecondary = path.join(
|
|
36
|
+
__dirname,
|
|
37
|
+
certificate.dir,
|
|
38
|
+
certificate.fileNameSecondary
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const currentPlatform = platformsNames[os.platform()];
|
|
42
|
+
let updatesPath;
|
|
43
|
+
|
|
44
|
+
log.info(`Current Platform: ${currentPlatform}`);
|
|
45
|
+
|
|
46
|
+
// Disable downloading and installation updates for the MAC
|
|
47
|
+
autoUpdater.autoDownload = currentPlatform !== platforms.MAC;
|
|
48
|
+
autoUpdater.autoInstallOnAppQuit = currentPlatform !== platforms.MAC;
|
|
49
|
+
|
|
50
|
+
// Enable usage of Portal's globalShortcuts. This is essential for cases when
|
|
51
|
+
// the app runs in a Wayland session.
|
|
52
|
+
app.commandLine.appendSwitch('enable-features', 'GlobalShortcutsPortal');
|
|
53
|
+
|
|
54
|
+
function createWindow() {
|
|
55
|
+
// Create the browser window.
|
|
56
|
+
const win = new BrowserWindow({
|
|
57
|
+
...config.mainWindow,
|
|
58
|
+
webPreferences: {
|
|
59
|
+
devTools: true,
|
|
60
|
+
nodeIntegration: true,
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
win.webContents.on('new-window', function (e, url) {
|
|
65
|
+
e.preventDefault();
|
|
66
|
+
shell.openExternal(url);
|
|
67
|
+
});
|
|
68
|
+
// Set Links Settings
|
|
69
|
+
|
|
70
|
+
win.webContents.setWindowOpenHandler(details => {
|
|
71
|
+
shell.openExternal(details.url); // Open URL in user's Browser
|
|
72
|
+
return { action: 'deny' };
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (!isEnableDevTools) {
|
|
76
|
+
win.removeMenu();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Register a config?.shortCuts?.devTools shortcut listener.
|
|
80
|
+
const ret = globalShortcut.register(config?.shortCuts?.devTools, () => {
|
|
81
|
+
const focusedWindow = BrowserWindow.getFocusedWindow();
|
|
82
|
+
log.info(`${config?.shortCuts?.devTools} is pressed`);
|
|
83
|
+
if (focusedWindow) {
|
|
84
|
+
const isOpen = focusedWindow.webContents.isDevToolsOpened();
|
|
85
|
+
if (isOpen) {
|
|
86
|
+
focusedWindow.webContents.closeDevTools();
|
|
87
|
+
} else {
|
|
88
|
+
focusedWindow.webContents.openDevTools({ mode: 'detach' });
|
|
89
|
+
}
|
|
90
|
+
} else {
|
|
91
|
+
log.warn('No focused window to toggle DevTools.');
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// and load the index.html of the app.
|
|
96
|
+
// win.loadFile("index.html");
|
|
97
|
+
win.loadURL(
|
|
98
|
+
isDev
|
|
99
|
+
? 'http://localhost:3000'
|
|
100
|
+
: `file://${path.join(__dirname, '../build/index.html')}`
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
// Open the DevTools.
|
|
104
|
+
if (isEnableDevTools) {
|
|
105
|
+
win.webContents.openDevTools({ mode: 'detach' });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Check up for updates
|
|
109
|
+
// Verify certificate for the autoUpdater
|
|
110
|
+
autoUpdater.netSession.setCertificateVerifyProc((request, callback) => {
|
|
111
|
+
const certStatuses = {
|
|
112
|
+
trusted: 0,
|
|
113
|
+
failed: -2,
|
|
114
|
+
browserChecked: -3,
|
|
115
|
+
};
|
|
116
|
+
const { hostname: hostName, verificationResult: e, certificate } = request;
|
|
117
|
+
let subjectName = certificate?.subjectName?.split('\n')[0];
|
|
118
|
+
subjectName = subjectName?.replace('*.', '');
|
|
119
|
+
const status = hostName?.includes(subjectName)
|
|
120
|
+
? certStatuses.trusted
|
|
121
|
+
: certStatuses.failed;
|
|
122
|
+
if (status === certStatuses.failed) {
|
|
123
|
+
log.error('Certificate validation error:');
|
|
124
|
+
log.error(e);
|
|
125
|
+
}
|
|
126
|
+
callback(status);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const generateUpdateConfig = async () => {
|
|
130
|
+
let status = true;
|
|
131
|
+
const domainURL = await localStorage.getItem(config.storageNames.domain);
|
|
132
|
+
// Test local server
|
|
133
|
+
// const domainURL = `http://localhost:3100/`;
|
|
134
|
+
if (!domainURL) {
|
|
135
|
+
status = false;
|
|
136
|
+
return status;
|
|
137
|
+
}
|
|
138
|
+
const platformPath =
|
|
139
|
+
config?.updatesPathForPlatform[currentPlatform] ??
|
|
140
|
+
config?.updatesPathForPlatform[platforms.WINDOWS];
|
|
141
|
+
|
|
142
|
+
updatesPath = `${domainURL}${platformPath}`;
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
log.info('domain: ', domainURL);
|
|
146
|
+
log.info('updates path: ', updatesPath);
|
|
147
|
+
autoUpdater.setFeedURL({
|
|
148
|
+
url: updatesPath,
|
|
149
|
+
provider: config.provider,
|
|
150
|
+
});
|
|
151
|
+
} catch (err) {
|
|
152
|
+
log.error(err);
|
|
153
|
+
status = false;
|
|
154
|
+
}
|
|
155
|
+
return status;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
if (app.isPackaged) {
|
|
159
|
+
if (isAvailableDomainInput) {
|
|
160
|
+
generateUpdateConfig()
|
|
161
|
+
.then(status => {
|
|
162
|
+
if (status) {
|
|
163
|
+
autoUpdater.logger = log;
|
|
164
|
+
autoUpdater.checkForUpdates();
|
|
165
|
+
}
|
|
166
|
+
})
|
|
167
|
+
.catch(e => log.error(e));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
autoUpdater.logger = log;
|
|
171
|
+
autoUpdater.checkForUpdates();
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// This method will be called when Electron has finished
|
|
176
|
+
// initialization and is ready to create browser windows.
|
|
177
|
+
// Some APIs can only be used after this event occurs.
|
|
178
|
+
app.whenReady().then(() => {
|
|
179
|
+
createWindow();
|
|
180
|
+
|
|
181
|
+
// MAC OS FIX: Re-create a window in the app when the dock icon is clicked
|
|
182
|
+
app.on('activate', () => {
|
|
183
|
+
if (BrowserWindow.getAllWindows().length === 0) createWindow();
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// Quit when all windows are closed, except on macOS. There, it's common
|
|
188
|
+
// for applications and their menu bar to stay active until the user quits
|
|
189
|
+
// explicitly with Cmd + Q.
|
|
190
|
+
app.on('window-all-closed', () => {
|
|
191
|
+
if (process.platform !== 'darwin') {
|
|
192
|
+
app.quit();
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// Auto updater events
|
|
197
|
+
// Check is auto update available
|
|
198
|
+
autoUpdater.on('update-available', info => {
|
|
199
|
+
log.info('Update available:', info);
|
|
200
|
+
log.info('Updates path:', updatesPath);
|
|
201
|
+
|
|
202
|
+
const showInfoDialog = (lang = 'en') => {
|
|
203
|
+
log.info('showInfoDialog lang', lang);
|
|
204
|
+
const options = {
|
|
205
|
+
type: 'info',
|
|
206
|
+
buttons: [
|
|
207
|
+
t('Download installer', lang),
|
|
208
|
+
t('Download manual', lang),
|
|
209
|
+
t('Cancel', lang),
|
|
210
|
+
],
|
|
211
|
+
defaultId: 2,
|
|
212
|
+
title: t('Update is available', lang),
|
|
213
|
+
message: t('Update is available', lang),
|
|
214
|
+
detail: '',
|
|
215
|
+
};
|
|
216
|
+
dialog.showMessageBox(options).then(response => {
|
|
217
|
+
if (response.response === 0) {
|
|
218
|
+
shell.openExternal(
|
|
219
|
+
`${updatesPath}${config?.macUpdateConfig?.installerName}`
|
|
220
|
+
);
|
|
221
|
+
showInfoDialog(lang);
|
|
222
|
+
} else if (response.response === 1) {
|
|
223
|
+
shell.openExternal(
|
|
224
|
+
`${updatesPath}${config?.macUpdateConfig?.manualMap[lang]}`
|
|
225
|
+
);
|
|
226
|
+
showInfoDialog(lang);
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
};
|
|
230
|
+
if (currentPlatform === platforms.MAC) {
|
|
231
|
+
getLang()
|
|
232
|
+
.then(lang => {
|
|
233
|
+
showInfoDialog(lang);
|
|
234
|
+
})
|
|
235
|
+
.catch(() => {
|
|
236
|
+
log.error('Unable get language');
|
|
237
|
+
showInfoDialog();
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
autoUpdater.on('update-downloaded', (_event, releaseNotes, releaseName) => {
|
|
242
|
+
const showTranslatedDialog = lang => {
|
|
243
|
+
const dialogOpts = {
|
|
244
|
+
type: 'info',
|
|
245
|
+
buttons: [t('Ok', lang), t('Later', lang)],
|
|
246
|
+
title: t('Update is available', lang),
|
|
247
|
+
message: process.platform === 'win32' ? releaseNotes : releaseName,
|
|
248
|
+
detail: t('Now application will start updating and restart.', lang),
|
|
249
|
+
};
|
|
250
|
+
dialog.showMessageBox(dialogOpts).then(returnValue => {
|
|
251
|
+
if (returnValue.response === 0) autoUpdater.quitAndInstall();
|
|
252
|
+
});
|
|
253
|
+
};
|
|
254
|
+
getLang()
|
|
255
|
+
.then(lang => {
|
|
256
|
+
showTranslatedDialog(lang);
|
|
257
|
+
})
|
|
258
|
+
.catch(() => {
|
|
259
|
+
log.error('Unable get language');
|
|
260
|
+
showTranslatedDialog();
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
autoUpdater.on('error', message => {
|
|
265
|
+
log.error(t('There was a problem updating the application'));
|
|
266
|
+
log.error(message);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
app.on(
|
|
270
|
+
'certificate-error',
|
|
271
|
+
(event, webContents, url, error, certificate, callback) => {
|
|
272
|
+
try {
|
|
273
|
+
const rootCertificateContent = fs.readFileSync(
|
|
274
|
+
rootCertificatePath,
|
|
275
|
+
'utf8'
|
|
276
|
+
);
|
|
277
|
+
const rootCertificateContentSecondary = fs.readFileSync(
|
|
278
|
+
rootCertificatePathSecondary,
|
|
279
|
+
'utf8'
|
|
280
|
+
);
|
|
281
|
+
const rootCert = forge.pki.certificateFromPem(rootCertificateContent);
|
|
282
|
+
const rootCertSecondary = forge.pki.certificateFromPem(
|
|
283
|
+
rootCertificateContentSecondary
|
|
284
|
+
);
|
|
285
|
+
const clientCert = forge.pki.certificateFromPem(
|
|
286
|
+
certificate.data.toString()
|
|
287
|
+
);
|
|
288
|
+
callback(
|
|
289
|
+
clientCert.isIssuer(rootCert) || clientCert.isIssuer(rootCertSecondary)
|
|
290
|
+
);
|
|
291
|
+
} catch (e) {
|
|
292
|
+
log.error('Certificate validation error:');
|
|
293
|
+
log.error(e);
|
|
294
|
+
callback(false);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
// Clear Cache
|
|
300
|
+
app.on('ready', () => {
|
|
301
|
+
session.defaultSession.clearCache().then(() => {
|
|
302
|
+
log.info('Cache cleared!');
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
app.on('will-quit', () => {
|
|
307
|
+
// Unregister a shortcut.
|
|
308
|
+
globalShortcut.unregister(config?.shortCuts?.devTools);
|
|
309
|
+
|
|
310
|
+
// Unregister all shortcuts.
|
|
311
|
+
globalShortcut.unregisterAll();
|
|
312
|
+
});
|