mirror of
https://github.com/bitwarden/browser
synced 2026-02-19 02:44:01 +00:00
Merge branch 'master' of github.com:bitwarden/browser into feature/safari-webext
# Conflicts: # src/browser/safariApp.ts # src/safari/safari/SafariExtensionViewController.swift # src/services/browserPlatformUtils.service.ts
This commit is contained in:
@@ -21,6 +21,7 @@ import {
|
||||
UserService,
|
||||
VaultTimeoutService,
|
||||
} from 'jslib/services';
|
||||
import { ConsoleLogService } from 'jslib/services/consoleLog.service';
|
||||
import { EventService } from 'jslib/services/event.service';
|
||||
import { ExportService } from 'jslib/services/export.service';
|
||||
import { NotificationsService } from 'jslib/services/notifications.service';
|
||||
@@ -93,6 +94,7 @@ export default class MainBackground {
|
||||
i18nService: I18nServiceAbstraction;
|
||||
platformUtilsService: PlatformUtilsServiceAbstraction;
|
||||
constantsService: ConstantsService;
|
||||
consoleLogService: ConsoleLogService;
|
||||
cryptoService: CryptoServiceAbstraction;
|
||||
cryptoFunctionService: CryptoFunctionServiceAbstraction;
|
||||
tokenService: TokenServiceAbstraction;
|
||||
@@ -169,8 +171,9 @@ export default class MainBackground {
|
||||
this.secureStorageService = new BrowserStorageService();
|
||||
this.i18nService = new I18nService(BrowserApi.getUILanguage(window));
|
||||
this.cryptoFunctionService = new WebCryptoFunctionService(window, this.platformUtilsService);
|
||||
this.consoleLogService = new ConsoleLogService(false);
|
||||
this.cryptoService = new CryptoService(this.storageService, this.secureStorageService,
|
||||
this.cryptoFunctionService, this.platformUtilsService);
|
||||
this.cryptoFunctionService, this.platformUtilsService, this.consoleLogService);
|
||||
this.tokenService = new TokenService(this.storageService);
|
||||
this.appIdService = new AppIdService(this.storageService);
|
||||
this.apiService = new ApiService(this.tokenService, this.platformUtilsService,
|
||||
@@ -178,7 +181,7 @@ export default class MainBackground {
|
||||
this.userService = new UserService(this.tokenService, this.storageService);
|
||||
this.authService = new AuthService(this.cryptoService, this.apiService, this.userService,
|
||||
this.tokenService, this.appIdService, this.i18nService, this.platformUtilsService,
|
||||
this.messagingService, this.vaultTimeoutService);
|
||||
this.messagingService, this.vaultTimeoutService, this.consoleLogService);
|
||||
this.settingsService = new SettingsService(this.userService, this.storageService);
|
||||
this.cipherService = new CipherService(this.cryptoService, this.userService, this.settingsService,
|
||||
this.apiService, this.storageService, this.i18nService, () => this.searchService);
|
||||
@@ -186,7 +189,7 @@ export default class MainBackground {
|
||||
this.storageService, this.i18nService, this.cipherService);
|
||||
this.collectionService = new CollectionService(this.cryptoService, this.userService, this.storageService,
|
||||
this.i18nService);
|
||||
this.searchService = new SearchService(this.cipherService);
|
||||
this.searchService = new SearchService(this.cipherService, this.consoleLogService);
|
||||
this.sendService = new SendService(this.cryptoService, this.userService, this.apiService, this.storageService,
|
||||
this.i18nService, this.cryptoFunctionService);
|
||||
this.stateService = new StateService();
|
||||
@@ -220,7 +223,7 @@ export default class MainBackground {
|
||||
this.auditService = new AuditService(this.cryptoFunctionService, this.apiService);
|
||||
this.exportService = new ExportService(this.folderService, this.cipherService, this.apiService);
|
||||
this.notificationsService = new NotificationsService(this.userService, this.syncService, this.appIdService,
|
||||
this.apiService, this.vaultTimeoutService, () => this.logout(true));
|
||||
this.apiService, this.vaultTimeoutService, () => this.logout(true), this.consoleLogService);
|
||||
this.environmentService = new EnvironmentService(this.apiService, this.storageService,
|
||||
this.notificationsService);
|
||||
this.analytics = new Analytics(window, () => BrowserApi.gaFilter(), this.platformUtilsService,
|
||||
@@ -245,7 +248,7 @@ export default class MainBackground {
|
||||
this.analytics, this.notificationsService, this.systemService, this.vaultTimeoutService,
|
||||
this.environmentService, this.policyService, this.userService);
|
||||
this.nativeMessagingBackground = new NativeMessagingBackground(this.storageService, this.cryptoService, this.cryptoFunctionService,
|
||||
this.vaultTimeoutService, this.runtimeBackground, this.i18nService, this.userService, this.messagingService);
|
||||
this.vaultTimeoutService, this.runtimeBackground, this.i18nService, this.userService, this.messagingService, this.appIdService);
|
||||
this.commandsBackground = new CommandsBackground(this, this.passwordGenerationService,
|
||||
this.platformUtilsService, this.analytics, this.vaultTimeoutService);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ConstantsService } from 'jslib/services/constants.service';
|
||||
import { AppIdService } from 'jslib/abstractions/appId.service';
|
||||
import { CryptoFunctionService } from 'jslib/abstractions/cryptoFunction.service';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
@@ -23,15 +24,19 @@ export class NativeMessagingBackground {
|
||||
|
||||
private resolver: any = null;
|
||||
private privateKey: ArrayBuffer = null;
|
||||
private publicKey: ArrayBuffer = null;
|
||||
private secureSetupResolve: any = null;
|
||||
private sharedSecret: SymmetricCryptoKey;
|
||||
private appId: string;
|
||||
|
||||
constructor(private storageService: StorageService, private cryptoService: CryptoService,
|
||||
private cryptoFunctionService: CryptoFunctionService, private vaultTimeoutService: VaultTimeoutService,
|
||||
private runtimeBackground: RuntimeBackground, private i18nService: I18nService, private userService: UserService,
|
||||
private messagingService: MessagingService) {}
|
||||
private messagingService: MessagingService, private appIdService: AppIdService) {}
|
||||
|
||||
async connect() {
|
||||
this.appId = await this.appIdService.getAppId();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
this.port = BrowserApi.connectNative('com.8bit.bitwarden');
|
||||
|
||||
@@ -58,6 +63,11 @@ export class NativeMessagingBackground {
|
||||
this.port.disconnect();
|
||||
break;
|
||||
case 'setupEncryption':
|
||||
// Ignore since it belongs to another device
|
||||
if (message.appId !== this.appId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const encrypted = Utils.fromB64ToArray(message.sharedSecret);
|
||||
const decrypted = await this.cryptoFunctionService.rsaDecrypt(encrypted.buffer, this.privateKey, EncryptionAlgorithm);
|
||||
|
||||
@@ -65,6 +75,11 @@ export class NativeMessagingBackground {
|
||||
this.secureSetupResolve();
|
||||
break;
|
||||
case 'invalidateEncryption':
|
||||
// Ignore since it belongs to another device
|
||||
if (message.appId !== this.appId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.sharedSecret = null;
|
||||
this.privateKey = null;
|
||||
this.connected = false;
|
||||
@@ -75,8 +90,20 @@ export class NativeMessagingBackground {
|
||||
confirmText: this.i18nService.t('ok'),
|
||||
type: 'error',
|
||||
});
|
||||
break;
|
||||
case 'verifyFingerprint': {
|
||||
if (this.sharedSecret == null) {
|
||||
this.showFingerprintDialog();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
this.onMessage(message);
|
||||
// Ignore since it belongs to another device
|
||||
if (message.appId !== this.appId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.onMessage(message.message);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -88,9 +115,7 @@ export class NativeMessagingBackground {
|
||||
error = chrome.runtime.lastError.message;
|
||||
}
|
||||
|
||||
if (error === 'Specified native messaging host not found.' ||
|
||||
error === 'Access to the specified native messaging host is forbidden.' ||
|
||||
error === 'An unexpected error occurred') {
|
||||
if (error != null) {
|
||||
this.messagingService.send('showDialog', {
|
||||
text: this.i18nService.t('desktopIntegrationDisabledDesc'),
|
||||
title: this.i18nService.t('desktopIntegrationDisabledTitle'),
|
||||
@@ -118,7 +143,7 @@ export class NativeMessagingBackground {
|
||||
message.timestamp = Date.now();
|
||||
|
||||
const encrypted = await this.cryptoService.encrypt(JSON.stringify(message), this.sharedSecret);
|
||||
this.port.postMessage(encrypted);
|
||||
this.postMessage({appId: this.appId, message: encrypted});
|
||||
}
|
||||
|
||||
getResponse(): Promise<any> {
|
||||
@@ -127,6 +152,27 @@ export class NativeMessagingBackground {
|
||||
});
|
||||
}
|
||||
|
||||
private postMessage(message: any) {
|
||||
// Wrap in try-catch to when the port disconnected without triggering `onDisconnect`.
|
||||
try {
|
||||
this.port.postMessage(message);
|
||||
} catch (e) {
|
||||
// tslint:disable-next-line
|
||||
console.error("NativeMessaging port disconnected, disconnecting.");
|
||||
|
||||
this.sharedSecret = null;
|
||||
this.privateKey = null;
|
||||
this.connected = false;
|
||||
|
||||
this.messagingService.send('showDialog', {
|
||||
text: this.i18nService.t('nativeMessagingInvalidEncryptionDesc'),
|
||||
title: this.i18nService.t('nativeMessagingInvalidEncryptionTitle'),
|
||||
confirmText: this.i18nService.t('ok'),
|
||||
type: 'error',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async onMessage(rawMessage: any) {
|
||||
const message = JSON.parse(await this.cryptoService.decryptToUtf8(rawMessage, this.sharedSecret));
|
||||
|
||||
@@ -140,6 +186,24 @@ export class NativeMessagingBackground {
|
||||
case 'biometricUnlock':
|
||||
await this.storageService.remove(ConstantsService.biometricAwaitingAcceptance);
|
||||
|
||||
if (message.response === 'not enabled') {
|
||||
this.messagingService.send('showDialog', {
|
||||
text: this.i18nService.t('biometricsNotEnabledDesc'),
|
||||
title: this.i18nService.t('biometricsNotEnabledTitle'),
|
||||
confirmText: this.i18nService.t('ok'),
|
||||
type: 'error',
|
||||
});
|
||||
break;
|
||||
} else if (message.response === 'not supported') {
|
||||
this.messagingService.send('showDialog', {
|
||||
text: this.i18nService.t('biometricsNotSupportedDesc'),
|
||||
title: this.i18nService.t('biometricsNotSupportedTitle'),
|
||||
confirmText: this.i18nService.t('ok'),
|
||||
type: 'error',
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
const enabled = await this.storageService.get(ConstantsService.biometricUnlockKey);
|
||||
if (enabled === null || enabled === false) {
|
||||
if (message.response === 'unlocked') {
|
||||
@@ -171,17 +235,10 @@ export class NativeMessagingBackground {
|
||||
|
||||
private async secureCommunication() {
|
||||
const [publicKey, privateKey] = await this.cryptoFunctionService.rsaGenerateKeyPair(2048);
|
||||
this.publicKey = publicKey;
|
||||
this.privateKey = privateKey;
|
||||
|
||||
this.sendUnencrypted({command: 'setupEncryption', publicKey: Utils.fromBufferToB64(publicKey)});
|
||||
const fingerprint = (await this.cryptoService.getFingerprint(await this.userService.getUserId(), publicKey)).join(' ');
|
||||
|
||||
this.messagingService.send('showDialog', {
|
||||
html: `${this.i18nService.t('desktopIntegrationVerificationText')}<br><br><strong>${fingerprint}</strong>`,
|
||||
title: this.i18nService.t('desktopSyncVerificationTitle'),
|
||||
confirmText: this.i18nService.t('ok'),
|
||||
type: 'warning',
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => this.secureSetupResolve = resolve);
|
||||
}
|
||||
@@ -193,6 +250,17 @@ export class NativeMessagingBackground {
|
||||
|
||||
message.timestamp = Date.now();
|
||||
|
||||
this.port.postMessage(message);
|
||||
this.postMessage({appId: this.appId, message: message});
|
||||
}
|
||||
|
||||
private async showFingerprintDialog() {
|
||||
const fingerprint = (await this.cryptoService.getFingerprint(await this.userService.getUserId(), this.publicKey)).join(' ');
|
||||
|
||||
this.messagingService.send('showDialog', {
|
||||
html: `${this.i18nService.t('desktopIntegrationVerificationText')}<br><br><strong>${fingerprint}</strong>`,
|
||||
title: this.i18nService.t('desktopSyncVerificationTitle'),
|
||||
confirmText: this.i18nService.t('ok'),
|
||||
type: 'warning',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,7 +455,7 @@ export default class RuntimeBackground {
|
||||
if (policy.enabled) {
|
||||
const org = await this.userService.getOrganization(policy.organizationId);
|
||||
if (org != null && org.enabled && org.usePolicies && !org.isAdmin
|
||||
&& org.status == OrganizationUserStatusType.Confirmed) {
|
||||
&& org.status === OrganizationUserStatusType.Confirmed) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user