Add settings toggle to enable/disable browser integration

This commit is contained in:
Hinton 2020-10-07 15:11:01 +02:00
parent 19edc24b0b
commit 45302e5bd5
7 changed files with 107 additions and 21 deletions

View File

@ -1,7 +1,7 @@
/* tslint:disable:no-console */
import IPC from 'ipc';
// Mostly copied from the example on
// Mostly based on the example from MDN,
// https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging
export default class NativeMessage {
ipc: IPC;

View File

@ -88,6 +88,16 @@
</div>
<small class="help-block">{{'disableFaviconDesc' | i18n}}</small>
</div>
<div class="form-group">
<div class="checkbox">
<label for="enableBrowserIntegration">
<input id="enableBrowserIntegration" type="checkbox" name="EnableBrowserIntegration"
[(ngModel)]="enableBrowserIntegration" (change)="saveBrowserIntegration()">
{{'enableBrowserIntegration' | i18n}}
</label>
</div>
<small class="help-block">{{'enableBrowserIntegrationDesc' | i18n}}</small>
</div>
<div class="form-group">
<div class="checkbox">
<label for="enableTray">

View File

@ -33,6 +33,7 @@ export class SettingsComponent implements OnInit {
vaultTimeoutAction: string;
pin: boolean = null;
disableFavicons: boolean = false;
enableBrowserIntegration: boolean = false;
enableMinToTray: boolean = false;
enableCloseToTray: boolean = false;
enableTray: boolean = false;
@ -119,6 +120,7 @@ export class SettingsComponent implements OnInit {
const pinSet = await this.vaultTimeoutService.isPinLockSet();
this.pin = pinSet[0] || pinSet[1];
this.disableFavicons = await this.storageService.get<boolean>(ConstantsService.disableFaviconKey);
this.enableBrowserIntegration = await this.storageService.get<boolean>(ElectronConstants.enableBrowserIntegration);
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);
@ -277,6 +279,11 @@ export class SettingsComponent implements OnInit {
});
}
async saveBrowserIntegration() {
await this.storageService.save(ElectronConstants.enableBrowserIntegration, this.enableBrowserIntegration);
this.messagingService.send(this.enableBrowserIntegration ? 'enableBrowserIntegration' : 'disableBrowserIntegration');
}
private callAnalytics(name: string, enabled: boolean) {
const status = enabled ? 'Enabled' : 'Disabled';
this.analytics.eventTrack.next({ action: `${status} ${name}` });

View File

@ -1401,5 +1401,11 @@
},
"masterPasswordPolicyRequirementsNotMet": {
"message": "Your new master password does not meet the policy requirements."
},
"enableBrowserIntegration": {
"message": "Enable browser integration"
},
"enableBrowserIntegrationDesc": {
"message": ""
}
}

View File

@ -144,6 +144,10 @@ export class Main {
await this.biometricMain.init();
}
if (await this.storageService.get<boolean>(ElectronConstants.enableBrowserIntegration)) {
this.nativeMessagingService.listen();
}
if (!app.isDefaultProtocolClient('bitwarden')) {
app.setAsDefaultProtocolClient('bitwarden');
}
@ -157,8 +161,6 @@ export class Main {
// tslint:disable-next-line
console.error(e);
});
this.nativeMessagingService.listen();
this.nativeMessagingService.generateManifests();
}
private processDeepLink(argv: string[]): void {

View File

@ -44,6 +44,14 @@ export class MessagingMain {
case 'hideToTray':
this.main.trayMain.hideToTray();
break;
case 'enableBrowserIntegration':
this.main.nativeMessagingService.generateManifests();
this.main.nativeMessagingService.listen();
break;
case 'disableBrowserIntegration':
this.main.nativeMessagingService.removeManifests();
this.main.nativeMessagingService.stop();
break;
default:
break;
}

View File

@ -38,6 +38,10 @@ export class NativeMessagingService {
ipc.server.start();
}
stop() {
ipc.server.stop();
}
generateManifests() {
const baseJson = {
'name': 'com.8bit.bitwarden',
@ -90,6 +94,35 @@ export class NativeMessagingService {
}
}
removeManifests() {
switch (process.platform) {
case 'win32':
this.deleteWindowsRegistry('HKCU\\SOFTWARE\\Mozilla\\NativeMessagingHosts\\com.8bit.bitwarden');
this.deleteWindowsRegistry('HKCU\\SOFTWARE\\Google\\Chrome\\NativeMessagingHosts\\com.8bit.bitwarden');
break;
case 'darwin':
if (existsSync('~/Library/Application Support/Mozilla/NativeMessagingHosts/com.8bit.bitwarden.json')) {
fs.unlink('~/Library/Application Support/Mozilla/NativeMessagingHosts/com.8bit.bitwarden.json')
}
if (existsSync('~/Library/Application Support/Google/Chrome/NativeMessagingHosts/com.8bit.bitwarden.json')) {
fs.unlink('~/Library/Application Support/Mozilla/NativeMessagingHosts/com.8bit.bitwarden.json')
}
break;
case 'linux':
if (existsSync('~/.mozilla/native-messaging-hosts/com.8bit.bitwarden.json')) {
fs.unlink('~/.mozilla/native-messaging-hosts/com.8bit.bitwarden.json')
}
if (existsSync('~/.config/google-chrome/NativeMessagingHosts/com.8bit.bitwarden.json')) {
fs.unlink('~/.config/google-chrome/NativeMessagingHosts/com.8bit.bitwarden.json')
}
break;
default:
break;
}
}
private writeManifest(destination: string, manifest: object) {
fs.writeFile(destination, JSON.stringify(manifest, null, 2)).catch(this.logService.error);
}
@ -106,7 +139,7 @@ export class NativeMessagingService {
}
}
private createWindowsRegistry(check: string, location: string, jsonFile: string) {
private async createWindowsRegistry(check: string, location: string, jsonFile: string) {
const regedit = require('regedit');
regedit.setExternalVBSLocation('resources/regedit/vbs');
@ -117,23 +150,43 @@ export class NativeMessagingService {
this.logService.debug(`Adding registry: ${location}`)
// Check installed
list(check)
.then(() => {
// Create path
return createKey(location);
})
.then(() => {
// Insert path to manifest
const obj: any = {};
obj[location] = {
'default': {
value: path.join(this.userPath, 'browsers', jsonFile),
type: 'REG_DEFAULT',
},
}
try {
await list(check)
} catch {
return;
}
return putValue(obj);
})
.catch(this.logService.error)
try {
await createKey(location);
// Insert path to manifest
const obj: any = {};
obj[location] = {
'default': {
value: path.join(this.userPath, 'browsers', jsonFile),
type: 'REG_DEFAULT',
},
}
return putValue(obj);
} catch (error) {
this.logService.error(error);
}
}
private async deleteWindowsRegistry(key: string) {
const regedit = require("regedit");
const list = util.promisify(regedit.list);
const deleteKey = util.promisify(regedit.deleteKey);
this.logService.debug(`Removing registry: ${location}`)
try {
await list(key);
await deleteKey(key);
} catch {
// Do nothing
}
}
}