diff --git a/jslib b/jslib index f8d8ca2253..fa5f6c0906 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit f8d8ca225360a0ed05f54642ed89da282d8a1021 +Subproject commit fa5f6c09068add3951889961f545e6990d9c3ea7 diff --git a/package-lock.json b/package-lock.json index 82e77b4d47..1374993a45 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3637,6 +3637,12 @@ "event-emitter": "0.3.5" } }, + "es6-object-assign": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", + "integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=", + "dev": true + }, "es6-promise": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", @@ -10945,6 +10951,12 @@ "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", "dev": true }, + "promise-polyfill": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-6.1.0.tgz", + "integrity": "sha1-36lpQ+qcEh/KTem1hoyznTRy4Fc=", + "dev": true + }, "proto-list": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", @@ -13009,10 +13021,14 @@ } }, "sweetalert": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sweetalert/-/sweetalert-1.1.3.tgz", - "integrity": "sha1-0sMepJKyK2qNiHrqFZiaI4/AhK4=", - "dev": true + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sweetalert/-/sweetalert-2.1.0.tgz", + "integrity": "sha512-9YKj0SvjKyBfRWco50UOsIbXVeifYbxzT9Qda7EsqC01eafHGCSG0IR7g942ufjzt7lnwO8ZZBwr6emXv2fQrg==", + "dev": true, + "requires": { + "es6-object-assign": "1.1.0", + "promise-polyfill": "6.1.0" + } }, "symbol-observable": { "version": "1.0.1", diff --git a/package.json b/package.json index 8513a35b10..6ece7815e4 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "papaparse": "4.3.5", "sass-loader": "^6.0.6", "style-loader": "^0.19.0", - "sweetalert": "1.1.3", + "sweetalert": "2.1.0", "tldjs": "2.0.0", "ts-loader": "^3.5.0", "tslint": "^5.9.1", diff --git a/src/background/main.background.ts b/src/background/main.background.ts index d3b3dd0fe9..f4865c12a1 100644 --- a/src/background/main.background.ts +++ b/src/background/main.background.ts @@ -115,9 +115,9 @@ export default class MainBackground { constructor() { // Services this.utilsService = new UtilsService(); - this.platformUtilsService = new BrowserPlatformUtilsService(); + this.messagingService = new BrowserMessagingService(); + this.platformUtilsService = new BrowserPlatformUtilsService(this.messagingService); const delayi18nLoad = this.platformUtilsService.isEdge() || this.platformUtilsService.isSafari() ? 1000 : 0; - this.messagingService = new BrowserMessagingService(this.platformUtilsService); this.storageService = new BrowserStorageService(this.platformUtilsService, false); this.secureStorageService = new BrowserStorageService(this.platformUtilsService, true); this.i18nService = i18nService(this.platformUtilsService); @@ -161,7 +161,8 @@ export default class MainBackground { // Background this.runtimeBackground = new RuntimeBackground(this, this.autofillService, this.cipherService, - this.platformUtilsService, this.storageService, this.i18nService, this.analytics); + this.platformUtilsService as BrowserPlatformUtilsService, this.storageService, this.i18nService, + this.analytics); this.tabsBackground = new TabsBackground(this, this.platformUtilsService); this.commandsBackground = new CommandsBackground(this, this.passwordGenerationService, this.platformUtilsService, this.analytics); diff --git a/src/background/runtime.background.ts b/src/background/runtime.background.ts index 1974d21816..1af8b549cb 100644 --- a/src/background/runtime.background.ts +++ b/src/background/runtime.background.ts @@ -11,7 +11,6 @@ import { Analytics } from 'jslib/misc'; import { CipherService, - PlatformUtilsService, StorageService, } from 'jslib/abstractions'; @@ -20,6 +19,7 @@ import { BrowserApi } from '../browser/browserApi'; import MainBackground from './main.background'; import { AutofillService } from '../services/abstractions/autofill.service'; +import BrowserPlatformUtilsService from '../services/browserPlatformUtils.service'; export default class RuntimeBackground { private runtime: any; @@ -29,7 +29,7 @@ export default class RuntimeBackground { private onInstalledReason: string = null; constructor(private main: MainBackground, private autofillService: AutofillService, - private cipherService: CipherService, private platformUtilsService: PlatformUtilsService, + private cipherService: CipherService, private platformUtilsService: BrowserPlatformUtilsService, private storageService: StorageService, private i18nService: any, private analytics: Analytics) { this.isSafari = this.platformUtilsService.isSafari(); this.runtime = this.isSafari ? safari.application : chrome.runtime; @@ -90,6 +90,9 @@ export default class RuntimeBackground { case 'openPopup': await this.main.openPopup(); break; + case 'showDialogResolve': + this.platformUtilsService.resolveDialogPromise(msg.dialogId, msg.confirmed); + break; case 'bgGetDataForTab': await this.getDataForTab(sender.tab, msg.responseCommand); break; diff --git a/src/popup/app/services/services.module.ts b/src/popup/app/services/services.module.ts index 698355b7be..2d1ad515ec 100644 --- a/src/popup/app/services/services.module.ts +++ b/src/popup/app/services/services.module.ts @@ -8,7 +8,7 @@ import { AuthService } from 'jslib/services/auth.service'; import BrowserMessagingService from '../../../services/browserMessaging.service'; -const messagingService = new BrowserMessagingService(backgroundServices.platformUtilsService()); +const messagingService = new BrowserMessagingService(); const authService = new AuthService(backgroundServices.cryptoService(), backgroundServices.apiService(), backgroundServices.userService(), backgroundServices.tokenService(), backgroundServices.appIdService(), backgroundServices.i18n2Service(), backgroundServices.platformUtilsService(), diff --git a/src/popup2/app.component.ts b/src/popup2/app.component.ts index af654ac74d..a2c61ce2b4 100644 --- a/src/popup2/app.component.ts +++ b/src/popup2/app.component.ts @@ -3,6 +3,7 @@ import { ToasterContainerComponent, } from 'angular2-toaster'; import { Angulartics2GoogleAnalytics } from 'angulartics2/ga'; +import swal from 'sweetalert'; import { Component, @@ -23,6 +24,7 @@ import { BroadcasterService } from 'jslib/angular/services/broadcaster.service'; import { AuthService } from 'jslib/abstractions/auth.service'; import { I18nService } from 'jslib/abstractions/i18n.service'; +import { MessagingService } from 'jslib/abstractions/messaging.service'; import { StateService } from 'jslib/abstractions/state.service'; import { StorageService } from 'jslib/abstractions/storage.service'; @@ -57,7 +59,7 @@ export class AppComponent implements OnInit { private toasterService: ToasterService, private storageService: StorageService, private broadcasterService: BroadcasterService, private authService: AuthService, private i18nService: I18nService, private router: Router, - private stateService: StateService) { } + private stateService: StateService, private messagingService: MessagingService) { } ngOnInit() { window.onmousemove = () => this.recordActivity(); @@ -67,7 +69,7 @@ export class AppComponent implements OnInit { window.onscroll = () => this.recordActivity(); window.onkeypress = () => this.recordActivity(); - (window as any).bitwardenPopupMainMessageListener = (msg: any, sender: any, sendResponse: any) => { + (window as any).bitwardenPopupMainMessageListener = async (msg: any, sender: any, sendResponse: any) => { if (msg.command === 'doneLoggingOut') { this.authService.logOut(() => { this.analytics.eventTrack.next({ action: 'Logged Out' }); @@ -77,6 +79,22 @@ export class AppComponent implements OnInit { } this.router.navigate(['home']); }); + } else if (msg.command === 'showDialog') { + const buttons = [msg.confirmText == null ? this.i18nService.t('ok') : msg.confirmText]; + if (msg.cancelText != null) { + buttons.unshift(msg.cancelText); + } + + const confirmed = await swal({ + title: msg.title, + text: msg.text, + buttons: buttons, + }); + + this.messagingService.send('showDialogResolve', { + dialogId: msg.dialogId, + confirmed: confirmed, + }); } else { msg.webExtSender = sender; this.broadcasterService.send(msg); diff --git a/src/popup2/services/services.module.ts b/src/popup2/services/services.module.ts index cbdac193ea..5fab8f4bd3 100644 --- a/src/popup2/services/services.module.ts +++ b/src/popup2/services/services.module.ts @@ -51,7 +51,7 @@ function getBgService(service: string) { } export const stateService = new StateService(); -export const messagingService = new BrowserMessagingService(getBgService('platformUtilsService')()); +export const messagingService = new BrowserMessagingService(); export const authService = new AuthService(getBgService('cryptoService')(), getBgService('apiService')(), getBgService('userService')(), getBgService('tokenService')(), getBgService('appIdService')(), diff --git a/src/popup2/vault/add-edit.component.ts b/src/popup2/vault/add-edit.component.ts index 268ffb2756..0d59ebc926 100644 --- a/src/popup2/vault/add-edit.component.ts +++ b/src/popup2/vault/add-edit.component.ts @@ -87,9 +87,12 @@ export class AddEditComponent extends BaseAddEditComponent implements OnInit { this.location.back(); } - async generatePassword() { - await super.generatePassword(); - this.stateService.save('addEditCipher', this.cipher); - this.router.navigate(['generator']); + async generatePassword(): Promise { + const confirmed = await super.generatePassword(); + if (confirmed) { + this.stateService.save('addEditCipher', this.cipher); + this.router.navigate(['generator']); + } + return confirmed; } } diff --git a/src/services/browserMessaging.service.ts b/src/services/browserMessaging.service.ts index 6d21732a0c..ec92bdc4f0 100644 --- a/src/services/browserMessaging.service.ts +++ b/src/services/browserMessaging.service.ts @@ -1,18 +1,12 @@ import { BrowserApi } from '../browser/browserApi'; -import { - MessagingService, - PlatformUtilsService, -} from 'jslib/abstractions'; +import { MessagingService } from 'jslib/abstractions'; export default class BrowserMessagingService implements MessagingService { - constructor(private platformUtilsService: PlatformUtilsService) { - } - send(subscriber: string, arg: any = {}) { const message = Object.assign({}, { command: subscriber }, arg); - if (this.platformUtilsService.isSafari()) { + if (BrowserApi.isSafariApi) { const bgPage = BrowserApi.getBackgroundPage(); bgPage.bitwardenMain.sendInternalRuntimeMessage(message); diff --git a/src/services/browserPlatformUtils.service.spec.ts b/src/services/browserPlatformUtils.service.spec.ts index 9c2500c569..e4ba8ccad0 100644 --- a/src/services/browserPlatformUtils.service.spec.ts +++ b/src/services/browserPlatformUtils.service.spec.ts @@ -48,7 +48,7 @@ describe('Browser Utils Service', () => { value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36' }); - const browserPlatformUtilsService = new BrowserPlatformUtilsService(); + const browserPlatformUtilsService = new BrowserPlatformUtilsService(null); expect(browserPlatformUtilsService.getDevice()).toBe(DeviceType.Chrome); }); @@ -58,7 +58,7 @@ describe('Browser Utils Service', () => { value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0' }); - const browserPlatformUtilsService = new BrowserPlatformUtilsService(); + const browserPlatformUtilsService = new BrowserPlatformUtilsService(null); expect(browserPlatformUtilsService.getDevice()).toBe(DeviceType.Firefox); }); @@ -68,7 +68,7 @@ describe('Browser Utils Service', () => { value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3175.3 Safari/537.36 OPR/49.0.2695.0 (Edition developer)' }); - const browserPlatformUtilsService = new BrowserPlatformUtilsService(); + const browserPlatformUtilsService = new BrowserPlatformUtilsService(null); expect(browserPlatformUtilsService.getDevice()).toBe(DeviceType.Opera); }); @@ -78,7 +78,7 @@ describe('Browser Utils Service', () => { value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; ServiceUI 9) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063' }); - const browserPlatformUtilsService = new BrowserPlatformUtilsService(); + const browserPlatformUtilsService = new BrowserPlatformUtilsService(null); expect(browserPlatformUtilsService.getDevice()).toBe(DeviceType.Edge); }); @@ -88,7 +88,7 @@ describe('Browser Utils Service', () => { value: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/602.4.8 (KHTML, like Gecko) Version/10.0.3 Safari/602.4.8' }); - const browserPlatformUtilsService = new BrowserPlatformUtilsService(); + const browserPlatformUtilsService = new BrowserPlatformUtilsService(null); expect(browserPlatformUtilsService.getDevice()).toBe(DeviceType.Safari); }); @@ -98,7 +98,7 @@ describe('Browser Utils Service', () => { value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.97 Safari/537.36 Vivaldi/1.94.1008.40' }); - const browserPlatformUtilsService = new BrowserPlatformUtilsService(); + const browserPlatformUtilsService = new BrowserPlatformUtilsService(null); expect(browserPlatformUtilsService.getDevice()).toBe(DeviceType.Vivaldi); }); }); diff --git a/src/services/browserPlatformUtils.service.ts b/src/services/browserPlatformUtils.service.ts index 4f1dedda9c..3f45ca97bf 100644 --- a/src/services/browserPlatformUtils.service.ts +++ b/src/services/browserPlatformUtils.service.ts @@ -2,11 +2,12 @@ import * as tldjs from 'tldjs'; import { BrowserApi } from '../browser/browserApi'; -import { DeviceType } from 'jslib/enums'; +import { DeviceType } from 'jslib/enums/deviceType'; -import { PlatformUtilsService } from 'jslib/abstractions'; +import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; +import { MessagingService } from 'jslib/abstractions/messaging.service'; -import { UtilsService } from 'jslib/services'; +import { UtilsService } from 'jslib/services/utils.service'; const AnalyticsIds = { [DeviceType.Chrome]: 'UA-81915606-6', @@ -17,6 +18,8 @@ const AnalyticsIds = { [DeviceType.Safari]: 'UA-81915606-16', }; +const DialogPromiseExpiration = 3600000; // 1 hour + export default class BrowserPlatformUtilsService implements PlatformUtilsService { static getDomain(uriString: string): string { if (uriString == null) { @@ -57,9 +60,12 @@ export default class BrowserPlatformUtilsService implements PlatformUtilsService identityClientId: string = 'browser'; + private showDialogResolves = new Map void, date: Date }>(); private deviceCache: DeviceType = null; private analyticsIdCache: string = null; + constructor(private messagingService: MessagingService) { } + getDevice(): DeviceType { if (this.deviceCache) { return this.deviceCache; @@ -169,8 +175,18 @@ export default class BrowserPlatformUtilsService implements PlatformUtilsService } showDialog(text: string, title?: string, confirmText?: string, cancelText?: string, type?: string) { - // TODO - return Promise.resolve(true); + const dialogId = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER); + this.messagingService.send('showDialog', { + text: text, + title: title, + confirmText: confirmText, + cancelText: cancelText, + type: type, + dialogId: dialogId, + }); + return new Promise((resolve) => { + this.showDialogResolves.set(dialogId, { resolve: resolve, date: new Date() }); + }); } isDev(): boolean { @@ -183,6 +199,26 @@ export default class BrowserPlatformUtilsService implements PlatformUtilsService UtilsService.copyToClipboard(text, doc); } + resolveDialogPromise(dialogId: number, confirmed: boolean) { + if (this.showDialogResolves.has(dialogId)) { + const resolveObj = this.showDialogResolves.get(dialogId); + resolveObj.resolve(confirmed); + this.showDialogResolves.delete(dialogId); + } + + // Clean up old promises + const deleteIds: number[] = []; + this.showDialogResolves.forEach((val, key) => { + const age = new Date().getTime() - val.date.getTime(); + if (age > DialogPromiseExpiration) { + deleteIds.push(key); + } + }); + deleteIds.forEach((id) => { + this.showDialogResolves.delete(id); + }); + } + private sidebarViewName(): string { if ((window as any).chrome.sidebarAction && this.isFirefox()) { return 'sidebar';