mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-27 12:36:14 +01:00
Make fingerprint validation optional, update readme with debug info for native messaging
This commit is contained in:
parent
02a3fbde99
commit
e639fa6674
12
README.md
12
README.md
@ -26,6 +26,18 @@ npm install
|
||||
npm run electron
|
||||
```
|
||||
|
||||
**Debug Native Messaging**
|
||||
|
||||
Native Messaging (communication with the browser extension) works by having the browser start a lightweight proxy application baked into our desktop binary. To setup an environment which allows
|
||||
for easy debugging you will need to build the application for distribution, i.e. `npm run dist:<platform>`, start the dist version and enable desktop integration. This will write some manifests
|
||||
to disk, Consult the [native manifests](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_manifests#Manifest_location) documentation for more details of the manigest
|
||||
format, and the exact locations for the different platforms. *Note* that disabling the desktop integration will delete the manifests, and the files will need to be updated again.
|
||||
|
||||
The generated manifests are pre-configured with the production ID for the browser extensions. In order to use them with the development builds, the browser extension ID of the development build
|
||||
needs to be added to the `allowed_extensions` section of the manifest. These IDs are generated by the browser, and can be found in the extension settings within the browser.
|
||||
|
||||
It will then be possible to run the desktop application as usual using `npm run electron` and communicate with the browser.
|
||||
|
||||
# Contribute
|
||||
|
||||
Code contributions are welcome! Please commit any pull requests against the `master` branch. Learn more about how to contribute by reading the [`CONTRIBUTING.md`](CONTRIBUTING.md) file.
|
||||
|
@ -98,6 +98,16 @@
|
||||
</div>
|
||||
<small class="help-block">{{'enableBrowserIntegrationDesc' | i18n}}</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<label for="enableBrowserIntegrationFingerprint">
|
||||
<input id="enableBrowserIntegrationFingerprint" type="checkbox" name="EnableBrowserIntegrationFingerprint"
|
||||
[(ngModel)]="enableBrowserIntegrationFingerprint" (change)="saveBrowserIntegrationFingerprint()" [disabled]="!enableBrowserIntegration">
|
||||
{{'enableBrowserIntegrationFingerprint' | i18n}}
|
||||
</label>
|
||||
</div>
|
||||
<small class="help-block">{{'enableBrowserIntegrationFingerprintDesc' | i18n}}</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<label for="enableTray">
|
||||
|
@ -34,6 +34,7 @@ export class SettingsComponent implements OnInit {
|
||||
pin: boolean = null;
|
||||
disableFavicons: boolean = false;
|
||||
enableBrowserIntegration: boolean = false;
|
||||
enableBrowserIntegrationFingerprint: boolean = false;
|
||||
enableMinToTray: boolean = false;
|
||||
enableCloseToTray: boolean = false;
|
||||
enableTray: boolean = false;
|
||||
@ -146,6 +147,7 @@ export class SettingsComponent implements OnInit {
|
||||
this.disableFavicons = await this.storageService.get<boolean>(ConstantsService.disableFaviconKey);
|
||||
this.enableBrowserIntegration = await this.storageService.get<boolean>(
|
||||
ElectronConstants.enableBrowserIntegration);
|
||||
this.enableBrowserIntegrationFingerprint = await this.storageService.get<boolean>(ElectronConstants.enableBrowserIntegrationFingerprint);
|
||||
this.enableMinToTray = await this.storageService.get<boolean>(ElectronConstants.enableMinimizeToTrayKey);
|
||||
this.enableCloseToTray = await this.storageService.get<boolean>(ElectronConstants.enableCloseToTrayKey);
|
||||
this.enableTray = await this.storageService.get<boolean>(ElectronConstants.enableTrayKey);
|
||||
@ -329,6 +331,15 @@ export class SettingsComponent implements OnInit {
|
||||
|
||||
await this.storageService.save(ElectronConstants.enableBrowserIntegration, this.enableBrowserIntegration);
|
||||
this.messagingService.send(this.enableBrowserIntegration ? 'enableBrowserIntegration' : 'disableBrowserIntegration');
|
||||
|
||||
if (!this.enableBrowserIntegration) {
|
||||
this.enableBrowserIntegrationFingerprint = false;
|
||||
this.saveBrowserIntegrationFingerprint();
|
||||
}
|
||||
}
|
||||
|
||||
async saveBrowserIntegrationFingerprint() {
|
||||
await this.storageService.save(ElectronConstants.enableBrowserIntegrationFingerprint, this.enableBrowserIntegrationFingerprint);
|
||||
}
|
||||
|
||||
private callAnalytics(name: string, enabled: boolean) {
|
||||
|
@ -135,7 +135,7 @@ const eventService = new EventService(storageService, apiService, userService, c
|
||||
const systemService = new SystemService(storageService, vaultTimeoutService, messagingService, platformUtilsService,
|
||||
null);
|
||||
const nativeMessagingService = new NativeMessagingService(cryptoFunctionService, cryptoService, platformUtilsService,
|
||||
logService, i18nService, userService, messagingService, vaultTimeoutService);
|
||||
logService, i18nService, userService, messagingService, vaultTimeoutService, storageService);
|
||||
|
||||
const analytics = new Analytics(window, () => isDev(), platformUtilsService, storageService, appIdService);
|
||||
containerService.attachToGlobal(window);
|
||||
|
@ -1453,6 +1453,12 @@
|
||||
"browserIntegrationMasOnlyDesc": {
|
||||
"message": "Unfortunately browser integration is only supported in the Mac App Store version for now."
|
||||
},
|
||||
"enableBrowserIntegrationFingerprint": {
|
||||
"message": "Require verification for browser integration"
|
||||
},
|
||||
"enableBrowserIntegrationFingerprintDesc": {
|
||||
"message": "Enable an additional layer of security by requiring fingerprint phrase validation when establishing a link between your desktop and browser. When enabled, this requires user intervention and verification each time a connection is established."
|
||||
},
|
||||
"approve": {
|
||||
"message": "Approve"
|
||||
},
|
||||
|
@ -10,6 +10,7 @@ import { WindowMain } from 'jslib/electron/window.main';
|
||||
|
||||
export class NativeMessagingMain {
|
||||
private connected = false;
|
||||
private socket: any;
|
||||
|
||||
constructor(private logService: LogService, private windowMain: WindowMain, private userPath: string, private appPath: string) {}
|
||||
|
||||
@ -19,15 +20,16 @@ export class NativeMessagingMain {
|
||||
|
||||
ipc.serve(() => {
|
||||
ipc.server.on('message', (data: any, socket: any) => {
|
||||
// This is a ugly hack until electron is updated 7.0.0 which supports ipcMain.invoke
|
||||
this.socket = socket;
|
||||
this.windowMain.win.webContents.send('nativeMessaging', data);
|
||||
ipcMain.once('nativeMessagingReply', (event, msg) => {
|
||||
if (msg != null) {
|
||||
this.send(msg, socket);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on('nativeMessagingReply', (event, msg) => {
|
||||
if (this.socket != null && msg != null) {
|
||||
this.send(msg, this.socket);
|
||||
}
|
||||
})
|
||||
|
||||
ipc.server.on('connect', () => {
|
||||
this.connected = true;
|
||||
})
|
||||
@ -36,6 +38,7 @@ export class NativeMessagingMain {
|
||||
'socket.disconnected',
|
||||
(socket: any, destroyedSocketID: any) => {
|
||||
this.connected = false;
|
||||
this.socket = null;
|
||||
ipc.log(
|
||||
'client ' + destroyedSocketID + ' has disconnected!'
|
||||
);
|
||||
|
@ -12,6 +12,8 @@ import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service';
|
||||
|
||||
import { Utils } from 'jslib/misc/utils';
|
||||
import { SymmetricCryptoKey } from 'jslib/models/domain/symmetricCryptoKey';
|
||||
import { StorageService } from 'jslib/abstractions';
|
||||
import { ElectronConstants } from 'jslib/electron/electronConstants';
|
||||
|
||||
const MessageValidTimeout = 10 * 1000;
|
||||
const EncryptionAlgorithm = 'sha1';
|
||||
@ -21,7 +23,7 @@ export class NativeMessagingService {
|
||||
|
||||
constructor(private cryptoFunctionService: CryptoFunctionService, private cryptoService: CryptoService,
|
||||
private platformUtilService: PlatformUtilsService, private logService: LogService, private i18nService: I18nService,
|
||||
private userService: UserService, private messagingService: MessagingService, private vaultTimeoutService: VaultTimeoutService) {
|
||||
private userService: UserService, private messagingService: MessagingService, private vaultTimeoutService: VaultTimeoutService, private storageService: StorageService) {
|
||||
ipcRenderer.on('nativeMessaging', async (event: any, message: any) => {
|
||||
this.messageHandler(message);
|
||||
});
|
||||
@ -34,25 +36,30 @@ export class NativeMessagingService {
|
||||
// Request to setup secure encryption
|
||||
if (rawMessage.command === 'setupEncryption') {
|
||||
const remotePublicKey = Utils.fromB64ToArray(rawMessage.publicKey).buffer;
|
||||
const fingerprint = (await this.cryptoService.getFingerprint(await this.userService.getUserId(), remotePublicKey)).join(' ');
|
||||
|
||||
this.messagingService.send('setFocus');
|
||||
if (await this.storageService.get<boolean>(ElectronConstants.enableBrowserIntegrationFingerprint)) {
|
||||
ipcRenderer.send('nativeMessagingReply', {command: 'verifyFingerprint', appId: appId});
|
||||
|
||||
// Await confirmation that fingerprint is correct
|
||||
const submitted = await Swal.fire({
|
||||
title: this.i18nService.t('verifyBrowserTitle'),
|
||||
html: `${this.i18nService.t('verifyBrowserDesc')}<br><br><strong>${fingerprint}</strong>`,
|
||||
showCancelButton: true,
|
||||
cancelButtonText: this.i18nService.t('cancel'),
|
||||
showConfirmButton: true,
|
||||
confirmButtonText: this.i18nService.t('approve'),
|
||||
allowOutsideClick: false,
|
||||
});
|
||||
const fingerprint = (await this.cryptoService.getFingerprint(await this.userService.getUserId(), remotePublicKey)).join(' ');
|
||||
|
||||
if (submitted.value !== true) {
|
||||
return;
|
||||
this.messagingService.send('setFocus');
|
||||
|
||||
// Await confirmation that fingerprint is correct
|
||||
const submitted = await Swal.fire({
|
||||
title: this.i18nService.t('verifyBrowserTitle'),
|
||||
html: `${this.i18nService.t('verifyBrowserDesc')}<br><br><strong>${fingerprint}</strong>`,
|
||||
showCancelButton: true,
|
||||
cancelButtonText: this.i18nService.t('cancel'),
|
||||
showConfirmButton: true,
|
||||
confirmButtonText: this.i18nService.t('approve'),
|
||||
allowOutsideClick: false,
|
||||
});
|
||||
|
||||
if (submitted.value !== true) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.secureCommunication(remotePublicKey, appId);
|
||||
return;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user