Feature/UI sideload (#2658)

* ui sideloading

* remove subtlecrypto import

* fix parser

* misc fixes

* allow docker pull during compat conversion
This commit is contained in:
Aiden McClelland
2024-06-28 15:03:01 -06:00
committed by GitHub
parent c16d8a1da1
commit 822dd5e100
101 changed files with 1901 additions and 797 deletions

View File

@@ -4,14 +4,15 @@ import { ApiService } from 'src/app/services/api/embassy-api.service'
import { ConfigService } from 'src/app/services/config.service'
import cbor from 'cbor'
import { ErrorToastService } from '@start9labs/shared'
import { T } from '@start9labs/start-sdk'
import { S9pk, T } from '@start9labs/start-sdk'
interface Positions {
[key: string]: [bigint, bigint] // [position, length]
}
const MAGIC = new Uint8Array([59, 59])
const VERSION = new Uint8Array([1])
const VERSION_1 = new Uint8Array([1])
const VERSION_2 = new Uint8Array([2])
@Component({
selector: 'sideload',
@@ -64,11 +65,36 @@ export class SideloadPage {
async validateS9pk(file: File) {
const magic = new Uint8Array(await blobToBuffer(file.slice(0, 2)))
const version = new Uint8Array(await blobToBuffer(file.slice(2, 3)))
if (compare(magic, MAGIC) && compare(version, VERSION)) {
await this.parseS9pk(file)
return {
invalid: false,
message: 'A valid package file has been detected!',
if (compare(magic, MAGIC)) {
try {
if (compare(version, VERSION_1)) {
await this.parseS9pkV1(file)
return {
invalid: false,
message: 'A valid package file has been detected!',
}
} else if (compare(version, VERSION_2)) {
await this.parseS9pkV2(file)
return {
invalid: false,
message: 'A valid package file has been detected!',
}
} else {
console.error(version)
return {
invalid: true,
message: 'Invalid package file',
}
}
} catch (e) {
console.error(e)
return {
invalid: true,
message:
e instanceof Error
? `Invalid package file: ${e.message}`
: 'Invalid package file',
}
}
} else {
return {
@@ -91,12 +117,9 @@ export class SideloadPage {
})
await loader.present()
try {
const guid = await this.api.sideloadPackage({
manifest: this.toUpload.manifest!,
icon: this.toUpload.icon!,
})
const res = await this.api.sideloadPackage()
this.api
.uploadPackage(guid, this.toUpload.file!)
.uploadPackage(res.upload, this.toUpload.file!)
.catch(e => console.error(e))
this.navCtrl.navigateRoot('/services')
@@ -108,7 +131,7 @@ export class SideloadPage {
}
}
async parseS9pk(file: File) {
async parseS9pkV1(file: File) {
const positions: Positions = {}
// magic=2bytes, version=1bytes, pubkey=32bytes, signature=64bytes, toc_length=4bytes = 103byte is starting point
let start = 103
@@ -122,6 +145,12 @@ export class SideloadPage {
await this.getIcon(positions, file)
}
async parseS9pkV2(file: File) {
const s9pk = await S9pk.deserialize(file, null)
this.toUpload.manifest = s9pk.manifest
this.toUpload.icon = await s9pk.icon()
}
async getManifest(positions: Positions, file: Blob) {
const data = await blobToBuffer(
file.slice(
@@ -225,6 +254,7 @@ async function readBlobToArrayBuffer(
}
function compare(a: Uint8Array, b: Uint8Array) {
if (a.length !== b.length) return false
for (let i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false
}

View File

@@ -273,7 +273,10 @@ export module RR {
manifest: T.Manifest
icon: string // base64
}
export type SideloadPacakgeRes = string //guid
export type SideloadPackageRes = {
upload: string // guid
progress: string // guid
}
// marketplace

View File

@@ -243,7 +243,5 @@ export abstract class ApiService {
params: RR.DryConfigureDependencyReq,
): Promise<RR.DryConfigureDependencyRes>
abstract sideloadPackage(
params: RR.SideloadPackageReq,
): Promise<RR.SideloadPacakgeRes>
abstract sideloadPackage(): Promise<RR.SideloadPackageRes>
}

View File

@@ -29,7 +29,7 @@ export class LiveApiService extends ApiService {
@Inject(PATCH_CACHE) private readonly cache$: Observable<Dump<DataModel>>,
) {
super()
; (window as any).rpcClient = this
;(window as any).rpcClient = this
}
// for getting static files: ex icons, instructions, licenses
@@ -460,12 +460,10 @@ export class LiveApiService extends ApiService {
})
}
async sideloadPackage(
params: RR.SideloadPackageReq,
): Promise<RR.SideloadPacakgeRes> {
async sideloadPackage(): Promise<RR.SideloadPackageRes> {
return this.rpcRequest({
method: 'package.sideload',
params,
params: {},
})
}

View File

@@ -1062,11 +1062,12 @@ export class MockApiService extends ApiService {
}
}
async sideloadPackage(
params: RR.SideloadPackageReq,
): Promise<RR.SideloadPacakgeRes> {
async sideloadPackage(): Promise<RR.SideloadPackageRes> {
await pauseFor(2000)
return '4120e092-05ab-4de2-9fbd-c3f1f4b1df9e' // no significance, randomly generated
return {
upload: '4120e092-05ab-4de2-9fbd-c3f1f4b1df9e', // no significance, randomly generated
progress: '5120e092-05ab-4de2-9fbd-c3f1f4b1df9e', // no significance, randomly generated
}
}
private async initProgress(): Promise<T.FullProgress> {