From 8a36536d40b406d3a06eac6afb4cf6f586c41536 Mon Sep 17 00:00:00 2001 From: Vincent Salucci <26154748+vincentsalucci@users.noreply.github.com> Date: Thu, 17 Mar 2022 08:55:00 -0500 Subject: [PATCH] [End User Vault Refresh] Security sub-page (#1538) * [End User Vault Refresh] Security section * Updated routing module * Update routing for change-password * Updated buttons of all modified classes // imported button module * Converted modified class to use bit-callout * removed comments * Update small button to current cl button --- src/app/oss-routing.module.ts | 11 ++-- src/app/oss.module.ts | 8 ++- src/app/settings/account.component.html | 30 +-------- src/app/settings/account.component.ts | 41 +------------ src/app/settings/change-kdf.component.html | 7 ++- .../settings/change-password.component.html | 8 ++- src/app/settings/change-password.component.ts | 12 +++- src/app/settings/security-keys.component.html | 18 ++++++ src/app/settings/security-keys.component.ts | 61 +++++++++++++++++++ src/app/settings/security.component.html | 22 +++++++ src/app/settings/security.component.ts | 17 ++++++ src/app/settings/security.module.ts | 39 ++++++++++++ src/app/settings/settings.component.html | 6 +- .../settings/two-factor-setup.component.html | 16 ++--- src/locales/en/messages.json | 9 +++ src/scss/base.scss | 8 ++- src/scss/navigation.scss | 33 ++++++---- 17 files changed, 244 insertions(+), 102 deletions(-) create mode 100644 src/app/settings/security-keys.component.html create mode 100644 src/app/settings/security-keys.component.ts create mode 100644 src/app/settings/security.component.html create mode 100644 src/app/settings/security.component.ts create mode 100644 src/app/settings/security.module.ts diff --git a/src/app/oss-routing.module.ts b/src/app/oss-routing.module.ts index 1f122840..911b93b2 100644 --- a/src/app/oss-routing.module.ts +++ b/src/app/oss-routing.module.ts @@ -58,9 +58,9 @@ import { EmergencyAccessComponent } from "./settings/emergency-access.component" import { OrganizationsComponent } from "./settings/organizations.component"; import { PreferencesComponent } from "./settings/preferences.component"; import { PremiumComponent } from "./settings/premium.component"; +import { SecurityComponent } from "./settings/security.component"; import { SettingsComponent } from "./settings/settings.component"; import { SponsoredFamiliesComponent } from "./settings/sponsored-families.component"; -import { TwoFactorSetupComponent } from "./settings/two-factor-setup.component"; import { UserBillingComponent } from "./settings/user-billing.component"; import { UserSubscriptionComponent } from "./settings/user-subscription.component"; import { BreachReportComponent } from "./tools/breach-report.component"; @@ -183,16 +183,15 @@ const routes: Routes = [ component: PreferencesComponent, data: { titleId: "preferences" }, }, + { + path: "security", + loadChildren: async () => (await import("./settings/security.module")).SecurityModule, + }, { path: "domain-rules", component: DomainRulesComponent, data: { titleId: "domainRules" }, }, - { - path: "two-factor", - component: TwoFactorSetupComponent, - data: { titleId: "twoStepLogin" }, - }, { path: "premium", component: PremiumComponent, data: { titleId: "goPremium" } }, { path: "billing", component: UserBillingComponent, data: { titleId: "billing" } }, { diff --git a/src/app/oss.module.ts b/src/app/oss.module.ts index daa8d37f..9f17cb8c 100644 --- a/src/app/oss.module.ts +++ b/src/app/oss.module.ts @@ -53,7 +53,7 @@ import localeZhTw from "@angular/common/locales/zh-Hant"; import { NgModule } from "@angular/core"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { RouterModule } from "@angular/router"; -import { BadgeModule } from "@bitwarden/components"; +import { BadgeModule, ButtonModule, CalloutModule } from "@bitwarden/components"; import { InfiniteScrollModule } from "ngx-infinite-scroll"; import { ToastrModule } from "ngx-toastr"; @@ -191,6 +191,8 @@ import { PreferencesComponent } from "./settings/preferences.component"; import { PremiumComponent } from "./settings/premium.component"; import { ProfileComponent } from "./settings/profile.component"; import { PurgeVaultComponent } from "./settings/purge-vault.component"; +import { SecurityKeysComponent } from "./settings/security-keys.component"; +import { SecurityComponent } from "./settings/security.component"; import { SettingsComponent } from "./settings/settings.component"; import { SponsoredFamiliesComponent } from "./settings/sponsored-families.component"; import { SponsoringOrgRowComponent } from "./settings/sponsoring-org-row.component"; @@ -296,6 +298,8 @@ registerLocaleData(localeZhTw, "zh-TW"); ReactiveFormsModule, RouterModule, BadgeModule, + ButtonModule, + CalloutModule, ], declarations: [ A11yInvalidDirective, @@ -431,6 +435,8 @@ registerLocaleData(localeZhTw, "zh-TW"); ReusedPasswordsReportComponent, SearchCiphersPipe, SearchPipe, + SecurityComponent, + SecurityKeysComponent, SelectCopyDirective, SendAddEditComponent, SendComponent, diff --git a/src/app/settings/account.component.html b/src/app/settings/account.component.html index af894442..18814983 100644 --- a/src/app/settings/account.component.html +++ b/src/app/settings/account.component.html @@ -8,43 +8,19 @@ - -
-

{{ "changeMasterPassword" | i18n }}

-
- -
- -
-

{{ "encKeySettings" | i18n }}

-
- -
-
-

{{ "apiKey" | i18n }}

-
-

- {{ "userApiKeyDesc" | i18n }} -

- -

{{ "dangerZone" | i18n }}

{{ "dangerZoneDesc" | i18n }}

- - -
diff --git a/src/app/settings/account.component.ts b/src/app/settings/account.component.ts index 557e4c82..aa13eb45 100644 --- a/src/app/settings/account.component.ts +++ b/src/app/settings/account.component.ts @@ -5,7 +5,6 @@ import { ApiService } from "jslib-common/abstractions/api.service"; import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service"; import { StateService } from "jslib-common/abstractions/state.service"; -import { ApiKeyComponent } from "./api-key.component"; import { DeauthorizeSessionsComponent } from "./deauthorize-sessions.component"; import { DeleteAccountComponent } from "./delete-account.component"; import { PurgeVaultComponent } from "./purge-vault.component"; @@ -21,13 +20,7 @@ export class AccountComponent { purgeModalRef: ViewContainerRef; @ViewChild("deleteAccountTemplate", { read: ViewContainerRef, static: true }) deleteModalRef: ViewContainerRef; - @ViewChild("viewUserApiKeyTemplate", { read: ViewContainerRef, static: true }) - viewUserApiKeyModalRef: ViewContainerRef; - @ViewChild("rotateUserApiKeyTemplate", { read: ViewContainerRef, static: true }) - rotateUserApiKeyModalRef: ViewContainerRef; - showChangePassword = true; - showChangeKdf = true; showChangeEmail = true; constructor( @@ -38,10 +31,7 @@ export class AccountComponent { ) {} async ngOnInit() { - this.showChangeEmail = - this.showChangeKdf = - this.showChangePassword = - !(await this.keyConnectorService.getUsesKeyConnector()); + this.showChangeEmail = !(await this.keyConnectorService.getUsesKeyConnector()); } async deauthorizeSessions() { @@ -55,33 +45,4 @@ export class AccountComponent { async deleteAccount() { await this.modalService.openViewRef(DeleteAccountComponent, this.deleteModalRef); } - - async viewUserApiKey() { - const entityId = await this.stateService.getUserId(); - await this.modalService.openViewRef(ApiKeyComponent, this.viewUserApiKeyModalRef, (comp) => { - comp.keyType = "user"; - comp.entityId = entityId; - comp.postKey = this.apiService.postUserApiKey.bind(this.apiService); - comp.scope = "api"; - comp.grantType = "client_credentials"; - comp.apiKeyTitle = "apiKey"; - comp.apiKeyWarning = "userApiKeyWarning"; - comp.apiKeyDescription = "userApiKeyDesc"; - }); - } - - async rotateUserApiKey() { - const entityId = await this.stateService.getUserId(); - await this.modalService.openViewRef(ApiKeyComponent, this.rotateUserApiKeyModalRef, (comp) => { - comp.keyType = "user"; - comp.isRotation = true; - comp.entityId = entityId; - comp.postKey = this.apiService.postUserRotateApiKey.bind(this.apiService); - comp.scope = "api"; - comp.grantType = "client_credentials"; - comp.apiKeyTitle = "apiKey"; - comp.apiKeyWarning = "userApiKeyWarning"; - comp.apiKeyDescription = "apiKeyRotateDesc"; - }); - } } diff --git a/src/app/settings/change-kdf.component.html b/src/app/settings/change-kdf.component.html index ebd616f1..b87e6c12 100644 --- a/src/app/settings/change-kdf.component.html +++ b/src/app/settings/change-kdf.component.html @@ -1,4 +1,7 @@ -{{ "loggedOutWarning" | i18n }} +
+

{{ "encKeySettings" | i18n }}

+
+{{ "loggedOutWarning" | i18n }}
@@ -68,7 +71,7 @@
- diff --git a/src/app/settings/change-password.component.html b/src/app/settings/change-password.component.html index 2b3b6f53..f8a4dd4c 100644 --- a/src/app/settings/change-password.component.html +++ b/src/app/settings/change-password.component.html @@ -1,4 +1,8 @@ -{{ "loggedOutWarning" | i18n }} +
+

{{ "changeMasterPassword" | i18n }}

+
+ +{{ "loggedOutWarning" | i18n }} - diff --git a/src/app/settings/change-password.component.ts b/src/app/settings/change-password.component.ts index d2311b1f..577c66b0 100644 --- a/src/app/settings/change-password.component.ts +++ b/src/app/settings/change-password.component.ts @@ -1,4 +1,5 @@ import { Component } from "@angular/core"; +import { Router } from "@angular/router"; import { ChangePasswordComponent as BaseChangePasswordComponent } from "jslib-angular/components/change-password.component"; import { ApiService } from "jslib-common/abstractions/api.service"; @@ -6,6 +7,7 @@ import { CipherService } from "jslib-common/abstractions/cipher.service"; import { CryptoService } from "jslib-common/abstractions/crypto.service"; import { FolderService } from "jslib-common/abstractions/folder.service"; import { I18nService } from "jslib-common/abstractions/i18n.service"; +import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service"; import { MessagingService } from "jslib-common/abstractions/messaging.service"; import { OrganizationService } from "jslib-common/abstractions/organization.service"; import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service"; @@ -47,7 +49,9 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { private syncService: SyncService, private apiService: ApiService, private sendService: SendService, - private organizationService: OrganizationService + private organizationService: OrganizationService, + private keyConnectorService: KeyConnectorService, + private router: Router ) { super( i18nService, @@ -60,6 +64,12 @@ export class ChangePasswordComponent extends BaseChangePasswordComponent { ); } + async ngOnInit() { + if (await this.keyConnectorService.getUsesKeyConnector()) { + this.router.navigate(["/settings/security/two-factor"]); + } + } + async rotateEncKeyClicked() { if (this.rotateEncKey) { const ciphers = await this.cipherService.getAllDecrypted(); diff --git a/src/app/settings/security-keys.component.html b/src/app/settings/security-keys.component.html new file mode 100644 index 00000000..9c9b8df5 --- /dev/null +++ b/src/app/settings/security-keys.component.html @@ -0,0 +1,18 @@ + +
+

{{ "apiKey" | i18n }}

+
+

+ {{ "userApiKeyDesc" | i18n }} +

+ + + + diff --git a/src/app/settings/security-keys.component.ts b/src/app/settings/security-keys.component.ts new file mode 100644 index 00000000..650f5c48 --- /dev/null +++ b/src/app/settings/security-keys.component.ts @@ -0,0 +1,61 @@ +import { Component, OnInit, ViewChild, ViewContainerRef } from "@angular/core"; + +import { ModalService } from "jslib-angular/services/modal.service"; +import { ApiService } from "jslib-common/abstractions/api.service"; +import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service"; +import { StateService } from "jslib-common/abstractions/state.service"; + +import { ApiKeyComponent } from "./api-key.component"; + +@Component({ + selector: "app-security-keys", + templateUrl: "security-keys.component.html", +}) +export class SecurityKeysComponent implements OnInit { + @ViewChild("viewUserApiKeyTemplate", { read: ViewContainerRef, static: true }) + viewUserApiKeyModalRef: ViewContainerRef; + @ViewChild("rotateUserApiKeyTemplate", { read: ViewContainerRef, static: true }) + rotateUserApiKeyModalRef: ViewContainerRef; + + showChangeKdf = true; + + constructor( + private keyConnectorService: KeyConnectorService, + private stateService: StateService, + private modalService: ModalService, + private apiService: ApiService + ) {} + + async ngOnInit() { + this.showChangeKdf = !(await this.keyConnectorService.getUsesKeyConnector()); + } + + async viewUserApiKey() { + const entityId = await this.stateService.getUserId(); + await this.modalService.openViewRef(ApiKeyComponent, this.viewUserApiKeyModalRef, (comp) => { + comp.keyType = "user"; + comp.entityId = entityId; + comp.postKey = this.apiService.postUserApiKey.bind(this.apiService); + comp.scope = "api"; + comp.grantType = "client_credentials"; + comp.apiKeyTitle = "apiKey"; + comp.apiKeyWarning = "userApiKeyWarning"; + comp.apiKeyDescription = "userApiKeyDesc"; + }); + } + + async rotateUserApiKey() { + const entityId = await this.stateService.getUserId(); + await this.modalService.openViewRef(ApiKeyComponent, this.rotateUserApiKeyModalRef, (comp) => { + comp.keyType = "user"; + comp.isRotation = true; + comp.entityId = entityId; + comp.postKey = this.apiService.postUserRotateApiKey.bind(this.apiService); + comp.scope = "api"; + comp.grantType = "client_credentials"; + comp.apiKeyTitle = "apiKey"; + comp.apiKeyWarning = "userApiKeyWarning"; + comp.apiKeyDescription = "apiKeyRotateDesc"; + }); + } +} diff --git a/src/app/settings/security.component.html b/src/app/settings/security.component.html new file mode 100644 index 00000000..6e6b76fb --- /dev/null +++ b/src/app/settings/security.component.html @@ -0,0 +1,22 @@ +
+ +
+ diff --git a/src/app/settings/security.component.ts b/src/app/settings/security.component.ts new file mode 100644 index 00000000..7312392e --- /dev/null +++ b/src/app/settings/security.component.ts @@ -0,0 +1,17 @@ +import { Component } from "@angular/core"; + +import { KeyConnectorService } from "jslib-common/abstractions/keyConnector.service"; + +@Component({ + selector: "app-security", + templateUrl: "security.component.html", +}) +export class SecurityComponent { + showChangePassword = true; + + constructor(private keyConnectorService: KeyConnectorService) {} + + async ngOnInit() { + this.showChangePassword = !(await this.keyConnectorService.getUsesKeyConnector()); + } +} diff --git a/src/app/settings/security.module.ts b/src/app/settings/security.module.ts new file mode 100644 index 00000000..16b79a5b --- /dev/null +++ b/src/app/settings/security.module.ts @@ -0,0 +1,39 @@ +import { NgModule } from "@angular/core"; +import { RouterModule, Routes } from "@angular/router"; + +import { ChangePasswordComponent } from "./change-password.component"; +import { SecurityKeysComponent } from "./security-keys.component"; +import { SecurityComponent } from "./security.component"; +import { TwoFactorSetupComponent } from "./two-factor-setup.component"; + +const routes: Routes = [ + { + path: "", + component: SecurityComponent, + data: { titleId: "security" }, + children: [ + { path: "", pathMatch: "full", redirectTo: "change-password" }, + { + path: "change-password", + component: ChangePasswordComponent, + data: { titleId: "masterPassword" }, + }, + { + path: "two-factor", + component: TwoFactorSetupComponent, + data: { titleId: "twoStepLogin" }, + }, + { + path: "security-keys", + component: SecurityKeysComponent, + data: { titleId: "keys" }, + }, + ], + }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], +}) +export class SecurityModule {} diff --git a/src/app/settings/settings.component.html b/src/app/settings/settings.component.html index a0e5a15f..9c3c36cc 100644 --- a/src/app/settings/settings.component.html +++ b/src/app/settings/settings.component.html @@ -7,6 +7,9 @@ {{ "myAccount" | i18n }} + + {{ "security" | i18n }} + {{ "preferences" | i18n }} @@ -37,9 +40,6 @@ > {{ "billing" | i18n }} - - {{ "twoStepLogin" | i18n }} - {{ "domainRules" | i18n }} diff --git a/src/app/settings/two-factor-setup.component.html b/src/app/settings/two-factor-setup.component.html index d3e4c453..549636f8 100644 --- a/src/app/settings/two-factor-setup.component.html +++ b/src/app/settings/two-factor-setup.component.html @@ -1,14 +1,14 @@ -