mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
* wip * restructure backend for new ui structure * new patchdb bootstrap, single websocket api, local storage migration, more * update db websocket * init apis * update patch-db * setup progress * feat: implement state service, alert and routing Signed-off-by: waterplea <alexander@inkin.ru> * update setup wizard for new types * feat: add init page Signed-off-by: waterplea <alexander@inkin.ru> * chore: refactor message, patch-db source stream and connection service Signed-off-by: waterplea <alexander@inkin.ru> * fix method not found on state * fix backend bugs * fix compat assets * address comments * remove unneeded styling * cleaner progress * bugfixes * fix init logs * fix progress reporting * fix navigation by getting state after init * remove patch dependency from live api * fix caching * re-add patchDB to live api * fix metrics values * send close frame * add bootId and fix polling --------- Signed-off-by: waterplea <alexander@inkin.ru> Co-authored-by: Aiden McClelland <me@drbonez.dev> Co-authored-by: waterplea <alexander@inkin.ru>
156 lines
4.6 KiB
Rust
156 lines
4.6 KiB
Rust
use std::path::PathBuf;
|
|
use std::sync::Arc;
|
|
|
|
use clap::Parser;
|
|
use imbl_value::InternedString;
|
|
use itertools::Itertools;
|
|
use rpc_toolkit::HandlerArgs;
|
|
use serde::{Deserialize, Serialize};
|
|
use ts_rs::TS;
|
|
use url::Url;
|
|
|
|
use crate::context::CliContext;
|
|
use crate::prelude::*;
|
|
use crate::progress::FullProgressTracker;
|
|
use crate::registry::context::RegistryContext;
|
|
use crate::registry::package::index::PackageVersionInfo;
|
|
use crate::registry::signer::commitment::merkle_archive::MerkleArchiveCommitment;
|
|
use crate::registry::signer::sign::ed25519::Ed25519;
|
|
use crate::registry::signer::sign::{AnySignature, AnyVerifyingKey, SignatureScheme};
|
|
use crate::s9pk::merkle_archive::source::http::HttpSource;
|
|
use crate::s9pk::v2::SIG_CONTEXT;
|
|
use crate::s9pk::S9pk;
|
|
use crate::util::io::TrackingIO;
|
|
|
|
#[derive(Debug, Deserialize, Serialize, TS)]
|
|
#[serde(rename_all = "camelCase")]
|
|
#[ts(export)]
|
|
pub struct AddPackageParams {
|
|
#[ts(type = "string")]
|
|
pub url: Url,
|
|
#[ts(skip)]
|
|
#[serde(rename = "__auth_signer")]
|
|
pub uploader: AnyVerifyingKey,
|
|
pub commitment: MerkleArchiveCommitment,
|
|
pub signature: AnySignature,
|
|
}
|
|
|
|
pub async fn add_package(
|
|
ctx: RegistryContext,
|
|
AddPackageParams {
|
|
url,
|
|
uploader,
|
|
commitment,
|
|
signature,
|
|
}: AddPackageParams,
|
|
) -> Result<(), Error> {
|
|
uploader
|
|
.scheme()
|
|
.verify_commitment(&uploader, &commitment, SIG_CONTEXT, &signature)?;
|
|
let peek = ctx.db.peek().await;
|
|
let uploader_guid = peek.as_index().as_signers().get_signer(&uploader)?;
|
|
let s9pk = S9pk::deserialize(
|
|
&Arc::new(HttpSource::new(ctx.client.clone(), url.clone()).await?),
|
|
Some(&commitment),
|
|
)
|
|
.await?;
|
|
|
|
let manifest = s9pk.as_manifest();
|
|
|
|
let mut info = PackageVersionInfo::from_s9pk(&s9pk, url).await?;
|
|
if !info.s9pk.signatures.contains_key(&uploader) {
|
|
info.s9pk.signatures.insert(uploader.clone(), signature);
|
|
}
|
|
|
|
ctx.db
|
|
.mutate(|db| {
|
|
if db.as_admins().de()?.contains(&uploader_guid)
|
|
|| db
|
|
.as_index()
|
|
.as_package()
|
|
.as_packages()
|
|
.as_idx(&manifest.id)
|
|
.or_not_found(&manifest.id)?
|
|
.as_authorized()
|
|
.de()?
|
|
.contains(&uploader_guid)
|
|
{
|
|
let package = db
|
|
.as_index_mut()
|
|
.as_package_mut()
|
|
.as_packages_mut()
|
|
.upsert(&manifest.id, || Ok(Default::default()))?;
|
|
package.as_versions_mut().insert(&manifest.version, &info)?;
|
|
|
|
Ok(())
|
|
} else {
|
|
Err(Error::new(eyre!("UNAUTHORIZED"), ErrorKind::Authorization))
|
|
}
|
|
})
|
|
.await
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Serialize, Parser)]
|
|
#[command(rename_all = "kebab-case")]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct CliAddPackageParams {
|
|
pub file: PathBuf,
|
|
pub url: Url,
|
|
}
|
|
|
|
pub async fn cli_add_package(
|
|
HandlerArgs {
|
|
context: ctx,
|
|
parent_method,
|
|
method,
|
|
params: CliAddPackageParams { file, url },
|
|
..
|
|
}: HandlerArgs<CliContext, CliAddPackageParams>,
|
|
) -> Result<(), Error> {
|
|
let s9pk = S9pk::open(&file, None).await?;
|
|
|
|
let progress = FullProgressTracker::new();
|
|
let mut sign_phase = progress.add_phase(InternedString::intern("Signing File"), Some(1));
|
|
let mut verify_phase = progress.add_phase(InternedString::intern("Verifying URL"), Some(100));
|
|
let mut index_phase = progress.add_phase(
|
|
InternedString::intern("Adding File to Registry Index"),
|
|
Some(1),
|
|
);
|
|
|
|
let progress_task =
|
|
progress.progress_bar_task(&format!("Adding {} to registry...", file.display()));
|
|
|
|
sign_phase.start();
|
|
let commitment = s9pk.as_archive().commitment().await?;
|
|
let signature = Ed25519.sign_commitment(ctx.developer_key()?, &commitment, SIG_CONTEXT)?;
|
|
sign_phase.complete();
|
|
|
|
verify_phase.start();
|
|
let mut src = S9pk::deserialize(
|
|
&Arc::new(HttpSource::new(ctx.client.clone(), url.clone()).await?),
|
|
Some(&commitment),
|
|
)
|
|
.await?;
|
|
src.serialize(&mut TrackingIO::new(0, tokio::io::sink()), true)
|
|
.await?;
|
|
verify_phase.complete();
|
|
|
|
index_phase.start();
|
|
ctx.call_remote::<RegistryContext>(
|
|
&parent_method.into_iter().chain(method).join("."),
|
|
imbl_value::json!({
|
|
"url": &url,
|
|
"signature": signature,
|
|
"commitment": commitment,
|
|
}),
|
|
)
|
|
.await?;
|
|
index_phase.complete();
|
|
|
|
progress.complete();
|
|
|
|
progress_task.await.with_kind(ErrorKind::Unknown)?;
|
|
|
|
Ok(())
|
|
}
|