Skip to content

Commit

Permalink
Merge pull request #2501 from numbersprotocol/feat-v230112-ask-user-b…
Browse files Browse the repository at this point in the history
…ack-private-key-before-account-deletion

feat(settings.page): ask user to backup private key before deletion
  • Loading branch information
sultanmyrza authored Jan 19, 2023
2 parents f0b0956 + cd5b370 commit 263360e
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 20 deletions.
2 changes: 1 addition & 1 deletion src/app/features/home/home.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
</mat-list-item>
<mat-list-item>
<a routerLink="/settings" (click)="sidenav.close()" mat-list-item>
{{ t('settings') }}
{{ t('settings.settings') }}
</a>
</mat-list-item>
<mat-list-item>
Expand Down
31 changes: 29 additions & 2 deletions src/app/features/settings/settings.page.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
>
<mat-icon svgIcon="capture-rebrand-arrow-left"></mat-icon>
</button>
<span (click)="onSettingsToolbarClicked()">{{ t('settings') }}</span>
<span (click)="onSettingsToolbarClicked()">{{ t('settings.settings') }}</span>
</mat-toolbar>

<ion-content *transloco="let t">
Expand Down Expand Up @@ -80,8 +80,35 @@
slot="end"
></ion-icon>
</ion-item>
<ion-item (click)="deleteAccount()">
<ion-item (click)="confirmDelete()">
<ion-label color="primary">{{ 'delete' | transloco }}</ion-label>
</ion-item>
</ion-list>

<ion-modal id="backup-private-key-modal" #modal>
<ng-template>
<ion-card>
<ion-card-content>
<div class="backup-modal-warning-text">
{{ t('settings.pleasePressThePrivateKeyBelowToCopy') }}
</div>

<ion-item button (click)="copyPrivateKeyToClipboard()">
<ion-label>
{{ privateKeyTruncated$ | async }}
</ion-label>
<ion-icon name="copy-outline" slot="end"></ion-icon>
</ion-item>

<ion-button
expand="block"
fill="clear"
(click)="modal.dismiss(); this.deleteAccount()"
>
{{ t('settings.iHaveCopiedMyPrivateKey') }}
</ion-button>
</ion-card-content>
</ion-card>
</ng-template>
</ion-modal>
</ion-content>
28 changes: 28 additions & 0 deletions src/app/features/settings/settings.page.scss
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,34 @@ ion-select {
width: auto;
}

ion-modal#backup-private-key-modal {
margin: 8px;

--width: fit-content;
--min-width: 250px;
--height: fit-content;

ion-card {
padding: 8px;

ion-card-content {
.backup-modal-warning-text {
font-size: 14px;
padding-bottom: 24px;
}

ion-item {
margin-bottom: 24px;

ion-label {
display: flex;
justify-content: center;
}
}
}
}
}

