diff --git a/jslib b/jslib
index dc01f0701ea..99e522a5d11 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 6f816ba96ca..cdeb8d5043b 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 a914438f57f..69100e308b6 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 7747e90ae72..d176ae16a5d 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 c6b44271648..b1138628d08 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 556a7ee0adf..f088020bb2c 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 21b55b2ae12..2a6ca26a869 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 00000000000..e8723742e10
--- /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 00000000000..5096b801af4
--- /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 00000000000..458ec337837
--- /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 00000000000..d1f939b14a6
--- /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 cf920286bbe..4628330329d 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 6d765e620df..a6de0c7abcb 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 e74fc871cd1..8b646e1ea29 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"
}
}