mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
Feature/UI sideload (#2658)
* ui sideloading * remove subtlecrypto import * fix parser * misc fixes * allow docker pull during compat conversion
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
@@ -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: {},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -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> {
|
||||
|
||||
Reference in New Issue
Block a user