ion-toggle {
height: 8px;
width: 28px;
Expand Down
59 changes: 44 additions & 15 deletions src/app/features/settings/settings.page.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { Component } from '@angular/core';
import { Component, ViewChild } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router';
import { Clipboard } from '@capacitor/clipboard';
import { IonModal } from '@ionic/angular';
import { TranslocoService } from '@ngneat/transloco';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { defer, EMPTY, iif, Subject } from 'rxjs';
import { defer, EMPTY, Subject } from 'rxjs';
import {
catchError,
concatMap,
concatMapTo,
count,
first,
Expand All @@ -16,6 +18,7 @@ import {
} from 'rxjs/operators';
import { BlockingActionService } from '../../shared/blocking-action/blocking-action.service';
import { CapacitorFactsProvider } from '../../shared/collector/facts/capacitor-facts-provider/capacitor-facts-provider.service';
import { WebCryptoApiSignatureProvider } from '../../shared/collector/signature/web-crypto-api-signature-provider/web-crypto-api-signature-provider.service';
import { ConfirmAlert } from '../../shared/confirm-alert/confirm-alert.service';
import { Database } from '../../shared/database/database.service';
import { DiaBackendAuthService } from '../../shared/dia-backend/auth/dia-backend-auth.service';
Expand Down Expand Up @@ -59,6 +62,16 @@ export class SettingsPage {
private readonly requiredClicks = 7;
showHiddenOption = false;

private readonly privateKey$ = this.webCryptoApiSignatureProvider.privateKey$;
readonly privateKeyTruncated$ = this.privateKey$.pipe(
map(key => {
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
return `${key.slice(0, 6)}******${key.slice(key.length - 6)}`;
})
);

@ViewChild('modal') modal?: IonModal;

constructor(
private readonly languageService: LanguageService,
private readonly database: Database,
Expand All @@ -72,7 +85,9 @@ export class SettingsPage {
private readonly capacitorFactsProvider: CapacitorFactsProvider,
private readonly versionService: VersionService,
private readonly router: Router,
private readonly route: ActivatedRoute
private readonly route: ActivatedRoute,
private readonly webCryptoApiSignatureProvider: WebCryptoApiSignatureProvider,
private readonly snackBar: MatSnackBar
) {}

ionViewDidEnter() {
Expand Down Expand Up @@ -121,6 +136,28 @@ export class SettingsPage {
.subscribe();
}

async confirmDelete() {
const confirmed = await this.confirmAlert.present({
message: this.translocoService.translate('message.confirmDelete'),
});
if (!confirmed) return;
this.modal?.present();
}

async copyPrivateKeyToClipboard() {
return this.privateKey$
.pipe(
first(),
switchMap(privateKey => Clipboard.write({ string: privateKey })),
tap(() => {
this.snackBar.open(
this.translocoService.translate('message.copiedToClipboard')
);
})
)
.subscribe();
}

/**
* // TODO: Integrate Storage Backend delete function after it's ready.
* Delete user account from Storage Backend.
Expand All @@ -137,17 +174,9 @@ export class SettingsPage {
catchError((err: unknown) => this.errorService.toastError$(err))
);

return defer(() =>
this.confirmAlert.present({
message: this.translocoService.translate('message.confirmDelete'),
})
)
.pipe(
concatMap(result =>
iif(() => result, this.blockingActionService.run$(action$))
),
untilDestroyed(this)
)
return this.blockingActionService
.run$(action$)
.pipe(untilDestroyed(this))
.subscribe();
}
}
6 changes: 5 additions & 1 deletion src/assets/i18n/en-us.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"capture": "Capture",
"profile": "Profile",
"settings": "Settings",
"privacy": "Privacy",
"informationDetails": "Information Details",
"caption": "Caption",
Expand Down Expand Up @@ -337,6 +336,11 @@
"inAppProductsNotAvailableYetPleaseTryAgainLater": "In App Products are not available yet. Try again later."
}
},
"settings": {
"settings": "Settings",
"pleasePressThePrivateKeyBelowToCopy": "Please press the private key below to copy. It is important to keep your private key in a safe place.",
"iHaveCopiedMyPrivateKey": "I have copied my private key"
},
"invitation": {
"invitation": "Invitation",
"inviteFriends": "Invite friends",
Expand Down
6 changes: 5 additions & 1 deletion src/assets/i18n/zh-tw.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"capture": "Capture",
"profile": "個人資料",
"settings": "設定",
"privacy": "隱私",
"informationDetails": "詳細資訊",
"caption": "標題",
Expand Down Expand Up @@ -337,6 +336,11 @@
"inAppProductsNotAvailableYetPleaseTryAgainLater": "App 內購買目前無法使用,請稍後再試."
}
},
"settings": {
"settings": "設定",
"pleasePressThePrivateKeyBelowToCopy": "請點擊下方私鑰複製,並妥善保存您的私鑰,私鑰遺失您將會永久失去該錢包的存取權。",
"iHaveCopiedMyPrivateKey": "我已複製私鑰,並已了解遺失私鑰的風險"
},
"invitation": {
"invitation": "邀請",
"inviteFriends": "邀請好友",
Expand Down

0 comments on commit 263360e

Please sign in to comment.