chore: enable strict mode (#1569)

* chore: enable strict mode

* refactor: remove sync data access from PatchDbService

* launchable even when no LAN url

Co-authored-by: Matt Hill <matthewonthemoon@gmail.com>
This commit is contained in:
Alex Inkin
2022-07-22 18:51:08 +03:00
committed by GitHub
parent 9a01a0df8e
commit 7b8a0eadf3
130 changed files with 1130 additions and 1045 deletions

View File

@@ -1,24 +1,33 @@
<ion-header>
<ion-toolbar>
<ion-title>
{{ !!storageDrive ? 'Set Password' : 'Unlock Drive' }}
{{ storageDrive ? 'Set Password' : 'Unlock Drive' }}
</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<div style="padding: 8px 24px;">
<div style="padding-bottom: 16px;">
<ng-container *ngIf="!!storageDrive">
<p>Choose a password for your Embassy. <i>Make it good. Write it down.</i></p>
<p style="color: var(--ion-color-warning);">Losing your password can result in total loss of data.</p>
</ng-container>
<p *ngIf="!storageDrive">Enter the password that was used to encrypt this drive.</p>
<div style="padding: 8px 24px">
<div style="padding-bottom: 16px">
<ng-template #choose>
<p>
Choose a password for your Embassy.
<i>Make it good. Write it down.</i>
</p>
<p style="color: var(--ion-color-warning)">
Losing your password can result in total loss of data.
</p>
</ng-template>
<p *ngIf="!storageDrive else choose">
Enter the password that was used to encrypt this drive.
</p>
</div>
<form (ngSubmit)="!!storageDrive ? submitPw() : verifyPw()">
<form (ngSubmit)="storageDrive ? submitPw() : verifyPw()">
<p>Password</p>
<ion-item [class]="pwError ? 'error-border' : password && !!storageDrive ? 'success-border' : ''">
<ion-item
[class]="pwError ? 'error-border' : password && storageDrive ? 'success-border' : ''"
>
<ion-input
#focusInput
[(ngModel)]="password"
@@ -29,15 +38,23 @@
maxlength="64"
></ion-input>
<ion-button fill="clear" color="light" (click)="unmasked1 = !unmasked1">
<ion-icon slot="icon-only" [name]="unmasked1 ? 'eye-off-outline' : 'eye-outline'" size="small"></ion-icon>
<ion-icon
slot="icon-only"
[name]="unmasked1 ? 'eye-off-outline' : 'eye-outline'"
size="small"
></ion-icon>
</ion-button>
</ion-item>
<div style="height: 16px;">
<p style="color: var(--ion-color-danger); font-size: x-small;">{{ pwError }}</p>
<div style="height: 16px">
<p style="color: var(--ion-color-danger); font-size: x-small">
{{ pwError }}
</p>
</div>
<ng-container *ngIf="!!storageDrive">
<ng-container *ngIf="storageDrive">
<p>Confirm Password</p>
<ion-item [class]="verError ? 'error-border' : passwordVer ? 'success-border' : ''">
<ion-item
[class]="verError ? 'error-border' : passwordVer ? 'success-border' : ''"
>
<ion-input
[(ngModel)]="passwordVer"
[ngModelOptions]="{'standalone': true}"
@@ -46,12 +63,22 @@
maxlength="64"
placeholder="Retype Password"
></ion-input>
<ion-button fill="clear" color="light" (click)="unmasked2 = !unmasked2">
<ion-icon slot="icon-only" [name]="unmasked2 ? 'eye-off-outline' : 'eye-outline'" size="small"></ion-icon>
<ion-button
fill="clear"
color="light"
(click)="unmasked2 = !unmasked2"
>
<ion-icon
slot="icon-only"
[name]="unmasked2 ? 'eye-off-outline' : 'eye-outline'"
size="small"
></ion-icon>
</ion-button>
</ion-item>
<div style="height: 16px;">
<p style="color: var(--ion-color-danger); font-size: x-small;">{{ verError }}</p>
<div style="height: 16px">
<p style="color: var(--ion-color-danger); font-size: x-small">
{{ verError }}
</p>
</div>
</ng-container>
<input type="submit" style="display: none" />
@@ -61,12 +88,24 @@
<ion-footer>
<ion-toolbar>
<ion-button class="ion-padding-end" slot="end" color="dark" fill="clear" (click)="cancel()">
<ion-button
class="ion-padding-end"
slot="end"
color="dark"
fill="clear"
(click)="cancel()"
>
Cancel
</ion-button>
<ion-button class="ion-padding-end" slot="end" color="dark" fill="clear" strong="true" (click)="!!storageDrive ? submitPw() : verifyPw()">
{{ !!storageDrive ? 'Finish' : 'Unlock' }}
<ion-button
class="ion-padding-end"
slot="end"
color="dark"
fill="clear"
strong="true"
(click)="storageDrive ? submitPw() : verifyPw()"
>
{{ storageDrive ? 'Finish' : 'Unlock' }}
</ion-button>
</ion-toolbar>
</ion-footer>

View File

@@ -13,9 +13,9 @@ import * as argon2 from '@start9labs/argon2'
styleUrls: ['password.page.scss'],
})
export class PasswordPage {
@ViewChild('focusInput') elem: IonInput
@Input() target: CifsBackupTarget | DiskBackupTarget
@Input() storageDrive: DiskInfo
@ViewChild('focusInput') elem?: IonInput
@Input() target?: CifsBackupTarget | DiskBackupTarget
@Input() storageDrive?: DiskInfo
pwError = ''
password = ''
@@ -28,7 +28,7 @@ export class PasswordPage {
constructor(private modalController: ModalController) {}
ngAfterViewInit() {
setTimeout(() => this.elem.setFocus(), 400)
setTimeout(() => this.elem?.setFocus(), 400)
}
async verifyPw() {
@@ -36,7 +36,7 @@ export class PasswordPage {
this.pwError = 'No recovery target' // unreachable
try {
const passwordHash = this.target['embassy-os']?.['password-hash'] || ''
const passwordHash = this.target!['embassy-os']?.['password-hash'] || ''
argon2.verify(passwordHash, this.password)
this.modalController.dismiss({ password: this.password }, 'success')

View File

@@ -9,8 +9,8 @@ import { HttpService } from 'src/app/services/api/http.service'
styleUrls: ['prod-key-modal.page.scss'],
})
export class ProdKeyModal {
@ViewChild('focusInput') elem: IonInput
@Input() target: DiskBackupTarget
@ViewChild('focusInput') elem?: IonInput
@Input() target!: DiskBackupTarget
error = ''
productKey = ''
@@ -24,7 +24,7 @@ export class ProdKeyModal {
) {}
ngAfterViewInit() {
setTimeout(() => this.elem.setFocus(), 400)
setTimeout(() => this.elem?.setFocus(), 400)
}
async verifyProductKey() {

View File

@@ -10,24 +10,24 @@ import { StateService } from 'src/app/services/state.service'
styleUrls: ['product-key.page.scss'],
})
export class ProductKeyPage {
@ViewChild('focusInput') elem: IonInput
productKey: string
error: string
@ViewChild('focusInput') elem?: IonInput
productKey = ''
error = ''
constructor (
constructor(
private readonly navCtrl: NavController,
private readonly stateService: StateService,
private readonly apiService: ApiService,
private readonly loadingCtrl: LoadingController,
private readonly httpService: HttpService,
) { }
) {}
ionViewDidEnter () {
setTimeout(() => this.elem.setFocus(), 400)
ionViewDidEnter() {
setTimeout(() => this.elem?.setFocus(), 400)
}
async submit () {
if (!this.productKey) return this.error = 'Must enter product key'
async submit() {
if (!this.productKey) return (this.error = 'Must enter product key')
const loader = await this.loadingCtrl.create({
message: 'Verifying Product Key',
@@ -50,4 +50,3 @@ export class ProductKeyPage {
}
}
}

View File

@@ -31,7 +31,7 @@ export class RecoverPage {
private readonly alertCtrl: AlertController,
private readonly loadingCtrl: LoadingController,
private readonly errorToastService: ErrorToastService,
public readonly stateService: StateService,
private readonly stateService: StateService,
) {}
async ngOnInit() {
@@ -243,8 +243,8 @@ export class RecoverPage {
styleUrls: ['./recover.page.scss'],
})
export class DriveStatusComponent {
@Input() hasValidBackup: boolean
@Input() is02x: boolean
@Input() hasValidBackup!: boolean
@Input() is02x!: boolean
}
interface MappedDisk {

View File

@@ -13,7 +13,7 @@
<ion-card-content>
<br />
<ng-template
[ngIf]="stateService.recoverySource && stateService.recoverySource.type === 'disk'"
[ngIf]="recoverySource && recoverySource.type === 'disk'"
>
<h2>You can now safely unplug your backup drive.</h2>
</ng-template>
@@ -53,15 +53,13 @@
<ion-item lines="none" color="dark">
<ion-label class="ion-text-wrap">
<code
><ion-text color="light"
>{{ stateService.torAddress }}</ion-text
></code
><ion-text color="light">{{ torAddress }}</ion-text></code
>
</ion-label>
<ion-button
color="light"
fill="clear"
(click)="copy(stateService.torAddress)"
(click)="copy(torAddress)"
>
<ion-icon slot="icon-only" name="copy-outline"></ion-icon>
</ion-button>
@@ -133,15 +131,13 @@
<ion-item lines="none" color="dark">
<ion-label class="ion-text-wrap">
<code
><ion-text color="light"
>{{ stateService.lanAddress }}</ion-text
></code
><ion-text color="light">{{ lanAddress }}</ion-text></code
>
</ion-label>
<ion-button
color="light"
fill="clear"
(click)="copy(stateService.lanAddress)"
(click)="copy(lanAddress)"
>
<ion-icon slot="icon-only" name="copy-outline"></ion-icon>
</ion-button>

View File

@@ -16,9 +16,21 @@ export class SuccessPage {
constructor(
private readonly toastCtrl: ToastController,
private readonly errCtrl: ErrorToastService,
public readonly stateService: StateService,
private readonly stateService: StateService,
) {}
get recoverySource() {
return this.stateService.recoverySource
}
get torAddress() {
return this.stateService.torAddress
}
get lanAddress() {
return this.stateService.lanAddress
}
async ngAfterViewInit() {
try {
await this.stateService.completeEmbassy()

View File

@@ -11,26 +11,26 @@ import { pauseFor, ErrorToastService } from '@start9labs/shared'
providedIn: 'root',
})
export class StateService {
hasProductKey: boolean
isMigrating: boolean
hasProductKey = false
isMigrating = false
polling = false
embassyLoaded = false
recoverySource: CifsRecoverySource | DiskRecoverySource
recoverySource?: CifsRecoverySource | DiskRecoverySource
recoveryPassword?: string
dataTransferProgress: {
dataTransferProgress?: {
bytesTransferred: number
totalBytes: number
complete: boolean
} | null
}
dataProgress = 0
dataCompletionSubject = new BehaviorSubject(false)
torAddress: string
lanAddress: string
cert: string
torAddress = ''
lanAddress = ''
cert = ''
constructor(
private readonly apiService: ApiService,