diff --git a/jslib b/jslib
index dc01f070..99e522a5 160000
--- a/jslib
+++ b/jslib
@@ -1 +1 @@
-Subproject commit dc01f0701ea7905d2da7c3babb19870e212d2337
+Subproject commit 99e522a5d119c1ac6917f1013a73d90770999b5a
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 6f816ba9..cdeb8d50 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -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,
],
diff --git a/src/app/layouts/navbar.component.html b/src/app/layouts/navbar.component.html
index a914438f..69100e30 100644
--- a/src/app/layouts/navbar.component.html
+++ b/src/app/layouts/navbar.component.html
@@ -9,7 +9,7 @@
{{'myVault' | i18n}}
- Tools
+ {{'tools' | i18n}}
{{'settings' | i18n}}
diff --git a/src/app/settings/account.component.html b/src/app/settings/account.component.html
index 7747e90a..d176ae16 100644
--- a/src/app/settings/account.component.html
+++ b/src/app/settings/account.component.html
@@ -19,3 +19,5 @@
{{'deleteAccount' | i18n}}
+
+
diff --git a/src/app/settings/account.component.ts b/src/app/settings/account.component.ts
index c6b44271..b1138628 100644
--- a/src/app/settings/account.component.ts
+++ b/src/app/settings/account.component.ts
@@ -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, 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, this.deleteModalRef);
+
+ this.modal.onClosed.subscribe(async () => {
+ this.modal = null;
+ });
}
}
diff --git a/src/app/settings/deauthorize-sessions.component.html b/src/app/settings/deauthorize-sessions.component.html
index 556a7ee0..f088020b 100644
--- a/src/app/settings/deauthorize-sessions.component.html
+++ b/src/app/settings/deauthorize-sessions.component.html
@@ -18,9 +18,9 @@
appAutoFocus>
diff --git a/src/app/settings/deauthorize-sessions.component.ts b/src/app/settings/deauthorize-sessions.component.ts
index 21b55b2a..2a6ca26a 100644
--- a/src/app/settings/deauthorize-sessions.component.ts
+++ b/src/app/settings/deauthorize-sessions.component.ts
@@ -1,6 +1,4 @@
-import {
- Component,
-} from '@angular/core';
+import { Component } from '@angular/core';
import { ToasterService } from 'angular2-toaster';
import { Angulartics2 } from 'angulartics2';
diff --git a/src/app/settings/delete-account.component.html b/src/app/settings/delete-account.component.html
new file mode 100644
index 00000000..e8723742
--- /dev/null
+++ b/src/app/settings/delete-account.component.html
@@ -0,0 +1,29 @@
+
diff --git a/src/app/settings/delete-account.component.ts b/src/app/settings/delete-account.component.ts
new file mode 100644
index 00000000..5096b801
--- /dev/null
+++ b/src/app/settings/delete-account.component.ts
@@ -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;
+
+ 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 { }
+ }
+}
diff --git a/src/app/settings/purge-vault.component.html b/src/app/settings/purge-vault.component.html
new file mode 100644
index 00000000..458ec337
--- /dev/null
+++ b/src/app/settings/purge-vault.component.html
@@ -0,0 +1,29 @@
+
diff --git a/src/app/settings/purge-vault.component.ts b/src/app/settings/purge-vault.component.ts
new file mode 100644
index 00000000..d1f939b1
--- /dev/null
+++ b/src/app/settings/purge-vault.component.ts
@@ -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;
+
+ 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 { }
+ }
+}
diff --git a/src/app/tools/export.component.html b/src/app/tools/export.component.html
index cf920286..46283303 100644
--- a/src/app/tools/export.component.html
+++ b/src/app/tools/export.component.html
@@ -14,6 +14,6 @@
- {{'submit' | i18n}}
+ {{'export' | i18n}}
diff --git a/src/app/tools/tools.component.html b/src/app/tools/tools.component.html
index 6d765e62..a6de0c7a 100644
--- a/src/app/tools/tools.component.html
+++ b/src/app/tools/tools.component.html
@@ -2,16 +2,16 @@
diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json
index e74fc871..8b646e1e 100644
--- a/src/locales/en/messages.json
+++ b/src/locales/en/messages.json
@@ -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"
}
}