mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 10:21:52 +00:00
Merge pull request #2668 from Start9Labs/fix/backup-create
solve infinite recursion and promise returning true
This commit is contained in:
94
web/package-lock.json
generated
94
web/package-lock.json
generated
@@ -28,12 +28,12 @@
|
||||
"@start9labs/argon2": "^0.2.2",
|
||||
"@start9labs/emver": "^0.1.5",
|
||||
"@start9labs/start-sdk": "file:../sdk/dist",
|
||||
"@taiga-ui/addon-charts": "3.84.0",
|
||||
"@taiga-ui/cdk": "3.84.0",
|
||||
"@taiga-ui/core": "3.84.0",
|
||||
"@taiga-ui/experimental": "3.84.0",
|
||||
"@taiga-ui/icons": "3.84.0",
|
||||
"@taiga-ui/kit": "3.84.0",
|
||||
"@taiga-ui/addon-charts": "3.86.0",
|
||||
"@taiga-ui/cdk": "3.86.0",
|
||||
"@taiga-ui/core": "3.86.0",
|
||||
"@taiga-ui/experimental": "3.86.0",
|
||||
"@taiga-ui/icons": "3.86.0",
|
||||
"@taiga-ui/kit": "3.86.0",
|
||||
"@tinkoff/ng-dompurify": "4.0.0",
|
||||
"@tinkoff/ng-event-plugins": "3.2.0",
|
||||
"angular-svg-round-progressbar": "^9.0.0",
|
||||
@@ -4128,9 +4128,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@taiga-ui/addon-charts": {
|
||||
"version": "3.84.0",
|
||||
"resolved": "https://registry.npmjs.org/@taiga-ui/addon-charts/-/addon-charts-3.84.0.tgz",
|
||||
"integrity": "sha512-XR7UFywnrv4NRLHOCbba63gXDYYDL4Rt0MbjnF54p5U2EXnbt2of7VbjlB6cPx40XkQqfqa3CNayYxWZP82Ijg==",
|
||||
"version": "3.86.0",
|
||||
"resolved": "https://registry.npmjs.org/@taiga-ui/addon-charts/-/addon-charts-3.86.0.tgz",
|
||||
"integrity": "sha512-Du/85qqaj8hpFSI6hPuFeIhtE93Z6WSkYZLt0gvnsaCb2qSAg8D4oHSogrtF1rsWGGoM+fvXjD7UEUw9GzFIPg==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
@@ -4138,15 +4138,15 @@
|
||||
"@angular/common": ">=12.0.0",
|
||||
"@angular/core": ">=12.0.0",
|
||||
"@ng-web-apis/common": "^3.0.6",
|
||||
"@taiga-ui/cdk": "^3.84.0",
|
||||
"@taiga-ui/core": "^3.84.0",
|
||||
"@taiga-ui/cdk": "^3.86.0",
|
||||
"@taiga-ui/core": "^3.86.0",
|
||||
"@tinkoff/ng-polymorpheus": "^4.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@taiga-ui/addon-commerce": {
|
||||
"version": "3.84.0",
|
||||
"resolved": "https://registry.npmjs.org/@taiga-ui/addon-commerce/-/addon-commerce-3.84.0.tgz",
|
||||
"integrity": "sha512-1zqLwnZLAYYcHvjH89d7JmtV2+QeZ2YnSJ3YWEMNLjGPzpev4RvQXtDfglIyu0LCyTxqpXmuzes9v/cgq2P5TQ==",
|
||||
"version": "3.86.0",
|
||||
"resolved": "https://registry.npmjs.org/@taiga-ui/addon-commerce/-/addon-commerce-3.86.0.tgz",
|
||||
"integrity": "sha512-8QSB490ckI4jnU+1sQ3x8os2GVE162hbvzPVYIZ0TruoeXl076dAz6PT2WRaFwjcaCAIGsuaQgQ4Cv02NjkiYQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.6.2"
|
||||
@@ -4159,18 +4159,18 @@
|
||||
"@maskito/core": "^1.9.0",
|
||||
"@maskito/kit": "^1.9.0",
|
||||
"@ng-web-apis/common": "^3.0.6",
|
||||
"@taiga-ui/cdk": "^3.84.0",
|
||||
"@taiga-ui/core": "^3.84.0",
|
||||
"@taiga-ui/i18n": "^3.84.0",
|
||||
"@taiga-ui/kit": "^3.84.0",
|
||||
"@taiga-ui/cdk": "^3.86.0",
|
||||
"@taiga-ui/core": "^3.86.0",
|
||||
"@taiga-ui/i18n": "^3.86.0",
|
||||
"@taiga-ui/kit": "^3.86.0",
|
||||
"@tinkoff/ng-polymorpheus": "^4.3.0",
|
||||
"rxjs": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@taiga-ui/cdk": {
|
||||
"version": "3.84.0",
|
||||
"resolved": "https://registry.npmjs.org/@taiga-ui/cdk/-/cdk-3.84.0.tgz",
|
||||
"integrity": "sha512-0umw/CUmYNEYOCUNQVTQS53zXzxZsH/6+lj1mFVzocvfJFJWAUT6ltCH9QvxYmxSDDGWwNGg16AaVo2K+aGL0w==",
|
||||
"version": "3.86.0",
|
||||
"resolved": "https://registry.npmjs.org/@taiga-ui/cdk/-/cdk-3.86.0.tgz",
|
||||
"integrity": "sha512-aVbnW01Oh0Er1sHKVGHP8W05mOSKxjSzFE3Qx4iF4T6KW7Rlz9HZoNx5ADMg0TATYChtWh9Kwjo8I4LSVj2ZUw==",
|
||||
"dependencies": {
|
||||
"@ng-web-apis/common": "3.0.6",
|
||||
"@ng-web-apis/mutation-observer": "3.1.0",
|
||||
@@ -4221,11 +4221,11 @@
|
||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
||||
},
|
||||
"node_modules/@taiga-ui/core": {
|
||||
"version": "3.84.0",
|
||||
"resolved": "https://registry.npmjs.org/@taiga-ui/core/-/core-3.84.0.tgz",
|
||||
"integrity": "sha512-FZy77z0E4qjYcszVcp+qPFkPwJPl8qXZb7t2P+juUtJvSmSn2foQHHdyhbIYN808H26tqCdgkTMG1BWQxVuDSg==",
|
||||
"version": "3.86.0",
|
||||
"resolved": "https://registry.npmjs.org/@taiga-ui/core/-/core-3.86.0.tgz",
|
||||
"integrity": "sha512-diQKOnPtDDfxPOMk6wLRq8nyDVfNSPSNy+1TeyqzUgOvJ6XAjfaBXGsL3iuR7AN8+sz/b3rJmBce+vdw6FjMLQ==",
|
||||
"dependencies": {
|
||||
"@taiga-ui/i18n": "^3.84.0",
|
||||
"@taiga-ui/i18n": "^3.86.0",
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
@@ -4237,35 +4237,35 @@
|
||||
"@angular/router": ">=12.0.0",
|
||||
"@ng-web-apis/common": "^3.0.6",
|
||||
"@ng-web-apis/mutation-observer": "^3.1.0",
|
||||
"@taiga-ui/cdk": "^3.84.0",
|
||||
"@taiga-ui/i18n": "^3.84.0",
|
||||
"@taiga-ui/cdk": "^3.86.0",
|
||||
"@taiga-ui/i18n": "^3.86.0",
|
||||
"@tinkoff/ng-event-plugins": "^3.2.0",
|
||||
"@tinkoff/ng-polymorpheus": "^4.3.0",
|
||||
"rxjs": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@taiga-ui/experimental": {
|
||||
"version": "3.84.0",
|
||||
"resolved": "https://registry.npmjs.org/@taiga-ui/experimental/-/experimental-3.84.0.tgz",
|
||||
"integrity": "sha512-q0hNVy+EmywCG8hpZlg/+haKIFhnmxicQiSeV/D1P7CHO10safjGo0ptT6e1hYMFa5/cJZOM4OwDPen2xs17Wg==",
|
||||
"version": "3.86.0",
|
||||
"resolved": "https://registry.npmjs.org/@taiga-ui/experimental/-/experimental-3.86.0.tgz",
|
||||
"integrity": "sha512-ACjoRVeX5MgsNJsiu2ukliXLD2mfEWm8Vtmk78vqcnkyPUmy1ZWK4sG3p5ybFN8AdIMHkblVq0l+x2qAwr/+LQ==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": ">=12.0.0",
|
||||
"@angular/core": ">=12.0.0",
|
||||
"@taiga-ui/addon-commerce": "^3.84.0",
|
||||
"@taiga-ui/cdk": "^3.84.0",
|
||||
"@taiga-ui/core": "^3.84.0",
|
||||
"@taiga-ui/kit": "^3.84.0",
|
||||
"@taiga-ui/addon-commerce": "^3.86.0",
|
||||
"@taiga-ui/cdk": "^3.86.0",
|
||||
"@taiga-ui/core": "^3.86.0",
|
||||
"@taiga-ui/kit": "^3.86.0",
|
||||
"@tinkoff/ng-polymorpheus": "^4.3.0",
|
||||
"rxjs": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@taiga-ui/i18n": {
|
||||
"version": "3.85.0",
|
||||
"resolved": "https://registry.npmjs.org/@taiga-ui/i18n/-/i18n-3.85.0.tgz",
|
||||
"integrity": "sha512-CGoxfq9WY+psX5ZOfWmuQZ6OA/0CAPYJTlbHkw5sRKAyhEQ3NM/Wbx3xcwrcYRRJDnt9yOlfibz+3a+WDF2bFA==",
|
||||
"version": "3.86.0",
|
||||
"resolved": "https://registry.npmjs.org/@taiga-ui/i18n/-/i18n-3.86.0.tgz",
|
||||
"integrity": "sha512-8zkNhMo/QtxZ2Zp6EP/nxo4SOLwaIrX+P3X/Wt+1cjFNZUYWWfdvfHLLdNviKFPVl4RAOxvkhDfza/wkrwv+iQ==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
@@ -4276,20 +4276,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@taiga-ui/icons": {
|
||||
"version": "3.84.0",
|
||||
"resolved": "https://registry.npmjs.org/@taiga-ui/icons/-/icons-3.84.0.tgz",
|
||||
"integrity": "sha512-KiH7BJRZ6wbkOHlJAS0XHq2gYnQTpRgdEogKW+GoD0da/4trCdM66vhDk2j0DwDFdBGq5U0inHJCjnskBI1nSQ==",
|
||||
"version": "3.86.0",
|
||||
"resolved": "https://registry.npmjs.org/@taiga-ui/icons/-/icons-3.86.0.tgz",
|
||||
"integrity": "sha512-jVBEbvE/r9JG+knmXMTn/l/js3JjYi8nSGbrLCryJZZoS2izRnQARN2txABieUJm8H463CoF0rcdXlHKRuA4Ew==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.6.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@taiga-ui/cdk": "^3.84.0"
|
||||
"@taiga-ui/cdk": "^3.86.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@taiga-ui/kit": {
|
||||
"version": "3.84.0",
|
||||
"resolved": "https://registry.npmjs.org/@taiga-ui/kit/-/kit-3.84.0.tgz",
|
||||
"integrity": "sha512-lSUPDco5FeBYK3ESnXeEPLCdMCmNXwcdHNK/we+0ZoH4VPx/OGg2hpEP0Fej7jfGHwXFTzDbufQD0hT6WlfTAw==",
|
||||
"version": "3.86.0",
|
||||
"resolved": "https://registry.npmjs.org/@taiga-ui/kit/-/kit-3.86.0.tgz",
|
||||
"integrity": "sha512-naAy4pyhCaQ9+vWxqSMjbV+9KwnMxT5ybrw+MAJgMn2evzRq0FjqzyFZFog7oiRbRvgVdoWPQfBNKaaLhJcpsw==",
|
||||
"dependencies": {
|
||||
"@maskito/angular": "1.9.0",
|
||||
"@maskito/core": "1.9.0",
|
||||
@@ -4306,9 +4306,9 @@
|
||||
"@ng-web-apis/common": "3.0.6",
|
||||
"@ng-web-apis/mutation-observer": "^3.1.0",
|
||||
"@ng-web-apis/resize-observer": "^3.0.6",
|
||||
"@taiga-ui/cdk": "^3.84.0",
|
||||
"@taiga-ui/core": "^3.84.0",
|
||||
"@taiga-ui/i18n": "^3.84.0",
|
||||
"@taiga-ui/cdk": "^3.86.0",
|
||||
"@taiga-ui/core": "^3.86.0",
|
||||
"@taiga-ui/i18n": "^3.86.0",
|
||||
"@tinkoff/ng-polymorpheus": "^4.3.0",
|
||||
"rxjs": ">=6.0.0"
|
||||
}
|
||||
|
||||
@@ -51,12 +51,12 @@
|
||||
"@start9labs/argon2": "^0.2.2",
|
||||
"@start9labs/emver": "^0.1.5",
|
||||
"@start9labs/start-sdk": "file:../sdk/dist",
|
||||
"@taiga-ui/addon-charts": "3.84.0",
|
||||
"@taiga-ui/cdk": "3.84.0",
|
||||
"@taiga-ui/core": "3.84.0",
|
||||
"@taiga-ui/experimental": "3.84.0",
|
||||
"@taiga-ui/icons": "3.84.0",
|
||||
"@taiga-ui/kit": "3.84.0",
|
||||
"@taiga-ui/addon-charts": "3.86.0",
|
||||
"@taiga-ui/cdk": "3.86.0",
|
||||
"@taiga-ui/core": "3.86.0",
|
||||
"@taiga-ui/experimental": "3.86.0",
|
||||
"@taiga-ui/icons": "3.86.0",
|
||||
"@taiga-ui/kit": "3.86.0",
|
||||
"@tinkoff/ng-dompurify": "4.0.0",
|
||||
"@tinkoff/ng-event-plugins": "3.2.0",
|
||||
"angular-svg-round-progressbar": "^9.0.0",
|
||||
|
||||
@@ -15,7 +15,6 @@ export class ErrorService extends ErrorHandler {
|
||||
this.alerts
|
||||
.open(getErrorMessage(error, link), {
|
||||
label: 'Error',
|
||||
autoClose: false,
|
||||
status: TuiNotification.Error,
|
||||
})
|
||||
.subscribe()
|
||||
|
||||
@@ -61,7 +61,7 @@ export class BackupService {
|
||||
)
|
||||
}
|
||||
|
||||
async hasThisBackup(target: BackupTarget, id: string): Promise<boolean> {
|
||||
hasThisBackup(target: BackupTarget, id: string): boolean {
|
||||
return (
|
||||
target.startOs[id] &&
|
||||
this.emver.compare(target.startOs[id].version, '0.3.6') !== -1
|
||||
|
||||
@@ -32,7 +32,7 @@ export class BadgeMenuComponent {
|
||||
constructor(
|
||||
private readonly splitPane: SplitPaneTracker,
|
||||
private readonly patch: PatchDB<DataModel>,
|
||||
private readonly dialog: TuiDialogService,
|
||||
private readonly dialogs: TuiDialogService,
|
||||
private readonly clientStorageService: ClientStorageService,
|
||||
) {}
|
||||
|
||||
@@ -44,6 +44,6 @@ export class BadgeMenuComponent {
|
||||
}
|
||||
|
||||
onWidgets() {
|
||||
this.dialog.open(WIDGETS_COMPONENT, { label: 'Widgets' }).subscribe()
|
||||
this.dialogs.open(WIDGETS_COMPONENT, { label: 'Widgets' }).subscribe()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<span *ngIf="spec.required">*</span>
|
||||
<select
|
||||
tuiSelect
|
||||
[placeholder]="spec.name"
|
||||
[items]="items"
|
||||
[disabledItemHandler]="disabledItemHandler"
|
||||
></select>
|
||||
|
||||
@@ -6,6 +6,10 @@ import {
|
||||
LoadingService,
|
||||
StartOSDiskInfo,
|
||||
} from '@start9labs/shared'
|
||||
import {
|
||||
PasswordPromptComponent,
|
||||
PromptOptions,
|
||||
} from 'src/app/modals/password-prompt.component'
|
||||
import {
|
||||
BackupInfo,
|
||||
CifsBackupTarget,
|
||||
@@ -14,7 +18,6 @@ import {
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { MappedBackupTarget } from 'src/app/types/mapped-backup-target'
|
||||
import { AppRecoverSelectPage } from '../app-recover-select/app-recover-select.page'
|
||||
import { PasswordPromptModal } from './password-prompt.modal'
|
||||
|
||||
@Component({
|
||||
selector: 'backup-server-select',
|
||||
@@ -38,23 +41,35 @@ export class BackupServerSelectModal {
|
||||
|
||||
async presentModalPassword(
|
||||
serverId: string,
|
||||
server: StartOSDiskInfo,
|
||||
{ passwordHash }: StartOSDiskInfo,
|
||||
): Promise<void> {
|
||||
const options: PromptOptions = {
|
||||
title: 'Password Required',
|
||||
message:
|
||||
'Enter the password that was used to encrypt this backup. On the next screen, you will select the individual services you want to restore.',
|
||||
label: 'Decrypt Backup',
|
||||
placeholder: 'Enter password',
|
||||
buttonText: 'Next',
|
||||
}
|
||||
const modal = await this.modalCtrl.create({
|
||||
component: PasswordPromptModal,
|
||||
component: PasswordPromptComponent,
|
||||
componentProps: { options },
|
||||
canDismiss: async password => {
|
||||
if (password === null) {
|
||||
return true
|
||||
}
|
||||
|
||||
try {
|
||||
argon2.verify(passwordHash!, password)
|
||||
await this.restoreFromBackup(serverId, password)
|
||||
return true
|
||||
} catch (e: any) {
|
||||
this.errorService.handleError(e)
|
||||
return false
|
||||
}
|
||||
},
|
||||
})
|
||||
modal.present()
|
||||
|
||||
const { data, role } = await modal.onWillDismiss()
|
||||
|
||||
if (role === 'confirm') {
|
||||
try {
|
||||
argon2.verify(server.passwordHash!, data)
|
||||
await this.restoreFromBackup(serverId, data)
|
||||
} catch (e: any) {
|
||||
this.errorService.handleError(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async restoreFromBackup(
|
||||
|
||||
@@ -1,14 +1,29 @@
|
||||
import { Component } from '@angular/core'
|
||||
import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
ElementRef,
|
||||
Input,
|
||||
ViewChild,
|
||||
} from '@angular/core'
|
||||
import { FormsModule } from '@angular/forms'
|
||||
import { IonicModule, ModalController } from '@ionic/angular'
|
||||
import { TuiTextfieldComponent } from '@taiga-ui/core'
|
||||
import { TuiInputPasswordModule } from '@taiga-ui/kit'
|
||||
|
||||
export interface PromptOptions {
|
||||
title: string
|
||||
message: string
|
||||
label: string
|
||||
placeholder: string
|
||||
buttonText: string
|
||||
}
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
template: `
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Decrypt Backup</ion-title>
|
||||
<ion-title>{{ options.title }}</ion-title>
|
||||
<ion-buttons slot="end">
|
||||
<ion-button (click)="cancel()">
|
||||
<ion-icon slot="icon-only" name="close"></ion-icon>
|
||||
@@ -18,13 +33,11 @@ import { TuiInputPasswordModule } from '@taiga-ui/kit'
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="ion-padding">
|
||||
<p>{{ options.message }}</p>
|
||||
<p>
|
||||
Enter the password that was used to encrypt this backup. On the next
|
||||
screen, you will select the individual services you want to restore.
|
||||
</p>
|
||||
<p>
|
||||
<tui-input-password [(ngModel)]="password">
|
||||
Enter password
|
||||
<tui-input-password [(ngModel)]="password" (keydown.enter)="confirm()">
|
||||
{{ options.label }}
|
||||
<input tuiTextfield [placeholder]="options.placeholder" />
|
||||
</tui-input-password>
|
||||
</p>
|
||||
</ion-content>
|
||||
@@ -47,18 +60,30 @@ import { TuiInputPasswordModule } from '@taiga-ui/kit'
|
||||
[disabled]="!password"
|
||||
(click)="confirm()"
|
||||
>
|
||||
Next
|
||||
{{ options.buttonText }}
|
||||
</ion-button>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
`,
|
||||
imports: [IonicModule, FormsModule, TuiInputPasswordModule],
|
||||
})
|
||||
export class PasswordPromptModal {
|
||||
export class PasswordPromptComponent implements AfterViewInit {
|
||||
@ViewChild(TuiTextfieldComponent, { read: ElementRef })
|
||||
input?: ElementRef<HTMLInputElement>
|
||||
|
||||
@Input()
|
||||
options!: PromptOptions
|
||||
|
||||
password = ''
|
||||
|
||||
constructor(private modalCtrl: ModalController) {}
|
||||
|
||||
ngAfterViewInit() {
|
||||
setTimeout(() => {
|
||||
this.input?.nativeElement.focus({ preventScroll: true })
|
||||
}, 300)
|
||||
}
|
||||
|
||||
cancel() {
|
||||
return this.modalCtrl.dismiss(null, 'cancel')
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
import { Component } from '@angular/core'
|
||||
import { ModalController, NavController } from '@ionic/angular'
|
||||
import { LoadingService } from '@start9labs/shared'
|
||||
import { TuiDialogService } from '@taiga-ui/core'
|
||||
import { PROMPT, PromptOptions } from 'src/app/modals/prompt.component'
|
||||
import { ErrorService, LoadingService } from '@start9labs/shared'
|
||||
import {
|
||||
PasswordPromptComponent,
|
||||
PromptOptions,
|
||||
} from 'src/app/modals/password-prompt.component'
|
||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||
import { PatchDB } from 'patch-db-client'
|
||||
import { skip, take, takeUntil } from 'rxjs/operators'
|
||||
import { skip, takeUntil } from 'rxjs/operators'
|
||||
import { MappedBackupTarget } from 'src/app/types/mapped-backup-target'
|
||||
import * as argon2 from '@start9labs/argon2'
|
||||
import { TuiDestroyService } from '@taiga-ui/cdk'
|
||||
@@ -22,7 +24,6 @@ import { BackupService } from 'src/app/components/backup-drives/backup.service'
|
||||
@Component({
|
||||
selector: 'server-backup',
|
||||
templateUrl: './server-backup.page.html',
|
||||
styleUrls: ['./server-backup.page.scss'],
|
||||
providers: [TuiDestroyService],
|
||||
})
|
||||
export class ServerBackupPage {
|
||||
@@ -31,8 +32,8 @@ export class ServerBackupPage {
|
||||
readonly backingUp$ = this.eosService.backingUp$
|
||||
|
||||
constructor(
|
||||
private readonly errorService: ErrorService,
|
||||
private readonly loader: LoadingService,
|
||||
private readonly dialogs: TuiDialogService,
|
||||
private readonly modalCtrl: ModalController,
|
||||
private readonly embassyApi: ApiService,
|
||||
private readonly navCtrl: NavController,
|
||||
@@ -60,7 +61,7 @@ export class ServerBackupPage {
|
||||
component: BackupSelectPage,
|
||||
})
|
||||
|
||||
modal.onWillDismiss().then(res => {
|
||||
modal.onDidDismiss().then(res => {
|
||||
if (res.data) {
|
||||
this.serviceIds = res.data
|
||||
this.presentModalPassword(target)
|
||||
@@ -74,28 +75,35 @@ export class ServerBackupPage {
|
||||
target: MappedBackupTarget<CifsBackupTarget | DiskBackupTarget>,
|
||||
): Promise<void> {
|
||||
const options: PromptOptions = {
|
||||
title: 'Master Password Needed',
|
||||
message: 'Enter your master password to encrypt this backup.',
|
||||
label: 'Master Password',
|
||||
placeholder: 'Enter master password',
|
||||
useMask: true,
|
||||
buttonText: 'Create Backup',
|
||||
}
|
||||
|
||||
this.dialogs
|
||||
.open<string>(PROMPT, {
|
||||
label: 'Master Password Needed',
|
||||
data: options,
|
||||
})
|
||||
.pipe(take(1))
|
||||
.subscribe(async (password: string) => {
|
||||
const modal = await this.modalCtrl.create({
|
||||
component: PasswordPromptComponent,
|
||||
componentProps: { options },
|
||||
canDismiss: async password => {
|
||||
if (password === null) {
|
||||
return true
|
||||
}
|
||||
|
||||
const { passwordHash, id } = await getServerInfo(this.patch)
|
||||
|
||||
// confirm password matches current master password
|
||||
argon2.verify(passwordHash, password)
|
||||
try {
|
||||
argon2.verify(passwordHash, password)
|
||||
} catch (e: any) {
|
||||
this.errorService.handleError(e)
|
||||
return false
|
||||
}
|
||||
|
||||
// first time backup
|
||||
if (!this.backupService.hasThisBackup(target.entry, id)) {
|
||||
await this.createBackup(target, password)
|
||||
this.createBackup(target, password)
|
||||
return true
|
||||
// existing backup
|
||||
} else {
|
||||
try {
|
||||
@@ -103,41 +111,51 @@ export class ServerBackupPage {
|
||||
} catch {
|
||||
setTimeout(
|
||||
() => this.presentModalOldPassword(target, password),
|
||||
500,
|
||||
250,
|
||||
)
|
||||
return
|
||||
return true
|
||||
}
|
||||
await this.createBackup(target, password)
|
||||
return true
|
||||
}
|
||||
})
|
||||
},
|
||||
})
|
||||
modal.present()
|
||||
}
|
||||
|
||||
private async presentModalOldPassword(
|
||||
target: MappedBackupTarget<CifsBackupTarget | DiskBackupTarget>,
|
||||
password: string,
|
||||
): Promise<void> {
|
||||
const { id } = await getServerInfo(this.patch)
|
||||
const options: PromptOptions = {
|
||||
title: 'Original Password Needed',
|
||||
message:
|
||||
'This backup was created with a different password. Enter the ORIGINAL password that was used to encrypt this backup.',
|
||||
label: 'Original Password',
|
||||
placeholder: 'Enter original password',
|
||||
useMask: true,
|
||||
buttonText: 'Create Backup',
|
||||
}
|
||||
|
||||
const { id } = await getServerInfo(this.patch)
|
||||
const modal = await this.modalCtrl.create({
|
||||
component: PasswordPromptComponent,
|
||||
componentProps: { options },
|
||||
canDismiss: async oldPassword => {
|
||||
if (oldPassword === null) {
|
||||
return true
|
||||
}
|
||||
|
||||
this.dialogs
|
||||
.open<string>(PROMPT, {
|
||||
label: 'Original Password Needed',
|
||||
data: options,
|
||||
})
|
||||
.pipe(take(1))
|
||||
.subscribe(async (oldPassword: string) => {
|
||||
const passwordHash = target.entry.startOs[id].passwordHash!
|
||||
argon2.verify(passwordHash, oldPassword)
|
||||
await this.createBackup(target, password, oldPassword)
|
||||
})
|
||||
try {
|
||||
argon2.verify(target.entry.startOs[id].passwordHash!, oldPassword)
|
||||
await this.createBackup(target, password, oldPassword)
|
||||
return true
|
||||
} catch (e: any) {
|
||||
this.errorService.handleError(e)
|
||||
return false
|
||||
}
|
||||
},
|
||||
})
|
||||
modal.present()
|
||||
}
|
||||
|
||||
private async createBackup(
|
||||
|
||||
@@ -56,7 +56,7 @@ export class WidgetsPage {
|
||||
@Optional()
|
||||
@Inject(POLYMORPHEUS_CONTEXT)
|
||||
readonly context: TuiDialogContext | null,
|
||||
private readonly dialog: TuiDialogService,
|
||||
private readonly dialogs: TuiDialogService,
|
||||
private readonly patch: PatchDB<DataModel>,
|
||||
private readonly cdr: ChangeDetectorRef,
|
||||
private readonly api: ApiService,
|
||||
@@ -83,7 +83,7 @@ export class WidgetsPage {
|
||||
}
|
||||
|
||||
add() {
|
||||
this.dialog.open(ADD_WIDGET, { label: 'Add widget' }).subscribe(widget => {
|
||||
this.dialogs.open(ADD_WIDGET, { label: 'Add widget' }).subscribe(widget => {
|
||||
this.addWidget(widget!)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user