From 260820711e50db1303c8b2f0aca797a4941e52a2 Mon Sep 17 00:00:00 2001 From: Sorin Davidoi Date: Mon, 31 Aug 2020 22:33:01 +0200 Subject: [PATCH 01/23] feat: Use system theme if available Depends on https://github.com/bitwarden/jslib/pull/161. Closes https://github.com/bitwarden/browser/issues/1256. --- src/popup/services/services.module.ts | 11 ++++++++--- src/services/browserPlatformUtils.service.ts | 11 +++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/popup/services/services.module.ts b/src/popup/services/services.module.ts index 526eff1fe3..8b27c899be 100644 --- a/src/popup/services/services.module.ts +++ b/src/popup/services/services.module.ts @@ -72,7 +72,7 @@ export const authService = new AuthService(getBgService('cryptoSe export const searchService = new PopupSearchService(getBgService('searchService')(), getBgService('cipherService')(), getBgService('platformUtilsService')()); -export function initFactory(i18nService: I18nService, storageService: StorageService, +export function initFactory(platformUtilsService: PlatformUtilsService, i18nService: I18nService, storageService: StorageService, popupUtilsService: PopupUtilsService): Function { return async () => { if (!popupUtilsService.inPopup(window)) { @@ -89,7 +89,12 @@ export function initFactory(i18nService: I18nService, storageService: StorageSer let theme = await storageService.get(ConstantsService.themeKey); if (theme == null) { - theme = 'light'; + theme = platformUtilsService.getDefaultSystemTheme(); + + platformUtilsService.onDefaultSystemThemeChange(theme => { + window.document.documentElement.classList.remove('theme_light', 'theme_dark'); + window.document.documentElement.classList.add('theme_' + theme); + }); } window.document.documentElement.classList.add('locale_' + i18nService.translationLocale); window.document.documentElement.classList.add('theme_' + theme); @@ -169,7 +174,7 @@ export function initFactory(i18nService: I18nService, storageService: StorageSer { provide: APP_INITIALIZER, useFactory: initFactory, - deps: [I18nService, StorageService, PopupUtilsService], + deps: [PlatformUtilsService, I18nService, StorageService, PopupUtilsService], multi: true, }, { diff --git a/src/services/browserPlatformUtils.service.ts b/src/services/browserPlatformUtils.service.ts index 13c6516c6f..7c59ab8ba2 100644 --- a/src/services/browserPlatformUtils.service.ts +++ b/src/services/browserPlatformUtils.service.ts @@ -16,6 +16,7 @@ export default class BrowserPlatformUtilsService implements PlatformUtilsService private showDialogResolves = new Map void, date: Date }>(); private deviceCache: DeviceType = null; private analyticsIdCache: string = null; + private prefersColorSchemeDark = window.matchMedia('(prefers-color-scheme: dark)'); constructor(private messagingService: MessagingService, private clipboardWriteCallback: (clipboardValue: string, clearMs: number) => void) { } @@ -308,4 +309,14 @@ export default class BrowserPlatformUtilsService implements PlatformUtilsService private isSafariExtension(): boolean { return (window as any).safariAppExtension === true; } + + getDefaultSystemTheme() { + return this.prefersColorSchemeDark.matches ? 'dark' : 'light'; + } + + onDefaultSystemThemeChange(callback: ((theme: 'light' | 'dark') => unknown)) { + this.prefersColorSchemeDark.addListener(({ matches }) => { + callback(matches ? 'dark' : 'light'); + }); + } } From cc59905cc26612a5fa62e69df4875e27ac78a249 Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Thu, 3 Sep 2020 11:24:13 -0400 Subject: [PATCH 02/23] Update services.module.ts --- src/popup/services/services.module.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/popup/services/services.module.ts b/src/popup/services/services.module.ts index 8b27c899be..b35d4fd7b3 100644 --- a/src/popup/services/services.module.ts +++ b/src/popup/services/services.module.ts @@ -91,7 +91,7 @@ export function initFactory(platformUtilsService: PlatformUtilsService, i18nServ if (theme == null) { theme = platformUtilsService.getDefaultSystemTheme(); - platformUtilsService.onDefaultSystemThemeChange(theme => { + platformUtilsService.onDefaultSystemThemeChange((theme) => { window.document.documentElement.classList.remove('theme_light', 'theme_dark'); window.document.documentElement.classList.add('theme_' + theme); }); From deae7a265374766386a33b2c011768bbe7062991 Mon Sep 17 00:00:00 2001 From: Marek Ciupak <6394528+marekciupak@users.noreply.github.com> Date: Thu, 8 Oct 2020 00:16:37 +0200 Subject: [PATCH 03/23] Upgrade bl: 2.2.0 -> 2.2.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To get rid of the following vulnerability: ┌───────────────┬──────────────────────────────────────────────────────────────┐ │ High │ Remote Memory Exposure │ ├───────────────┼──────────────────────────────────────────────────────────────┤ │ Package │ bl │ ├───────────────┼──────────────────────────────────────────────────────────────┤ │ Dependency of │ @microsoft/signalr-protocol-msgpack │ ├───────────────┼──────────────────────────────────────────────────────────────┤ │ Path │ @microsoft/signalr-protocol-msgpack > msgpack5 > bl │ ├───────────────┼──────────────────────────────────────────────────────────────┤ │ More info │ https://npmjs.com/advisories/1555 │ └───────────────┴──────────────────────────────────────────────────────────────┘ --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6a8db88c15..b223a806d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1778,9 +1778,9 @@ "dev": true }, "bl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.0.tgz", - "integrity": "sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", "requires": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" From e23d96a35002099b25f8abf87aa97e3f1bbe55f8 Mon Sep 17 00:00:00 2001 From: Matt Gibson Date: Mon, 14 Dec 2020 11:56:40 -0600 Subject: [PATCH 04/23] Add ConsoleLogService dependency from jslib (#1488) * Pre-emptively add new jslib dependency * Add ConsoleLogService dependency * Update jslib Co-authored-by: Matt Gibson --- jslib | 2 +- package.json | 1 + src/background/main.background.ts | 11 +++++++---- src/background/runtime.background.ts | 2 +- src/popup/services/popup-search.service.ts | 6 ++++-- src/popup/services/services.module.ts | 5 +++-- 6 files changed, 17 insertions(+), 10 deletions(-) diff --git a/jslib b/jslib index 72bf18f369..2c414ce27a 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit 72bf18f369068d36767794bdc0ca377f734cf373 +Subproject commit 2c414ce27a5c14f6cd7f86cfd07096a192d058ca diff --git a/package.json b/package.json index 113bccba15..764d5e0c48 100644 --- a/package.json +++ b/package.json @@ -94,6 +94,7 @@ "angular2-toaster": "8.0.0", "angulartics2": "9.1.0", "big-integer": "1.6.36", + "browser-process-hrtime": "1.0.0", "core-js": "2.6.2", "duo_web_sdk": "git+https://github.com/duosecurity/duo_web_sdk.git", "font-awesome": "4.7.0", diff --git a/src/background/main.background.ts b/src/background/main.background.ts index c3e235015c..07b80e35bd 100644 --- a/src/background/main.background.ts +++ b/src/background/main.background.ts @@ -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.platformUtilsService); 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, diff --git a/src/background/runtime.background.ts b/src/background/runtime.background.ts index c7ef83e954..cb6cede46d 100644 --- a/src/background/runtime.background.ts +++ b/src/background/runtime.background.ts @@ -479,7 +479,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; } } diff --git a/src/popup/services/popup-search.service.ts b/src/popup/services/popup-search.service.ts index 37a9d0ecf0..2bab18acee 100644 --- a/src/popup/services/popup-search.service.ts +++ b/src/popup/services/popup-search.service.ts @@ -1,10 +1,12 @@ import { CipherService } from 'jslib/abstractions/cipher.service'; +import { ConsoleLogService } from 'jslib/services/consoleLog.service'; import { SearchService } from 'jslib/services/search.service'; export class PopupSearchService extends SearchService { - constructor(private mainSearchService: SearchService, cipherService: CipherService) { - super(cipherService); + constructor(private mainSearchService: SearchService, cipherService: CipherService, + consoleLogService: ConsoleLogService) { + super(cipherService, consoleLogService); } clearIndex() { diff --git a/src/popup/services/services.module.ts b/src/popup/services/services.module.ts index 6791075017..6a84ee7e55 100644 --- a/src/popup/services/services.module.ts +++ b/src/popup/services/services.module.ts @@ -50,6 +50,7 @@ import { AuthService } from 'jslib/services/auth.service'; import { ConstantsService } from 'jslib/services/constants.service'; import { SearchService } from 'jslib/services/search.service'; import { StateService } from 'jslib/services/state.service'; +import { ConsoleLogService } from 'jslib/services/consoleLog.service'; import { Analytics } from 'jslib/misc/analytics'; @@ -69,9 +70,9 @@ export const authService = new AuthService(getBgService('cryptoSe getBgService('apiService')(), getBgService('userService')(), getBgService('tokenService')(), getBgService('appIdService')(), getBgService('i18nService')(), getBgService('platformUtilsService')(), - messagingService, getBgService('vaultTimeoutService')()); + messagingService, getBgService('vaultTimeoutService')(), getBgService('consoleLogService')()); export const searchService = new PopupSearchService(getBgService('searchService')(), - getBgService('cipherService')()); + getBgService('cipherService')(), getBgService('consoleLogService')()); export function initFactory(i18nService: I18nService, storageService: StorageService, popupUtilsService: PopupUtilsService): Function { From 29c624e37b9e7d9f46625b239b235841da241c4e Mon Sep 17 00:00:00 2001 From: Matt Gibson Date: Tue, 15 Dec 2020 10:26:01 -0600 Subject: [PATCH 05/23] Add totp copy to clipboard button to cipher view (#1493) * Add totp copy to clipboard button to cipher view * Hide quick-copy rather than disable if no totp * Revert to disabled TOTP button * Enforce premium access to TOTPs * Update jslib reference --- jslib | 2 +- .../components/action-buttons.component.html | 5 ++++ .../components/action-buttons.component.ts | 23 +++++++++++++++---- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/jslib b/jslib index 2c414ce27a..cc801ce0d7 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit 2c414ce27a5c14f6cd7f86cfd07096a192d058ca +Subproject commit cc801ce0d7e200a365bed02c35b8d97666dbeab4 diff --git a/src/popup/components/action-buttons.component.html b/src/popup/components/action-buttons.component.html index f6c225f51b..5d81817e9c 100644 --- a/src/popup/components/action-buttons.component.html +++ b/src/popup/components/action-buttons.component.html @@ -16,6 +16,11 @@ [ngClass]="{disabled: (!cipher.login.password || !cipher.viewPassword)}"> + + + Date: Tue, 15 Dec 2020 16:09:52 -0500 Subject: [PATCH 06/23] Add locale info for hint equals password (#1458) Co-authored-by: Kyle Spearrin --- src/_locales/en/messages.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 946dba4b98..6db7940fe1 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -1381,6 +1381,9 @@ "privacyPolicy": { "message": "Privacy Policy" }, + "hintEqualsPassword": { + "message": "Your password hint cannot be the same as your password." + }, "ok": { "message": "Ok" }, From c4185fe6ee54194ae923d617be94c0ae45bdbebe Mon Sep 17 00:00:00 2001 From: Hinton Date: Wed, 16 Dec 2020 15:47:30 +0100 Subject: [PATCH 07/23] Add support for multiple concurrent extensions with native messaging --- src/background/main.background.ts | 2 +- src/background/nativeMessaging.background.ts | 27 +++++++++++++++++--- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/background/main.background.ts b/src/background/main.background.ts index 07b80e35bd..a929d52749 100644 --- a/src/background/main.background.ts +++ b/src/background/main.background.ts @@ -248,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); diff --git a/src/background/nativeMessaging.background.ts b/src/background/nativeMessaging.background.ts index 88397c0538..6cebf49dfd 100644 --- a/src/background/nativeMessaging.background.ts +++ b/src/background/nativeMessaging.background.ts @@ -12,6 +12,7 @@ import { SymmetricCryptoKey } from 'jslib/models/domain'; import { BrowserApi } from '../browser/browserApi'; import RuntimeBackground from './runtime.background'; +import { AppIdService } from 'jslib/abstractions'; const MessageValidTimeout = 10 * 1000; const EncryptionAlgorithm = 'sha1'; @@ -25,13 +26,16 @@ export class NativeMessagingBackground { private privateKey: 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 +62,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 +74,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; @@ -76,7 +90,12 @@ export class NativeMessagingBackground { type: 'error', }); default: - this.onMessage(message); + // Ignore since it belongs to another device + if (message.appId !== this.appId) { + return; + } + + this.onMessage(message.message); } }); @@ -118,7 +137,7 @@ export class NativeMessagingBackground { message.timestamp = Date.now(); const encrypted = await this.cryptoService.encrypt(JSON.stringify(message), this.sharedSecret); - this.port.postMessage(encrypted); + this.port.postMessage({appId: this.appId, message: encrypted}); } getResponse(): Promise { @@ -193,6 +212,6 @@ export class NativeMessagingBackground { message.timestamp = Date.now(); - this.port.postMessage(message); + this.port.postMessage({appId: this.appId, message: message}); } } From ab5de83b2291a26b80e285f2477620bd9723868d Mon Sep 17 00:00:00 2001 From: Chad Scharf <3904944+cscharf@users.noreply.github.com> Date: Wed, 16 Dec 2020 10:34:56 -0500 Subject: [PATCH 08/23] jslib update --- jslib | 2 +- package-lock.json | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/jslib b/jslib index cc801ce0d7..ceb78d054c 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit cc801ce0d7e200a365bed02c35b8d97666dbeab4 +Subproject commit ceb78d054ccbd362459bca60bb4b05c16f164ffa diff --git a/package-lock.json b/package-lock.json index ca7f2bb787..d907f23b21 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1894,6 +1894,11 @@ "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", "dev": true }, + "browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==" + }, "browser-resolve": { "version": "1.11.3", "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", From 95d475a9d3561f058bd80aacaa360229fd52ac9f Mon Sep 17 00:00:00 2001 From: Hinton Date: Wed, 16 Dec 2020 17:32:51 +0100 Subject: [PATCH 09/23] Show an error when biometrics is disabeld in desktop app or not supported --- src/_locales/en/messages.json | 12 ++++++++++++ src/background/nativeMessaging.background.ts | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 6db7940fe1..3bc78c2382 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -1417,6 +1417,18 @@ "nativeMessagingInvalidEncryptionTitle": { "message": "Desktop communication interupted" }, + "biometricsNotEnabledTitle": { + "message": "Biometrics not enabled" + }, + "biometricsNotEnabledDesc": { + "message": "Browser biometric requires desktop biometric to be enabled in the settings first." + }, + "biometricsNotSupportedTitle": { + "message": "Biometrics not supported" + }, + "biometricsNotSupportedDesc": { + "message": "Browser biometric is not supported on this device." + }, "personalOwnershipSubmitError": { "message": "Due to an Enterprise Policy, you are restricted from saving items to your personal vault. Change the Ownership option to an organization and choose from available Collections." } diff --git a/src/background/nativeMessaging.background.ts b/src/background/nativeMessaging.background.ts index 6cebf49dfd..c8b8713861 100644 --- a/src/background/nativeMessaging.background.ts +++ b/src/background/nativeMessaging.background.ts @@ -159,6 +159,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') { From 72c6f52ae29b24efe71bb88cc73e904d97a4521c Mon Sep 17 00:00:00 2001 From: Hinton Date: Wed, 16 Dec 2020 21:44:12 +0100 Subject: [PATCH 10/23] Resolve review comments --- src/_locales/en/messages.json | 6 +++--- src/background/nativeMessaging.background.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index 3bc78c2382..94e5f5ad63 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -1415,19 +1415,19 @@ "message": "Desktop application invalidated the secure communication channel. Please retry this operation" }, "nativeMessagingInvalidEncryptionTitle": { - "message": "Desktop communication interupted" + "message": "Desktop communication interrupted" }, "biometricsNotEnabledTitle": { "message": "Biometrics not enabled" }, "biometricsNotEnabledDesc": { - "message": "Browser biometric requires desktop biometric to be enabled in the settings first." + "message": "Browser biometrics requires desktop biometric to be enabled in the settings first." }, "biometricsNotSupportedTitle": { "message": "Biometrics not supported" }, "biometricsNotSupportedDesc": { - "message": "Browser biometric is not supported on this device." + "message": "Browser biometrics is not supported on this device." }, "personalOwnershipSubmitError": { "message": "Due to an Enterprise Policy, you are restricted from saving items to your personal vault. Change the Ownership option to an organization and choose from available Collections." diff --git a/src/background/nativeMessaging.background.ts b/src/background/nativeMessaging.background.ts index c8b8713861..0f76615406 100644 --- a/src/background/nativeMessaging.background.ts +++ b/src/background/nativeMessaging.background.ts @@ -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'; @@ -12,7 +13,6 @@ import { SymmetricCryptoKey } from 'jslib/models/domain'; import { BrowserApi } from '../browser/browserApi'; import RuntimeBackground from './runtime.background'; -import { AppIdService } from 'jslib/abstractions'; const MessageValidTimeout = 10 * 1000; const EncryptionAlgorithm = 'sha1'; From 0cd6efd67f11dfd9f831dee4799553a1bee9fc5c Mon Sep 17 00:00:00 2001 From: Matt Gibson Date: Thu, 17 Dec 2020 11:06:31 -0600 Subject: [PATCH 11/23] Move share from edit to view. Fix animations (#1497) * Move share from edit to view. Fix animations Editing and Sharing a cipher simultaneously results in lost edits. Move share button to the view page to resolve this confusion. Previous routing caused the share form to be animated again on submition, resulting in a stuttering page load. This method correctly animates all transitions with the concession that the share page always takes you back to the view page. This is not necessarily the current behavior, but it is the most likely behavior in the current scheme * Update jslib reference --- jslib | 2 +- src/popup/app-routing.animations.ts | 6 +++--- src/popup/components/action-buttons.component.ts | 2 +- src/popup/vault/add-edit.component.html | 9 --------- src/popup/vault/add-edit.component.ts | 6 ------ src/popup/vault/share.component.ts | 6 ++---- src/popup/vault/view.component.html | 8 ++++++++ src/popup/vault/view.component.ts | 7 +++++++ 8 files changed, 22 insertions(+), 24 deletions(-) diff --git a/jslib b/jslib index ceb78d054c..f9042408f4 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit ceb78d054ccbd362459bca60bb4b05c16f164ffa +Subproject commit f9042408f44b299a7cdd1286490b70f5fd2db999 diff --git a/src/popup/app-routing.animations.ts b/src/popup/app-routing.animations.ts index a852922b0c..b75b15e2a7 100644 --- a/src/popup/app-routing.animations.ts +++ b/src/popup/app-routing.animations.ts @@ -150,6 +150,9 @@ export const routerTransition = trigger('routerTransition', [ transition('view-cipher => clone-cipher', inSlideUp), transition('clone-cipher => view-cipher, clone-cipher => tabs', outSlideDown), + transition('view-cipher => share-cipher', inSlideUp), + transition('share-cipher => view-cipher', outSlideDown), + transition('tabs => add-cipher', inSlideUp), transition('add-cipher => tabs', outSlideDown), @@ -159,9 +162,6 @@ export const routerTransition = trigger('routerTransition', [ transition('add-cipher => generator, edit-cipher => generator, clone-cipher => generator', inSlideUp), transition('generator => add-cipher, generator => edit-cipher, generator => clone-cipher', outSlideDown), - transition('edit-cipher => share-cipher', inSlideUp), - transition('share-cipher => edit-cipher, share-cipher => view-cipher', outSlideDown), - transition('edit-cipher => attachments, edit-cipher => collections', inSlideLeft), transition('attachments => edit-cipher, collections => edit-cipher', outSlideRight), diff --git a/src/popup/components/action-buttons.component.ts b/src/popup/components/action-buttons.component.ts index 4c7a82173d..ab22d38678 100644 --- a/src/popup/components/action-buttons.component.ts +++ b/src/popup/components/action-buttons.component.ts @@ -43,7 +43,7 @@ export class ActionButtonsComponent { async ngOnInit() { this.userHasPremiumAccess = await this.userService.canAccessPremium(); } - + launch() { if (this.cipher.type !== CipherType.Login || !this.cipher.login.canLaunch) { return; diff --git a/src/popup/vault/add-edit.component.html b/src/popup/vault/add-edit.component.html index 65f344e29b..c2961321b2 100644 --- a/src/popup/vault/add-edit.component.html +++ b/src/popup/vault/add-edit.component.html @@ -374,15 +374,6 @@
- -
- - {{'shareItem' | i18n}} -
-
diff --git a/src/popup/vault/add-edit.component.ts b/src/popup/vault/add-edit.component.ts index fdecd141d8..0a32bdf89a 100644 --- a/src/popup/vault/add-edit.component.ts +++ b/src/popup/vault/add-edit.component.ts @@ -118,12 +118,6 @@ export class AddEditComponent extends BaseAddEditComponent { this.router.navigate(['/attachments'], { queryParams: { cipherId: this.cipher.id } }); } - share() { - super.share(); - if (this.cipher.organizationId == null) { - this.router.navigate(['/share-cipher'], { queryParams: { cipherId: this.cipher.id } }); - } - } editCollections() { super.editCollections(); diff --git a/src/popup/vault/share.component.ts b/src/popup/vault/share.component.ts index 4fb14ea6c1..230e27ac86 100644 --- a/src/popup/vault/share.component.ts +++ b/src/popup/vault/share.component.ts @@ -41,14 +41,12 @@ export class ShareComponent extends BaseShareComponent { async submit(): Promise { const success = await super.submit(); if (success) { - window.setTimeout(() => { - this.location.back(); - }, 200); + this.cancel(); } return success; } cancel() { - this.location.back(); + this.router.navigate(['/view-cipher'], { replaceUrl: true, queryParams: { cipherId: this.cipher.id } }); } } diff --git a/src/popup/vault/view.component.html b/src/popup/vault/view.component.html index 439b3f2bfa..524fc735e9 100644 --- a/src/popup/vault/view.component.html +++ b/src/popup/vault/view.component.html @@ -295,6 +295,14 @@ {{'cloneItem' | i18n}}
+ +
+ + {{'shareItem' | i18n}} +
+
From a0a032957e344e95ee2ecf1ebe1c2d8e8aec6ea1 Mon Sep 17 00:00:00 2001 From: Matt Gibson Date: Tue, 29 Dec 2020 09:18:14 -0600 Subject: [PATCH 15/23] Fix safari sso (#1508) * Fix extension tab creation TODO: still getting errors thrown by safariApp at `(window as any).webkit.messageHandlers` upon loading the extension window * Support message sending from app extension context * Load sso login in popover * Handle nil urlComponents and nil queryItems --- src/browser/safariApp.ts | 20 +++++++++---- src/content/sso.ts | 9 ++++++ src/popup/accounts/sso.component.ts | 4 +-- .../SafariExtensionViewController.swift | 28 +++++++++++++++---- 4 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/browser/safariApp.ts b/src/browser/safariApp.ts index 5593b069b8..894ae2c6d4 100644 --- a/src/browser/safariApp.ts +++ b/src/browser/safariApp.ts @@ -25,12 +25,20 @@ export class SafariApp { return new Promise((resolve) => { const now = new Date(); const messageId = now.getTime().toString() + '_' + Math.floor(Math.random() * Number.MAX_SAFE_INTEGER); - (window as any).webkit.messageHandlers.bitwardenApp.postMessage(JSON.stringify({ - id: messageId, - command: command, - data: data, - responseData: null, - })); + if (typeof safari === typeof undefined) { + (window as any).webkit.messageHandlers.bitwardenApp.postMessage(JSON.stringify({ + id: messageId, + command: command, + data: data, + responseData: null, + })); + } else { + safari.extension.dispatchMessage('bitwarden', { + command: command, + data: data, + responseData: null, + }); + } if (resolveNow) { resolve(); } else { diff --git a/src/content/sso.ts b/src/content/sso.ts index 508bc2aea3..a127a39d55 100644 --- a/src/content/sso.ts +++ b/src/content/sso.ts @@ -3,6 +3,15 @@ window.addEventListener('message', (event) => { return; if (event.data.command && (event.data.command === 'authResult')) { + if (typeof chrome === typeof undefined) { + safari.extension.dispatchMessage('bitwarden', { + command: event.data.command, + code: event.data.code, + state: event.data.state, + referrer: event.source.location.hostname, + }); + return; + } chrome.runtime.sendMessage({ command: event.data.command, code: event.data.code, diff --git a/src/popup/accounts/sso.component.ts b/src/popup/accounts/sso.component.ts index c88f3d1e60..0867b781a7 100644 --- a/src/popup/accounts/sso.component.ts +++ b/src/popup/accounts/sso.component.ts @@ -41,11 +41,11 @@ export class SsoComponent extends BaseSsoComponent { this.redirectUri = url + '/sso-connector.html'; this.clientId = 'browser'; - super.onSuccessfulLogin = () => { + super.onSuccessfulLogin = async () => { + await syncService.fullSync(true); BrowserApi.reloadOpenWindows(); const thisWindow = window.open('', '_self'); thisWindow.close(); - return syncService.fullSync(true); }; } } diff --git a/src/safari/safari/SafariExtensionViewController.swift b/src/safari/safari/SafariExtensionViewController.swift index 0f2ac13eaa..0241df00ce 100644 --- a/src/safari/safari/SafariExtensionViewController.swift +++ b/src/safari/safari/SafariExtensionViewController.swift @@ -16,14 +16,10 @@ class SafariExtensionViewController: SFSafariExtensionViewController, WKScriptMe if initedWebView { return } - let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String initedWebView = true let parentHeight = SafariExtensionViewController.shared.preferredContentSize.height let parentWidth = SafariExtensionViewController.shared.preferredContentSize.width let webViewConfig = WKWebViewConfiguration() - let bundleURL = Bundle.main.resourceURL!.absoluteURL - let html = bundleURL.appendingPathComponent("app/popup/index.html") - let url = URL(string: "\(html.absoluteString)?appVersion=\(version!)") webViewConfig.preferences.setValue(true, forKey: "allowFileAccessFromFileURLs") webViewConfig.preferences.setValue(true, forKey: "developerExtrasEnabled") webViewConfig.userContentController.add(self, name: "bitwardenApp") @@ -31,12 +27,26 @@ class SafariExtensionViewController: SFSafariExtensionViewController, WKScriptMe configuration: webViewConfig) webView.navigationDelegate = self webView.allowsLinkPreview = false - webView.loadFileURL(url!, allowingReadAccessTo: bundleURL) + navigateWebView("app/popup/index.html") webView.alphaValue = 0.0 webView.uiDelegate = self view.addSubview(webView) } + func navigateWebView(_ relativeUrl: String){ + let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String + let bundleUrl = Bundle.main.resourceURL!.absoluteURL + + if var urlComponents = URLComponents(string: bundleUrl.absoluteString + relativeUrl) { + if (urlComponents.queryItems?.first(where: { $0.name == "appVersion" })?.value == nil) { + urlComponents.queryItems = urlComponents.queryItems ?? [] + urlComponents.queryItems!.append(URLQueryItem(name: "appVersion", value: version)) + } + + webView.loadFileURL(urlComponents.url!, allowingReadAccessTo: bundleUrl) + } + } + func webView(_ webView: WKWebView, didFinish _: WKNavigation!) { if #available(OSXApplicationExtension 10.12, *) { NSAnimationContext.runAnimationGroup({ _ in @@ -179,6 +189,14 @@ class SafariExtensionViewController: SFSafariExtensionViewController, WKScriptMe replyMessage(message: m) } else if command == "createNewTab" { if let data = m.data, let url = URL(string: data) { + if !data.starts(with: "https://") && !data.starts(with: "http://") { + SFSafariApplication.getActiveWindow { win in + win?.getToolbarItem(completionHandler: { item in + item?.showPopover() + self.navigateWebView("app/" + url.absoluteString) + }) + } + } SFSafariApplication.getActiveWindow { win in win?.openTab(with: url, makeActiveIfPossible: true, completionHandler: { _ in // Tab opened From 74a9ff799227759628de01669208fc1e1ea14829 Mon Sep 17 00:00:00 2001 From: Vincent Salucci <26154748+vincentsalucci@users.noreply.github.com> Date: Wed, 30 Dec 2020 20:35:06 -0600 Subject: [PATCH 16/23] update jslib (48144a7) (#1510) --- jslib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jslib b/jslib index aa1499f70a..48144a7eae 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit aa1499f70a4ccb0556460942c7c5be1fd517d598 +Subproject commit 48144a7eaea34984d98b5f22e14a73a24348dcd2 From 8d2b84cbb35d129e123a37029cb6f35ed4bb5a34 Mon Sep 17 00:00:00 2001 From: wusatosi <26424577+wusatosi@users.noreply.github.com> Date: Sun, 3 Jan 2021 00:32:22 +0800 Subject: [PATCH 17/23] [ref] Improved readability for #1441 --- src/services/autofill.service.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/services/autofill.service.ts b/src/services/autofill.service.ts index 7498248bbe..82d5224a6e 100644 --- a/src/services/autofill.service.ts +++ b/src/services/autofill.service.ts @@ -254,7 +254,7 @@ export default class AutofillService implements AutofillServiceInterface { } } - const autoFillResponse = await this.doAutoFill({ + const totpCode = await this.doAutoFill({ cipher: cipher, pageDetails: pageDetails, skipTotp: !fromCommand, @@ -265,12 +265,12 @@ export default class AutofillService implements AutofillServiceInterface { fillNewPassword: fromCommand, }); - // Only update last used index if doAutoFill didn't throw an exception + // Update last used index as autofill has succeed if (fromCommand) { this.cipherService.updateLastUsedIndexForUrl(tab.url); } - return autoFillResponse; + return totpCode; } // Helpers From 3541f458e5d62c4e856f141c42b8428275852d63 Mon Sep 17 00:00:00 2001 From: Matt Gibson Date: Mon, 4 Jan 2021 11:38:21 -0600 Subject: [PATCH 18/23] Update jslib (#1520) --- jslib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jslib b/jslib index 48144a7eae..afa01f67f4 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit 48144a7eaea34984d98b5f22e14a73a24348dcd2 +Subproject commit afa01f67f4f5f45506bb14ccb194bb22e11d803e From e922ff0bc291ff6fa493c9eb910545e2f41b2b14 Mon Sep 17 00:00:00 2001 From: Hinton Date: Mon, 4 Jan 2021 20:53:49 +0100 Subject: [PATCH 19/23] Make error handler more generic --- src/background/nativeMessaging.background.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/background/nativeMessaging.background.ts b/src/background/nativeMessaging.background.ts index a8db0cbf04..902ddee06a 100644 --- a/src/background/nativeMessaging.background.ts +++ b/src/background/nativeMessaging.background.ts @@ -115,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'), From 98cc69c6faccc1d943406c8ca3ae758c240ddc1f Mon Sep 17 00:00:00 2001 From: Hinton Date: Tue, 5 Jan 2021 15:12:48 +0100 Subject: [PATCH 20/23] Solve native messaging silently disconnecting when restarting the desktop app --- src/background/nativeMessaging.background.ts | 25 ++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/background/nativeMessaging.background.ts b/src/background/nativeMessaging.background.ts index 902ddee06a..ddd9317da8 100644 --- a/src/background/nativeMessaging.background.ts +++ b/src/background/nativeMessaging.background.ts @@ -143,7 +143,7 @@ export class NativeMessagingBackground { message.timestamp = Date.now(); const encrypted = await this.cryptoService.encrypt(JSON.stringify(message), this.sharedSecret); - this.port.postMessage({appId: this.appId, message: encrypted}); + this.postMessage({appId: this.appId, message: encrypted}); } getResponse(): Promise { @@ -152,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)); @@ -229,7 +250,7 @@ export class NativeMessagingBackground { message.timestamp = Date.now(); - this.port.postMessage({appId: this.appId, message: message}); + this.postMessage({appId: this.appId, message: message}); } private async showFingerprintDialog() { From 8af54375f3e36ae78d3308b4f71aab30f3b73549 Mon Sep 17 00:00:00 2001 From: Vincent Salucci <26154748+vincentsalucci@users.noreply.github.com> Date: Tue, 5 Jan 2021 17:34:00 -0600 Subject: [PATCH 21/23] [Policy] Personal Ownership banner (#1523) * Initial commit of ownership banner * updated capitlization --- src/_locales/en/messages.json | 3 +++ src/popup/vault/add-edit.component.html | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index c21743085f..cdcbd64736 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -1434,5 +1434,8 @@ }, "personalOwnershipSubmitError": { "message": "Due to an Enterprise Policy, you are restricted from saving items to your personal vault. Change the Ownership option to an organization and choose from available Collections." + }, + "personalOwnershipPolicyInEffect": { + "message": "An organization policy is affecting your ownership options." } } diff --git a/src/popup/vault/add-edit.component.html b/src/popup/vault/add-edit.component.html index c2961321b2..a94e8217da 100644 --- a/src/popup/vault/add-edit.component.html +++ b/src/popup/vault/add-edit.component.html @@ -14,6 +14,9 @@
+ + {{'personalOwnershipPolicyInEffect' | i18n}} +
{{'itemInformation' | i18n}} From b1e376ce669b149ebad3afe9f50de48ae27116cf Mon Sep 17 00:00:00 2001 From: Hinton Date: Fri, 8 Jan 2021 15:48:48 +0100 Subject: [PATCH 22/23] Fix action buttons not working when TOTP is not available --- src/popup/components/action-buttons.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/popup/components/action-buttons.component.ts b/src/popup/components/action-buttons.component.ts index ab22d38678..909d20b8e2 100644 --- a/src/popup/components/action-buttons.component.ts +++ b/src/popup/components/action-buttons.component.ts @@ -57,7 +57,7 @@ export class ActionButtonsComponent { } async copy(cipher: CipherView, value: string, typeI18nKey: string, aType: string) { - if (value == null || !this.displayTotpCopyButton(cipher)) { + if (value == null || aType === 'TOTP' && !this.displayTotpCopyButton(cipher)) { return; } else if (value === cipher.login.totp) { value = await this.totpService.getCode(value); From ad1c1cb5687c47e5a348e1f48fca697e94b3135b Mon Sep 17 00:00:00 2001 From: Matt Gibson Date: Fri, 8 Jan 2021 12:13:15 -0600 Subject: [PATCH 23/23] Update jslib (#1526) --- jslib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jslib b/jslib index afa01f67f4..cea09a22e5 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit afa01f67f4f5f45506bb14ccb194bb22e11d803e +Subproject commit cea09a22e533ef3598bb497ba0503c2fcd5b2dc1