1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-02 13:23:29 +01:00
bitwarden-browser/src/services/nativeMessaging.service.ts

75 lines
3.1 KiB
TypeScript
Raw Normal View History

import { ipcRenderer } from 'electron';
2020-10-05 20:05:48 +02:00
import { CryptoService } from 'jslib/abstractions/crypto.service';
2020-10-16 17:09:17 +02:00
import { CryptoFunctionService } from 'jslib/abstractions/cryptoFunction.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { LogService } from 'jslib/abstractions/log.service';
2020-10-16 17:09:17 +02:00
import { Utils } from 'jslib/misc/utils';
2020-10-19 12:21:07 +02:00
import { SymmetricCryptoKey } from 'jslib/models/domain/symmetricCryptoKey';
const MessageValidTimeout = 10 * 1000;
2020-10-19 12:21:07 +02:00
const EncryptionAlgorithm = 'sha1';
export class NativeMessagingService {
2020-10-16 17:09:17 +02:00
private remotePublicKey: ArrayBuffer;
2020-10-19 12:21:07 +02:00
private sharedSecret: any;
2020-10-16 17:09:17 +02:00
constructor(private cryptoFunctionService: CryptoFunctionService, private cryptoService: CryptoService,
private platformUtilService: PlatformUtilsService, private logService: LogService) {
ipcRenderer.on('nativeMessaging', async (event: any, message: any) => {
this.messageHandler(message);
});
}
private async messageHandler(rawMessage: any) {
2020-10-16 17:09:17 +02:00
if (rawMessage.command == 'setupEncryption') {
this.remotePublicKey = Utils.fromB64ToArray(rawMessage.publicKey).buffer;
this.secureCommunication();
return;
}
2020-10-05 20:05:48 +02:00
2020-10-19 12:21:07 +02:00
// TODO: Add error handler, if it fails we should invalidate the key and send a re-authenticate message to browser
const message = JSON.parse(await this.cryptoService.decryptToUtf8(rawMessage, this.sharedSecret));
if (Math.abs(message.timestamp - Date.now()) > MessageValidTimeout) {
this.logService.error('NativeMessage is to old, ignoring.');
return;
}
switch (message.command) {
case 'biometricUnlock':
if (! this.platformUtilService.supportsBiometric()) {
ipcRenderer.send('nativeMessagingSync', )
return this.send({command: 'biometricUnlock', response: 'not supported'})
}
const response = await this.platformUtilService.authenticateBiometric();
if (response) {
this.send({command: 'biometricUnlock', response: 'unlocked'});
} else {
this.send({command: 'biometricUnlock', response: 'canceled'});
}
2020-10-12 18:03:16 +02:00
break;
default:
this.logService.error('NativeMessage, got unknown command.');
}
}
private async send(message: any) {
message.timestamp = Date.now();
2020-10-19 12:21:07 +02:00
const encrypted = await this.cryptoService.encrypt(JSON.stringify(message), this.sharedSecret);
ipcRenderer.send('nativeMessagingReply', encrypted);
}
2020-10-16 17:09:17 +02:00
private async secureCommunication() {
2020-10-19 12:21:07 +02:00
const secret = await this.cryptoFunctionService.randomBytes(64);
this.sharedSecret = new SymmetricCryptoKey(secret);
2020-10-16 17:09:17 +02:00
2020-10-19 12:21:07 +02:00
const encryptedSecret = await this.cryptoFunctionService.rsaEncrypt(secret, this.remotePublicKey, EncryptionAlgorithm);
ipcRenderer.send('nativeMessagingReply', {command: 'setupEncryption', sharedSecret: Utils.fromBufferToB64(encryptedSecret)});
2020-10-16 17:09:17 +02:00
}
}