From 56808a7dbbae05d7ed2081e0e3fdab970c00e16f Mon Sep 17 00:00:00 2001 From: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Date: Tue, 19 Apr 2022 17:49:59 +1000 Subject: [PATCH 01/20] Update jslib (#1602) * Update jslib * Update name of UserVerificationComponent --- jslib | 2 +- .../organizations/settings/delete-organization.component.html | 4 ++-- src/app/oss.module.ts | 4 ++-- src/app/settings/api-key.component.html | 4 ++-- src/app/settings/deauthorize-sessions.component.html | 4 ++-- src/app/settings/delete-account.component.html | 4 ++-- src/app/settings/purge-vault.component.html | 4 ++-- src/app/settings/two-factor-verify.component.html | 4 ++-- src/app/tools/export.component.html | 4 ++-- 9 files changed, 17 insertions(+), 17 deletions(-) diff --git a/jslib b/jslib index 3b9ef68f..6bcadc4f 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit 3b9ef68f4b01036c84321d6bb4c3c14288bf137b +Subproject commit 6bcadc4f408db2c150753f53a07d6f8888b6e9ff diff --git a/src/app/organizations/settings/delete-organization.component.html b/src/app/organizations/settings/delete-organization.component.html index 2c3cae47..80d8ae0f 100644 --- a/src/app/organizations/settings/delete-organization.component.html +++ b/src/app/organizations/settings/delete-organization.component.html @@ -44,8 +44,8 @@

- - + +
- - + +
+ {{ "cancel" | i18n }} diff --git a/src/app/accounts/lock.component.ts b/src/app/accounts/lock.component.ts index e61a98a6..4b8a0d4b 100644 --- a/src/app/accounts/lock.component.ts +++ b/src/app/accounts/lock.component.ts @@ -58,7 +58,7 @@ export class LockComponent extends BaseLockComponent { if (previousUrl !== "/" && previousUrl.indexOf("lock") === -1) { this.successRoute = previousUrl; } - this.router.navigate([this.successRoute]); + this.router.navigateByUrl(this.successRoute); }; } } diff --git a/src/app/accounts/login.component.ts b/src/app/accounts/login.component.ts index d5b38bde..d00a6e10 100644 --- a/src/app/accounts/login.component.ts +++ b/src/app/accounts/login.component.ts @@ -20,6 +20,7 @@ import { ListResponse } from "jslib-common/models/response/listResponse"; import { PolicyResponse } from "jslib-common/models/response/policyResponse"; import { StateService } from "../../abstractions/state.service"; +import { RouterService } from "../services/router.service"; @Component({ selector: "app-login", @@ -44,7 +45,8 @@ export class LoginComponent extends BaseLoginComponent { logService: LogService, ngZone: NgZone, protected stateService: StateService, - private messagingService: MessagingService + private messagingService: MessagingService, + private routerService: RouterService ) { super( authService, @@ -70,21 +72,20 @@ export class LoginComponent extends BaseLoginComponent { this.email = qParams.email; } if (qParams.premium != null) { - this.stateService.setLoginRedirect({ route: "/settings/premium" }); + this.routerService.setPreviousUrl("/settings/premium"); } else if (qParams.org != null) { - this.stateService.setLoginRedirect({ - route: "/settings/create-organization", - qParams: { plan: qParams.org }, + const route = this.router.createUrlTree(["settings/create-organization"], { + queryParams: { plan: qParams.org }, }); + this.routerService.setPreviousUrl(route.toString()); } // Are they coming from an email for sponsoring a families organization if (qParams.sponsorshipToken != null) { - // After logging in redirect them to setup the families sponsorship - this.stateService.setLoginRedirect({ - route: "/setup/families-for-enterprise", - qParams: { token: qParams.sponsorshipToken }, + const route = this.router.createUrlTree(["setup/families-for-enterprise"], { + queryParams: { plan: qParams.sponsorshipToken }, }); + this.routerService.setPreviousUrl(route.toString()); } await super.ngOnInit(); this.rememberEmail = await this.stateService.getRememberEmail(); @@ -145,10 +146,9 @@ export class LoginComponent extends BaseLoginComponent { } } - const loginRedirect = await this.stateService.getLoginRedirect(); - if (loginRedirect != null) { - this.router.navigate([loginRedirect.route], { queryParams: loginRedirect.qParams }); - await this.stateService.setLoginRedirect(null); + const previousUrl = this.routerService.getPreviousUrl(); + if (previousUrl) { + this.router.navigateByUrl(previousUrl); } else { this.router.navigate([this.successRoute]); } diff --git a/src/app/accounts/recover-delete.component.html b/src/app/accounts/recover-delete.component.html index a0678e84..5b3ba905 100644 --- a/src/app/accounts/recover-delete.component.html +++ b/src/app/accounts/recover-delete.component.html @@ -33,7 +33,7 @@ aria-hidden="true" > - + {{ "cancel" | i18n }} diff --git a/src/app/accounts/recover-two-factor.component.html b/src/app/accounts/recover-two-factor.component.html index 47744b89..744ce3da 100644 --- a/src/app/accounts/recover-two-factor.component.html +++ b/src/app/accounts/recover-two-factor.component.html @@ -65,7 +65,7 @@ aria-hidden="true" > - + {{ "cancel" | i18n }} diff --git a/src/app/accounts/register.component.html b/src/app/accounts/register.component.html index 75d3883d..d86e0a43 100644 --- a/src/app/accounts/register.component.html +++ b/src/app/accounts/register.component.html @@ -258,7 +258,7 @@ aria-hidden="true" > - + {{ "cancel" | i18n }} diff --git a/src/app/accounts/register.component.ts b/src/app/accounts/register.component.ts index b0fe063f..fd2f3b56 100644 --- a/src/app/accounts/register.component.ts +++ b/src/app/accounts/register.component.ts @@ -18,6 +18,8 @@ import { MasterPasswordPolicyOptions } from "jslib-common/models/domain/masterPa import { Policy } from "jslib-common/models/domain/policy"; import { ReferenceEventRequest } from "jslib-common/models/request/referenceEventRequest"; +import { RouterService } from "../services/router.service"; + @Component({ selector: "app-register", templateUrl: "register.component.html", @@ -41,7 +43,8 @@ export class RegisterComponent extends BaseRegisterComponent { passwordGenerationService: PasswordGenerationService, private policyService: PolicyService, environmentService: EnvironmentService, - logService: LogService + logService: LogService, + private routerService: RouterService ) { super( authService, @@ -64,14 +67,14 @@ export class RegisterComponent extends BaseRegisterComponent { this.email = qParams.email; } if (qParams.premium != null) { - this.stateService.setLoginRedirect({ route: "/settings/premium" }); + this.routerService.setPreviousUrl("/settings/premium"); } else if (qParams.org != null) { this.showCreateOrgMessage = true; this.referenceData.flow = qParams.org; - this.stateService.setLoginRedirect({ - route: "/settings/create-organization", - qParams: { plan: qParams.org }, + const route = this.router.createUrlTree(["settings/create-organization"], { + queryParams: { plan: qParams.org }, }); + this.routerService.setPreviousUrl(route.toString()); } if (qParams.layout != null) { this.layout = this.referenceData.layout = qParams.layout; @@ -88,10 +91,10 @@ export class RegisterComponent extends BaseRegisterComponent { // Are they coming from an email for sponsoring a families organization if (qParams.sponsorshipToken != null) { // After logging in redirect them to setup the families sponsorship - this.stateService.setLoginRedirect({ - route: "/setup/families-for-enterprise", - qParams: { token: qParams.sponsorshipToken }, + const route = this.router.createUrlTree(["setup/families-for-enterprise"], { + queryParams: { plan: qParams.sponsorshipToken }, }); + this.routerService.setPreviousUrl(route.toString()); } if (this.referenceData.id === "") { this.referenceData.id = null; diff --git a/src/app/accounts/sso.component.html b/src/app/accounts/sso.component.html index 84ae4749..f5588953 100644 --- a/src/app/accounts/sso.component.html +++ b/src/app/accounts/sso.component.html @@ -41,7 +41,7 @@ aria-hidden="true" > - + {{ "cancel" | i18n }} diff --git a/src/app/accounts/two-factor.component.html b/src/app/accounts/two-factor.component.html index 64961e98..835fd12e 100644 --- a/src/app/accounts/two-factor.component.html +++ b/src/app/accounts/two-factor.component.html @@ -138,7 +138,7 @@ aria-hidden="true" > - + {{ "cancel" | i18n }} diff --git a/src/app/accounts/two-factor.component.ts b/src/app/accounts/two-factor.component.ts index 34cb40a9..5c75577b 100644 --- a/src/app/accounts/two-factor.component.ts +++ b/src/app/accounts/two-factor.component.ts @@ -13,6 +13,8 @@ import { StateService } from "jslib-common/abstractions/state.service"; import { TwoFactorService } from "jslib-common/abstractions/twoFactor.service"; import { TwoFactorProviderType } from "jslib-common/enums/twoFactorProviderType"; +import { RouterService } from "../services/router.service"; + import { TwoFactorOptionsComponent } from "./two-factor-options.component"; @Component({ @@ -34,7 +36,8 @@ export class TwoFactorComponent extends BaseTwoFactorComponent { private modalService: ModalService, route: ActivatedRoute, logService: LogService, - twoFactorService: TwoFactorService + twoFactorService: TwoFactorService, + private routerService: RouterService ) { super( authService, @@ -70,10 +73,9 @@ export class TwoFactorComponent extends BaseTwoFactorComponent { } async goAfterLogIn() { - const loginRedirect = await this.stateService.getLoginRedirect(); - if (loginRedirect != null) { - this.router.navigate([loginRedirect.route], { queryParams: loginRedirect.qParams }); - await this.stateService.setLoginRedirect(null); + const previousUrl = this.routerService.getPreviousUrl(); + if (previousUrl) { + this.router.navigateByUrl(previousUrl); } else { this.router.navigate([this.successRoute], { queryParams: { diff --git a/src/app/accounts/verify-recover-delete.component.html b/src/app/accounts/verify-recover-delete.component.html index 79fc2fcd..975858ac 100644 --- a/src/app/accounts/verify-recover-delete.component.html +++ b/src/app/accounts/verify-recover-delete.component.html @@ -23,7 +23,7 @@ aria-hidden="true" > - + {{ "cancel" | i18n }} diff --git a/src/app/app.component.ts b/src/app/app.component.ts index cd94408f..9e26f680 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -91,11 +91,17 @@ export class AppComponent implements OnDestroy, OnInit { this.ngZone.run(async () => { switch (message.command) { case "loggedIn": + this.notificationsService.updateConnection(false); + break; case "loggedOut": + this.routerService.setPreviousUrl(null); + this.notificationsService.updateConnection(false); + break; case "unlocked": this.notificationsService.updateConnection(false); break; case "authBlocked": + this.routerService.setPreviousUrl(message.url); this.router.navigate(["/"]); break; case "logout": @@ -109,7 +115,7 @@ export class AppComponent implements OnDestroy, OnInit { this.router.navigate(["lock"]); break; case "lockedUrl": - window.setTimeout(() => this.routerService.setPreviousUrl(message.url), 500); + this.routerService.setPreviousUrl(message.url); break; case "syncStarted": break; diff --git a/src/app/common/base.accept.component.ts b/src/app/common/base.accept.component.ts index fa3398f8..36375fbd 100644 --- a/src/app/common/base.accept.component.ts +++ b/src/app/common/base.accept.component.ts @@ -30,7 +30,6 @@ export abstract class BaseAcceptComponent implements OnInit { ngOnInit() { this.route.queryParams.pipe(first()).subscribe(async (qParams) => { - await this.stateService.setLoginRedirect(null); let error = this.requiredParameters.some((e) => qParams?.[e] == null || qParams[e] === ""); let errorMessage: string = null; if (!error) { @@ -44,11 +43,6 @@ export abstract class BaseAcceptComponent implements OnInit { errorMessage = e.message; } } else { - await this.stateService.setLoginRedirect({ - route: this.getRedirectRoute(), - qParams: qParams, - }); - this.email = qParams.email; await this.unauthedHandler(qParams); } @@ -66,10 +60,4 @@ export abstract class BaseAcceptComponent implements OnInit { this.loading = false; }); } - - getRedirectRoute() { - const urlTree = this.router.parseUrl(this.router.url); - urlTree.queryParams = {}; - return urlTree.toString(); - } } diff --git a/src/app/guards/home.guard.ts b/src/app/guards/home.guard.ts new file mode 100644 index 00000000..c7fa9402 --- /dev/null +++ b/src/app/guards/home.guard.ts @@ -0,0 +1,24 @@ +import { Injectable } from "@angular/core"; +import { ActivatedRouteSnapshot, CanActivate, Router } from "@angular/router"; + +import { StateService } from "jslib-common/abstractions/state.service"; +import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service"; + +@Injectable() +export class HomeGuard implements CanActivate { + constructor( + private vaultTimeoutService: VaultTimeoutService, + private router: Router, + private stateService: StateService + ) {} + + async canActivate(route: ActivatedRouteSnapshot) { + if (!(await this.stateService.getIsAuthenticated())) { + return this.router.createUrlTree(["/login"], { queryParams: route.queryParams }); + } + if (await this.vaultTimeoutService.isLocked()) { + return this.router.createUrlTree(["/lock"], { queryParams: route.queryParams }); + } + return this.router.createUrlTree(["/vault"], { queryParams: route.queryParams }); + } +} diff --git a/src/app/organizations/sponsorships/accept-family-sponsorship.component.html b/src/app/organizations/sponsorships/accept-family-sponsorship.component.html new file mode 100644 index 00000000..e7eb29a3 --- /dev/null +++ b/src/app/organizations/sponsorships/accept-family-sponsorship.component.html @@ -0,0 +1,13 @@ +
+
+ +

+ + {{ "loading" | i18n }} +

+
+
diff --git a/src/app/organizations/sponsorships/accept-family-sponsorship.component.ts b/src/app/organizations/sponsorships/accept-family-sponsorship.component.ts new file mode 100644 index 00000000..acbcaa85 --- /dev/null +++ b/src/app/organizations/sponsorships/accept-family-sponsorship.component.ts @@ -0,0 +1,26 @@ +import { Component } from "@angular/core"; + +import { BaseAcceptComponent } from "src/app/common/base.accept.component"; + +@Component({ + selector: "app-accept-family-sponsorship", + templateUrl: "accept-family-sponsorship.component.html", +}) +export class AcceptFamilySponsorshipComponent extends BaseAcceptComponent { + failedShortMessage = "inviteAcceptFailedShort"; + failedMessage = "inviteAcceptFailed"; + + requiredParameters = ["email", "token"]; + + async authedHandler(qParams: any) { + this.router.navigate(["/setup/families-for-enterprise"], { queryParams: qParams }); + } + + async unauthedHandler(qParams: any) { + if (!qParams.register) { + this.router.navigate(["/login"], { queryParams: { email: qParams.email } }); + } else { + this.router.navigate(["/register"], { queryParams: { email: qParams.email } }); + } + } +} diff --git a/src/app/organizations/vault/vault.component.ts b/src/app/organizations/vault/vault.component.ts index ea7d683e..61c8b100 100644 --- a/src/app/organizations/vault/vault.component.ts +++ b/src/app/organizations/vault/vault.component.ts @@ -12,6 +12,7 @@ import { first } from "rxjs/operators"; import { ModalService } from "jslib-angular/services/modal.service"; import { BroadcasterService } from "jslib-common/abstractions/broadcaster.service"; +import { CipherService } from "jslib-common/abstractions/cipher.service"; import { I18nService } from "jslib-common/abstractions/i18n.service"; import { MessagingService } from "jslib-common/abstractions/messaging.service"; import { OrganizationService } from "jslib-common/abstractions/organization.service"; @@ -64,7 +65,8 @@ export class VaultComponent implements OnInit, OnDestroy { private messagingService: MessagingService, private broadcasterService: BroadcasterService, private ngZone: NgZone, - private platformUtilsService: PlatformUtilsService + private platformUtilsService: PlatformUtilsService, + private cipherService: CipherService ) {} ngOnInit() { @@ -126,6 +128,24 @@ export class VaultComponent implements OnInit, OnDestroy { this.viewEvents(cipher[0]); } } + + this.route.queryParams.subscribe(async (params) => { + if (params.cipherId) { + if ((await this.cipherService.get(params.cipherId)) != null) { + this.editCipherId(params.cipherId); + } else { + this.platformUtilsService.showToast( + "error", + this.i18nService.t("errorOccurred"), + this.i18nService.t("unknownCipher") + ); + this.router.navigate([], { + queryParams: { cipherId: null }, + queryParamsHandling: "merge", + }); + } + } + }); }); }); } @@ -257,12 +277,16 @@ export class VaultComponent implements OnInit, OnDestroy { } async editCipher(cipher: CipherView) { + return this.editCipherId(cipher?.id); + } + + async editCipherId(cipherId: string) { const [modal, childComponent] = await this.modalService.openViewRef( AddEditComponent, this.cipherAddEditModalRef, (comp) => { comp.organization = this.organization; - comp.cipherId = cipher == null ? null : cipher.id; + comp.cipherId = cipherId; comp.onSavedCipher.subscribe(async () => { modal.close(); await this.ciphersComponent.refresh(); @@ -278,6 +302,11 @@ export class VaultComponent implements OnInit, OnDestroy { } ); + modal.onClosedPromise().then(() => { + this.route.params; + this.router.navigate([], { queryParams: { cipherId: null }, queryParamsHandling: "merge" }); + }); + return childComponent; } @@ -321,6 +350,7 @@ export class VaultComponent implements OnInit, OnDestroy { this.router.navigate([], { relativeTo: this.route, queryParams: queryParams, + queryParamsHandling: "merge", replaceUrl: true, }); } diff --git a/src/app/oss-routing.module.ts b/src/app/oss-routing.module.ts index 6c408c13..440113bf 100644 --- a/src/app/oss-routing.module.ts +++ b/src/app/oss-routing.module.ts @@ -22,6 +22,7 @@ import { UpdatePasswordComponent } from "./accounts/update-password.component"; import { UpdateTempPasswordComponent } from "./accounts/update-temp-password.component"; import { VerifyEmailTokenComponent } from "./accounts/verify-email-token.component"; import { VerifyRecoverDeleteComponent } from "./accounts/verify-recover-delete.component"; +import { HomeGuard } from "./guards/home.guard"; import { FrontendLayoutComponent } from "./layouts/frontend-layout.component"; import { OrganizationLayoutComponent } from "./layouts/organization-layout.component"; import { UserLayoutComponent } from "./layouts/user-layout.component"; @@ -36,6 +37,7 @@ import { OrganizationBillingComponent } from "./organizations/settings/organizat import { OrganizationSubscriptionComponent } from "./organizations/settings/organization-subscription.component"; import { SettingsComponent as OrgSettingsComponent } from "./organizations/settings/settings.component"; import { TwoFactorSetupComponent as OrgTwoFactorSetupComponent } from "./organizations/settings/two-factor-setup.component"; +import { AcceptFamilySponsorshipComponent } from "./organizations/sponsorships/accept-family-sponsorship.component"; import { FamiliesForEnterpriseSetupComponent } from "./organizations/sponsorships/families-for-enterprise-setup.component"; import { ExportComponent as OrgExportComponent } from "./organizations/tools/export.component"; import { ExposedPasswordsReportComponent as OrgExposedPasswordsReportComponent } from "./organizations/tools/exposed-passwords-report.component"; @@ -73,8 +75,15 @@ const routes: Routes = [ { path: "", component: FrontendLayoutComponent, + data: { doNotSaveUrl: true }, children: [ - { path: "", pathMatch: "full", component: LoginComponent, canActivate: [UnauthGuardService] }, + { + path: "", + pathMatch: "full", + children: [], // Children lets us have an empty component. + canActivate: [HomeGuard], // Redirects either to vault, login or lock page. + }, + { path: "login", component: LoginComponent, canActivate: [UnauthGuardService] }, { path: "2fa", component: TwoFactorComponent, canActivate: [UnauthGuardService] }, { path: "register", @@ -108,12 +117,17 @@ const routes: Routes = [ { path: "accept-organization", component: AcceptOrganizationComponent, - data: { titleId: "joinOrganization" }, + data: { titleId: "joinOrganization", doNotSaveUrl: false }, }, { path: "accept-emergency", component: AcceptEmergencyComponent, - data: { titleId: "acceptEmergency" }, + data: { titleId: "acceptEmergency", doNotSaveUrl: false }, + }, + { + path: "accept-families-for-enterprise", + component: AcceptFamilySponsorshipComponent, + data: { titleId: "acceptFamilySponsorship", doNotSaveUrl: false }, }, { path: "recover", pathMatch: "full", redirectTo: "recover-2fa" }, { diff --git a/src/app/oss.module.ts b/src/app/oss.module.ts index b4470f0e..4be1f094 100644 --- a/src/app/oss.module.ts +++ b/src/app/oss.module.ts @@ -122,6 +122,7 @@ import { OrganizationBillingComponent } from "./organizations/settings/organizat import { OrganizationSubscriptionComponent } from "./organizations/settings/organization-subscription.component"; import { SettingsComponent as OrgSettingComponent } from "./organizations/settings/settings.component"; import { TwoFactorSetupComponent as OrgTwoFactorSetupComponent } from "./organizations/settings/two-factor-setup.component"; +import { AcceptFamilySponsorshipComponent } from "./organizations/sponsorships/accept-family-sponsorship.component"; import { FamiliesForEnterpriseSetupComponent } from "./organizations/sponsorships/families-for-enterprise-setup.component"; import { ExportComponent as OrgExportComponent } from "./organizations/tools/export.component"; import { ExposedPasswordsReportComponent as OrgExposedPasswordsReportComponent } from "./organizations/tools/exposed-passwords-report.component"; @@ -283,6 +284,7 @@ registerLocaleData(localeZhTw, "zh-TW"); declarations: [ PremiumBadgeComponent, AcceptEmergencyComponent, + AcceptFamilySponsorshipComponent, AcceptOrganizationComponent, AccessComponent, AccountComponent, diff --git a/src/app/services/organization-guard.service.ts b/src/app/services/organization-guard.service.ts index bd999eea..8e883648 100644 --- a/src/app/services/organization-guard.service.ts +++ b/src/app/services/organization-guard.service.ts @@ -4,6 +4,7 @@ import { ActivatedRouteSnapshot, CanActivate, Router } from "@angular/router"; import { I18nService } from "jslib-common/abstractions/i18n.service"; import { OrganizationService } from "jslib-common/abstractions/organization.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; +import { SyncService } from "jslib-common/abstractions/sync.service"; @Injectable() export class OrganizationGuardService implements CanActivate { @@ -11,14 +12,19 @@ export class OrganizationGuardService implements CanActivate { private router: Router, private platformUtilsService: PlatformUtilsService, private i18nService: I18nService, - private organizationService: OrganizationService + private organizationService: OrganizationService, + private syncService: SyncService ) {} async canActivate(route: ActivatedRouteSnapshot) { + // TODO: We need to fix this issue once and for all. + if ((await this.syncService.getLastSync()) == null) { + await this.syncService.fullSync(false); + } + const org = await this.organizationService.get(route.params.organizationId); if (org == null) { - this.router.navigate(["/"]); - return false; + return this.router.createUrlTree(["/"]); } if (!org.isOwner && !org.enabled) { this.platformUtilsService.showToast( @@ -26,8 +32,7 @@ export class OrganizationGuardService implements CanActivate { null, this.i18nService.t("organizationIsDisabled") ); - this.router.navigate(["/"]); - return false; + return this.router.createUrlTree(["/"]); } return true; diff --git a/src/app/services/router.service.ts b/src/app/services/router.service.ts index c71c1a46..7493e2cb 100644 --- a/src/app/services/router.service.ts +++ b/src/app/services/router.service.ts @@ -1,6 +1,7 @@ import { Injectable } from "@angular/core"; import { Title } from "@angular/platform-browser"; import { ActivatedRoute, NavigationEnd, Router } from "@angular/router"; +import { filter } from "rxjs"; import { I18nService } from "jslib-common/abstractions/i18n.service"; @@ -16,31 +17,22 @@ export class RouterService { i18nService: I18nService ) { this.currentUrl = this.router.url; - router.events.subscribe((event) => { - if (event instanceof NavigationEnd) { - this.previousUrl = this.currentUrl; + + router.events + .pipe(filter((e) => e instanceof NavigationEnd)) + .subscribe((event: NavigationEnd) => { this.currentUrl = event.url; let title = i18nService.t("pageTitle", "Bitwarden"); - let titleId: string = null; - let rawTitle: string = null; let child = this.activatedRoute.firstChild; - while (child != null) { - if (child.firstChild != null) { - child = child.firstChild; - } else if (child.snapshot.data != null && child.snapshot.data.title != null) { - rawTitle = child.snapshot.data.title; - break; - } else if (child.snapshot.data != null && child.snapshot.data.titleId != null) { - titleId = child.snapshot.data.titleId; - break; - } else { - titleId = null; - rawTitle = null; - break; - } + while (child.firstChild) { + child = child.firstChild; } + const titleId: string = child?.snapshot?.data?.titleId; + const rawTitle: string = child?.snapshot?.data?.title; + const updateUrl = !child?.snapshot?.data?.doNotSaveUrl ?? true; + if (titleId != null || rawTitle != null) { const newTitle = rawTitle != null ? rawTitle : i18nService.t(titleId); if (newTitle != null && newTitle !== "") { @@ -48,8 +40,10 @@ export class RouterService { } } this.titleService.setTitle(title); - } - }); + if (updateUrl) { + this.setPreviousUrl(this.currentUrl); + } + }); } getPreviousUrl() { diff --git a/src/app/services/services.module.ts b/src/app/services/services.module.ts index c8e95320..cb632358 100644 --- a/src/app/services/services.module.ts +++ b/src/app/services/services.module.ts @@ -45,6 +45,7 @@ import { PasswordRepromptService } from "../../services/passwordReprompt.service import { StateService } from "../../services/state.service"; import { StateMigrationService } from "../../services/stateMigration.service"; import { WebPlatformUtilsService } from "../../services/webPlatformUtils.service"; +import { HomeGuard } from "../guards/home.guard"; import { EventService } from "./event.service"; import { ModalService } from "./modal.service"; @@ -218,6 +219,7 @@ export function initFactory( provide: PasswordRepromptServiceAbstraction, useClass: PasswordRepromptService, }, + HomeGuard, ], }) export class ServicesModule {} diff --git a/src/app/vault/ciphers.component.html b/src/app/vault/ciphers.component.html index f36366b5..17db5838 100644 --- a/src/app/vault/ciphers.component.html +++ b/src/app/vault/ciphers.component.html @@ -17,10 +17,10 @@ {{ c.name }} diff --git a/src/app/vault/vault.component.ts b/src/app/vault/vault.component.ts index c3730bfa..694f2bc6 100644 --- a/src/app/vault/vault.component.ts +++ b/src/app/vault/vault.component.ts @@ -12,6 +12,7 @@ import { first } from "rxjs/operators"; import { ModalService } from "jslib-angular/services/modal.service"; import { BroadcasterService } from "jslib-common/abstractions/broadcaster.service"; +import { CipherService } from "jslib-common/abstractions/cipher.service"; import { CryptoService } from "jslib-common/abstractions/crypto.service"; import { I18nService } from "jslib-common/abstractions/i18n.service"; import { MessagingService } from "jslib-common/abstractions/messaging.service"; @@ -85,7 +86,8 @@ export class VaultComponent implements OnInit, OnDestroy { private ngZone: NgZone, private stateService: StateService, private organizationService: OrganizationService, - private providerService: ProviderService + private providerService: ProviderService, + private cipherService: CipherService ) {} async ngOnInit() { @@ -136,6 +138,24 @@ export class VaultComponent implements OnInit, OnDestroy { } } + this.route.queryParams.subscribe(async (params) => { + if (params.cipherId) { + if ((await this.cipherService.get(params.cipherId)) != null) { + this.editCipherId(params.cipherId); + } else { + this.platformUtilsService.showToast( + "error", + this.i18nService.t("errorOccurred"), + this.i18nService.t("unknownCipher") + ); + this.router.navigate([], { + queryParams: { cipherId: null }, + queryParamsHandling: "merge", + }); + } + } + }); + this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => { this.ngZone.run(async () => { switch (message.command) { @@ -334,11 +354,15 @@ export class VaultComponent implements OnInit, OnDestroy { } async editCipher(cipher: CipherView) { + return this.editCipherId(cipher?.id); + } + + async editCipherId(id: string) { const [modal, childComponent] = await this.modalService.openViewRef( AddEditComponent, this.cipherAddEditModalRef, (comp) => { - comp.cipherId = cipher == null ? null : cipher.id; + comp.cipherId = id; comp.onSavedCipher.subscribe(async () => { modal.close(); await this.ciphersComponent.refresh(); @@ -354,6 +378,11 @@ export class VaultComponent implements OnInit, OnDestroy { } ); + modal.onClosedPromise().then(() => { + this.route.params; + this.router.navigate([], { queryParams: { cipherId: null }, queryParamsHandling: "merge" }); + }); + return childComponent; } @@ -388,6 +417,7 @@ export class VaultComponent implements OnInit, OnDestroy { this.router.navigate([], { relativeTo: this.route, queryParams: queryParams, + queryParamsHandling: "merge", replaceUrl: true, }); } diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json index 2dca55ab..79667769 100644 --- a/src/locales/en/messages.json +++ b/src/locales/en/messages.json @@ -4890,5 +4890,8 @@ }, "service": { "message": "Service" + }, + "unknownCipher": { + "message": "Unknown Item, you may need to login with another account to access this item." } } From 97f38aa654c5fec09228c21f99e95a31bdef6c2a Mon Sep 17 00:00:00 2001 From: Matt Gibson Date: Wed, 27 Apr 2022 09:09:38 -0400 Subject: [PATCH 08/20] Fix login sponsorship redirect (#1620) --- src/app/accounts/login.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/accounts/login.component.ts b/src/app/accounts/login.component.ts index d00a6e10..21a1f6d0 100644 --- a/src/app/accounts/login.component.ts +++ b/src/app/accounts/login.component.ts @@ -83,7 +83,7 @@ export class LoginComponent extends BaseLoginComponent { // Are they coming from an email for sponsoring a families organization if (qParams.sponsorshipToken != null) { const route = this.router.createUrlTree(["setup/families-for-enterprise"], { - queryParams: { plan: qParams.sponsorshipToken }, + queryParams: { token: qParams.sponsorshipToken }, }); this.routerService.setPreviousUrl(route.toString()); } From 0439d37c145e28fa2ba8d881450a5dd3545a4c0f Mon Sep 17 00:00:00 2001 From: dwbit <98768076+dwbit@users.noreply.github.com> Date: Wed, 27 Apr 2022 17:05:30 -0400 Subject: [PATCH 09/20] Contribution Documentation edits (#1599) Making corrections to the mobile contributions doc: Update Crowdin contact from Kyle to dwbit. Update 'User-to-User Support' forum category to 'Ask the Bitwarden Community' --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 21e158bc..bdb83691 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ Here is how you can get involved: - **Write code for a new feature:** Make a new post in the [Github Contributions category](https://community.bitwarden.com/c/github-contributions/) of the Community Forums. Include a description of your proposed contribution, screeshots, and links to any relevant feature requests. This helps get feedback from the community and Bitwarden team members before you start writing code - **Report a bug or submit a bugfix:** Use Github issues and pull requests - **Write documentation:** Submit a pull request to the [Bitwarden help repository](https://github.com/bitwarden/help) -- **Help other users:** Go to the [User-to-User Support category](https://community.bitwarden.com/c/support/) on the Community Forums +- **Help other users:** Go to the [Ask the Bitwarden Community category](https://community.bitwarden.com/c/support/) on the Community Forums - **Translate:** See the localization (l10n) section below ## Contributor Agreement @@ -31,6 +31,6 @@ We use a translation tool called [Crowdin](https://crowdin.com) to help manage o If you are interested in helping translate the Bitwarden web vault into another language (or make a translation correction), please register an account at Crowdin and join our project here: https://crowdin.com/project/bitwarden-web -If the language that you are interested in translating is not already listed, create a new account on Crowdin, join the project, and contact the project owner (https://crowdin.com/profile/kspearrin). +If the language that you are interested in translating is not already listed, create a new account on Crowdin, join the project, and contact the project owner (https://crowdin.com/profile/dwbit). You can read Crowdin's getting started guide for translators here: https://support.crowdin.com/crowdin-intro/ From df7db8ad076b466660184a1a5a6e827e0e5c6e85 Mon Sep 17 00:00:00 2001 From: dwbit <98768076+dwbit@users.noreply.github.com> Date: Wed, 27 Apr 2022 17:06:16 -0400 Subject: [PATCH 10/20] Add description for the A-Z & a-z items (#1615) --- src/locales/en/messages.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json index 79667769..2d872a6e 100644 --- a/src/locales/en/messages.json +++ b/src/locales/en/messages.json @@ -892,10 +892,12 @@ "message": "Length" }, "uppercase": { - "message": "Uppercase (A-Z)" + "message": "Uppercase (A-Z)", + "description": "Include uppercase letters in the password generator." }, "lowercase": { - "message": "Lowercase (a-z)" + "message": "Lowercase (a-z)", + "description": "Include lowercase letters in the password generator." }, "numbers": { "message": "Numbers (0-9)" From 572758c598c85b16283acc655d89ffa20b3a4efd Mon Sep 17 00:00:00 2001 From: dwbit <98768076+dwbit@users.noreply.github.com> Date: Wed, 27 Apr 2022 17:06:50 -0400 Subject: [PATCH 11/20] Add description for reports message (#1600) Add "Vault Health Reports can be used to evaluate the security of your Bitwarden Personal or Organization Vault" description to the source string, "Identify and close security gaps in your online accounts by clicking the reports below." --- src/locales/en/messages.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json index 2d872a6e..cf7c0d4d 100644 --- a/src/locales/en/messages.json +++ b/src/locales/en/messages.json @@ -1445,7 +1445,8 @@ "message": "Reports" }, "reportsDesc": { - "message": "Identify and close security gaps in your online accounts by clicking the reports below." + "message": "Identify and close security gaps in your online accounts by clicking the reports below.", + "description": "Vault Health Reports can be used to evaluate the security of your Bitwarden Personal or Organization Vault." }, "unsecuredWebsitesReport": { "message": "Unsecure Websites" From 96641cf1957514228f62c19a03e398c4de88ad8d Mon Sep 17 00:00:00 2001 From: Matt Gibson Date: Thu, 28 Apr 2022 08:39:59 -0400 Subject: [PATCH 12/20] [PS-301] Load OssModule from BitwardenLicense (#1626) --- bitwarden_license/src/app/app.module.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bitwarden_license/src/app/app.module.ts b/bitwarden_license/src/app/app.module.ts index 781e3f45..a5456619 100644 --- a/bitwarden_license/src/app/app.module.ts +++ b/bitwarden_license/src/app/app.module.ts @@ -8,6 +8,7 @@ import { InfiniteScrollModule } from "ngx-infinite-scroll"; import { JslibModule } from "jslib-angular/jslib.module"; import { OssRoutingModule } from "src/app/oss-routing.module"; +import { OssModule } from "src/app/oss.module"; import { ServicesModule } from "src/app/services/services.module"; import { WildcardRoutingModule } from "src/app/wildcard-routing.module"; @@ -19,6 +20,7 @@ import { MaximumVaultTimeoutPolicyComponent } from "./policies/maximum-vault-tim @NgModule({ imports: [ + OssModule, JslibModule, BrowserAnimationsModule, FormsModule, From f5863596109fdf7fc6b7a3f915b9744950cf0bbd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 28 Apr 2022 11:50:04 -0700 Subject: [PATCH 13/20] Bumped version to 2.28.1 (#1629) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index d0597522..b8cea340 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bitwarden/web-vault", - "version": "2.28.0", + "version": "2.28.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@bitwarden/web-vault", - "version": "2.28.0", + "version": "2.28.1", "hasInstallScript": true, "license": "GPL-3.0", "dependencies": { diff --git a/package.json b/package.json index df7a772f..51124761 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@bitwarden/web-vault", - "version": "2.28.0", + "version": "2.28.1", "license": "GPL-3.0", "repository": "https://github.com/bitwarden/web", "scripts": { From 2b03162bfd180b6f99031091758eb9bc1b60fec1 Mon Sep 17 00:00:00 2001 From: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Date: Fri, 29 Apr 2022 17:45:47 +1000 Subject: [PATCH 14/20] [EC-154] [BEEEP] Remove factory providers in Angular DI (#1609) * use InjectionTokens * Use InitService --- jslib | 2 +- src/app/accounts/two-factor.component.ts | 7 +- src/app/services/init.service.ts | 69 ++++++++++ src/app/services/services.module.ts | 160 +++++------------------ src/app/tools/generator.component.ts | 3 + src/services/webPlatformUtils.service.ts | 2 + 6 files changed, 115 insertions(+), 128 deletions(-) create mode 100644 src/app/services/init.service.ts diff --git a/jslib b/jslib index f6e3481f..d7e55465 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit f6e3481fe96690a3c52f7701d92b4e57f69f976a +Subproject commit d7e554653a7e593f8cdaf7e2fe926eb04fb5d5c5 diff --git a/src/app/accounts/two-factor.component.ts b/src/app/accounts/two-factor.component.ts index 5c75577b..9c860553 100644 --- a/src/app/accounts/two-factor.component.ts +++ b/src/app/accounts/two-factor.component.ts @@ -4,6 +4,7 @@ import { ActivatedRoute, Router } from "@angular/router"; import { TwoFactorComponent as BaseTwoFactorComponent } from "jslib-angular/components/two-factor.component"; import { ModalService } from "jslib-angular/services/modal.service"; import { ApiService } from "jslib-common/abstractions/api.service"; +import { AppIdService } from "jslib-common/abstractions/appId.service"; import { AuthService } from "jslib-common/abstractions/auth.service"; import { EnvironmentService } from "jslib-common/abstractions/environment.service"; import { I18nService } from "jslib-common/abstractions/i18n.service"; @@ -37,7 +38,8 @@ export class TwoFactorComponent extends BaseTwoFactorComponent { route: ActivatedRoute, logService: LogService, twoFactorService: TwoFactorService, - private routerService: RouterService + private routerService: RouterService, + appIdService: AppIdService ) { super( authService, @@ -50,7 +52,8 @@ export class TwoFactorComponent extends BaseTwoFactorComponent { stateService, route, logService, - twoFactorService + twoFactorService, + appIdService ); this.onSuccessfulLoginNavigate = this.goAfterLogIn; } diff --git a/src/app/services/init.service.ts b/src/app/services/init.service.ts new file mode 100644 index 00000000..eacfea97 --- /dev/null +++ b/src/app/services/init.service.ts @@ -0,0 +1,69 @@ +import { Inject, Injectable } from "@angular/core"; + +import { WINDOW } from "jslib-angular/services/jslib-services.module"; +import { CryptoService as CryptoServiceAbstraction } from "jslib-common/abstractions/crypto.service"; +import { + EnvironmentService as EnvironmentServiceAbstraction, + Urls, +} from "jslib-common/abstractions/environment.service"; +import { EventService as EventLoggingServiceAbstraction } from "jslib-common/abstractions/event.service"; +import { I18nService as I18nServiceAbstraction } from "jslib-common/abstractions/i18n.service"; +import { NotificationsService as NotificationsServiceAbstraction } from "jslib-common/abstractions/notifications.service"; +import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "jslib-common/abstractions/platformUtils.service"; +import { StateService as StateServiceAbstraction } from "jslib-common/abstractions/state.service"; +import { TwoFactorService as TwoFactorServiceAbstraction } from "jslib-common/abstractions/twoFactor.service"; +import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "jslib-common/abstractions/vaultTimeout.service"; +import { ThemeType } from "jslib-common/enums/themeType"; +import { ContainerService } from "jslib-common/services/container.service"; +import { EventService as EventLoggingService } from "jslib-common/services/event.service"; +import { VaultTimeoutService as VaultTimeoutService } from "jslib-common/services/vaultTimeout.service"; + +import { I18nService as I18nService } from "../../services/i18n.service"; + +@Injectable() +export class InitService { + constructor( + @Inject(WINDOW) private win: Window, + private environmentService: EnvironmentServiceAbstraction, + private notificationsService: NotificationsServiceAbstraction, + private vaultTimeoutService: VaultTimeoutServiceAbstraction, + private i18nService: I18nServiceAbstraction, + private eventLoggingService: EventLoggingServiceAbstraction, + private twoFactorService: TwoFactorServiceAbstraction, + private stateService: StateServiceAbstraction, + private platformUtilsService: PlatformUtilsServiceAbstraction, + private cryptoService: CryptoServiceAbstraction + ) {} + + init() { + return async () => { + await this.stateService.init(); + + const urls = process.env.URLS as Urls; + urls.base ??= this.win.location.origin; + this.environmentService.setUrls(urls); + + setTimeout(() => this.notificationsService.init(), 3000); + + (this.vaultTimeoutService as VaultTimeoutService).init(true); + const locale = await this.stateService.getLocale(); + await (this.i18nService as I18nService).init(locale); + (this.eventLoggingService as EventLoggingService).init(true); + this.twoFactorService.init(); + const htmlEl = this.win.document.documentElement; + htmlEl.classList.add("locale_" + this.i18nService.translationLocale); + + // Initial theme is set in index.html which must be updated if there are any changes to theming logic + this.platformUtilsService.onDefaultSystemThemeChange(async (sysTheme) => { + const bwTheme = await this.stateService.getTheme(); + if (bwTheme === ThemeType.System) { + htmlEl.classList.remove("theme_" + ThemeType.Light, "theme_" + ThemeType.Dark); + htmlEl.classList.add("theme_" + sysTheme); + } + }); + + const containerService = new ContainerService(this.cryptoService); + containerService.attachToWindow(this.win); + }; + } +} diff --git a/src/app/services/services.module.ts b/src/app/services/services.module.ts index cb632358..4c5ae204 100644 --- a/src/app/services/services.module.ts +++ b/src/app/services/services.module.ts @@ -1,38 +1,32 @@ import { APP_INITIALIZER, NgModule } from "@angular/core"; import { ToastrModule } from "ngx-toastr"; -import { JslibServicesModule } from "jslib-angular/services/jslib-services.module"; +import { + JslibServicesModule, + WINDOW, + SECURE_STORAGE, + STATE_FACTORY, + STATE_SERVICE_USE_CACHE, + LOCALES_DIRECTORY, + SYSTEM_LANGUAGE, +} from "jslib-angular/services/jslib-services.module"; import { ModalService as ModalServiceAbstraction } from "jslib-angular/services/modal.service"; import { ApiService as ApiServiceAbstraction } from "jslib-common/abstractions/api.service"; import { CipherService as CipherServiceAbstraction } from "jslib-common/abstractions/cipher.service"; import { CollectionService as CollectionServiceAbstraction } from "jslib-common/abstractions/collection.service"; import { CryptoService as CryptoServiceAbstraction } from "jslib-common/abstractions/crypto.service"; -import { CryptoFunctionService as CryptoFunctionServiceAbstraction } from "jslib-common/abstractions/cryptoFunction.service"; -import { - EnvironmentService as EnvironmentServiceAbstraction, - Urls, -} from "jslib-common/abstractions/environment.service"; -import { EventService as EventLoggingServiceAbstraction } from "jslib-common/abstractions/event.service"; import { FolderService as FolderServiceAbstraction } from "jslib-common/abstractions/folder.service"; import { I18nService as I18nServiceAbstraction } from "jslib-common/abstractions/i18n.service"; import { ImportService as ImportServiceAbstraction } from "jslib-common/abstractions/import.service"; import { LogService } from "jslib-common/abstractions/log.service"; import { MessagingService as MessagingServiceAbstraction } from "jslib-common/abstractions/messaging.service"; -import { NotificationsService as NotificationsServiceAbstraction } from "jslib-common/abstractions/notifications.service"; import { PasswordRepromptService as PasswordRepromptServiceAbstraction } from "jslib-common/abstractions/passwordReprompt.service"; import { PlatformUtilsService as PlatformUtilsServiceAbstraction } from "jslib-common/abstractions/platformUtils.service"; import { StateService as BaseStateServiceAbstraction } from "jslib-common/abstractions/state.service"; import { StateMigrationService as StateMigrationServiceAbstraction } from "jslib-common/abstractions/stateMigration.service"; import { StorageService as StorageServiceAbstraction } from "jslib-common/abstractions/storage.service"; -import { TwoFactorService as TwoFactorServiceAbstraction } from "jslib-common/abstractions/twoFactor.service"; -import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "jslib-common/abstractions/vaultTimeout.service"; -import { ThemeType } from "jslib-common/enums/themeType"; import { StateFactory } from "jslib-common/factories/stateFactory"; -import { ContainerService } from "jslib-common/services/container.service"; -import { CryptoService } from "jslib-common/services/crypto.service"; -import { EventService as EventLoggingService } from "jslib-common/services/event.service"; import { ImportService } from "jslib-common/services/import.service"; -import { VaultTimeoutService } from "jslib-common/services/vaultTimeout.service"; import { StateService as StateServiceAbstraction } from "../../abstractions/state.service"; import { Account } from "../../models/account"; @@ -48,107 +42,52 @@ import { WebPlatformUtilsService } from "../../services/webPlatformUtils.service import { HomeGuard } from "../guards/home.guard"; import { EventService } from "./event.service"; +import { InitService } from "./init.service"; import { ModalService } from "./modal.service"; import { OrganizationGuardService } from "./organization-guard.service"; import { OrganizationTypeGuardService } from "./organization-type-guard.service"; import { PolicyListService } from "./policy-list.service"; import { RouterService } from "./router.service"; -export function initFactory( - window: Window, - environmentService: EnvironmentServiceAbstraction, - notificationsService: NotificationsServiceAbstraction, - vaultTimeoutService: VaultTimeoutService, - i18nService: I18nService, - eventLoggingService: EventLoggingService, - twoFactorService: TwoFactorServiceAbstraction, - stateService: StateServiceAbstraction, - platformUtilsService: PlatformUtilsServiceAbstraction, - cryptoService: CryptoServiceAbstraction -): () => void { - return async () => { - await stateService.init(); - - const urls = process.env.URLS as Urls; - urls.base ??= window.location.origin; - environmentService.setUrls(urls); - - setTimeout(() => notificationsService.init(), 3000); - - vaultTimeoutService.init(true); - const locale = await stateService.getLocale(); - await i18nService.init(locale); - eventLoggingService.init(true); - twoFactorService.init(); - const htmlEl = window.document.documentElement; - htmlEl.classList.add("locale_" + i18nService.translationLocale); - - // Initial theme is set in index.html which must be updated if there are any changes to theming logic - platformUtilsService.onDefaultSystemThemeChange(async (sysTheme) => { - const bwTheme = await stateService.getTheme(); - if (bwTheme === ThemeType.System) { - htmlEl.classList.remove("theme_" + ThemeType.Light, "theme_" + ThemeType.Dark); - htmlEl.classList.add("theme_" + sysTheme); - } - }); - - const containerService = new ContainerService(cryptoService); - containerService.attachToWindow(window); - }; -} - @NgModule({ imports: [ToastrModule, JslibServicesModule], declarations: [], providers: [ - { - provide: APP_INITIALIZER, - useFactory: initFactory, - deps: [ - "WINDOW", - EnvironmentServiceAbstraction, - NotificationsServiceAbstraction, - VaultTimeoutServiceAbstraction, - I18nServiceAbstraction, - EventLoggingServiceAbstraction, - TwoFactorServiceAbstraction, - StateServiceAbstraction, - PlatformUtilsServiceAbstraction, - CryptoServiceAbstraction, - ], - multi: true, - }, + InitService, OrganizationGuardService, OrganizationTypeGuardService, RouterService, EventService, PolicyListService, + { + provide: APP_INITIALIZER, + useFactory: (initService: InitService) => initService.init(), + deps: [InitService], + multi: true, + }, + { + provide: STATE_FACTORY, + useValue: new StateFactory(GlobalState, Account), + }, + { + provide: STATE_SERVICE_USE_CACHE, + useValue: false, + }, { provide: I18nServiceAbstraction, - useFactory: (window: Window) => new I18nService(window.navigator.language, "locales"), - deps: ["WINDOW"], + useClass: I18nService, + deps: [SYSTEM_LANGUAGE, LOCALES_DIRECTORY], }, { provide: StorageServiceAbstraction, useClass: HtmlStorageService }, { - provide: "SECURE_STORAGE", + provide: SECURE_STORAGE, // TODO: platformUtilsService.isDev has a helper for this, but using that service here results in a circular dependency. // We have a tech debt item in the backlog to break up platformUtilsService, but in the meantime simply checking the environement here is less cumbersome. useClass: process.env.NODE_ENV === "development" ? HtmlStorageService : MemoryStorageService, }, { provide: PlatformUtilsServiceAbstraction, - useFactory: ( - i18nService: I18nServiceAbstraction, - messagingService: MessagingServiceAbstraction, - logService: LogService, - stateService: StateServiceAbstraction - ) => new WebPlatformUtilsService(i18nService, messagingService, logService, stateService), - deps: [ - I18nServiceAbstraction, - MessagingServiceAbstraction, - LogService, - StateServiceAbstraction, - ], + useClass: WebPlatformUtilsService, }, { provide: MessagingServiceAbstraction, useClass: BroadcasterMessagingService }, { provide: ModalServiceAbstraction, useClass: ModalService }, @@ -165,50 +104,21 @@ export function initFactory( CryptoServiceAbstraction, ], }, - { - provide: CryptoServiceAbstraction, - useClass: CryptoService, - deps: [ - CryptoFunctionServiceAbstraction, - PlatformUtilsServiceAbstraction, - LogService, - StateServiceAbstraction, - ], - }, { provide: StateMigrationServiceAbstraction, - useFactory: ( - storageService: StorageServiceAbstraction, - secureStorageService: StorageServiceAbstraction - ) => - new StateMigrationService( - storageService, - secureStorageService, - new StateFactory(GlobalState, Account) - ), - deps: [StorageServiceAbstraction, "SECURE_STORAGE"], + useClass: StateMigrationService, + deps: [StorageServiceAbstraction, SECURE_STORAGE, STATE_FACTORY], }, { provide: StateServiceAbstraction, - useFactory: ( - storageService: StorageServiceAbstraction, - secureStorageService: StorageServiceAbstraction, - logService: LogService, - stateMigrationService: StateMigrationServiceAbstraction - ) => - new StateService( - storageService, - secureStorageService, - logService, - stateMigrationService, - new StateFactory(GlobalState, Account), - false - ), + useClass: StateService, deps: [ StorageServiceAbstraction, - "SECURE_STORAGE", + SECURE_STORAGE, LogService, StateMigrationServiceAbstraction, + STATE_FACTORY, + STATE_SERVICE_USE_CACHE, ], }, { diff --git a/src/app/tools/generator.component.ts b/src/app/tools/generator.component.ts index 30aeb575..daef4fea 100644 --- a/src/app/tools/generator.component.ts +++ b/src/app/tools/generator.component.ts @@ -4,6 +4,7 @@ import { ActivatedRoute } from "@angular/router"; import { GeneratorComponent as BaseGeneratorComponent } from "jslib-angular/components/generator.component"; import { ModalService } from "jslib-angular/services/modal.service"; import { I18nService } from "jslib-common/abstractions/i18n.service"; +import { LogService } from "jslib-common/abstractions/log.service"; import { PasswordGenerationService } from "jslib-common/abstractions/passwordGeneration.service"; import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service"; import { StateService } from "jslib-common/abstractions/state.service"; @@ -26,6 +27,7 @@ export class GeneratorComponent extends BaseGeneratorComponent { platformUtilsService: PlatformUtilsService, i18nService: I18nService, route: ActivatedRoute, + logService: LogService, private modalService: ModalService ) { super( @@ -34,6 +36,7 @@ export class GeneratorComponent extends BaseGeneratorComponent { platformUtilsService, stateService, i18nService, + logService, route, window ); diff --git a/src/services/webPlatformUtils.service.ts b/src/services/webPlatformUtils.service.ts index 0c9b56fa..755600a1 100644 --- a/src/services/webPlatformUtils.service.ts +++ b/src/services/webPlatformUtils.service.ts @@ -1,3 +1,4 @@ +import { Injectable } from "@angular/core"; import Swal, { SweetAlertIcon } from "sweetalert2"; import { I18nService } from "jslib-common/abstractions/i18n.service"; @@ -9,6 +10,7 @@ import { ClientType } from "jslib-common/enums/clientType"; import { DeviceType } from "jslib-common/enums/deviceType"; import { ThemeType } from "jslib-common/enums/themeType"; +@Injectable() export class WebPlatformUtilsService implements PlatformUtilsService { private browserCache: DeviceType = null; private prefersColorSchemeDark = window.matchMedia("(prefers-color-scheme: dark)"); From 1f0d496f21cfe0eaec4b0860d7efa23330270221 Mon Sep 17 00:00:00 2001 From: Federico Maccaroni Date: Fri, 29 Apr 2022 13:05:05 -0300 Subject: [PATCH 15/20] PS-79 Updated two-factor component to to align to jslib change to send the deviceId on 2fa email resend code (#1624) --- src/app/accounts/two-factor.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/accounts/two-factor.component.ts b/src/app/accounts/two-factor.component.ts index 9c860553..72aa8cf2 100644 --- a/src/app/accounts/two-factor.component.ts +++ b/src/app/accounts/two-factor.component.ts @@ -38,8 +38,8 @@ export class TwoFactorComponent extends BaseTwoFactorComponent { route: ActivatedRoute, logService: LogService, twoFactorService: TwoFactorService, - private routerService: RouterService, - appIdService: AppIdService + appIdService: AppIdService, + private routerService: RouterService ) { super( authService, From 446f2027b4d5d7ed235a92ac648f2244cef0da4f Mon Sep 17 00:00:00 2001 From: Thomas Rittson <31796059+eliykat@users.noreply.github.com> Date: Sat, 30 Apr 2022 10:51:33 +1000 Subject: [PATCH 16/20] [PS-74] Fix user authentication state checks (#1632) * Update to use new authStatus method * Delete unused services and import * update jslib --- jslib | 2 +- src/app/guards/home.guard.ts | 16 +++++++--------- src/app/services/services.module.ts | 1 - 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/jslib b/jslib index d7e55465..2e2849b4 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit d7e554653a7e593f8cdaf7e2fe926eb04fb5d5c5 +Subproject commit 2e2849b4def0534f3f72b7a84c3183ab0b1589f2 diff --git a/src/app/guards/home.guard.ts b/src/app/guards/home.guard.ts index c7fa9402..5dfed1db 100644 --- a/src/app/guards/home.guard.ts +++ b/src/app/guards/home.guard.ts @@ -1,22 +1,20 @@ import { Injectable } from "@angular/core"; import { ActivatedRouteSnapshot, CanActivate, Router } from "@angular/router"; -import { StateService } from "jslib-common/abstractions/state.service"; -import { VaultTimeoutService } from "jslib-common/abstractions/vaultTimeout.service"; +import { AuthService } from "jslib-common/abstractions/auth.service"; +import { AuthenticationStatus } from "jslib-common/enums/authenticationStatus"; @Injectable() export class HomeGuard implements CanActivate { - constructor( - private vaultTimeoutService: VaultTimeoutService, - private router: Router, - private stateService: StateService - ) {} + constructor(private router: Router, private authService: AuthService) {} async canActivate(route: ActivatedRouteSnapshot) { - if (!(await this.stateService.getIsAuthenticated())) { + const authStatus = await this.authService.getAuthStatus(); + + if (authStatus === AuthenticationStatus.LoggedOut) { return this.router.createUrlTree(["/login"], { queryParams: route.queryParams }); } - if (await this.vaultTimeoutService.isLocked()) { + if (authStatus === AuthenticationStatus.Locked) { return this.router.createUrlTree(["/lock"], { queryParams: route.queryParams }); } return this.router.createUrlTree(["/vault"], { queryParams: route.queryParams }); diff --git a/src/app/services/services.module.ts b/src/app/services/services.module.ts index 4c5ae204..543a199c 100644 --- a/src/app/services/services.module.ts +++ b/src/app/services/services.module.ts @@ -3,7 +3,6 @@ import { ToastrModule } from "ngx-toastr"; import { JslibServicesModule, - WINDOW, SECURE_STORAGE, STATE_FACTORY, STATE_SERVICE_USE_CACHE, From 06d95bb22458fe84acf50956c1af7dd7cbbac409 Mon Sep 17 00:00:00 2001 From: Oscar Hinton Date: Mon, 2 May 2022 15:32:44 +0200 Subject: [PATCH 17/20] [PS-381] Fix locale being empty when not configuring a language (#1631) --- src/app/settings/options.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/settings/options.component.ts b/src/app/settings/options.component.ts index 79068240..ccfd9d33 100644 --- a/src/app/settings/options.component.ts +++ b/src/app/settings/options.component.ts @@ -74,7 +74,7 @@ export class OptionsComponent implements OnInit { this.enableGravatars = await this.stateService.getEnableGravitars(); this.enableFullWidth = await this.stateService.getEnableFullWidth(); - this.locale = await this.stateService.getLocale(); + this.locale = (await this.stateService.getLocale()) ?? null; this.startingLocale = this.locale; this.theme = await this.stateService.getTheme(); From 248938ca008b23456da54ac17b831b91db3deade Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Mon, 2 May 2022 10:32:15 -0400 Subject: [PATCH 18/20] Forwarded email providers to username generator (#1628) * forwarded emails * firefox relay * remove firefox relay * update jslib ref * remove dupe logService --- src/app/tools/export.component.html | 15 ++-- src/app/tools/generator.component.html | 103 ++++++++++++++++++++----- src/app/tools/generator.component.ts | 7 +- src/locales/en/messages.json | 13 ++++ webpack.config.js | 2 +- 5 files changed, 111 insertions(+), 29 deletions(-) diff --git a/src/app/tools/export.component.html b/src/app/tools/export.component.html index 077885bc..da667f3e 100644 --- a/src/app/tools/export.component.html +++ b/src/app/tools/export.component.html @@ -31,13 +31,12 @@ - diff --git a/src/app/tools/generator.component.html b/src/app/tools/generator.component.html index 935e07da..f090a99d 100644 --- a/src/app/tools/generator.component.html +++ b/src/app/tools/generator.component.html @@ -265,23 +265,82 @@ -
-
- - + +
+ +
+ + +
-
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+
+
+ + +
+
+
@@ -333,9 +392,15 @@
-
-