From da636e26c299acece410650aecc127e097115cba Mon Sep 17 00:00:00 2001 From: Tom Rittson Date: Mon, 31 Aug 2020 17:14:50 +1000 Subject: [PATCH 1/3] add settings -> Excluded Domains component Provides a UI to edit the domains for which Bitwarden does not offer to save login details. --- src/_locales/en/messages.json | 9 ++ src/popup/app-routing.module.ts | 7 ++ src/popup/app.module.ts | 2 + .../settings/excluded-domains.component.html | 53 +++++++++ .../settings/excluded-domains.component.ts | 111 ++++++++++++++++++ src/popup/settings/settings.component.html | 4 + 6 files changed, 186 insertions(+) create mode 100644 src/popup/settings/excluded-domains.component.html create mode 100644 src/popup/settings/excluded-domains.component.ts diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index cdcbd64736..ba36b04c3b 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -1437,5 +1437,14 @@ }, "personalOwnershipPolicyInEffect": { "message": "An organization policy is affecting your ownership options." + }, + "excludedDomains": { + "message": "Excluded Domains" + }, + "excludedDomainsDesc": { + "message": "Bitwarden will not ask to save login details for these domains." + }, + "excludedDomainsInvalidDomain": { + "message": " is not a valid domain" } } diff --git a/src/popup/app-routing.module.ts b/src/popup/app-routing.module.ts index 5c3ea8dbba..d4d37b07bd 100644 --- a/src/popup/app-routing.module.ts +++ b/src/popup/app-routing.module.ts @@ -40,6 +40,7 @@ import { GroupingsComponent } from './vault/groupings.component'; import { PasswordHistoryComponent } from './vault/password-history.component'; import { ShareComponent } from './vault/share.component'; import { ViewComponent } from './vault/view.component'; +import { ExcludedDomainsComponent } from './settings/excluded-domains.component'; const routes: Routes = [ { @@ -200,6 +201,12 @@ const routes: Routes = [ canActivate: [AuthGuardService], data: { state: 'sync' }, }, + { + path: 'excluded-domains', + component: ExcludedDomainsComponent, + canActivate: [AuthGuardService], + data: { state: 'excluded-domains' }, + }, { path: 'premium', component: PremiumComponent, diff --git a/src/popup/app.module.ts b/src/popup/app.module.ts index 125f7a713e..3b6bc204c2 100644 --- a/src/popup/app.module.ts +++ b/src/popup/app.module.ts @@ -46,6 +46,7 @@ import { GroupingsComponent } from './vault/groupings.component'; import { PasswordHistoryComponent } from './vault/password-history.component'; import { ShareComponent } from './vault/share.component'; import { ViewComponent } from './vault/view.component'; +import { ExcludedDomainsComponent } from './settings/excluded-domains.component'; import { A11yTitleDirective } from 'jslib/angular/directives/a11y-title.directive'; import { ApiActionDirective } from 'jslib/angular/directives/api-action.directive'; @@ -181,6 +182,7 @@ registerLocaleData(localeZhTw, 'zh-TW'); ColorPasswordPipe, CurrentTabComponent, EnvironmentComponent, + ExcludedDomainsComponent, ExportComponent, FallbackSrcDirective, FolderAddEditComponent, diff --git a/src/popup/settings/excluded-domains.component.html b/src/popup/settings/excluded-domains.component.html new file mode 100644 index 0000000000..7a10449282 --- /dev/null +++ b/src/popup/settings/excluded-domains.component.html @@ -0,0 +1,53 @@ +
+
+ +
+ {{'excludedDomains' | i18n}} +
+
+ +
+
+ +
+
+ +
+ + + +
+ + + + +
+
+ + + +
+
+
+ + {{'newUri' | i18n}} + +
+ +
+
+
\ No newline at end of file diff --git a/src/popup/settings/excluded-domains.component.ts b/src/popup/settings/excluded-domains.component.ts new file mode 100644 index 0000000000..5be9939e87 --- /dev/null +++ b/src/popup/settings/excluded-domains.component.ts @@ -0,0 +1,111 @@ +import { + Component, + OnInit, + NgZone, + OnDestroy +} from '@angular/core'; +import { Router } from '@angular/router'; + +import { I18nService } from 'jslib/abstractions/i18n.service'; +import { StorageService } from 'jslib/abstractions/storage.service'; +import { ConstantsService } from 'jslib/services/constants.service'; +import { BrowserApi } from '../../browser/browserApi'; +import { BroadcasterService } from 'jslib/angular/services/broadcaster.service'; +import { Utils } from 'jslib/misc/utils'; +import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; + +interface ExcludedDomain { + uri: string, + showCurrentUris: boolean +} + +const BroadcasterSubscriptionId = 'excludedDomains'; + +@Component({ + selector: 'app-excluded-domains', + templateUrl: 'excluded-domains.component.html', +}) +export class ExcludedDomainsComponent implements OnInit, OnDestroy { + excludedDomains: ExcludedDomain[] = []; + currentUris: string[]; + loadCurrentUrisTimeout: number; + + constructor(private storageService: StorageService, + private i18nService: I18nService, private router: Router, + private broadcasterService: BroadcasterService, private ngZone: NgZone, + private platformUtilsService: PlatformUtilsService) { + } + + async ngOnInit() { + const savedDomains = await this.storageService.get(ConstantsService.neverDomainsKey); + if (savedDomains) { + for (const uri of Object.keys(savedDomains)) { + this.excludedDomains.push({uri: uri, showCurrentUris: false}) + } + } + + this.loadCurrentUris(); + + this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => { + this.ngZone.run(async () => { + switch (message.command) { + case 'tabChanged': + case 'windowChanged': + if (this.loadCurrentUrisTimeout != null) { + window.clearTimeout(this.loadCurrentUrisTimeout); + } + this.loadCurrentUrisTimeout = window.setTimeout(() => this.loadCurrentUris(), 500); + break; + default: + break; + } + }); + }); + } + + ngOnDestroy() { + this.broadcasterService.unsubscribe(BroadcasterSubscriptionId); + } + + async addUri() { + this.excludedDomains.push({uri: '', showCurrentUris: false}) + } + + async removeUri(i: number) { + this.excludedDomains.splice(i, 1); + } + + async submit() { + const savedDomains: {[name: string]: null} = {}; + for (const domain of this.excludedDomains) { + if (domain.uri && domain.uri !== '') { + const validDomain = Utils.getHostname(domain.uri); + if (!validDomain) { + this.platformUtilsService.showToast('error', null, + '\'' + domain.uri + '\'' + this.i18nService.t('excludedDomainsInvalidDomain')); + return; + } + savedDomains[validDomain] = null + } + } + await this.storageService.save(ConstantsService.neverDomainsKey, savedDomains); + this.router.navigate(['/tabs/settings']); + } + + trackByFunction(index: number, item: any) { + return index; + } + + toggleUriInput(domain: ExcludedDomain) { + domain.showCurrentUris = !domain.showCurrentUris; + } + + async loadCurrentUris() { + const tabs = await BrowserApi.tabsQuery({ windowType: 'normal' }); + if (tabs) { + const uriSet = new Set(tabs.map((tab) => Utils.getHostname(tab.url))); + uriSet.delete(null); + this.currentUris = Array.from(uriSet); + } + } +} \ No newline at end of file diff --git a/src/popup/settings/settings.component.html b/src/popup/settings/settings.component.html index fc1eeedfe7..7b1f81c162 100644 --- a/src/popup/settings/settings.component.html +++ b/src/popup/settings/settings.component.html @@ -19,6 +19,10 @@
{{'sync' | i18n}}
+ +
{{'excludedDomains' | i18n}}
+ +
From 078111a4fc07ba254c55e92faf5f7a46ed5d2927 Mon Sep 17 00:00:00 2001 From: Thomas Rittson Date: Wed, 13 Jan 2021 18:40:10 +1000 Subject: [PATCH 2/3] Fix formatting and style --- src/popup/app-routing.module.ts | 2 +- src/popup/app.module.ts | 2 +- .../settings/excluded-domains.component.ts | 17 +++++++++-------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/popup/app-routing.module.ts b/src/popup/app-routing.module.ts index d4d37b07bd..96090c98f3 100644 --- a/src/popup/app-routing.module.ts +++ b/src/popup/app-routing.module.ts @@ -23,6 +23,7 @@ import { SsoComponent } from './accounts/sso.component'; import { PasswordGeneratorHistoryComponent } from './generator/password-generator-history.component'; import { PasswordGeneratorComponent } from './generator/password-generator.component'; import { PrivateModeComponent } from './private-mode.component'; +import { ExcludedDomainsComponent } from './settings/excluded-domains.component'; import { ExportComponent } from './settings/export.component'; import { FolderAddEditComponent } from './settings/folder-add-edit.component'; import { FoldersComponent } from './settings/folders.component'; @@ -40,7 +41,6 @@ import { GroupingsComponent } from './vault/groupings.component'; import { PasswordHistoryComponent } from './vault/password-history.component'; import { ShareComponent } from './vault/share.component'; import { ViewComponent } from './vault/view.component'; -import { ExcludedDomainsComponent } from './settings/excluded-domains.component'; const routes: Routes = [ { diff --git a/src/popup/app.module.ts b/src/popup/app.module.ts index 3b6bc204c2..63e8c92c32 100644 --- a/src/popup/app.module.ts +++ b/src/popup/app.module.ts @@ -29,6 +29,7 @@ import { AppComponent } from './app.component'; import { PasswordGeneratorHistoryComponent } from './generator/password-generator-history.component'; import { PasswordGeneratorComponent } from './generator/password-generator.component'; import { PrivateModeComponent } from './private-mode.component'; +import { ExcludedDomainsComponent } from './settings/excluded-domains.component'; import { ExportComponent } from './settings/export.component'; import { FolderAddEditComponent } from './settings/folder-add-edit.component'; import { FoldersComponent } from './settings/folders.component'; @@ -46,7 +47,6 @@ import { GroupingsComponent } from './vault/groupings.component'; import { PasswordHistoryComponent } from './vault/password-history.component'; import { ShareComponent } from './vault/share.component'; import { ViewComponent } from './vault/view.component'; -import { ExcludedDomainsComponent } from './settings/excluded-domains.component'; import { A11yTitleDirective } from 'jslib/angular/directives/a11y-title.directive'; import { ApiActionDirective } from 'jslib/angular/directives/api-action.directive'; diff --git a/src/popup/settings/excluded-domains.component.ts b/src/popup/settings/excluded-domains.component.ts index 5be9939e87..b09d8570dd 100644 --- a/src/popup/settings/excluded-domains.component.ts +++ b/src/popup/settings/excluded-domains.component.ts @@ -1,18 +1,19 @@ import { Component, + OnDestroy, OnInit, - NgZone, - OnDestroy + NgZone } from '@angular/core'; import { Router } from '@angular/router'; import { I18nService } from 'jslib/abstractions/i18n.service'; +import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; import { StorageService } from 'jslib/abstractions/storage.service'; import { ConstantsService } from 'jslib/services/constants.service'; -import { BrowserApi } from '../../browser/browserApi'; import { BroadcasterService } from 'jslib/angular/services/broadcaster.service'; + +import { BrowserApi } from '../../browser/browserApi'; import { Utils } from 'jslib/misc/utils'; -import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; interface ExcludedDomain { uri: string, @@ -40,7 +41,7 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy { const savedDomains = await this.storageService.get(ConstantsService.neverDomainsKey); if (savedDomains) { for (const uri of Object.keys(savedDomains)) { - this.excludedDomains.push({uri: uri, showCurrentUris: false}) + this.excludedDomains.push({ uri: uri, showCurrentUris: false }) } } @@ -68,7 +69,7 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy { } async addUri() { - this.excludedDomains.push({uri: '', showCurrentUris: false}) + this.excludedDomains.push({ uri: '', showCurrentUris: false }) } async removeUri(i: number) { @@ -76,7 +77,7 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy { } async submit() { - const savedDomains: {[name: string]: null} = {}; + const savedDomains: { [name: string]: null } = {}; for (const domain of this.excludedDomains) { if (domain.uri && domain.uri !== '') { const validDomain = Utils.getHostname(domain.uri); @@ -108,4 +109,4 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy { this.currentUris = Array.from(uriSet); } } -} \ No newline at end of file +} From caa4d5990dd4e06fed3b5455c6dfdd56f3ec5717 Mon Sep 17 00:00:00 2001 From: Thomas Rittson Date: Thu, 14 Jan 2021 18:04:30 +1000 Subject: [PATCH 3/3] Use placeholders, minor code and style fixes --- src/_locales/en/messages.json | 8 +++++++- src/popup/settings/excluded-domains.component.ts | 16 ++++++++-------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index ba36b04c3b..157148445c 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -1445,6 +1445,12 @@ "message": "Bitwarden will not ask to save login details for these domains." }, "excludedDomainsInvalidDomain": { - "message": " is not a valid domain" + "message": "$DOMAIN$ is not a valid domain", + "placeholders": { + "domain": { + "content": "$1", + "example": "googlecom" + } + } } } diff --git a/src/popup/settings/excluded-domains.component.ts b/src/popup/settings/excluded-domains.component.ts index b09d8570dd..57bfa0bb02 100644 --- a/src/popup/settings/excluded-domains.component.ts +++ b/src/popup/settings/excluded-domains.component.ts @@ -16,8 +16,8 @@ import { BrowserApi } from '../../browser/browserApi'; import { Utils } from 'jslib/misc/utils'; interface ExcludedDomain { - uri: string, - showCurrentUris: boolean + uri: string; + showCurrentUris: boolean; } const BroadcasterSubscriptionId = 'excludedDomains'; @@ -41,11 +41,11 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy { const savedDomains = await this.storageService.get(ConstantsService.neverDomainsKey); if (savedDomains) { for (const uri of Object.keys(savedDomains)) { - this.excludedDomains.push({ uri: uri, showCurrentUris: false }) + this.excludedDomains.push({ uri: uri, showCurrentUris: false }); } } - this.loadCurrentUris(); + await this.loadCurrentUris(); this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => { this.ngZone.run(async () => { @@ -55,7 +55,7 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy { if (this.loadCurrentUrisTimeout != null) { window.clearTimeout(this.loadCurrentUrisTimeout); } - this.loadCurrentUrisTimeout = window.setTimeout(() => this.loadCurrentUris(), 500); + this.loadCurrentUrisTimeout = window.setTimeout(async () => await this.loadCurrentUris(), 500); break; default: break; @@ -69,7 +69,7 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy { } async addUri() { - this.excludedDomains.push({ uri: '', showCurrentUris: false }) + this.excludedDomains.push({ uri: '', showCurrentUris: false }); } async removeUri(i: number) { @@ -83,10 +83,10 @@ export class ExcludedDomainsComponent implements OnInit, OnDestroy { const validDomain = Utils.getHostname(domain.uri); if (!validDomain) { this.platformUtilsService.showToast('error', null, - '\'' + domain.uri + '\'' + this.i18nService.t('excludedDomainsInvalidDomain')); + this.i18nService.t('excludedDomainsInvalidDomain', domain.uri)); return; } - savedDomains[validDomain] = null + savedDomains[validDomain] = null; } } await this.storageService.save(ConstantsService.neverDomainsKey, savedDomains);