diff --git a/setup-wizard/src/app/modals/cifs-modal/cifs-modal.page.ts b/setup-wizard/src/app/modals/cifs-modal/cifs-modal.page.ts index a6c2012dd..44ca3dde5 100644 --- a/setup-wizard/src/app/modals/cifs-modal/cifs-modal.page.ts +++ b/setup-wizard/src/app/modals/cifs-modal/cifs-modal.page.ts @@ -1,6 +1,6 @@ import { Component } from '@angular/core' import { AlertController, LoadingController, ModalController } from '@ionic/angular' -import { ApiService, BackupTarget, CifsBackupTarget, EmbassyOSRecoveryInfo } from 'src/app/services/api/api.service' +import { ApiService, CifsBackupTarget, EmbassyOSRecoveryInfo } from 'src/app/services/api/api.service' import { PasswordPage } from '../password/password.page' @Component({ @@ -47,7 +47,6 @@ export class CifsModal { private async presentModalPassword (embassyOS: EmbassyOSRecoveryInfo): Promise { const target: CifsBackupTarget = { - type: 'cifs', ...this.cifs, mountable: true, 'embassy-os': embassyOS, diff --git a/setup-wizard/src/app/modals/password/password.page.ts b/setup-wizard/src/app/modals/password/password.page.ts index 4da67086b..b95238092 100644 --- a/setup-wizard/src/app/modals/password/password.page.ts +++ b/setup-wizard/src/app/modals/password/password.page.ts @@ -1,6 +1,6 @@ import { Component, Input, ViewChild } from '@angular/core' import { IonInput, ModalController } from '@ionic/angular' -import { BackupTarget, DiskInfo } from 'src/app/services/api/api.service' +import { DiskInfo, CifsBackupTarget, DiskBackupTarget } from 'src/app/services/api/api.service' import * as argon2 from '@start9labs/argon2' @Component({ @@ -10,7 +10,7 @@ import * as argon2 from '@start9labs/argon2' }) export class PasswordPage { @ViewChild('focusInput') elem: IonInput - @Input() target: BackupTarget + @Input() target: CifsBackupTarget | DiskBackupTarget @Input() storageDrive: DiskInfo pwError = '' diff --git a/setup-wizard/src/app/pages/embassy/embassy.page.html b/setup-wizard/src/app/pages/embassy/embassy.page.html index db1184694..dbd7d4934 100644 --- a/setup-wizard/src/app/pages/embassy/embassy.page.html +++ b/setup-wizard/src/app/pages/embassy/embassy.page.html @@ -25,13 +25,13 @@ - +

{{ drive.vendor || 'Unknown Vendor' }} - {{ drive.model || 'Unknown Model' }}

{{ drive.logicalname }} - {{ drive.capacity | convertBytes }}

-

- +

+ Drive capacity too small.

diff --git a/setup-wizard/src/app/pages/embassy/embassy.page.ts b/setup-wizard/src/app/pages/embassy/embassy.page.ts index a4036a917..2c40111e3 100644 --- a/setup-wizard/src/app/pages/embassy/embassy.page.ts +++ b/setup-wizard/src/app/pages/embassy/embassy.page.ts @@ -28,6 +28,10 @@ export class EmbassyPage { await this.getDrives() } + tooSmall (drive: DiskInfo) { + return drive.capacity < 34359738368 + } + async refresh () { this.loading = true await this.getDrives() diff --git a/setup-wizard/src/app/pages/recover/drive-status.component.html b/setup-wizard/src/app/pages/recover/drive-status.component.html index 01c4b0d10..2cc055662 100644 --- a/setup-wizard/src/app/pages/recover/drive-status.component.html +++ b/setup-wizard/src/app/pages/recover/drive-status.component.html @@ -1,10 +1,14 @@
-

+ +

- Embassy backup detected -

-

- - No Embassy backup + {{ is02x ? 'Embassy 0.2.x backup detected' : 'Embassy backup detected' }}

+ + +

+ + No Embassy backup +

+
\ No newline at end of file diff --git a/setup-wizard/src/app/pages/recover/recover.page.html b/setup-wizard/src/app/pages/recover/recover.page.html index efaae27fe..adca7a62b 100644 --- a/setup-wizard/src/app/pages/recover/recover.page.html +++ b/setup-wizard/src/app/pages/recover/recover.page.html @@ -45,12 +45,12 @@ To restore from a physical drive, please follow the instructions.

- - + +

{{ drive.label || drive.logicalname }}

- +

{{ drive.vendor || 'Unknown Vendor' }} - {{ drive.model || 'Unknown Model' }}

Capacity: {{ drive.capacity | convertBytes }}

diff --git a/setup-wizard/src/app/pages/recover/recover.page.ts b/setup-wizard/src/app/pages/recover/recover.page.ts index ce6cf7303..72cb08061 100644 --- a/setup-wizard/src/app/pages/recover/recover.page.ts +++ b/setup-wizard/src/app/pages/recover/recover.page.ts @@ -1,10 +1,9 @@ import { Component, Input } from '@angular/core' import { AlertController, LoadingController, ModalController, NavController } from '@ionic/angular' import { CifsModal } from 'src/app/modals/cifs-modal/cifs-modal.page' -import { ApiService, CifsBackupTarget, DiskBackupTarget, DiskRecoverySource, RecoverySource } from 'src/app/services/api/api.service' +import { ApiService, DiskBackupTarget } from 'src/app/services/api/api.service' import { ErrorToastService } from 'src/app/services/error-toast.service' import { StateService } from 'src/app/services/state.service' -import { MappedDisk } from 'src/app/util/misc.util' import { PasswordPage } from '../../modals/password/password.page' import { ProdKeyModal } from '../../modals/prod-key-modal/prod-key-modal.page' @@ -15,7 +14,7 @@ import { ProdKeyModal } from '../../modals/prod-key-modal/prod-key-modal.page' }) export class RecoverPage { loading = true - driveTargets: MappedDisk[] = [] + mappedDrives: MappedDisk[] = [] hasShownGuidAlert = false constructor ( @@ -38,29 +37,30 @@ export class RecoverPage { await this.getDrives() } - driveClickable (drive: DiskBackupTarget) { - return drive['embassy-os']?.full && (this.stateService.hasProductKey || this.is02x(drive)) + driveClickable (mapped: MappedDisk) { + return mapped.drive['embassy-os']?.full && (this.stateService.hasProductKey || mapped.is02x) } async getDrives () { - this.driveTargets = [] + this.mappedDrives = [] try { const drives = await this.apiService.getDrives() drives.filter(d => d.partitions.length).forEach(d => { d.partitions.forEach(p => { - this.driveTargets.push( + const drive: DiskBackupTarget = { + vendor: d.vendor, + model: d.model, + logicalname: p.logicalname, + label: p.label, + capacity: p.capacity, + used: p.used, + 'embassy-os': p['embassy-os'], + } + this.mappedDrives.push( { hasValidBackup: p['embassy-os']?.full, - drive: { - type: 'disk', - vendor: d.vendor, - model: d.model, - logicalname: p.logicalname, - label: p.label, - capacity: p.capacity, - used: p.used, - 'embassy-os': p['embassy-os'], - }, + is02x: drive['embassy-os']?.version.startsWith('0.2'), + drive, }, ) }) @@ -102,7 +102,6 @@ export class RecoverPage { if (res.role === 'success') { const { hostname, path, username, password } = res.data.cifs this.stateService.recoverySource = { - type: 'cifs', hostname, path, username, @@ -166,16 +165,11 @@ export class RecoverPage { private async selectRecoverySource (logicalname: string, password?: string) { this.stateService.recoverySource = { - type: 'disk', logicalname, } this.stateService.recoveryPassword = password this.navCtrl.navigateForward(`/embassy`) } - - private is02x (drive: DiskBackupTarget): boolean { - return !this.stateService.hasProductKey && drive['embassy-os']?.version.startsWith('0.2') - } } @@ -186,4 +180,12 @@ export class RecoverPage { }) export class DriveStatusComponent { @Input() hasValidBackup: boolean + @Input() is02x: boolean +} + + +interface MappedDisk { + is02x: boolean + hasValidBackup: boolean + drive: DiskBackupTarget } diff --git a/setup-wizard/src/app/services/api/api.service.ts b/setup-wizard/src/app/services/api/api.service.ts index 93edc91e4..e17a24405 100644 --- a/setup-wizard/src/app/services/api/api.service.ts +++ b/setup-wizard/src/app/services/api/api.service.ts @@ -6,7 +6,7 @@ export abstract class ApiService { abstract getRecoveryStatus (): Promise // setup.recovery.status // encrypted - abstract verifyCifs (cifs: VerifyCifs): Promise // setup.cifs.verify + abstract verifyCifs (cifs: CifsRecoverySource): Promise // setup.cifs.verify abstract verifyProductKey (): Promise // echo - throws error if invalid abstract importDrive (guid: string): Promise // setup.execute abstract setupEmbassy (setupInfo: SetupEmbassyReq): Promise // setup.execute @@ -18,12 +18,10 @@ export interface GetStatusRes { migrating: boolean } -export type VerifyCifs = Omit - export interface SetupEmbassyReq { 'embassy-logicalname': string 'embassy-password': string - 'recovery-source': RecoverySource | null + 'recovery-source': CifsRecoverySource | DiskRecoverySource | null 'recovery-password': string | null } @@ -33,8 +31,6 @@ export interface SetupEmbassyRes { 'root-ca': string } -export type BackupTarget = DiskBackupTarget | CifsBackupTarget - export interface EmbassyOSRecoveryInfo { version: string full: boolean @@ -43,7 +39,6 @@ export interface EmbassyOSRecoveryInfo { } export interface DiskBackupTarget { - type: 'disk' vendor: string | null model: string | null logicalname: string | null @@ -54,7 +49,6 @@ export interface DiskBackupTarget { } export interface CifsBackupTarget { - type: 'cifs' hostname: string path: string username: string @@ -62,15 +56,11 @@ export interface CifsBackupTarget { 'embassy-os': EmbassyOSRecoveryInfo | null } -export type RecoverySource = DiskRecoverySource | CifsRecoverySource - export interface DiskRecoverySource { - type: 'disk' logicalname: string // partition logicalname } export interface CifsRecoverySource { - type: 'cifs' hostname: string path: string username: string diff --git a/setup-wizard/src/app/services/api/live-api.service.ts b/setup-wizard/src/app/services/api/live-api.service.ts index 516263ade..5cda53ff0 100644 --- a/setup-wizard/src/app/services/api/live-api.service.ts +++ b/setup-wizard/src/app/services/api/live-api.service.ts @@ -1,5 +1,5 @@ import { Injectable } from '@angular/core' -import { ApiService, DiskInfo, EmbassyOSRecoveryInfo, GetStatusRes, RecoverySource, RecoveryStatusRes, SetupEmbassyReq, SetupEmbassyRes, VerifyCifs } from './api.service' +import { ApiService, CifsRecoverySource, DiskInfo, DiskRecoverySource, EmbassyOSRecoveryInfo, GetStatusRes, RecoveryStatusRes, SetupEmbassyReq, SetupEmbassyRes } from './api.service' import { HttpService } from './http.service' @Injectable({ @@ -43,11 +43,11 @@ export class LiveApiService extends ApiService { // ** ENCRYPTED ** - async verifyCifs (params: VerifyCifs) { - params.path = params.path.replace('/\\/g', '/') + async verifyCifs (source: CifsRecoverySource) { + source.path = source.path.replace('/\\/g', '/') return this.http.rpcRequest({ method: 'setup.cifs.verify', - params, + params: source as any, }) } @@ -71,7 +71,7 @@ export class LiveApiService extends ApiService { } async setupEmbassy (setupInfo: SetupEmbassyReq) { - if (setupInfo['recovery-source']?.type === 'cifs') { + if (isCifsSource(setupInfo['recovery-source'])) { setupInfo['recovery-source'].path = setupInfo['recovery-source'].path.replace('/\\/g', '/') } @@ -93,3 +93,7 @@ export class LiveApiService extends ApiService { }) } } + +function isCifsSource (source: CifsRecoverySource | DiskRecoverySource | undefined): source is CifsRecoverySource { + return !!(source as CifsRecoverySource)?.hostname +} diff --git a/setup-wizard/src/app/services/api/mock-api.service.ts b/setup-wizard/src/app/services/api/mock-api.service.ts index c667e16ab..f9b609763 100644 --- a/setup-wizard/src/app/services/api/mock-api.service.ts +++ b/setup-wizard/src/app/services/api/mock-api.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core' import { pauseFor } from 'src/app/util/misc.util' -import { ApiService, RecoverySource, SetupEmbassyReq, VerifyCifs } from './api.service' +import { ApiService, CifsRecoverySource, SetupEmbassyReq } from './api.service' let tries = 0 @@ -137,13 +137,13 @@ export class MockApiService extends ApiService { return { 'bytes-transferred': tries, 'total-bytes': 4, - complete: tries === 4 + complete: tries === 4, } } // ** ENCRYPTED ** - async verifyCifs (params: VerifyCifs) { + async verifyCifs (params: CifsRecoverySource) { await pauseFor(1000) return { version: '0.3.0', diff --git a/setup-wizard/src/app/services/state.service.ts b/setup-wizard/src/app/services/state.service.ts index 1bc814a74..6a5037b2c 100644 --- a/setup-wizard/src/app/services/state.service.ts +++ b/setup-wizard/src/app/services/state.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core' import { BehaviorSubject } from 'rxjs' -import { ApiService, RecoverySource } from './api/api.service' +import { ApiService, CifsRecoverySource, DiskRecoverySource } from './api/api.service' import { ErrorToastService } from './error-toast.service' import { pauseFor } from '../util/misc.util' @@ -14,7 +14,7 @@ export class StateService { polling = false embassyLoaded = false - recoverySource: RecoverySource + recoverySource: CifsRecoverySource | DiskRecoverySource recoveryPassword: string dataTransferProgress: { bytesTransferred: number, totalBytes: number, complete: boolean } | null diff --git a/setup-wizard/src/app/util/misc.util.ts b/setup-wizard/src/app/util/misc.util.ts index 1a6afc405..1a21a3ab1 100644 --- a/setup-wizard/src/app/util/misc.util.ts +++ b/setup-wizard/src/app/util/misc.util.ts @@ -1,10 +1,3 @@ -import { DiskBackupTarget } from '../services/api/api.service' - -export interface MappedDisk { - hasValidBackup: boolean - drive: DiskBackupTarget -} - export const pauseFor = (ms: number) => { return new Promise(resolve => setTimeout(resolve, ms)) } \ No newline at end of file diff --git a/ui/src/app/services/config.service.ts b/ui/src/app/services/config.service.ts index eb0f32747..74ac799a3 100644 --- a/ui/src/app/services/config.service.ts +++ b/ui/src/app/services/config.service.ts @@ -37,7 +37,8 @@ export class ConfigService { mocks = mocks skipStartupAlerts = mocks.enabled && mocks.skipStartupAlerts - supportsWebSockets = 'WebSocket' in window || 'MozWebSocket' in window + isConsulate = window['platform'] === 'ios' + supportsWebSockets = !!window.WebSocket || this.isConsulate isTor (): boolean { return (mocks.enabled && mocks.maskAs === 'tor') || this.origin.endsWith('.onion')