mirror of
https://github.com/bitwarden/browser.git
synced 2025-03-19 14:49:13 +01:00
[EC-143] [BEEEP] Allow linking to ciphers (#1579)
Co-authored-by: Matt Gibson <mgibson@bitwarden.com>
This commit is contained in:
parent
705251fbe2
commit
0444b78ad1
@ -24,7 +24,11 @@
|
||||
<p>{{ "joinProviderDesc" | i18n }}</p>
|
||||
<hr />
|
||||
<div class="d-flex">
|
||||
<a routerLink="/" [queryParams]="{ email: email }" class="btn btn-primary btn-block">
|
||||
<a
|
||||
routerLink="/login"
|
||||
[queryParams]="{ email: email }"
|
||||
class="btn btn-primary btn-block"
|
||||
>
|
||||
{{ "logIn" | i18n }}
|
||||
</a>
|
||||
<a
|
||||
|
@ -20,7 +20,11 @@
|
||||
<p>{{ "setupProviderLoginDesc" | i18n }}</p>
|
||||
<hr />
|
||||
<div class="d-flex">
|
||||
<a routerLink="/" [queryParams]="{ email: email }" class="btn btn-primary btn-block">
|
||||
<a
|
||||
routerLink="/login"
|
||||
[queryParams]="{ email: email }"
|
||||
class="btn btn-primary btn-block"
|
||||
>
|
||||
{{ "logIn" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
|
2
jslib
2
jslib
@ -1 +1 @@
|
||||
Subproject commit 6bcadc4f408db2c150753f53a07d6f8888b6e9ff
|
||||
Subproject commit f6e3481fe96690a3c52f7701d92b4e57f69f976a
|
@ -23,7 +23,11 @@
|
||||
<p>{{ "acceptEmergencyAccess" | i18n }}</p>
|
||||
<hr />
|
||||
<div class="d-flex">
|
||||
<a routerLink="/" [queryParams]="{ email: email }" class="btn btn-primary btn-block">
|
||||
<a
|
||||
routerLink="/login"
|
||||
[queryParams]="{ email: email }"
|
||||
class="btn btn-primary btn-block"
|
||||
>
|
||||
{{ "logIn" | i18n }}
|
||||
</a>
|
||||
<a
|
||||
|
@ -24,7 +24,11 @@
|
||||
<p>{{ "joinOrganizationDesc" | i18n }}</p>
|
||||
<hr />
|
||||
<div class="d-flex">
|
||||
<a routerLink="/" [queryParams]="{ email: email }" class="btn btn-primary btn-block">
|
||||
<a
|
||||
routerLink="/login"
|
||||
[queryParams]="{ email: email }"
|
||||
class="btn btn-primary btn-block"
|
||||
>
|
||||
{{ "logIn" | i18n }}
|
||||
</a>
|
||||
<a
|
||||
|
@ -33,7 +33,7 @@
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</button>
|
||||
<a routerLink="/" class="btn btn-outline-secondary btn-block ml-2 mt-0">
|
||||
<a routerLink="/login" class="btn btn-outline-secondary btn-block ml-2 mt-0">
|
||||
{{ "cancel" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -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]);
|
||||
}
|
||||
|
@ -33,7 +33,7 @@
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</button>
|
||||
<a routerLink="/" class="btn btn-outline-secondary btn-block ml-2 mt-0">
|
||||
<a routerLink="/login" class="btn btn-outline-secondary btn-block ml-2 mt-0">
|
||||
{{ "cancel" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
|
@ -65,7 +65,7 @@
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</button>
|
||||
<a routerLink="/" class="btn btn-outline-secondary btn-block ml-2 mt-0">
|
||||
<a routerLink="/login" class="btn btn-outline-secondary btn-block ml-2 mt-0">
|
||||
{{ "cancel" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
|
@ -258,7 +258,7 @@
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</button>
|
||||
<a routerLink="/" class="btn btn-outline-secondary btn-block ml-2 mt-0">
|
||||
<a routerLink="/login" class="btn btn-outline-secondary btn-block ml-2 mt-0">
|
||||
{{ "cancel" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
|
@ -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;
|
||||
|
@ -41,7 +41,7 @@
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</button>
|
||||
<a routerLink="/" class="btn btn-outline-secondary btn-block ml-2 mt-0">
|
||||
<a routerLink="/login" class="btn btn-outline-secondary btn-block ml-2 mt-0">
|
||||
{{ "cancel" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
|
@ -138,7 +138,7 @@
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</button>
|
||||
<a routerLink="/" class="btn btn-outline-secondary btn-block ml-2 mt-0">
|
||||
<a routerLink="/login" class="btn btn-outline-secondary btn-block ml-2 mt-0">
|
||||
{{ "cancel" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
|
@ -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: {
|
||||
|
@ -23,7 +23,7 @@
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</button>
|
||||
<a routerLink="/" class="btn btn-outline-secondary btn-block ml-2 mt-0">
|
||||
<a routerLink="/login" class="btn btn-outline-secondary btn-block ml-2 mt-0">
|
||||
{{ "cancel" | i18n }}
|
||||
</a>
|
||||
</div>
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
24
src/app/guards/home.guard.ts
Normal file
24
src/app/guards/home.guard.ts
Normal file
@ -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 });
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
<div class="mt-5 d-flex justify-content-center" *ngIf="loading">
|
||||
<div>
|
||||
<img class="mb-4 logo logo-themed" alt="Bitwarden" />
|
||||
<p class="text-center">
|
||||
<i
|
||||
class="bwi bwi-spinner bwi-spin bwi-2x text-muted"
|
||||
title="{{ 'loading' | i18n }}"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
<span class="sr-only">{{ "loading" | i18n }}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
@ -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 } });
|
||||
}
|
||||
}
|
||||
}
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
@ -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" },
|
||||
{
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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 {}
|
||||
|
@ -17,10 +17,10 @@
|
||||
</td>
|
||||
<td (click)="checkCipher(c)" class="reduced-lh wrap">
|
||||
<a
|
||||
href="#"
|
||||
appStopClick
|
||||
appStopProp
|
||||
(click)="selectCipher(c)"
|
||||
[routerLink]="[]"
|
||||
[queryParams]="{ cipherId: c.id }"
|
||||
queryParamsHandling="merge"
|
||||
title="{{ 'editItem' | i18n }}"
|
||||
>{{ c.name }}</a
|
||||
>
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
@ -4890,5 +4890,8 @@
|
||||
},
|
||||
"service": {
|
||||
"message": "Service"
|
||||
},
|
||||
"unknownCipher": {
|
||||
"message": "Unknown Item, you may need to login with another account to access this item."
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user