mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-23 11:56:00 +01:00
purge vault and delete account features
This commit is contained in:
parent
cb1a62ee27
commit
cccd2abb55
2
jslib
2
jslib
@ -1 +1 @@
|
||||
Subproject commit dc01f0701ea7905d2da7c3babb19870e212d2337
|
||||
Subproject commit 99e522a5d119c1ac6917f1013a73d90770999b5a
|
@ -35,7 +35,9 @@ import { AccountComponent } from './settings/account.component';
|
||||
import { ChangeEmailComponent } from './settings/change-email.component';
|
||||
import { ChangePasswordComponent } from './settings/change-password.component';
|
||||
import { DeauthorizeSessionsComponent } from './settings/deauthorize-sessions.component';
|
||||
import { DeleteAccountComponent } from './settings/delete-account.component';
|
||||
import { ProfileComponent } from './settings/profile.component';
|
||||
import { PurgeVaultComponent } from './settings/purge-vault.component';
|
||||
import { SettingsComponent } from './settings/settings.component';
|
||||
|
||||
import { ExportComponent } from './tools/export.component';
|
||||
@ -104,6 +106,7 @@ import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe';
|
||||
CiphersComponent,
|
||||
CollectionsComponent,
|
||||
DeauthorizeSessionsComponent,
|
||||
DeleteAccountComponent,
|
||||
ExportComponent,
|
||||
FallbackSrcDirective,
|
||||
FolderAddEditComponent,
|
||||
@ -124,6 +127,7 @@ import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe';
|
||||
PasswordGeneratorComponent,
|
||||
PasswordGeneratorHistoryComponent,
|
||||
ProfileComponent,
|
||||
PurgeVaultComponent,
|
||||
RegisterComponent,
|
||||
SearchCiphersPipe,
|
||||
SettingsComponent,
|
||||
@ -145,9 +149,11 @@ import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe';
|
||||
BulkShareComponent,
|
||||
CollectionsComponent,
|
||||
DeauthorizeSessionsComponent,
|
||||
DeleteAccountComponent,
|
||||
FolderAddEditComponent,
|
||||
ModalComponent,
|
||||
PasswordGeneratorHistoryComponent,
|
||||
PurgeVaultComponent,
|
||||
ShareComponent,
|
||||
TwoFactorOptionsComponent,
|
||||
],
|
||||
|
@ -9,7 +9,7 @@
|
||||
<a class="nav-link" routerLink="/vault">{{'myVault' | i18n}}</a>
|
||||
</li>
|
||||
<li class="nav-item" routerLinkActive="active">
|
||||
<a class="nav-link" routerLink="/tools">Tools</a>
|
||||
<a class="nav-link" routerLink="/tools">{{'tools' | i18n}}</a>
|
||||
</li>
|
||||
<li class="nav-item" routerLinkActive="active">
|
||||
<a class="nav-link" routerLink="/settings">{{'settings' | i18n}}</a>
|
||||
|
@ -19,3 +19,5 @@
|
||||
<button type="button" class="btn btn-outline-secondary" (click)="deleteAccount()">{{'deleteAccount' | i18n}}</button>
|
||||
|
||||
<ng-template #deauthorizeSessionsTemplate></ng-template>
|
||||
<ng-template #purgeVaultTemplate></ng-template>
|
||||
<ng-template #deleteAccountTemplate></ng-template>
|
||||
|
@ -7,6 +7,8 @@ import {
|
||||
|
||||
import { ModalComponent } from '../modal.component';
|
||||
import { DeauthorizeSessionsComponent } from './deauthorize-sessions.component';
|
||||
import { DeleteAccountComponent } from './delete-account.component';
|
||||
import { PurgeVaultComponent } from './purge-vault.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-account',
|
||||
@ -14,6 +16,8 @@ import { DeauthorizeSessionsComponent } from './deauthorize-sessions.component';
|
||||
})
|
||||
export class AccountComponent {
|
||||
@ViewChild('deauthorizeSessionsTemplate', { read: ViewContainerRef }) deauthModalRef: ViewContainerRef;
|
||||
@ViewChild('purgeVaultTemplate', { read: ViewContainerRef }) purgeModalRef: ViewContainerRef;
|
||||
@ViewChild('deleteAccountTemplate', { read: ViewContainerRef }) deleteModalRef: ViewContainerRef;
|
||||
|
||||
private modal: ModalComponent = null;
|
||||
|
||||
@ -34,10 +38,30 @@ export class AccountComponent {
|
||||
}
|
||||
|
||||
purgeVault() {
|
||||
if (this.modal != null) {
|
||||
this.modal.close();
|
||||
}
|
||||
|
||||
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
|
||||
this.modal = this.purgeModalRef.createComponent(factory).instance;
|
||||
this.modal.show<PurgeVaultComponent>(PurgeVaultComponent, this.purgeModalRef);
|
||||
|
||||
this.modal.onClosed.subscribe(async () => {
|
||||
this.modal = null;
|
||||
});
|
||||
}
|
||||
|
||||
deleteAccount() {
|
||||
if (this.modal != null) {
|
||||
this.modal.close();
|
||||
}
|
||||
|
||||
const factory = this.componentFactoryResolver.resolveComponentFactory(ModalComponent);
|
||||
this.modal = this.deleteModalRef.createComponent(factory).instance;
|
||||
this.modal.show<DeleteAccountComponent>(DeleteAccountComponent, this.deleteModalRef);
|
||||
|
||||
this.modal.onClosed.subscribe(async () => {
|
||||
this.modal = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -18,9 +18,9 @@
|
||||
appAutoFocus>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button appBlurClick type="submit" class="btn btn-primary btn-submit" [disabled]="form.loading">
|
||||
<button appBlurClick type="submit" class="btn btn-danger btn-submit" [disabled]="form.loading">
|
||||
<i class="fa fa-spinner fa-spin"></i>
|
||||
<span>{{'submit' | i18n}}</span>
|
||||
<span>{{'deauthorize' | i18n}}</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">{{'close' | i18n}}</button>
|
||||
</div>
|
||||
|
@ -1,6 +1,4 @@
|
||||
import {
|
||||
Component,
|
||||
} from '@angular/core';
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
import { Angulartics2 } from 'angulartics2';
|
||||
|
29
src/app/settings/delete-account.component.html
Normal file
29
src/app/settings/delete-account.component.html
Normal file
@ -0,0 +1,29 @@
|
||||
<div class="modal fade">
|
||||
<div class="modal-dialog">
|
||||
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise">
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title">{{'deleteAccount' | i18n}}</h2>
|
||||
<button type="button" class="close" data-dismiss="modal" attr.aria-label="{{'close' | i18n}}">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>{{'deleteAccountDesc' | i18n}}</p>
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<h4 class="alert-heading">{{'warning' | i18n}}</h4>
|
||||
<p class="mb-0">{{'deleteAccountWarning' | i18n}}</p>
|
||||
</div>
|
||||
<label for="masterPassword">{{'masterPass' | i18n}}</label>
|
||||
<input id="masterPassword" type="password" name="MasterPasswordHash" class="form-control" [(ngModel)]="masterPassword" required
|
||||
appAutofocus>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button appBlurClick type="submit" class="btn btn-danger btn-submit" [disabled]="form.loading">
|
||||
<i class="fa fa-spinner fa-spin"></i>
|
||||
<span>{{'deleteAccount' | i18n}}</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">{{'close' | i18n}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
43
src/app/settings/delete-account.component.ts
Normal file
43
src/app/settings/delete-account.component.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
import { Angulartics2 } from 'angulartics2';
|
||||
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
|
||||
import { PasswordVerificationRequest } from 'jslib/models/request/passwordVerificationRequest';
|
||||
|
||||
@Component({
|
||||
selector: 'app-delete-account',
|
||||
templateUrl: 'delete-account.component.html',
|
||||
})
|
||||
export class DeleteAccountComponent {
|
||||
masterPassword: string;
|
||||
formPromise: Promise<any>;
|
||||
|
||||
constructor(private apiService: ApiService, private i18nService: I18nService,
|
||||
private analytics: Angulartics2, private toasterService: ToasterService,
|
||||
private cryptoService: CryptoService, private messagingService: MessagingService) { }
|
||||
|
||||
async submit() {
|
||||
if (this.masterPassword == null || this.masterPassword === '') {
|
||||
this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'),
|
||||
this.i18nService.t('masterPassRequired'));
|
||||
return;
|
||||
}
|
||||
|
||||
const request = new PasswordVerificationRequest();
|
||||
request.masterPasswordHash = await this.cryptoService.hashPassword(this.masterPassword, null);
|
||||
try {
|
||||
this.formPromise = this.apiService.postDeleteAccount(request);
|
||||
await this.formPromise;
|
||||
this.analytics.eventTrack.next({ action: 'Deleted Account' });
|
||||
this.toasterService.popAsync('success', this.i18nService.t('accountDeleted'),
|
||||
this.i18nService.t('accountDeletedDesc'));
|
||||
this.messagingService.send('logout');
|
||||
} catch { }
|
||||
}
|
||||
}
|
29
src/app/settings/purge-vault.component.html
Normal file
29
src/app/settings/purge-vault.component.html
Normal file
@ -0,0 +1,29 @@
|
||||
<div class="modal fade">
|
||||
<div class="modal-dialog">
|
||||
<form class="modal-content" #form (ngSubmit)="submit()" [appApiAction]="formPromise">
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title">{{'purgeVault' | i18n}}</h2>
|
||||
<button type="button" class="close" data-dismiss="modal" attr.aria-label="{{'close' | i18n}}">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>{{'purgeVaultDesc' | i18n}}</p>
|
||||
<div class="alert alert-warning" role="alert">
|
||||
<h4 class="alert-heading">{{'warning' | i18n}}</h4>
|
||||
<p class="mb-0">{{'purgeVaultWarning' | i18n}}</p>
|
||||
</div>
|
||||
<label for="masterPassword">{{'masterPass' | i18n}}</label>
|
||||
<input id="masterPassword" type="password" name="MasterPasswordHash" class="form-control" [(ngModel)]="masterPassword" required
|
||||
appAutofocus>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button appBlurClick type="submit" class="btn btn-danger btn-submit" [disabled]="form.loading">
|
||||
<i class="fa fa-spinner fa-spin"></i>
|
||||
<span>{{'purgeVault' | i18n}}</span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">{{'close' | i18n}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
42
src/app/settings/purge-vault.component.ts
Normal file
42
src/app/settings/purge-vault.component.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
import { Angulartics2 } from 'angulartics2';
|
||||
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
|
||||
import { PasswordVerificationRequest } from 'jslib/models/request/passwordVerificationRequest';
|
||||
|
||||
@Component({
|
||||
selector: 'app-purge-vault',
|
||||
templateUrl: 'purge-vault.component.html',
|
||||
})
|
||||
export class PurgeVaultComponent {
|
||||
masterPassword: string;
|
||||
formPromise: Promise<any>;
|
||||
|
||||
constructor(private apiService: ApiService, private i18nService: I18nService,
|
||||
private analytics: Angulartics2, private toasterService: ToasterService,
|
||||
private cryptoService: CryptoService, private router: Router) { }
|
||||
|
||||
async submit() {
|
||||
if (this.masterPassword == null || this.masterPassword === '') {
|
||||
this.toasterService.popAsync('error', this.i18nService.t('errorOccurred'),
|
||||
this.i18nService.t('masterPassRequired'));
|
||||
return;
|
||||
}
|
||||
|
||||
const request = new PasswordVerificationRequest();
|
||||
request.masterPasswordHash = await this.cryptoService.hashPassword(this.masterPassword, null);
|
||||
try {
|
||||
this.formPromise = this.apiService.postPurgeCiphers(request);
|
||||
await this.formPromise;
|
||||
this.analytics.eventTrack.next({ action: 'Purged Vault' });
|
||||
this.toasterService.popAsync('success', null, this.i18nService.t('vaultPurged'));
|
||||
this.router.navigate(['vault']);
|
||||
} catch { }
|
||||
}
|
||||
}
|
@ -14,6 +14,6 @@
|
||||
</div>
|
||||
</div>
|
||||
<button appBlurClick type="submit" class="btn btn-primary">
|
||||
{{'submit' | i18n}}
|
||||
{{'export' | i18n}}
|
||||
</button>
|
||||
</form>
|
||||
|
@ -2,16 +2,16 @@
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<div class="card">
|
||||
<div class="card-header">Tools</div>
|
||||
<div class="card-header">{{'tools' | i18n}}</div>
|
||||
<div class="list-group list-group-flush">
|
||||
<a routerLink="generator" class="list-group-item" routerLinkActive="active">
|
||||
Password Generator
|
||||
{{'passwordGenerator' | i18n}}
|
||||
</a>
|
||||
<a routerLink="import" class="list-group-item" routerLinkActive="active">
|
||||
Import
|
||||
</a>
|
||||
<a routerLink="export" class="list-group-item" routerLinkActive="active">
|
||||
Export
|
||||
{{'exportVault' | i18n}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -733,6 +733,9 @@
|
||||
"exportVault": {
|
||||
"message": "Export Vault"
|
||||
},
|
||||
"export": {
|
||||
"message": "Export"
|
||||
},
|
||||
"exportSuccess": {
|
||||
"message": "Your vault data has been exported."
|
||||
},
|
||||
@ -818,6 +821,9 @@
|
||||
"deauthorizeSessions": {
|
||||
"message": "Deauthorize Sessions"
|
||||
},
|
||||
"deauthorize": {
|
||||
"message": "Deauthorize"
|
||||
},
|
||||
"deauthorizeSessionsDesc": {
|
||||
"message": "Concerned your account is logged in on another device? Proceed below to deauthorize all computers or devices that you have previously used. This security step is recommended if you previously used a public PC or accidentally saved your password on a device that isn't yours. This step will also clear all previously remembered two-step login sessions."
|
||||
},
|
||||
@ -830,10 +836,34 @@
|
||||
"purgeVault": {
|
||||
"message": "Purge Vault"
|
||||
},
|
||||
"purgeVaultDesc": {
|
||||
"message": "Proceed below to delete all items and folders in your vault. Items that belong to an organization that you share with will not be deleted."
|
||||
},
|
||||
"purgeVaultWarning": {
|
||||
"message": "Purging your vault is permanent. It cannot be undone."
|
||||
},
|
||||
"vaultPurged": {
|
||||
"message": "Your vault has been purged."
|
||||
},
|
||||
"deleteAccount": {
|
||||
"message": "Delete Account"
|
||||
},
|
||||
"deleteAccountDesc": {
|
||||
"message": "Proceed below to delete your account and all associated data."
|
||||
},
|
||||
"deleteAccountWarning": {
|
||||
"message": "Deleting your account is permanent. It cannot be undone."
|
||||
},
|
||||
"accountDeleted": {
|
||||
"message": "Account Deleted"
|
||||
},
|
||||
"accountDeletedDesc": {
|
||||
"message": "Your account has been closed and all associated data has been deleted."
|
||||
},
|
||||
"myAccount": {
|
||||
"message": "My Account"
|
||||
},
|
||||
"tools": {
|
||||
"message": "Tools"
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user