bitwarden-estensione-browser/src/app/vault/add-edit.component.ts

285 lines
11 KiB
TypeScript
Raw Normal View History

2018-01-26 20:56:54 +01:00
import * as template from './add-edit.component.html';
2018-01-24 23:41:57 +01:00
import {
Component,
2018-01-26 20:56:54 +01:00
EventEmitter,
2018-01-24 23:41:57 +01:00
Input,
OnChanges,
2018-01-26 20:56:54 +01:00
Output,
2018-01-24 23:41:57 +01:00
} from '@angular/core';
2018-01-26 20:12:41 +01:00
import { ToasterService } from 'angular2-toaster';
2018-02-08 16:37:54 +01:00
import { Angulartics2 } from 'angulartics2';
2018-01-26 20:12:41 +01:00
2018-01-25 20:57:49 +01:00
import { CipherType } from 'jslib/enums/cipherType';
2018-01-25 22:15:47 +01:00
import { FieldType } from 'jslib/enums/fieldType';
2018-01-25 20:57:49 +01:00
import { SecureNoteType } from 'jslib/enums/secureNoteType';
2018-03-02 05:45:12 +01:00
import { UriMatchType } from 'jslib/enums/uriMatchType';
2018-01-25 20:57:49 +01:00
import { AuditService } from 'jslib/abstractions/audit.service';
2018-01-24 23:41:57 +01:00
import { CipherService } from 'jslib/abstractions/cipher.service';
2018-01-25 22:15:47 +01:00
import { FolderService } from 'jslib/abstractions/folder.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
2018-01-26 05:15:56 +01:00
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
2018-01-24 23:41:57 +01:00
2018-01-25 20:57:49 +01:00
import { CardView } from 'jslib/models/view/cardView';
2018-01-24 23:41:57 +01:00
import { CipherView } from 'jslib/models/view/cipherView';
2018-01-26 04:54:09 +01:00
import { FieldView } from 'jslib/models/view/fieldView';
2018-01-25 22:15:47 +01:00
import { FolderView } from 'jslib/models/view/folderView';
2018-01-25 20:57:49 +01:00
import { IdentityView } from 'jslib/models/view/identityView';
2018-03-02 05:45:12 +01:00
import { LoginUriView } from 'jslib/models/view/loginUriView';
2018-01-25 20:57:49 +01:00
import { LoginView } from 'jslib/models/view/loginView';
import { SecureNoteView } from 'jslib/models/view/secureNoteView';
2018-01-24 23:41:57 +01:00
@Component({
2018-01-26 20:56:54 +01:00
selector: 'app-vault-add-edit',
2018-01-24 23:41:57 +01:00
template: template,
})
2018-01-26 20:56:54 +01:00
export class AddEditComponent implements OnChanges {
2018-01-24 23:41:57 +01:00
@Input() folderId: string;
2018-01-26 20:56:54 +01:00
@Input() cipherId: string;
2018-02-08 21:58:47 +01:00
@Input() type: CipherType;
2018-01-26 20:56:54 +01:00
@Output() onSavedCipher = new EventEmitter<CipherView>();
2018-01-26 21:44:02 +01:00
@Output() onDeletedCipher = new EventEmitter<CipherView>();
2018-01-26 20:56:54 +01:00
@Output() onCancelled = new EventEmitter<CipherView>();
@Output() onEditAttachments = new EventEmitter<CipherView>();
2018-01-29 15:33:43 +01:00
@Output() onGeneratePassword = new EventEmitter();
2018-01-26 20:56:54 +01:00
editMode: boolean = false;
2018-01-24 23:41:57 +01:00
cipher: CipherView;
2018-01-25 22:15:47 +01:00
folders: FolderView[];
2018-01-31 18:52:12 +01:00
title: string;
formPromise: Promise<any>;
deletePromise: Promise<any>;
checkPasswordPromise: Promise<number>;
2018-01-29 23:11:31 +01:00
showPassword: boolean = false;
2018-01-25 22:15:47 +01:00
cipherType = CipherType;
fieldType = FieldType;
2018-01-26 04:54:09 +01:00
addFieldType: FieldType = FieldType.Text;
2018-01-25 22:15:47 +01:00
typeOptions: any[];
cardBrandOptions: any[];
cardExpMonthOptions: any[];
identityTitleOptions: any[];
2018-01-26 04:54:09 +01:00
addFieldTypeOptions: any[];
2018-03-02 05:45:12 +01:00
uriMatchOptions: any[];
2018-01-24 23:41:57 +01:00
2018-01-25 22:15:47 +01:00
constructor(private cipherService: CipherService, private folderService: FolderService,
2018-01-26 20:12:41 +01:00
private i18nService: I18nService, private platformUtilsService: PlatformUtilsService,
private analytics: Angulartics2, private toasterService: ToasterService,
private auditService: AuditService) {
2018-01-25 22:15:47 +01:00
this.typeOptions = [
{ name: i18nService.t('typeLogin'), value: CipherType.Login },
{ name: i18nService.t('typeCard'), value: CipherType.Card },
{ name: i18nService.t('typeIdentity'), value: CipherType.Identity },
{ name: i18nService.t('typeSecureNote'), value: CipherType.SecureNote },
];
this.cardBrandOptions = [
{ name: '-- ' + i18nService.t('select') + ' --', value: null },
{ name: 'Visa', value: 'Visa' },
{ name: 'Mastercard', value: 'Mastercard' },
{ name: 'American Express', value: 'Amex' },
{ name: 'Discover', value: 'Discover' },
{ name: 'Diners Club', value: 'Diners Club' },
{ name: 'JCB', value: 'JCB' },
{ name: 'Maestro', value: 'Maestro' },
{ name: 'UnionPay', value: 'UnionPay' },
{ name: i18nService.t('other'), value: 'Other' },
];
this.cardExpMonthOptions = [
{ name: '-- ' + i18nService.t('select') + ' --', value: null },
{ name: '01 - ' + i18nService.t('january'), value: '1' },
{ name: '02 - ' + i18nService.t('february'), value: '2' },
{ name: '03 - ' + i18nService.t('march'), value: '3' },
{ name: '04 - ' + i18nService.t('april'), value: '4' },
{ name: '05 - ' + i18nService.t('may'), value: '5' },
{ name: '06 - ' + i18nService.t('june'), value: '6' },
{ name: '07 - ' + i18nService.t('july'), value: '7' },
{ name: '08 - ' + i18nService.t('august'), value: '8' },
{ name: '09 - ' + i18nService.t('september'), value: '9' },
{ name: '10 - ' + i18nService.t('october'), value: '10' },
{ name: '11 - ' + i18nService.t('november'), value: '11' },
{ name: '12 - ' + i18nService.t('december'), value: '12' },
];
this.identityTitleOptions = [
{ name: '-- ' + i18nService.t('select') + ' --', value: null },
{ name: i18nService.t('mr'), value: i18nService.t('mr') },
{ name: i18nService.t('mrs'), value: i18nService.t('mrs') },
{ name: i18nService.t('ms'), value: i18nService.t('ms') },
{ name: i18nService.t('dr'), value: i18nService.t('dr') },
];
2018-01-26 04:54:09 +01:00
this.addFieldTypeOptions = [
{ name: i18nService.t('cfTypeText'), value: FieldType.Text },
{ name: i18nService.t('cfTypeHidden'), value: FieldType.Hidden },
{ name: i18nService.t('cfTypeBoolean'), value: FieldType.Boolean },
];
2018-03-02 05:45:12 +01:00
this.uriMatchOptions = [
2018-03-12 17:28:41 +01:00
{ name: i18nService.t('defaultMatchDetection'), value: null },
2018-03-02 19:50:35 +01:00
{ name: i18nService.t('baseDomain'), value: UriMatchType.Domain },
2018-03-02 18:03:27 +01:00
{ name: i18nService.t('host'), value: UriMatchType.Host },
2018-03-02 05:45:12 +01:00
{ name: i18nService.t('startsWith'), value: UriMatchType.StartsWith },
{ name: i18nService.t('regEx'), value: UriMatchType.RegularExpression },
{ name: i18nService.t('exact'), value: UriMatchType.Exact },
{ name: i18nService.t('never'), value: UriMatchType.Never },
];
2018-01-24 23:41:57 +01:00
}
async ngOnChanges() {
2018-01-26 20:56:54 +01:00
this.editMode = this.cipherId != null;
if (this.editMode) {
this.editMode = true;
2018-01-31 18:52:12 +01:00
this.title = this.i18nService.t('editItem');
2018-01-26 20:56:54 +01:00
const cipher = await this.cipherService.get(this.cipherId);
this.cipher = await cipher.decrypt();
} else {
2018-01-31 18:52:12 +01:00
this.title = this.i18nService.t('addItem');
2018-01-26 20:56:54 +01:00
this.cipher = new CipherView();
this.cipher.folderId = this.folderId;
2018-02-08 21:58:47 +01:00
this.cipher.type = this.type == null ? CipherType.Login : this.type;
2018-01-26 20:56:54 +01:00
this.cipher.login = new LoginView();
2018-03-02 05:45:12 +01:00
this.cipher.login.uris = [new LoginUriView()];
2018-01-26 20:56:54 +01:00
this.cipher.card = new CardView();
this.cipher.identity = new IdentityView();
this.cipher.secureNote = new SecureNoteView();
this.cipher.secureNote.type = SecureNoteType.Generic;
}
2018-01-25 22:15:47 +01:00
this.folders = await this.folderService.getAllDecrypted();
2018-01-24 23:41:57 +01:00
}
2018-01-26 04:54:09 +01:00
2018-01-31 18:52:12 +01:00
async submit() {
2018-01-26 05:15:56 +01:00
if (this.cipher.name == null || this.cipher.name === '') {
2018-01-26 20:12:41 +01:00
this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'),
2018-01-26 05:15:56 +01:00
this.i18nService.t('nameRequired'));
return;
}
const cipher = await this.cipherService.encrypt(this.cipher);
2018-01-31 18:52:12 +01:00
try {
this.formPromise = this.cipherService.saveWithServer(cipher);
await this.formPromise;
this.cipher.id = cipher.id;
2018-01-31 18:52:12 +01:00
this.analytics.eventTrack.next({ action: this.editMode ? 'Edited Cipher' : 'Added Cipher' });
2018-02-08 16:37:54 +01:00
this.toasterService.popAsync('success', null,
this.i18nService.t(this.editMode ? 'editedItem' : 'addedItem'));
2018-01-31 18:52:12 +01:00
this.onSavedCipher.emit(this.cipher);
} catch { }
2018-01-26 21:44:02 +01:00
}
2018-01-26 05:15:56 +01:00
2018-03-02 05:45:12 +01:00
addUri() {
if (this.cipher.type !== CipherType.Login) {
return;
}
if (this.cipher.login.uris == null) {
this.cipher.login.uris = [];
}
this.cipher.login.uris.push(new LoginUriView());
}
removeUri(uri: LoginUriView) {
if (this.cipher.type !== CipherType.Login || this.cipher.login.uris == null) {
return;
}
const i = this.cipher.login.uris.indexOf(uri);
if (i > -1) {
this.cipher.login.uris.splice(i, 1);
}
}
2018-01-26 04:54:09 +01:00
addField() {
if (this.cipher.fields == null) {
this.cipher.fields = [];
}
const f = new FieldView();
f.type = this.addFieldType;
this.cipher.fields.push(f);
2018-01-26 21:44:02 +01:00
}
2018-01-26 04:54:09 +01:00
removeField(field: FieldView) {
const i = this.cipher.fields.indexOf(field);
if (i > -1) {
this.cipher.fields.splice(i, 1);
}
2018-01-26 22:41:26 +01:00
}
2018-01-26 20:56:54 +01:00
cancel() {
this.onCancelled.emit(this.cipher);
2018-01-26 21:44:02 +01:00
}
2018-01-26 20:56:54 +01:00
attachments() {
this.onEditAttachments.emit(this.cipher);
2018-01-26 21:44:02 +01:00
}
async delete() {
2018-02-03 05:42:33 +01:00
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t('deleteItemConfirmation'), this.i18nService.t('deleteItem'),
2018-02-08 16:37:54 +01:00
this.i18nService.t('yes'), this.i18nService.t('no'), 'warning');
2018-02-03 05:42:33 +01:00
if (!confirmed) {
2018-01-26 21:44:02 +01:00
return;
}
2018-01-31 18:52:12 +01:00
try {
this.deletePromise = this.cipherService.deleteWithServer(this.cipher.id);
await this.deletePromise;
this.analytics.eventTrack.next({ action: 'Deleted Cipher' });
this.toasterService.popAsync('success', null, this.i18nService.t('deletedItem'));
this.onDeletedCipher.emit(this.cipher);
} catch { }
2018-01-26 21:44:02 +01:00
}
2018-01-29 15:33:43 +01:00
2018-02-03 05:42:33 +01:00
async generatePassword() {
if (this.cipher.login != null && this.cipher.login.password != null && this.cipher.login.password.length) {
const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t('overwritePasswordConfirmation'), this.i18nService.t('overwritePassword'),
2018-02-08 16:37:54 +01:00
this.i18nService.t('yes'), this.i18nService.t('no'));
2018-02-03 05:42:33 +01:00
if (!confirmed) {
return;
}
2018-01-29 22:33:38 +01:00
}
2018-01-29 15:33:43 +01:00
this.onGeneratePassword.emit();
}
2018-01-29 23:11:31 +01:00
togglePassword() {
this.analytics.eventTrack.next({ action: 'Toggled Password on Edit' });
this.showPassword = !this.showPassword;
2018-02-24 19:51:12 +01:00
document.getElementById('loginPassword').focus();
2018-01-29 23:11:31 +01:00
}
toggleFieldValue(field: FieldView) {
const f = (field as any);
f.showValue = !f.showValue;
}
2018-03-02 14:15:55 +01:00
toggleUriOptions(uri: LoginUriView) {
const u = (uri as any);
u.showOptions = u.showOptions == null && uri.match != null ? false : !u.showOptions;
2018-03-02 14:15:55 +01:00
}
2018-03-04 04:55:33 +01:00
loginUriMatchChanged(uri: LoginUriView) {
const u = (uri as any);
u.showOptions = u.showOptions == null ? true : u.showOptions;
}
async checkPassword() {
if (this.cipher.login == null || this.cipher.login.password == null || this.cipher.login.password === '') {
return;
}
this.analytics.eventTrack.next({ action: 'Check Password' });
this.checkPasswordPromise = this.auditService.passwordLeaked(this.cipher.login.password);
const matches = await this.checkPasswordPromise;
if (matches > 0) {
this.toasterService.popAsync('warning', null, this.i18nService.t('passwordExposed', matches.toString()));
} else {
this.toasterService.popAsync('success', null, this.i18nService.t('passwordSafe'));
}
}
2018-01-24 23:41:57 +01:00
}