diff --git a/jslib b/jslib
index dc01f0701e..99e522a5d1 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 6f816ba96c..cdeb8d5043 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 a914438f57..69100e308b 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 7747e90ae7..d176ae16a5 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 c6b4427164..b1138628d0 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 556a7ee0ad..f088020bb2 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 21b55b2ae1..2a6ca26a86 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 0000000000..e8723742e1
--- /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 0000000000..5096b801af
--- /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 0000000000..458ec33783
--- /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 0000000000..d1f939b14a
--- /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 cf920286bb..4628330329 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 6d765e620d..a6de0c7abc 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 e74fc871cd..8b646e1ea2 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"
}
}