2018-01-16 22:12:26 +01:00
|
|
|
import {
|
2018-02-08 21:58:47 +01:00
|
|
|
ChangeDetectorRef,
|
2018-01-16 22:12:26 +01:00
|
|
|
Component,
|
2018-02-08 21:58:47 +01:00
|
|
|
NgZone,
|
2018-02-10 05:25:18 +01:00
|
|
|
OnDestroy,
|
2018-01-16 22:12:26 +01:00
|
|
|
OnInit,
|
2018-01-26 21:44:02 +01:00
|
|
|
ViewChild,
|
2018-01-29 15:33:43 +01:00
|
|
|
ViewContainerRef,
|
2018-01-16 22:12:26 +01:00
|
|
|
} from "@angular/core";
|
2018-01-25 17:21:08 +01:00
|
|
|
import { ActivatedRoute, Router } from "@angular/router";
|
2021-10-14 23:59:08 +02:00
|
|
|
import { first } from "rxjs/operators";
|
2021-12-20 15:47:17 +01:00
|
|
|
|
2021-08-27 15:30:44 +02:00
|
|
|
import { ModalRef } from "jslib-angular/components/modal/modal.ref";
|
2022-05-09 14:19:18 +02:00
|
|
|
import { VaultFilter } from "jslib-angular/modules/vault-filter/models/vault-filter.model";
|
2021-08-27 15:30:44 +02:00
|
|
|
import { ModalService } from "jslib-angular/services/modal.service";
|
2021-12-06 12:03:02 +01:00
|
|
|
import { BroadcasterService } from "jslib-common/abstractions/broadcaster.service";
|
2021-06-07 19:26:36 +02:00
|
|
|
import { EventService } from "jslib-common/abstractions/event.service";
|
|
|
|
import { I18nService } from "jslib-common/abstractions/i18n.service";
|
|
|
|
import { MessagingService } from "jslib-common/abstractions/messaging.service";
|
|
|
|
import { PasswordRepromptService } from "jslib-common/abstractions/passwordReprompt.service";
|
|
|
|
import { PlatformUtilsService } from "jslib-common/abstractions/platformUtils.service";
|
2021-12-15 23:32:00 +01:00
|
|
|
import { StateService } from "jslib-common/abstractions/state.service";
|
2021-06-07 19:26:36 +02:00
|
|
|
import { SyncService } from "jslib-common/abstractions/sync.service";
|
|
|
|
import { TotpService } from "jslib-common/abstractions/totp.service";
|
2022-02-24 20:50:19 +01:00
|
|
|
import { CipherRepromptType } from "jslib-common/enums/cipherRepromptType";
|
|
|
|
import { CipherType } from "jslib-common/enums/cipherType";
|
|
|
|
import { EventType } from "jslib-common/enums/eventType";
|
|
|
|
import { CipherView } from "jslib-common/models/view/cipherView";
|
|
|
|
import { FolderView } from "jslib-common/models/view/folderView";
|
2021-06-07 19:26:36 +02:00
|
|
|
import { invokeMenu, RendererMenuItem } from "jslib-electron/utils";
|
2021-12-20 15:47:17 +01:00
|
|
|
|
2022-02-24 20:50:19 +01:00
|
|
|
import { SearchBarService } from "../layout/search/search-bar.service";
|
2022-05-09 14:19:18 +02:00
|
|
|
import { VaultFilterComponent } from "../modules/vault-filter/vault-filter.component";
|
2022-02-24 20:50:19 +01:00
|
|
|
|
|
|
|
import { AddEditComponent } from "./add-edit.component";
|
|
|
|
import { AttachmentsComponent } from "./attachments.component";
|
|
|
|
import { CiphersComponent } from "./ciphers.component";
|
|
|
|
import { CollectionsComponent } from "./collections.component";
|
|
|
|
import { FolderAddEditComponent } from "./folder-add-edit.component";
|
2022-04-01 00:49:53 +02:00
|
|
|
import { GeneratorComponent } from "./generator.component";
|
2022-02-24 20:50:19 +01:00
|
|
|
import { PasswordHistoryComponent } from "./password-history.component";
|
|
|
|
import { ShareComponent } from "./share.component";
|
|
|
|
import { ViewComponent } from "./view.component";
|
|
|
|
|
2018-02-10 21:22:07 +01:00
|
|
|
const BroadcasterSubscriptionId = "VaultComponent";
|
2018-02-09 21:49:00 +01:00
|
|
|
|
2018-01-16 22:12:26 +01:00
|
|
|
@Component({
|
|
|
|
selector: "app-vault",
|
2018-04-06 18:25:22 +02:00
|
|
|
templateUrl: "vault.component.html",
|
2018-01-16 22:12:26 +01:00
|
|
|
})
|
2018-02-10 05:25:18 +01:00
|
|
|
export class VaultComponent implements OnInit, OnDestroy {
|
2020-02-11 05:00:39 +01:00
|
|
|
@ViewChild(ViewComponent) viewComponent: ViewComponent;
|
2018-01-29 22:33:38 +01:00
|
|
|
@ViewChild(AddEditComponent) addEditComponent: AddEditComponent;
|
2020-08-18 22:13:15 +02:00
|
|
|
@ViewChild(CiphersComponent, { static: true }) ciphersComponent: CiphersComponent;
|
2022-04-01 00:49:53 +02:00
|
|
|
@ViewChild("generator", { read: ViewContainerRef, static: true })
|
|
|
|
generatorModalRef: ViewContainerRef;
|
2022-05-09 14:19:18 +02:00
|
|
|
@ViewChild(VaultFilterComponent, { static: true }) vaultFilterComponent: VaultFilterComponent;
|
2020-08-18 22:13:15 +02:00
|
|
|
@ViewChild("attachments", { read: ViewContainerRef, static: true })
|
|
|
|
attachmentsModalRef: ViewContainerRef;
|
|
|
|
@ViewChild("passwordHistory", { read: ViewContainerRef, static: true })
|
|
|
|
passwordHistoryModalRef: ViewContainerRef;
|
|
|
|
@ViewChild("share", { read: ViewContainerRef, static: true }) shareModalRef: ViewContainerRef;
|
|
|
|
@ViewChild("collections", { read: ViewContainerRef, static: true })
|
|
|
|
collectionsModalRef: ViewContainerRef;
|
2021-02-22 19:17:02 +01:00
|
|
|
@ViewChild("folderAddEdit", { read: ViewContainerRef, static: true })
|
2018-01-27 05:56:43 +01:00
|
|
|
folderAddEditModalRef: ViewContainerRef;
|
2021-12-20 15:47:17 +01:00
|
|
|
|
2018-01-27 05:56:43 +01:00
|
|
|
action: string;
|
|
|
|
cipherId: string = null;
|
2022-02-24 20:50:19 +01:00
|
|
|
favorites = false;
|
2018-02-08 21:58:47 +01:00
|
|
|
type: CipherType = null;
|
2018-10-30 03:43:02 +01:00
|
|
|
folderId: string = null;
|
2019-04-02 15:02:31 +02:00
|
|
|
collectionId: string = null;
|
2022-05-09 14:19:18 +02:00
|
|
|
organizationId: string = null;
|
|
|
|
myVaultOnly = false;
|
2021-08-27 15:30:44 +02:00
|
|
|
addType: CipherType = null;
|
2018-11-30 16:12:30 +01:00
|
|
|
addOrganizationId: string = null;
|
|
|
|
addCollectionIds: string[] = null;
|
2021-08-27 15:30:44 +02:00
|
|
|
showingModal = false;
|
2018-02-08 21:58:47 +01:00
|
|
|
deleted = false;
|
2021-12-15 23:32:00 +01:00
|
|
|
userHasPremiumAccess = false;
|
2022-05-09 14:19:18 +02:00
|
|
|
activeFilter: VaultFilter = new VaultFilter();
|
2021-12-20 15:47:17 +01:00
|
|
|
|
2021-12-15 23:32:00 +01:00
|
|
|
private modal: ModalRef = null;
|
2021-12-20 15:47:17 +01:00
|
|
|
|
2018-02-10 21:22:07 +01:00
|
|
|
constructor(
|
|
|
|
private route: ActivatedRoute,
|
2019-11-07 16:06:00 +01:00
|
|
|
private router: Router,
|
2018-02-08 21:58:47 +01:00
|
|
|
private i18nService: I18nService,
|
2019-11-07 16:06:00 +01:00
|
|
|
private modalService: ModalService,
|
2018-02-08 21:58:47 +01:00
|
|
|
private broadcasterService: BroadcasterService,
|
2018-02-09 18:12:41 +01:00
|
|
|
private changeDetectorRef: ChangeDetectorRef,
|
2021-04-14 23:43:22 +02:00
|
|
|
private ngZone: NgZone,
|
|
|
|
private syncService: SyncService,
|
2018-02-09 18:12:41 +01:00
|
|
|
private messagingService: MessagingService,
|
|
|
|
private platformUtilsService: PlatformUtilsService,
|
|
|
|
private eventService: EventService,
|
|
|
|
private totpService: TotpService,
|
|
|
|
private passwordRepromptService: PasswordRepromptService,
|
2018-02-12 21:06:39 +01:00
|
|
|
private stateService: StateService,
|
2020-02-11 04:37:25 +01:00
|
|
|
private searchBarService: SearchBarService
|
2021-12-20 15:47:17 +01:00
|
|
|
) {}
|
|
|
|
|
2020-02-11 05:00:39 +01:00
|
|
|
async ngOnInit() {
|
|
|
|
this.userHasPremiumAccess = await this.stateService.getCanAccessPremium();
|
|
|
|
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
|
|
|
|
this.ngZone.run(async () => {
|
|
|
|
let detectChanges = true;
|
2021-12-20 15:47:17 +01:00
|
|
|
|
2020-02-11 05:00:39 +01:00
|
|
|
switch (message.command) {
|
|
|
|
case "newLogin":
|
2021-05-04 21:32:03 +02:00
|
|
|
await this.addCipher(CipherType.Login);
|
2020-02-11 04:37:25 +01:00
|
|
|
break;
|
|
|
|
case "newCard":
|
2021-05-04 21:32:03 +02:00
|
|
|
await this.addCipher(CipherType.Card);
|
2020-02-11 04:37:25 +01:00
|
|
|
break;
|
2021-02-08 18:20:12 +01:00
|
|
|
case "newIdentity":
|
|
|
|
await this.addCipher(CipherType.Identity);
|
2021-12-20 15:47:17 +01:00
|
|
|
break;
|
2021-02-08 18:20:12 +01:00
|
|
|
case "newSecureNote":
|
|
|
|
await this.addCipher(CipherType.SecureNote);
|
2021-12-20 15:47:17 +01:00
|
|
|
break;
|
2021-02-08 18:20:12 +01:00
|
|
|
case "focusSearch":
|
2021-05-04 21:32:03 +02:00
|
|
|
(document.querySelector("#search") as HTMLInputElement).select();
|
2018-02-08 21:58:47 +01:00
|
|
|
detectChanges = false;
|
|
|
|
break;
|
2022-03-29 21:01:57 +02:00
|
|
|
case "openGenerator":
|
|
|
|
await this.openGenerator(false);
|
2018-02-08 21:58:47 +01:00
|
|
|
break;
|
2018-02-09 19:47:59 +01:00
|
|
|
case "syncCompleted":
|
2022-05-18 16:46:50 +02:00
|
|
|
await this.ciphersComponent.reload(this.buildFilter());
|
2022-05-09 14:19:18 +02:00
|
|
|
await this.vaultFilterComponent.reloadCollectionsAndFolders(this.activeFilter);
|
2022-05-18 03:08:29 +02:00
|
|
|
await this.vaultFilterComponent.reloadOrganizations();
|
2019-04-14 03:17:05 +02:00
|
|
|
break;
|
2018-02-10 21:22:07 +01:00
|
|
|
case "refreshCiphers":
|
2018-02-09 19:47:59 +01:00
|
|
|
this.ciphersComponent.refresh();
|
2021-12-20 15:47:17 +01:00
|
|
|
break;
|
2018-02-09 19:47:59 +01:00
|
|
|
case "modalShown":
|
|
|
|
this.showingModal = true;
|
2019-03-19 16:34:56 +01:00
|
|
|
break;
|
2020-01-31 17:07:32 +01:00
|
|
|
case "modalClosed":
|
2021-02-22 21:00:19 +01:00
|
|
|
this.showingModal = false;
|
2021-12-20 15:47:17 +01:00
|
|
|
break;
|
2022-02-24 20:50:19 +01:00
|
|
|
case "copyUsername": {
|
2020-04-13 21:13:10 +02:00
|
|
|
const uComponent =
|
2018-12-20 16:16:19 +01:00
|
|
|
this.addEditComponent == null ? this.viewComponent : this.addEditComponent;
|
|
|
|
const uCipher = uComponent != null ? uComponent.cipher : null;
|
2021-12-20 15:47:17 +01:00
|
|
|
if (
|
2018-12-20 16:16:19 +01:00
|
|
|
this.cipherId != null &&
|
|
|
|
uCipher != null &&
|
|
|
|
uCipher.id === this.cipherId &&
|
|
|
|
uCipher.login != null &&
|
|
|
|
uCipher.login.username != null
|
2018-02-09 19:47:59 +01:00
|
|
|
) {
|
2019-03-19 16:34:56 +01:00
|
|
|
this.copyValue(uCipher, uCipher.login.username, "username", "Username");
|
2018-01-27 05:56:43 +01:00
|
|
|
}
|
2018-02-09 19:47:59 +01:00
|
|
|
break;
|
2022-02-24 20:50:19 +01:00
|
|
|
}
|
|
|
|
case "copyPassword": {
|
2018-01-26 20:56:54 +01:00
|
|
|
const pComponent =
|
2018-01-25 17:21:08 +01:00
|
|
|
this.addEditComponent == null ? this.viewComponent : this.addEditComponent;
|
2021-04-07 20:25:15 +02:00
|
|
|
const pCipher = pComponent != null ? pComponent.cipher : null;
|
2020-04-13 21:13:10 +02:00
|
|
|
if (
|
|
|
|
this.cipherId != null &&
|
|
|
|
pCipher != null &&
|
|
|
|
pCipher.id === this.cipherId &&
|
2018-02-16 19:59:46 +01:00
|
|
|
pCipher.login != null &&
|
|
|
|
pCipher.login.password != null &&
|
2019-01-07 16:33:16 +01:00
|
|
|
pCipher.viewPassword
|
2018-02-16 19:59:46 +01:00
|
|
|
) {
|
2021-05-04 21:32:03 +02:00
|
|
|
this.copyValue(pCipher, pCipher.login.password, "password", "Password");
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
break;
|
2022-02-24 20:50:19 +01:00
|
|
|
}
|
|
|
|
case "copyTotp": {
|
2021-02-08 18:20:12 +01:00
|
|
|
const tComponent =
|
2019-07-12 21:23:31 +02:00
|
|
|
this.addEditComponent == null ? this.viewComponent : this.addEditComponent;
|
2018-02-16 19:59:46 +01:00
|
|
|
const tCipher = tComponent != null ? tComponent.cipher : null;
|
|
|
|
if (
|
2021-05-04 21:32:03 +02:00
|
|
|
this.cipherId != null &&
|
2018-02-16 19:59:46 +01:00
|
|
|
tCipher != null &&
|
2019-07-12 21:23:31 +02:00
|
|
|
tCipher.id === this.cipherId &&
|
2019-11-07 16:06:00 +01:00
|
|
|
tCipher.login != null &&
|
|
|
|
tCipher.login.hasTotp &&
|
2021-05-28 20:08:44 +02:00
|
|
|
this.userHasPremiumAccess
|
|
|
|
) {
|
|
|
|
const value = await this.totpService.getCode(tCipher.login.totp);
|
|
|
|
this.copyValue(tCipher, value, "verificationCodeTotp", "TOTP");
|
2018-01-25 17:28:52 +01:00
|
|
|
}
|
2022-02-24 20:50:19 +01:00
|
|
|
break;
|
|
|
|
}
|
2021-12-20 15:47:17 +01:00
|
|
|
default:
|
2018-01-25 17:21:08 +01:00
|
|
|
detectChanges = false;
|
2020-01-31 17:07:32 +01:00
|
|
|
break;
|
2021-05-28 20:08:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (detectChanges) {
|
|
|
|
this.changeDetectorRef.detectChanges();
|
2020-01-31 17:07:32 +01:00
|
|
|
}
|
2021-12-20 15:47:17 +01:00
|
|
|
});
|
|
|
|
});
|
2020-01-31 17:07:32 +01:00
|
|
|
|
|
|
|
if (!this.syncService.syncInProgress) {
|
|
|
|
await this.load();
|
|
|
|
}
|
2019-04-14 03:17:05 +02:00
|
|
|
document.body.classList.remove("layout_frontend");
|
2020-01-31 17:07:32 +01:00
|
|
|
|
2021-05-28 20:08:44 +02:00
|
|
|
this.searchBarService.setEnabled(true);
|
2019-11-07 16:06:00 +01:00
|
|
|
this.searchBarService.setPlaceholderText(this.i18nService.t("searchVault"));
|
2018-01-25 17:28:52 +01:00
|
|
|
}
|
|
|
|
|
2018-01-25 17:21:08 +01:00
|
|
|
ngOnDestroy() {
|
2018-01-26 20:56:54 +01:00
|
|
|
this.searchBarService.setEnabled(false);
|
2018-10-30 03:43:02 +01:00
|
|
|
this.broadcasterService.unsubscribe(BroadcasterSubscriptionId);
|
2018-01-27 14:52:39 +01:00
|
|
|
document.body.classList.add("layout_frontend");
|
2018-01-26 20:56:54 +01:00
|
|
|
}
|
|
|
|
|
2018-02-16 19:59:46 +01:00
|
|
|
async load() {
|
2021-04-07 20:25:15 +02:00
|
|
|
this.route.queryParams.pipe(first()).subscribe(async (params) => {
|
2022-05-09 14:19:18 +02:00
|
|
|
if (params.cipherId) {
|
|
|
|
const cipherView = new CipherView();
|
|
|
|
cipherView.id = params.cipherId;
|
|
|
|
if (params.action === "clone") {
|
|
|
|
await this.cloneCipher(cipherView);
|
|
|
|
} else if (params.action === "edit") {
|
|
|
|
await this.editCipher(cipherView);
|
2021-12-20 15:47:17 +01:00
|
|
|
} else {
|
2022-05-09 14:19:18 +02:00
|
|
|
await this.viewCipher(cipherView);
|
2018-10-23 21:50:21 +02:00
|
|
|
}
|
2022-05-09 14:19:18 +02:00
|
|
|
} else if (params.action === "add") {
|
|
|
|
this.addType = Number(params.addType);
|
|
|
|
this.addCipher(this.addType);
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
2022-05-09 14:19:18 +02:00
|
|
|
|
|
|
|
this.activeFilter = new VaultFilter({
|
|
|
|
status: params.deleted ? "trash" : params.favorites ? "favorites" : "all",
|
|
|
|
cipherType:
|
|
|
|
params.action === "add" || params.type == null ? null : parseInt(params.type, null),
|
|
|
|
selectedFolderId: params.folderId,
|
|
|
|
selectedCollectionId: params.selectedCollectionId,
|
|
|
|
selectedOrganizationId: params.selectedOrganizationId,
|
|
|
|
myVaultOnly: params.myVaultOnly ?? false,
|
|
|
|
});
|
|
|
|
await this.ciphersComponent.reload(this.buildFilter());
|
2021-12-20 15:47:17 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-08-27 15:30:44 +02:00
|
|
|
async viewCipher(cipher: CipherView) {
|
|
|
|
if (!(await this.canNavigateAway("view", cipher))) {
|
|
|
|
return;
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2021-02-03 19:21:22 +01:00
|
|
|
this.cipherId = cipher.id;
|
2021-08-27 15:30:44 +02:00
|
|
|
this.action = "view";
|
2018-01-27 14:52:39 +01:00
|
|
|
this.go();
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2018-10-23 21:50:21 +02:00
|
|
|
viewCipherMenu(cipher: CipherView) {
|
|
|
|
const menu: RendererMenuItem[] = [
|
2021-12-20 15:47:17 +01:00
|
|
|
{
|
2018-10-23 21:50:21 +02:00
|
|
|
label: this.i18nService.t("view"),
|
|
|
|
click: () =>
|
|
|
|
this.functionWithChangeDetection(() => {
|
|
|
|
this.viewCipher(cipher);
|
2021-12-20 15:47:17 +01:00
|
|
|
}),
|
|
|
|
},
|
2018-10-23 21:50:21 +02:00
|
|
|
];
|
|
|
|
if (!cipher.isDeleted) {
|
|
|
|
menu.push({
|
|
|
|
label: this.i18nService.t("edit"),
|
|
|
|
click: () =>
|
|
|
|
this.functionWithChangeDetection(() => {
|
|
|
|
this.editCipher(cipher);
|
2021-12-20 15:47:17 +01:00
|
|
|
}),
|
2018-10-23 21:50:21 +02:00
|
|
|
});
|
2021-04-07 20:25:15 +02:00
|
|
|
menu.push({
|
2021-08-27 15:30:44 +02:00
|
|
|
label: this.i18nService.t("clone"),
|
|
|
|
click: () =>
|
|
|
|
this.functionWithChangeDetection(() => {
|
|
|
|
this.cloneCipher(cipher);
|
2021-12-20 15:47:17 +01:00
|
|
|
}),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-02-16 19:59:46 +01:00
|
|
|
switch (cipher.type) {
|
2021-08-27 15:30:44 +02:00
|
|
|
case CipherType.Login:
|
2018-10-23 21:50:21 +02:00
|
|
|
if (
|
2018-02-16 19:59:46 +01:00
|
|
|
cipher.login.canLaunch ||
|
2018-10-23 21:50:21 +02:00
|
|
|
cipher.login.username != null ||
|
2020-05-27 22:41:57 +02:00
|
|
|
cipher.login.password != null
|
2018-10-23 21:50:21 +02:00
|
|
|
) {
|
|
|
|
menu.push({ type: "separator" });
|
|
|
|
}
|
2021-08-27 15:30:44 +02:00
|
|
|
if (cipher.login.canLaunch) {
|
|
|
|
menu.push({
|
|
|
|
label: this.i18nService.t("launch"),
|
|
|
|
click: () => this.platformUtilsService.launchUri(cipher.login.launchUri),
|
2018-10-23 21:50:21 +02:00
|
|
|
});
|
2018-07-30 16:05:36 +02:00
|
|
|
}
|
2018-01-26 20:56:54 +01:00
|
|
|
if (cipher.login.username != null) {
|
2018-01-27 05:32:03 +01:00
|
|
|
menu.push({
|
2021-12-15 23:32:00 +01:00
|
|
|
label: this.i18nService.t("copyUsername"),
|
2021-02-03 19:21:22 +01:00
|
|
|
click: () => this.copyValue(cipher, cipher.login.username, "username", "Username"),
|
2018-10-30 03:43:02 +01:00
|
|
|
});
|
2018-02-09 18:12:41 +01:00
|
|
|
}
|
2019-01-25 15:30:29 +01:00
|
|
|
if (cipher.login.password != null && cipher.viewPassword) {
|
|
|
|
menu.push({
|
2021-04-22 17:13:21 +02:00
|
|
|
label: this.i18nService.t("copyPassword"),
|
2018-01-29 22:33:38 +01:00
|
|
|
click: () => {
|
|
|
|
this.copyValue(cipher, cipher.login.password, "password", "Password");
|
2021-02-22 19:17:02 +01:00
|
|
|
this.eventService.collect(EventType.Cipher_ClientCopiedPassword, cipher.id);
|
2018-01-30 21:40:06 +01:00
|
|
|
},
|
2018-02-09 18:36:33 +01:00
|
|
|
});
|
|
|
|
}
|
2021-08-27 15:30:44 +02:00
|
|
|
if (cipher.login.hasTotp && (cipher.organizationUseTotp || this.userHasPremiumAccess)) {
|
2018-01-30 21:40:06 +01:00
|
|
|
menu.push({
|
2019-11-07 16:06:00 +01:00
|
|
|
label: this.i18nService.t("copyVerificationCodeTotp"),
|
|
|
|
click: async () => {
|
|
|
|
const value = await this.totpService.getCode(cipher.login.totp);
|
2018-01-27 05:56:43 +01:00
|
|
|
this.copyValue(cipher, value, "verificationCodeTotp", "TOTP");
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
2018-11-30 16:12:30 +01:00
|
|
|
break;
|
2021-05-04 21:32:03 +02:00
|
|
|
case CipherType.Card:
|
2018-10-30 03:43:02 +01:00
|
|
|
if (cipher.card.number != null || cipher.card.code != null) {
|
2021-02-03 19:21:22 +01:00
|
|
|
menu.push({ type: "separator" });
|
2018-10-30 03:43:02 +01:00
|
|
|
}
|
2021-05-28 20:08:44 +02:00
|
|
|
if (cipher.card.number != null) {
|
2021-04-07 20:25:15 +02:00
|
|
|
menu.push({
|
2021-05-28 20:08:44 +02:00
|
|
|
label: this.i18nService.t("copyNumber"),
|
|
|
|
click: () => this.copyValue(cipher, cipher.card.number, "number", "Card Number"),
|
|
|
|
});
|
|
|
|
}
|
2018-02-16 19:59:46 +01:00
|
|
|
if (cipher.card.code != null) {
|
2021-04-07 20:25:15 +02:00
|
|
|
menu.push({
|
2018-02-16 19:59:46 +01:00
|
|
|
label: this.i18nService.t("copySecurityCode"),
|
2019-07-12 21:23:31 +02:00
|
|
|
click: () => {
|
2021-05-28 20:08:44 +02:00
|
|
|
this.copyValue(cipher, cipher.card.code, "securityCode", "Security Code");
|
2019-07-12 21:23:31 +02:00
|
|
|
this.eventService.collect(EventType.Cipher_ClientCopiedCardCode, cipher.id);
|
2021-12-20 15:47:17 +01:00
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-04-07 20:25:15 +02:00
|
|
|
invokeMenu(menu);
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2021-05-28 20:08:44 +02:00
|
|
|
async editCipher(cipher: CipherView) {
|
|
|
|
if (!(await this.canNavigateAway("edit", cipher))) {
|
|
|
|
return;
|
|
|
|
} else if (!(await this.passwordReprompt(cipher))) {
|
2021-12-20 15:47:17 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-05-28 20:08:44 +02:00
|
|
|
await this.editCipherWithoutPasswordPrompt(cipher);
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2021-05-28 20:08:44 +02:00
|
|
|
async editCipherWithoutPasswordPrompt(cipher: CipherView) {
|
|
|
|
if (!(await this.canNavigateAway("edit", cipher))) {
|
2021-12-20 15:47:17 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-26 20:56:54 +01:00
|
|
|
this.cipherId = cipher.id;
|
2020-02-19 20:59:38 +01:00
|
|
|
this.action = "edit";
|
2018-01-27 14:52:39 +01:00
|
|
|
this.go();
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2020-01-31 17:07:32 +01:00
|
|
|
async cloneCipher(cipher: CipherView) {
|
2021-05-28 20:08:44 +02:00
|
|
|
if (!(await this.canNavigateAway("clone", cipher))) {
|
2021-12-20 15:47:17 +01:00
|
|
|
return;
|
2021-05-28 20:08:44 +02:00
|
|
|
} else if (!(await this.passwordReprompt(cipher))) {
|
2021-12-20 15:47:17 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-05-28 20:08:44 +02:00
|
|
|
await this.cloneCipherWithoutPasswordPrompt(cipher);
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2021-05-28 20:08:44 +02:00
|
|
|
async cloneCipherWithoutPasswordPrompt(cipher: CipherView) {
|
|
|
|
if (!(await this.canNavigateAway("edit", cipher))) {
|
2021-12-20 15:47:17 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-26 20:56:54 +01:00
|
|
|
this.cipherId = cipher.id;
|
2020-01-31 17:07:32 +01:00
|
|
|
this.action = "clone";
|
2018-01-27 14:52:39 +01:00
|
|
|
this.go();
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2019-11-07 16:06:00 +01:00
|
|
|
async addCipher(type: CipherType = null) {
|
2021-05-28 20:08:44 +02:00
|
|
|
if (!(await this.canNavigateAway("add", null))) {
|
2021-12-20 15:47:17 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-02-08 21:58:47 +01:00
|
|
|
this.addType = type;
|
2018-01-25 17:21:08 +01:00
|
|
|
this.action = "add";
|
2020-04-13 21:13:10 +02:00
|
|
|
this.cipherId = null;
|
2022-05-18 16:36:33 +02:00
|
|
|
this.prefillNewCipherFromFilter();
|
2018-01-27 14:52:39 +01:00
|
|
|
this.go();
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2018-02-16 19:59:46 +01:00
|
|
|
addCipherOptions() {
|
2021-04-07 20:25:15 +02:00
|
|
|
const menu: RendererMenuItem[] = [
|
2021-12-20 15:47:17 +01:00
|
|
|
{
|
2021-04-07 20:25:15 +02:00
|
|
|
label: this.i18nService.t("typeLogin"),
|
|
|
|
click: () => this.addCipherWithChangeDetection(CipherType.Login),
|
2021-12-20 15:47:17 +01:00
|
|
|
},
|
|
|
|
{
|
2021-04-07 20:25:15 +02:00
|
|
|
label: this.i18nService.t("typeCard"),
|
|
|
|
click: () => this.addCipherWithChangeDetection(CipherType.Card),
|
2021-12-20 15:47:17 +01:00
|
|
|
},
|
|
|
|
{
|
2021-04-07 20:25:15 +02:00
|
|
|
label: this.i18nService.t("typeIdentity"),
|
|
|
|
click: () => this.addCipherWithChangeDetection(CipherType.Identity),
|
2021-12-20 15:47:17 +01:00
|
|
|
},
|
|
|
|
{
|
2021-04-07 20:25:15 +02:00
|
|
|
label: this.i18nService.t("typeSecureNote"),
|
|
|
|
click: () => this.addCipherWithChangeDetection(CipherType.SecureNote),
|
2021-12-20 15:47:17 +01:00
|
|
|
},
|
|
|
|
];
|
|
|
|
|
2021-04-07 20:25:15 +02:00
|
|
|
invokeMenu(menu);
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2018-01-31 23:20:27 +01:00
|
|
|
async savedCipher(cipher: CipherView) {
|
2018-01-26 20:56:54 +01:00
|
|
|
this.cipherId = cipher.id;
|
|
|
|
this.action = "view";
|
2020-04-13 21:13:10 +02:00
|
|
|
this.go();
|
|
|
|
await this.ciphersComponent.refresh();
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2020-04-13 21:13:10 +02:00
|
|
|
async deletedCipher(cipher: CipherView) {
|
|
|
|
this.cipherId = null;
|
2018-01-26 20:56:54 +01:00
|
|
|
this.action = null;
|
2020-04-13 21:13:10 +02:00
|
|
|
this.go();
|
|
|
|
await this.ciphersComponent.refresh();
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2020-04-13 21:13:10 +02:00
|
|
|
async restoredCipher(cipher: CipherView) {
|
|
|
|
this.cipherId = null;
|
2018-01-26 20:56:54 +01:00
|
|
|
this.action = null;
|
2020-04-13 21:13:10 +02:00
|
|
|
this.go();
|
|
|
|
await this.ciphersComponent.refresh();
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2021-05-28 20:08:44 +02:00
|
|
|
async editCipherAttachments(cipher: CipherView) {
|
2018-10-23 21:50:21 +02:00
|
|
|
if (this.modal != null) {
|
|
|
|
this.modal.close();
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2021-08-27 15:30:44 +02:00
|
|
|
const [modal, childComponent] = await this.modalService.openViewRef(
|
|
|
|
AttachmentsComponent,
|
|
|
|
this.attachmentsModalRef,
|
|
|
|
(comp) => (comp.cipherId = cipher.id)
|
2021-12-20 15:47:17 +01:00
|
|
|
);
|
2021-08-27 15:30:44 +02:00
|
|
|
this.modal = modal;
|
2021-12-20 15:47:17 +01:00
|
|
|
|
2018-06-09 19:29:23 +02:00
|
|
|
let madeAttachmentChanges = false;
|
|
|
|
childComponent.onUploadedAttachment.subscribe(() => (madeAttachmentChanges = true));
|
|
|
|
childComponent.onDeletedAttachment.subscribe(() => (madeAttachmentChanges = true));
|
2021-12-20 15:47:17 +01:00
|
|
|
|
2018-10-23 21:50:21 +02:00
|
|
|
this.modal.onClosed.subscribe(async () => {
|
|
|
|
this.modal = null;
|
2018-06-09 19:29:23 +02:00
|
|
|
if (madeAttachmentChanges) {
|
2020-04-13 21:13:10 +02:00
|
|
|
await this.ciphersComponent.refresh();
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
2018-06-09 19:29:23 +02:00
|
|
|
madeAttachmentChanges = false;
|
2021-12-20 15:47:17 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-08-27 15:30:44 +02:00
|
|
|
async shareCipher(cipher: CipherView) {
|
2018-07-30 16:05:36 +02:00
|
|
|
if (this.modal != null) {
|
|
|
|
this.modal.close();
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2021-08-27 15:30:44 +02:00
|
|
|
const [modal, childComponent] = await this.modalService.openViewRef(
|
|
|
|
ShareComponent,
|
|
|
|
this.shareModalRef,
|
|
|
|
(comp) => (comp.cipherId = cipher.id)
|
2021-12-20 15:47:17 +01:00
|
|
|
);
|
2021-08-27 15:30:44 +02:00
|
|
|
this.modal = modal;
|
2021-12-20 15:47:17 +01:00
|
|
|
|
2018-01-30 21:40:06 +01:00
|
|
|
childComponent.onSharedCipher.subscribe(async () => {
|
2018-07-30 16:05:36 +02:00
|
|
|
this.modal.close();
|
2018-10-23 21:50:21 +02:00
|
|
|
this.viewCipher(cipher);
|
2020-04-13 21:13:10 +02:00
|
|
|
await this.ciphersComponent.refresh();
|
2021-12-20 15:47:17 +01:00
|
|
|
});
|
2018-07-30 16:05:36 +02:00
|
|
|
this.modal.onClosed.subscribe(async () => {
|
|
|
|
this.modal = null;
|
2021-12-20 15:47:17 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-05-28 20:08:44 +02:00
|
|
|
async cipherCollections(cipher: CipherView) {
|
2018-07-30 16:05:36 +02:00
|
|
|
if (this.modal != null) {
|
|
|
|
this.modal.close();
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2021-08-27 15:30:44 +02:00
|
|
|
const [modal, childComponent] = await this.modalService.openViewRef(
|
|
|
|
CollectionsComponent,
|
|
|
|
this.collectionsModalRef,
|
|
|
|
(comp) => (comp.cipherId = cipher.id)
|
2021-12-20 15:47:17 +01:00
|
|
|
);
|
2021-08-27 15:30:44 +02:00
|
|
|
this.modal = modal;
|
2021-12-20 15:47:17 +01:00
|
|
|
|
2018-10-23 21:50:21 +02:00
|
|
|
childComponent.onSavedCollections.subscribe(() => {
|
2018-02-09 18:36:33 +01:00
|
|
|
this.modal.close();
|
2018-10-23 21:50:21 +02:00
|
|
|
this.viewCipher(cipher);
|
2021-12-20 15:47:17 +01:00
|
|
|
});
|
2018-07-30 16:05:36 +02:00
|
|
|
this.modal.onClosed.subscribe(async () => {
|
|
|
|
this.modal = null;
|
2021-12-20 15:47:17 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-08-27 15:30:44 +02:00
|
|
|
async viewCipherPasswordHistory(cipher: CipherView) {
|
2018-02-09 18:36:33 +01:00
|
|
|
if (this.modal != null) {
|
|
|
|
this.modal.close();
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2021-08-27 15:30:44 +02:00
|
|
|
[this.modal] = await this.modalService.openViewRef(
|
|
|
|
PasswordHistoryComponent,
|
|
|
|
this.passwordHistoryModalRef,
|
|
|
|
(comp) => (comp.cipherId = cipher.id)
|
2021-12-20 15:47:17 +01:00
|
|
|
);
|
|
|
|
|
2018-07-30 16:05:36 +02:00
|
|
|
this.modal.onClosed.subscribe(async () => {
|
2018-08-02 05:21:32 +02:00
|
|
|
this.modal = null;
|
2021-12-20 15:47:17 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-01-26 20:56:54 +01:00
|
|
|
cancelledAddEdit(cipher: CipherView) {
|
|
|
|
this.cipherId = cipher.id;
|
|
|
|
this.action = this.cipherId != null ? "view" : null;
|
2018-01-27 05:56:43 +01:00
|
|
|
this.go();
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2022-05-09 14:19:18 +02:00
|
|
|
async applyVaultFilter(vaultFilter: VaultFilter) {
|
|
|
|
this.searchBarService.setPlaceholderText(
|
|
|
|
this.i18nService.t(this.calculateSearchBarLocalizationString(vaultFilter))
|
|
|
|
);
|
|
|
|
this.activeFilter = vaultFilter;
|
|
|
|
await this.ciphersComponent.reload(this.buildFilter());
|
2018-01-27 05:56:43 +01:00
|
|
|
this.go();
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2022-05-09 14:19:18 +02:00
|
|
|
private calculateSearchBarLocalizationString(vaultFilter: VaultFilter): string {
|
|
|
|
if (vaultFilter.status === "favorites") {
|
|
|
|
return "searchFavorites";
|
|
|
|
}
|
|
|
|
if (vaultFilter.status === "trash") {
|
|
|
|
return "searchTrash";
|
|
|
|
}
|
|
|
|
if (vaultFilter.cipherType != null) {
|
|
|
|
return "searchType";
|
|
|
|
}
|
|
|
|
if (vaultFilter.selectedFolderId != null && vaultFilter.selectedFolderId != "none") {
|
|
|
|
return "searchFolder";
|
|
|
|
}
|
|
|
|
if (vaultFilter.selectedCollectionId != null) {
|
|
|
|
return "searchCollection";
|
|
|
|
}
|
|
|
|
if (vaultFilter.selectedOrganizationId != null) {
|
|
|
|
return "searchOrganization";
|
|
|
|
}
|
|
|
|
if (vaultFilter.myVaultOnly) {
|
|
|
|
return "searchMyVault";
|
|
|
|
}
|
2021-12-20 15:47:17 +01:00
|
|
|
|
2022-05-09 14:19:18 +02:00
|
|
|
return "searchVault";
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2022-05-09 14:19:18 +02:00
|
|
|
private buildFilter(): (cipher: CipherView) => boolean {
|
|
|
|
return (cipher) => {
|
|
|
|
let cipherPassesFilter = true;
|
|
|
|
if (this.activeFilter.status === "favorites" && cipherPassesFilter) {
|
|
|
|
cipherPassesFilter = cipher.favorite;
|
|
|
|
}
|
|
|
|
if (this.activeFilter.status === "trash" && cipherPassesFilter) {
|
|
|
|
cipherPassesFilter = cipher.isDeleted;
|
|
|
|
}
|
|
|
|
if (this.activeFilter.cipherType != null && cipherPassesFilter) {
|
|
|
|
cipherPassesFilter = cipher.type === this.activeFilter.cipherType;
|
|
|
|
}
|
|
|
|
if (
|
|
|
|
this.activeFilter.selectedFolderId != null &&
|
|
|
|
this.activeFilter.selectedFolderId != "none" &&
|
|
|
|
cipherPassesFilter
|
|
|
|
) {
|
|
|
|
cipherPassesFilter = cipher.folderId === this.activeFilter.selectedFolderId;
|
|
|
|
}
|
|
|
|
if (this.activeFilter.selectedCollectionId != null && cipherPassesFilter) {
|
|
|
|
cipherPassesFilter =
|
|
|
|
cipher.collectionIds != null &&
|
|
|
|
cipher.collectionIds.indexOf(this.activeFilter.selectedCollectionId) > -1;
|
|
|
|
}
|
|
|
|
if (this.activeFilter.selectedOrganizationId != null && cipherPassesFilter) {
|
|
|
|
cipherPassesFilter = cipher.organizationId === this.activeFilter.selectedOrganizationId;
|
|
|
|
}
|
|
|
|
if (this.activeFilter.myVaultOnly && cipherPassesFilter) {
|
|
|
|
cipherPassesFilter = cipher.organizationId === null;
|
|
|
|
}
|
|
|
|
return cipherPassesFilter;
|
|
|
|
};
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2022-04-01 00:49:53 +02:00
|
|
|
async openGenerator(comingFromAddEdit: boolean, passwordType = true) {
|
2018-02-09 18:36:33 +01:00
|
|
|
if (this.modal != null) {
|
|
|
|
this.modal.close();
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2022-03-29 21:01:57 +02:00
|
|
|
const cipher = this.addEditComponent?.cipher;
|
|
|
|
const loginType = cipher != null && cipher.type === CipherType.Login && cipher.login != null;
|
|
|
|
|
2021-08-27 15:30:44 +02:00
|
|
|
const [modal, childComponent] = await this.modalService.openViewRef(
|
2022-04-01 00:49:53 +02:00
|
|
|
GeneratorComponent,
|
|
|
|
this.generatorModalRef,
|
2022-03-29 21:01:57 +02:00
|
|
|
(comp) => {
|
2022-04-01 00:49:53 +02:00
|
|
|
comp.comingFromAddEdit = comingFromAddEdit;
|
|
|
|
if (comingFromAddEdit) {
|
2022-03-29 21:01:57 +02:00
|
|
|
comp.type = passwordType ? "password" : "username";
|
|
|
|
if (loginType && cipher.login.hasUris && cipher.login.uris[0].hostname != null) {
|
|
|
|
comp.usernameWebsite = cipher.login.uris[0].hostname;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-12-20 15:47:17 +01:00
|
|
|
);
|
2021-08-27 15:30:44 +02:00
|
|
|
this.modal = modal;
|
2021-12-20 15:47:17 +01:00
|
|
|
|
2022-03-29 21:01:57 +02:00
|
|
|
childComponent.onSelected.subscribe((value: string) => {
|
2018-02-09 18:36:33 +01:00
|
|
|
this.modal.close();
|
2022-03-29 21:01:57 +02:00
|
|
|
if (loginType) {
|
2021-04-22 17:13:21 +02:00
|
|
|
this.addEditComponent.markPasswordAsDirty();
|
2022-03-29 21:01:57 +02:00
|
|
|
if (passwordType) {
|
|
|
|
this.addEditComponent.cipher.login.password = value;
|
|
|
|
} else {
|
|
|
|
this.addEditComponent.cipher.login.username = value;
|
|
|
|
}
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2018-02-09 18:36:33 +01:00
|
|
|
this.modal.onClosed.subscribe(() => {
|
|
|
|
this.modal = null;
|
2021-12-20 15:47:17 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-01-30 21:40:06 +01:00
|
|
|
async addFolder() {
|
2020-04-14 22:52:03 +02:00
|
|
|
this.messagingService.send("newFolder");
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2018-01-30 21:40:06 +01:00
|
|
|
async editFolder(folderId: string) {
|
2018-02-09 18:36:33 +01:00
|
|
|
if (this.modal != null) {
|
|
|
|
this.modal.close();
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2021-08-27 15:30:44 +02:00
|
|
|
const [modal, childComponent] = await this.modalService.openViewRef(
|
|
|
|
FolderAddEditComponent,
|
|
|
|
this.folderAddEditModalRef,
|
|
|
|
(comp) => (comp.folderId = folderId)
|
2021-12-20 15:47:17 +01:00
|
|
|
);
|
2021-08-27 15:30:44 +02:00
|
|
|
this.modal = modal;
|
2021-12-20 15:47:17 +01:00
|
|
|
|
2018-01-30 21:40:06 +01:00
|
|
|
childComponent.onSavedFolder.subscribe(async (folder: FolderView) => {
|
2018-02-09 18:36:33 +01:00
|
|
|
this.modal.close();
|
2022-05-09 14:19:18 +02:00
|
|
|
await this.vaultFilterComponent.reloadCollectionsAndFolders(this.activeFilter);
|
2021-12-20 15:47:17 +01:00
|
|
|
});
|
2018-01-30 21:40:06 +01:00
|
|
|
childComponent.onDeletedFolder.subscribe(async (folder: FolderView) => {
|
2018-02-09 18:36:33 +01:00
|
|
|
this.modal.close();
|
2022-05-09 14:19:18 +02:00
|
|
|
await this.vaultFilterComponent.reloadCollectionsAndFolders(this.activeFilter);
|
2021-12-20 15:47:17 +01:00
|
|
|
});
|
|
|
|
|
2018-02-09 18:36:33 +01:00
|
|
|
this.modal.onClosed.subscribe(() => {
|
|
|
|
this.modal = null;
|
2021-12-20 15:47:17 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-11-07 16:06:00 +01:00
|
|
|
private dirtyInput(): boolean {
|
2021-12-20 15:47:17 +01:00
|
|
|
return (
|
2020-02-19 20:59:38 +01:00
|
|
|
(this.action === "add" || this.action === "edit" || this.action === "clone") &&
|
2019-11-07 16:06:00 +01:00
|
|
|
document.querySelectorAll("app-vault-add-edit .ng-dirty").length > 0
|
2021-12-20 15:47:17 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-05-28 20:08:44 +02:00
|
|
|
private async wantsToSaveChanges(): Promise<boolean> {
|
|
|
|
const confirmed = await this.platformUtilsService.showDialog(
|
2019-11-07 16:06:00 +01:00
|
|
|
this.i18nService.t("unsavedChangesConfirmation"),
|
|
|
|
this.i18nService.t("unsavedChangesTitle"),
|
2021-04-07 20:25:15 +02:00
|
|
|
this.i18nService.t("yes"),
|
|
|
|
this.i18nService.t("no"),
|
2021-12-20 15:47:17 +01:00
|
|
|
"warning"
|
2021-05-28 20:08:44 +02:00
|
|
|
);
|
|
|
|
return !confirmed;
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2018-01-27 05:56:43 +01:00
|
|
|
private go(queryParams: any = null) {
|
2021-05-28 20:08:44 +02:00
|
|
|
if (queryParams == null) {
|
2018-01-27 05:56:43 +01:00
|
|
|
queryParams = {
|
|
|
|
action: this.action,
|
2018-01-26 20:56:54 +01:00
|
|
|
cipherId: this.cipherId,
|
2018-01-27 05:56:43 +01:00
|
|
|
favorites: this.favorites ? true : null,
|
|
|
|
type: this.type,
|
|
|
|
folderId: this.folderId,
|
|
|
|
collectionId: this.collectionId,
|
2020-04-13 21:13:10 +02:00
|
|
|
deleted: this.deleted ? true : null,
|
2022-05-09 14:19:18 +02:00
|
|
|
organizationId: this.organizationId,
|
|
|
|
myVaultOnly: this.myVaultOnly,
|
2021-12-20 15:47:17 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-11-30 16:12:30 +01:00
|
|
|
this.router.navigate([], {
|
|
|
|
relativeTo: this.route,
|
|
|
|
queryParams: queryParams,
|
|
|
|
replaceUrl: true,
|
2021-12-20 15:47:17 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-02-16 19:59:46 +01:00
|
|
|
private addCipherWithChangeDetection(type: CipherType = null) {
|
2018-02-23 22:31:52 +01:00
|
|
|
this.functionWithChangeDetection(() => this.addCipher(type));
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
2021-05-04 21:32:03 +02:00
|
|
|
private copyValue(cipher: CipherView, value: string, labelI18nKey: string, aType: string) {
|
|
|
|
this.functionWithChangeDetection(async () => {
|
2021-12-20 15:47:17 +01:00
|
|
|
if (
|
2021-05-28 20:08:44 +02:00
|
|
|
cipher.reprompt !== CipherRepromptType.None &&
|
2021-05-04 21:32:03 +02:00
|
|
|
this.passwordRepromptService.protectedFields().includes(aType) &&
|
2021-05-28 20:08:44 +02:00
|
|
|
!(await this.passwordRepromptService.showPasswordPrompt())
|
2021-12-20 15:47:17 +01:00
|
|
|
) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-02-23 22:31:52 +01:00
|
|
|
this.platformUtilsService.copyToClipboard(value);
|
2021-12-07 20:42:31 +01:00
|
|
|
this.platformUtilsService.showToast(
|
2021-12-20 15:47:17 +01:00
|
|
|
"info",
|
|
|
|
null,
|
2018-02-23 22:31:52 +01:00
|
|
|
this.i18nService.t("valueCopied", this.i18nService.t(labelI18nKey))
|
2021-12-20 15:47:17 +01:00
|
|
|
);
|
2020-04-14 22:52:03 +02:00
|
|
|
if (this.action === "view") {
|
|
|
|
this.messagingService.send("minimizeOnCopy");
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-02-24 20:50:19 +01:00
|
|
|
private functionWithChangeDetection(func: () => void) {
|
2019-11-07 17:25:20 +01:00
|
|
|
this.ngZone.run(() => {
|
2021-12-20 15:47:17 +01:00
|
|
|
func();
|
2018-02-16 19:59:46 +01:00
|
|
|
this.changeDetectorRef.detectChanges();
|
2021-12-20 15:47:17 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-05-18 16:36:33 +02:00
|
|
|
private prefillNewCipherFromFilter() {
|
|
|
|
if (this.activeFilter.selectedCollectionId != null) {
|
|
|
|
const collection = this.vaultFilterComponent.collections.fullList.filter(
|
|
|
|
(c) => c.id === this.activeFilter.selectedCollectionId
|
2021-12-20 15:47:17 +01:00
|
|
|
);
|
2022-05-18 16:36:33 +02:00
|
|
|
if (collection.length > 0) {
|
2018-10-30 03:43:02 +01:00
|
|
|
this.addOrganizationId = collection[0].organizationId;
|
2022-05-18 16:36:33 +02:00
|
|
|
this.addCollectionIds = [this.activeFilter.selectedCollectionId];
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
2022-05-18 16:36:33 +02:00
|
|
|
} else if (this.activeFilter.selectedOrganizationId) {
|
|
|
|
this.addOrganizationId = this.activeFilter.selectedOrganizationId;
|
|
|
|
}
|
|
|
|
if (this.activeFilter.selectedFolderId && this.activeFilter.selectedFolder) {
|
|
|
|
this.folderId = this.activeFilter.selectedFolderId;
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-28 20:08:44 +02:00
|
|
|
private async canNavigateAway(action: string, cipher?: CipherView) {
|
|
|
|
// Don't navigate to same route
|
|
|
|
if (this.action === action && (cipher == null || this.cipherId === cipher.id)) {
|
|
|
|
return false;
|
|
|
|
} else if (this.dirtyInput() && (await this.wantsToSaveChanges())) {
|
|
|
|
return false;
|
2021-12-20 15:47:17 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-05-28 20:08:44 +02:00
|
|
|
private async passwordReprompt(cipher: CipherView) {
|
2021-12-20 15:47:17 +01:00
|
|
|
return (
|
2021-05-04 21:32:03 +02:00
|
|
|
cipher.reprompt === CipherRepromptType.None ||
|
|
|
|
(await this.passwordRepromptService.showPasswordPrompt())
|
2021-12-20 15:47:17 +01:00
|
|
|
);
|
|
|
|
}
|
2018-01-16 22:12:26 +01:00
|
|
|
}
|