diff --git a/src/app/services.module.ts b/src/app/services.module.ts
index 783eea73e7..89ebe65486 100644
--- a/src/app/services.module.ts
+++ b/src/app/services.module.ts
@@ -129,7 +129,7 @@ const environmentService = new EnvironmentService(apiService, storageService, no
const eventService = new EventService(storageService, apiService, userService, cipherService);
const systemService = new SystemService(storageService, vaultTimeoutService, messagingService, platformUtilsService,
null);
-const nativeMessagingService = new NativeMessagingService(cryptoFunctionService, cryptoService, platformUtilsService, logService);
+const nativeMessagingService = new NativeMessagingService(cryptoFunctionService, cryptoService, platformUtilsService, logService, i18nService, userService);
const analytics = new Analytics(window, () => isDev(), platformUtilsService, storageService, appIdService);
containerService.attachToGlobal(window);
diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json
index eaf6cd656c..df3db26ee3 100644
--- a/src/locales/en/messages.json
+++ b/src/locales/en/messages.json
@@ -1407,5 +1407,14 @@
},
"enableBrowserIntegrationDesc": {
"message": "Browser integration is used for biometrics in browser."
+ },
+ "approve": {
+ "message": "Approve"
+ },
+ "verifyBrowserTitle": {
+ "message": "Verify browser connection"
+ },
+ "verifyBrowserDescription": {
+ "message": "Please ensure the shown fingerprint is identical to the fingerprint showed in the browser extension."
}
}
diff --git a/src/services/nativeMessaging.service.ts b/src/services/nativeMessaging.service.ts
index 434956b378..750818c1a9 100644
--- a/src/services/nativeMessaging.service.ts
+++ b/src/services/nativeMessaging.service.ts
@@ -1,4 +1,5 @@
import { ipcRenderer } from 'electron';
+import Swal from 'sweetalert2';
import { CryptoService } from 'jslib/abstractions/crypto.service';
import { CryptoFunctionService } from 'jslib/abstractions/cryptoFunction.service';
@@ -6,16 +7,17 @@ import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { LogService } from 'jslib/abstractions/log.service';
import { Utils } from 'jslib/misc/utils';
import { SymmetricCryptoKey } from 'jslib/models/domain/symmetricCryptoKey';
+import { I18nService } from 'jslib/abstractions/i18n.service';
+import { UserService } from 'jslib/abstractions/user.service';
const MessageValidTimeout = 10 * 1000;
const EncryptionAlgorithm = 'sha1';
export class NativeMessagingService {
- private remotePublicKey: ArrayBuffer;
private sharedSecret: any;
constructor(private cryptoFunctionService: CryptoFunctionService, private cryptoService: CryptoService,
- private platformUtilService: PlatformUtilsService, private logService: LogService) {
+ private platformUtilService: PlatformUtilsService, private logService: LogService, private i18nService: I18nService, private userService: UserService) {
ipcRenderer.on('nativeMessaging', async (event: any, message: any) => {
this.messageHandler(message);
});
@@ -23,8 +25,24 @@ export class NativeMessagingService {
private async messageHandler(rawMessage: any) {
if (rawMessage.command == 'setupEncryption') {
- this.remotePublicKey = Utils.fromB64ToArray(rawMessage.publicKey).buffer;
- this.secureCommunication();
+ const remotePublicKey = Utils.fromB64ToArray(rawMessage.publicKey).buffer;
+ const fingerprint = (await this.cryptoService.getFingerprint(await this.userService.getUserId(), remotePublicKey)).join(' ');
+
+ const submitted = await Swal.fire({
+ title: this.i18nService.t('verifyBrowserTitle'),
+ html: `${this.i18nService.t('verifyBrowserDescription')}
${fingerprint}`,
+ showCancelButton: true,
+ cancelButtonText: this.i18nService.t('cancel'),
+ showConfirmButton: true,
+ confirmButtonText: this.i18nService.t('approve'),
+ allowOutsideClick: false,
+ });
+
+ if (submitted.value !== true) {
+ return;
+ }
+
+ this.secureCommunication(remotePublicKey);
return;
}
@@ -64,11 +82,11 @@ export class NativeMessagingService {
ipcRenderer.send('nativeMessagingReply', encrypted);
}
- private async secureCommunication() {
+ private async secureCommunication(remotePublicKey: ArrayBuffer) {
const secret = await this.cryptoFunctionService.randomBytes(64);
this.sharedSecret = new SymmetricCryptoKey(secret);
- const encryptedSecret = await this.cryptoFunctionService.rsaEncrypt(secret, this.remotePublicKey, EncryptionAlgorithm);
+ const encryptedSecret = await this.cryptoFunctionService.rsaEncrypt(secret, remotePublicKey, EncryptionAlgorithm);
ipcRenderer.send('nativeMessagingReply', {command: 'setupEncryption', sharedSecret: Utils.fromBufferToB64(encryptedSecret)});
}
}