mirror of
https://github.com/bitwarden/browser.git
synced 2025-03-24 15:39:43 +01:00
[EC-317] Desktop client delete user account (#3151)
* [EC-317] feat: add delete account section in settings * [EC-317] feat: add new delete account modal * [EC-317] feat: add ability to replace top-most modal * [EC-317] chore: remove unecessary lint ignore * [EC-317] fix: so delete account is closed if export vault is opened * [EC-317] feat: inital delete account design without i18n * [EC-317] feat: disabled but basic working delete functionality * [EC-317] feat: implement according to new design * [EC-317] feat: use translations * [EC-317] feat: implement working deletion * [EC-317] feat: add loading state and error messages * [EC-317] feat: add menu bar item * [EC-317] feat: update form to support typed reactive forms * [EC-317] chore: update translation text after design review * [EC-317] feat: move deletion logic to service * [EC-317] refactor: update web deletion * [EC-317] feat: disable submit if secret is empty * [EC-317] fix: handle errors in components as well * [EC-317] fix: use abstraction as interface * [EC-317] refactor: extract deleteAccount from api service * [EC-317] fix: typo in translations * [EC-317] chore: rename to accountApiService
This commit is contained in:
parent
cc91b79a15
commit
a22ef4d36c
38
apps/desktop/src/app/accounts/delete-account.component.html
Normal file
38
apps/desktop/src/app/accounts/delete-account.component.html
Normal file
@ -0,0 +1,38 @@
|
||||
<div class="modal fade" role="dialog" aria-modal="true" attr.aria-label="{{ 'settings' | i18n }}">
|
||||
<div class="modal-dialog" role="document">
|
||||
<form
|
||||
class="modal-content"
|
||||
#form
|
||||
[appApiAction]="formPromise"
|
||||
(ngSubmit)="submit()"
|
||||
[formGroup]="deleteForm"
|
||||
>
|
||||
<div class="modal-body">
|
||||
<p class="modal-text">{{ "deleteAccountDesc" | i18n }}</p>
|
||||
<app-callout type="warning" title="{{ 'warning' | i18n }}">
|
||||
{{ "deleteAccountWarning" | i18n }}
|
||||
</app-callout>
|
||||
<div class="box last">
|
||||
<div class="box-header">{{ "deleteAccount" | i18n }}</div>
|
||||
<div class="box-content">
|
||||
<app-user-verification
|
||||
ngDefaultControl
|
||||
formControlName="verification"
|
||||
name="verification"
|
||||
>
|
||||
</app-user-verification>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="danger" [disabled]="form.loading || !secret">
|
||||
<i class="bwi bwi-spinner bwi-spin" [hidden]="!form.loading" aria-hidden="true"></i>
|
||||
<span [hidden]="form.loading">{{ "deleteAccount" | i18n }}</span>
|
||||
</button>
|
||||
<button type="button" data-dismiss="modal" [disabled]="form.loading">
|
||||
{{ "cancel" | i18n }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
48
apps/desktop/src/app/accounts/delete-account.component.ts
Normal file
48
apps/desktop/src/app/accounts/delete-account.component.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
|
||||
import { AccountService } from "@bitwarden/common/abstractions/account/account.service.abstraction";
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||
|
||||
import { Verification } from "../../../../../libs/common/src/types/verification";
|
||||
|
||||
@Component({
|
||||
selector: "app-delete-account",
|
||||
templateUrl: "delete-account.component.html",
|
||||
})
|
||||
export class DeleteAccountComponent {
|
||||
formPromise: Promise<void>;
|
||||
|
||||
deleteForm = this.formBuilder.group({
|
||||
verification: undefined as Verification | undefined,
|
||||
});
|
||||
|
||||
constructor(
|
||||
private i18nService: I18nService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private formBuilder: FormBuilder,
|
||||
private accountService: AccountService,
|
||||
private logService: LogService
|
||||
) {}
|
||||
|
||||
get secret() {
|
||||
return this.deleteForm.get("verification")?.value?.secret;
|
||||
}
|
||||
|
||||
async submit() {
|
||||
try {
|
||||
const verification = this.deleteForm.get("verification").value;
|
||||
this.formPromise = this.accountService.delete(verification);
|
||||
await this.formPromise;
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
this.i18nService.t("accountDeleted"),
|
||||
this.i18nService.t("accountDeletedDesc")
|
||||
);
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -108,6 +108,14 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>{{ "deleteAccount" | i18n }}</label>
|
||||
<small class="help-block">
|
||||
{{ "deleteAccountDesc" | i18n }}
|
||||
<a (click)="openDeleteAccount()">{{ "deleteAccount" | i18n }}</a>
|
||||
</small>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -18,6 +18,8 @@ import { isWindowsStore } from "@bitwarden/electron/utils";
|
||||
|
||||
import { SetPinComponent } from "../components/set-pin.component";
|
||||
|
||||
import { DeleteAccountComponent } from "./delete-account.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-settings",
|
||||
templateUrl: "settings.component.html",
|
||||
@ -437,4 +439,8 @@ export class SettingsComponent implements OnInit {
|
||||
this.enableBrowserIntegrationFingerprint
|
||||
);
|
||||
}
|
||||
|
||||
async openDeleteAccount() {
|
||||
this.modalService.open(DeleteAccountComponent, { replaceTopModal: true });
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ import { CipherType } from "@bitwarden/common/enums/cipherType";
|
||||
|
||||
import { MenuUpdateRequest } from "../main/menu/menu.updater";
|
||||
|
||||
import { DeleteAccountComponent } from "./accounts/delete-account.component";
|
||||
import { PremiumComponent } from "./accounts/premium.component";
|
||||
import { SettingsComponent } from "./accounts/settings.component";
|
||||
import { ExportComponent } from "./vault/export.component";
|
||||
@ -153,9 +154,7 @@ export class AppComponent implements OnInit {
|
||||
this.systemService.cancelProcessReload();
|
||||
break;
|
||||
case "loggedOut":
|
||||
if (this.modal != null) {
|
||||
this.modal.close();
|
||||
}
|
||||
this.modalService.closeAll();
|
||||
this.notificationsService.updateConnection();
|
||||
this.updateAppMenu();
|
||||
await this.systemService.clearPendingClipboard();
|
||||
@ -180,9 +179,7 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
break;
|
||||
case "locked":
|
||||
if (this.modal != null) {
|
||||
this.modal.close();
|
||||
}
|
||||
this.modalService.closeAll();
|
||||
if (
|
||||
message.userId == null ||
|
||||
message.userId === (await this.stateService.getUserId())
|
||||
@ -223,6 +220,9 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "deleteAccount":
|
||||
this.modalService.open(DeleteAccountComponent, { replaceTopModal: true });
|
||||
break;
|
||||
case "openPasswordHistory":
|
||||
await this.openModal<PasswordGeneratorHistoryComponent>(
|
||||
PasswordGeneratorHistoryComponent,
|
||||
@ -368,9 +368,7 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
|
||||
async openExportVault() {
|
||||
if (this.modal != null) {
|
||||
this.modal.close();
|
||||
}
|
||||
this.modalService.closeAll();
|
||||
|
||||
const [modal, childComponent] = await this.modalService.openViewRef(
|
||||
ExportComponent,
|
||||
@ -388,9 +386,7 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
|
||||
async addFolder() {
|
||||
if (this.modal != null) {
|
||||
this.modal.close();
|
||||
}
|
||||
this.modalService.closeAll();
|
||||
|
||||
const [modal, childComponent] = await this.modalService.openViewRef(
|
||||
FolderAddEditComponent,
|
||||
@ -410,9 +406,7 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
|
||||
async openGenerator() {
|
||||
if (this.modal != null) {
|
||||
this.modal.close();
|
||||
}
|
||||
this.modalService.closeAll();
|
||||
|
||||
[this.modal] = await this.modalService.openViewRef(
|
||||
GeneratorComponent,
|
||||
@ -542,9 +536,7 @@ export class AppComponent implements OnInit {
|
||||
}
|
||||
|
||||
private async openModal<T>(type: Type<T>, ref: ViewContainerRef) {
|
||||
if (this.modal != null) {
|
||||
this.modal.close();
|
||||
}
|
||||
this.modalService.closeAll();
|
||||
|
||||
[this.modal] = await this.modalService.openViewRef(type, ref);
|
||||
|
||||
|
@ -57,6 +57,7 @@ import localeZhTw from "@angular/common/locales/zh-Hant";
|
||||
import { NgModule } from "@angular/core";
|
||||
|
||||
import { AccessibilityCookieComponent } from "./accounts/accessibility-cookie.component";
|
||||
import { DeleteAccountComponent } from "./accounts/delete-account.component";
|
||||
import { EnvironmentComponent } from "./accounts/environment.component";
|
||||
import { HintComponent } from "./accounts/hint.component";
|
||||
import { LockComponent } from "./accounts/lock.component";
|
||||
@ -165,6 +166,7 @@ registerLocaleData(localeZhTw, "zh-TW");
|
||||
AttachmentsComponent,
|
||||
CiphersComponent,
|
||||
CollectionsComponent,
|
||||
DeleteAccountComponent,
|
||||
EnvironmentComponent,
|
||||
ExportComponent,
|
||||
FolderAddEditComponent,
|
||||
|
@ -1393,6 +1393,21 @@
|
||||
"lockWithMasterPassOnRestart": {
|
||||
"message": "Lock with master password on restart"
|
||||
},
|
||||
"deleteAccount": {
|
||||
"message": "Delete account"
|
||||
},
|
||||
"deleteAccountDesc": {
|
||||
"message": "Proceed below to delete your account and all vault 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."
|
||||
},
|
||||
"preferences": {
|
||||
"message": "Preferences"
|
||||
},
|
||||
@ -1975,5 +1990,5 @@
|
||||
},
|
||||
"cardBrandMir": {
|
||||
"message": "Mir"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ export class AccountMenu implements IMenubarMenu {
|
||||
this.changeMasterPassword,
|
||||
this.twoStepLogin,
|
||||
this.fingerprintPhrase,
|
||||
this.separator,
|
||||
this.deleteAccount,
|
||||
];
|
||||
}
|
||||
|
||||
@ -105,6 +107,19 @@ export class AccountMenu implements IMenubarMenu {
|
||||
};
|
||||
}
|
||||
|
||||
private get deleteAccount(): MenuItemConstructorOptions {
|
||||
return {
|
||||
label: this.localize("deleteAccount"),
|
||||
id: "deleteAccount",
|
||||
click: () => this.sendMessage("deleteAccount"),
|
||||
enabled: !this._isLocked,
|
||||
};
|
||||
}
|
||||
|
||||
private get separator(): MenuItemConstructorOptions {
|
||||
return { type: "separator" };
|
||||
}
|
||||
|
||||
private localize(s: string) {
|
||||
return this._i18nService.t(s);
|
||||
}
|
||||
|
@ -102,6 +102,10 @@
|
||||
color: themed("mutedColor");
|
||||
}
|
||||
}
|
||||
|
||||
&.last {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.box-content-row {
|
||||
|
@ -336,6 +336,25 @@ form,
|
||||
@include themify($themes) {
|
||||
color: themed("mutedColor");
|
||||
}
|
||||
|
||||
a {
|
||||
@extend .btn;
|
||||
@extend .link;
|
||||
|
||||
padding: 0;
|
||||
font-size: inherit;
|
||||
font-weight: bold;
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed("mutedColor");
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@include themify($themes) {
|
||||
color: darken(themed("mutedColor"), 6%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,10 +71,6 @@
|
||||
|
||||
.box {
|
||||
margin-bottom: 20px;
|
||||
|
||||
&.last {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.buttons {
|
||||
|
@ -6,6 +6,7 @@
|
||||
(ngSubmit)="submit()"
|
||||
[appApiAction]="formPromise"
|
||||
ngNativeValidate
|
||||
[formGroup]="deleteForm"
|
||||
>
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-title" id="deleteAccountTitle">{{ "deleteAccount" | i18n }}</h2>
|
||||
@ -21,7 +22,7 @@
|
||||
<div class="modal-body">
|
||||
<p>{{ "deleteAccountDesc" | i18n }}</p>
|
||||
<app-callout type="warning">{{ "deleteAccountWarning" | i18n }}</app-callout>
|
||||
<app-user-verification [(ngModel)]="masterPassword" ngDefaultControl name="secret">
|
||||
<app-user-verification ngDefaultControl formControlName="verification" name="verification">
|
||||
</app-user-verification>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { Component } from "@angular/core";
|
||||
import { FormBuilder } from "@angular/forms";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AccountService } from "@bitwarden/common/abstractions/account/account.service.abstraction";
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/abstractions/platformUtils.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
||||
import { Verification } from "@bitwarden/common/types/verification";
|
||||
|
||||
@Component({
|
||||
@ -13,30 +12,30 @@ import { Verification } from "@bitwarden/common/types/verification";
|
||||
templateUrl: "delete-account.component.html",
|
||||
})
|
||||
export class DeleteAccountComponent {
|
||||
masterPassword: Verification;
|
||||
formPromise: Promise<any>;
|
||||
formPromise: Promise<void>;
|
||||
|
||||
deleteForm = this.formBuilder.group({
|
||||
verification: undefined as Verification | undefined,
|
||||
});
|
||||
|
||||
constructor(
|
||||
private apiService: ApiService,
|
||||
private i18nService: I18nService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
private userVerificationService: UserVerificationService,
|
||||
private messagingService: MessagingService,
|
||||
private formBuilder: FormBuilder,
|
||||
private accountService: AccountService,
|
||||
private logService: LogService
|
||||
) {}
|
||||
|
||||
async submit() {
|
||||
try {
|
||||
this.formPromise = this.userVerificationService
|
||||
.buildRequest(this.masterPassword)
|
||||
.then((request) => this.apiService.deleteAccount(request));
|
||||
const verification = this.deleteForm.get("verification").value;
|
||||
this.formPromise = this.accountService.delete(verification);
|
||||
await this.formPromise;
|
||||
this.platformUtilsService.showToast(
|
||||
"success",
|
||||
this.i18nService.t("accountDeleted"),
|
||||
this.i18nService.t("accountDeletedDesc")
|
||||
);
|
||||
this.messagingService.send("logout");
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
}
|
||||
|
@ -1088,7 +1088,7 @@
|
||||
"message": "Account Deleted"
|
||||
},
|
||||
"accountDeletedDesc": {
|
||||
"message": "Your Bitwarden account and vault data were permanently deleted."
|
||||
"message": "Your account has been closed and all associated data has been deleted."
|
||||
},
|
||||
"myAccount": {
|
||||
"message": "My Account"
|
||||
|
@ -5,6 +5,7 @@ import { ControlValueAccessor, UntypedFormControl, NG_VALUE_ACCESSOR } from "@an
|
||||
import { KeyConnectorService } from "@bitwarden/common/abstractions/keyConnector.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
||||
import { VerificationType } from "@bitwarden/common/enums/verificationType";
|
||||
import { Utils } from "@bitwarden/common/misc/utils";
|
||||
import { Verification } from "@bitwarden/common/types/verification";
|
||||
|
||||
/**
|
||||
@ -90,7 +91,7 @@ export class UserVerificationComponent implements ControlValueAccessor, OnInit {
|
||||
|
||||
this.onChange({
|
||||
type: this.usesKeyConnector ? VerificationType.OTP : VerificationType.MasterPassword,
|
||||
secret: secret,
|
||||
secret: Utils.isNullOrWhitespace(secret) ? null : secret,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ import { InjectionToken, Injector, LOCALE_ID, NgModule } from "@angular/core";
|
||||
import { ThemingService } from "@bitwarden/angular/services/theming/theming.service";
|
||||
import { AbstractThemingService } from "@bitwarden/angular/services/theming/theming.service.abstraction";
|
||||
import { AbstractEncryptService } from "@bitwarden/common/abstractions/abstractEncrypt.service";
|
||||
import { AccountApiService as AccountApiServiceAbstraction } from "@bitwarden/common/abstractions/account/account-api.service.abstraction";
|
||||
import { AccountService as AccountServiceAbstraction } from "@bitwarden/common/abstractions/account/account.service.abstraction";
|
||||
import { ApiService as ApiServiceAbstraction } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AppIdService as AppIdServiceAbstraction } from "@bitwarden/common/abstractions/appId.service";
|
||||
import { AuditService as AuditServiceAbstraction } from "@bitwarden/common/abstractions/audit.service";
|
||||
@ -49,6 +51,8 @@ import { VaultTimeoutService as VaultTimeoutServiceAbstraction } from "@bitwarde
|
||||
import { StateFactory } from "@bitwarden/common/factories/stateFactory";
|
||||
import { Account } from "@bitwarden/common/models/domain/account";
|
||||
import { GlobalState } from "@bitwarden/common/models/domain/globalState";
|
||||
import { AccountApiService } from "@bitwarden/common/services/account/account-api.service";
|
||||
import { AccountService } from "@bitwarden/common/services/account/account.service";
|
||||
import { ApiService } from "@bitwarden/common/services/api.service";
|
||||
import { AppIdService } from "@bitwarden/common/services/appId.service";
|
||||
import { AuditService } from "@bitwarden/common/services/audit.service";
|
||||
@ -234,6 +238,21 @@ export const LOG_MAC_FAILURES = new InjectionToken<string>("LOG_MAC_FAILURES");
|
||||
useClass: FolderApiService,
|
||||
deps: [FolderServiceAbstraction, ApiServiceAbstraction],
|
||||
},
|
||||
{
|
||||
provide: AccountApiServiceAbstraction,
|
||||
useClass: AccountApiService,
|
||||
deps: [ApiServiceAbstraction],
|
||||
},
|
||||
{
|
||||
provide: AccountServiceAbstraction,
|
||||
useClass: AccountService,
|
||||
deps: [
|
||||
AccountApiServiceAbstraction,
|
||||
UserVerificationServiceAbstraction,
|
||||
MessagingServiceAbstraction,
|
||||
LogService,
|
||||
],
|
||||
},
|
||||
{ provide: LogService, useFactory: () => new ConsoleLogService(false) },
|
||||
{
|
||||
provide: CollectionServiceAbstraction,
|
||||
|
@ -17,7 +17,8 @@ import { ModalRef } from "../components/modal/modal.ref";
|
||||
|
||||
export class ModalConfig<D = any> {
|
||||
data?: D;
|
||||
allowMultipleModals = false;
|
||||
allowMultipleModals?: boolean;
|
||||
replaceTopModal?: boolean;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
@ -63,13 +64,18 @@ export class ModalService {
|
||||
return [modalRef, modalComponentRef.instance.componentRef.instance];
|
||||
}
|
||||
|
||||
open(componentType: Type<any>, config?: ModalConfig) {
|
||||
if (!(config?.allowMultipleModals ?? false) && this.modalCount > 0) {
|
||||
open(componentType: Type<any>, config: ModalConfig = {}) {
|
||||
const { replaceTopModal = false, allowMultipleModals = false } = config;
|
||||
|
||||
if (this.modalCount > 0 && replaceTopModal) {
|
||||
this.topModal.instance.close();
|
||||
}
|
||||
|
||||
if (this.modalCount > 0 && !allowMultipleModals) {
|
||||
return;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line
|
||||
const [modalRef, _] = this.openInternal(componentType, config, true);
|
||||
const [modalRef] = this.openInternal(componentType, config, true);
|
||||
|
||||
return modalRef;
|
||||
}
|
||||
@ -89,6 +95,10 @@ export class ModalService {
|
||||
return this.componentFactoryResolver.resolveComponentFactory(componentType);
|
||||
}
|
||||
|
||||
closeAll(): void {
|
||||
this.modalList.forEach((modal) => modal.instance.close());
|
||||
}
|
||||
|
||||
protected openInternal(
|
||||
componentType: Type<any>,
|
||||
config?: ModalConfig,
|
||||
|
@ -0,0 +1,5 @@
|
||||
import { SecretVerificationRequest } from "@bitwarden/common/models/request/secretVerificationRequest";
|
||||
|
||||
export abstract class AccountApiService {
|
||||
abstract deleteAccount(request: SecretVerificationRequest): Promise<void>;
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
import { Verification } from "../../types/verification";
|
||||
|
||||
export abstract class AccountService {
|
||||
abstract delete(verification: Verification): Promise<any>;
|
||||
}
|
@ -209,7 +209,6 @@ export abstract class ApiService {
|
||||
setPassword: (request: SetPasswordRequest) => Promise<any>;
|
||||
postSetKeyConnectorKey: (request: SetKeyConnectorKeyRequest) => Promise<any>;
|
||||
postSecurityStamp: (request: SecretVerificationRequest) => Promise<any>;
|
||||
deleteAccount: (request: SecretVerificationRequest) => Promise<any>;
|
||||
getAccountRevisionDate: () => Promise<number>;
|
||||
postPasswordHint: (request: PasswordHintRequest) => Promise<any>;
|
||||
postRegister: (request: RegisterRequest) => Promise<any>;
|
||||
|
11
libs/common/src/services/account/account-api.service.ts
Normal file
11
libs/common/src/services/account/account-api.service.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { AccountApiService as AccountApiServiceAbstraction } from "@bitwarden/common/abstractions/account/account-api.service.abstraction";
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { SecretVerificationRequest } from "@bitwarden/common/models/request/secretVerificationRequest";
|
||||
|
||||
export class AccountApiService implements AccountApiServiceAbstraction {
|
||||
constructor(private apiService: ApiService) {}
|
||||
|
||||
deleteAccount(request: SecretVerificationRequest): Promise<void> {
|
||||
return this.apiService.send("DELETE", "/accounts", request, true, false);
|
||||
}
|
||||
}
|
27
libs/common/src/services/account/account.service.ts
Normal file
27
libs/common/src/services/account/account.service.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { AccountApiService } from "@bitwarden/common/abstractions/account/account-api.service.abstraction";
|
||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||
import { MessagingService } from "@bitwarden/common/abstractions/messaging.service";
|
||||
import { UserVerificationService } from "@bitwarden/common/abstractions/userVerification.service";
|
||||
|
||||
import { AccountService as AccountServiceAbstraction } from "../../abstractions/account/account.service.abstraction";
|
||||
import { Verification } from "../../types/verification";
|
||||
|
||||
export class AccountService implements AccountServiceAbstraction {
|
||||
constructor(
|
||||
private accountApiService: AccountApiService,
|
||||
private userVerificationService: UserVerificationService,
|
||||
private messagingService: MessagingService,
|
||||
private logService: LogService
|
||||
) {}
|
||||
|
||||
async delete(verification: Verification): Promise<any> {
|
||||
try {
|
||||
const verificationRequest = await this.userVerificationService.buildRequest(verification);
|
||||
await this.accountApiService.deleteAccount(verificationRequest);
|
||||
this.messagingService.send("logout");
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
@ -350,10 +350,6 @@ export class ApiService implements ApiServiceAbstraction {
|
||||
return this.send("POST", "/accounts/security-stamp", request, true, false);
|
||||
}
|
||||
|
||||
deleteAccount(request: SecretVerificationRequest): Promise<any> {
|
||||
return this.send("DELETE", "/accounts", request, true, false);
|
||||
}
|
||||
|
||||
async getAccountRevisionDate(): Promise<number> {
|
||||
const r = await this.send("GET", "/accounts/revision-date", null, true, true);
|
||||
return r as number;
|
||||
|
Loading…
Reference in New Issue
Block a user