mirror of
https://github.com/uqbar-dao/nectar.git
synced 2024-12-23 00:21:38 +03:00
Merge branch 'develop' into bp/new-eth
This commit is contained in:
commit
f0892203f2
1383
Cargo.lock
generated
1383
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -17,13 +17,14 @@ async fn main() -> anyhow::Result<()> {
|
||||
let mut bootstrapped_processes = Vec::new();
|
||||
writeln!(
|
||||
bootstrapped_processes,
|
||||
"pub static BOOTSTRAPPED_PROCESSES: &[(&str, &[u8])] = &[",
|
||||
"pub static BOOTSTRAPPED_PROCESSES: &[(&str, &[u8], &[u8])] = &[",
|
||||
)
|
||||
.unwrap();
|
||||
let packages_dir = format!("{}/packages", pwd.display());
|
||||
eprintln!("{packages_dir:?}");
|
||||
for entry in std::fs::read_dir(packages_dir).unwrap() {
|
||||
let entry_path = entry.unwrap().path();
|
||||
let metadata_path = format!("{}/metadata.json", entry_path.display());
|
||||
let parent_pkg_path = format!("{}/pkg", entry_path.display());
|
||||
|
||||
kit::build::execute(&entry_path, false, false, false, true).await?;
|
||||
@ -72,8 +73,8 @@ async fn main() -> anyhow::Result<()> {
|
||||
// Add zip bytes to bootstrapped_processes.rs
|
||||
writeln!(
|
||||
bootstrapped_processes,
|
||||
" (\"{}\", include_bytes!(\"{}\")),",
|
||||
zip_filename, zip_path,
|
||||
" (\"{}\", include_bytes!(\"{}\"), include_bytes!(\"{}\")),",
|
||||
zip_filename, metadata_path, zip_path,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ pub fn handle_http_request(
|
||||
req: &IncomingHttpRequest,
|
||||
) -> anyhow::Result<()> {
|
||||
match serve_paths(our, state, requested_packages, req) {
|
||||
Ok((status_code, headers, body)) => send_response(
|
||||
Ok((status_code, _headers, body)) => send_response(
|
||||
status_code,
|
||||
Some(HashMap::from([(
|
||||
String::from("Content-Type"),
|
||||
@ -81,6 +81,7 @@ fn gen_package_info(
|
||||
"caps_approved": state.caps_approved,
|
||||
"mirroring": state.mirroring,
|
||||
"auto_update": state.auto_update,
|
||||
"verified": state.verified,
|
||||
}),
|
||||
None => json!(null),
|
||||
},
|
||||
@ -188,7 +189,7 @@ fn serve_paths(
|
||||
}
|
||||
Method::PUT => {
|
||||
// update an app
|
||||
let pkg_listing: &PackageListing = state
|
||||
let _pkg_listing: &PackageListing = state
|
||||
.get_listing(&package_id)
|
||||
.ok_or(anyhow::anyhow!("No package"))?;
|
||||
let pkg_state: &PackageState = state
|
||||
@ -277,10 +278,10 @@ fn serve_paths(
|
||||
let mirrors: &Vec<NodeId> = pkg_listing
|
||||
.metadata
|
||||
.as_ref()
|
||||
.ok_or(anyhow::anyhow!("No metadata for package {package_id}"))?
|
||||
.expect("Package does not have metadata")
|
||||
.properties
|
||||
.mirrors
|
||||
.as_ref()
|
||||
.ok_or(anyhow::anyhow!("No mirrors for package {package_id}"))?;
|
||||
.as_ref();
|
||||
let download_from = body_json
|
||||
.get("download_from")
|
||||
.unwrap_or(&json!(mirrors
|
||||
|
@ -283,6 +283,7 @@ fn handle_local_request(
|
||||
mirrored_from: Some(our.node.clone()),
|
||||
our_version,
|
||||
installed: false,
|
||||
verified: true, // side loaded apps are implicitly verified because there is no "source" to verify against
|
||||
caps_approved: true, // TODO see if we want to auto-approve local installs
|
||||
manifest_hash: None, // generated in the add fn
|
||||
mirroring: *mirror,
|
||||
@ -425,35 +426,56 @@ fn handle_receive_download(
|
||||
// check the version hash for this download against requested!!
|
||||
// for now we can reject if it's not latest.
|
||||
let download_hash = generate_version_hash(&blob.bytes);
|
||||
let mut verified = false;
|
||||
match requested_package.desired_version_hash {
|
||||
Some(hash) => {
|
||||
if download_hash != hash {
|
||||
return Err(anyhow::anyhow!(
|
||||
"app store: downloaded package is not desired version--rejecting download! download hash: {download_hash}, desired hash: {hash}"
|
||||
));
|
||||
if hash.is_empty() {
|
||||
println!(
|
||||
"\x1b[33mwarning: downloaded package has no version hashes--cannot verify code integrity, proceeding anyways\x1b[0m"
|
||||
);
|
||||
} else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"app store: downloaded package is not desired version--rejecting download! download hash: {download_hash}, desired hash: {hash}"
|
||||
));
|
||||
}
|
||||
} else {
|
||||
verified = true;
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// check against latest from listing
|
||||
// check against `metadata.properties.current_version`
|
||||
let Some(package_listing) = state.get_listing(&package_id) else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"app store: downloaded package cannot be found in manager--rejecting download!"
|
||||
));
|
||||
};
|
||||
if let Some(metadata) = &package_listing.metadata {
|
||||
if let Some(latest_hash) = metadata.versions.clone().unwrap_or(vec![]).last() {
|
||||
if &download_hash != latest_hash {
|
||||
return Err(anyhow::anyhow!(
|
||||
"app store: downloaded package is not latest version--rejecting download! download hash: {download_hash}, latest hash: {latest_hash}"
|
||||
));
|
||||
}
|
||||
let Some(metadata) = &package_listing.metadata else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"app store: downloaded package has no metadata to check validity against!"
|
||||
));
|
||||
};
|
||||
let Some(latest_hash) = metadata
|
||||
.properties
|
||||
.code_hashes
|
||||
.get(&metadata.properties.current_version)
|
||||
else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"app store: downloaded package has no versions in manager--rejecting download!"
|
||||
));
|
||||
};
|
||||
if &download_hash != latest_hash {
|
||||
if latest_hash.is_empty() {
|
||||
println!(
|
||||
"\x1b[33mwarning: downloaded package has no version hashes--cannot verify code integrity, proceeding anyways\x1b[0m"
|
||||
);
|
||||
} else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"app store: downloaded package has no versions in manager--rejecting download!"
|
||||
"app store: downloaded package is not latest version--rejecting download! download hash: {download_hash}, latest hash: {latest_hash}"
|
||||
));
|
||||
}
|
||||
} else {
|
||||
println!("app store: warning: downloaded package has no listing metadata to check validity against!")
|
||||
verified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -472,6 +494,7 @@ fn handle_receive_download(
|
||||
mirrored_from: Some(requested_package.from),
|
||||
our_version: download_hash,
|
||||
installed: false,
|
||||
verified,
|
||||
caps_approved: false,
|
||||
manifest_hash: None, // generated in the add fn
|
||||
mirroring: requested_package.mirror,
|
||||
|
@ -50,22 +50,7 @@ pub struct PackageListing {
|
||||
pub name: String,
|
||||
pub publisher: NodeId,
|
||||
pub metadata_hash: String,
|
||||
pub metadata: Option<OnchainPackageMetadata>,
|
||||
}
|
||||
|
||||
/// metadata derived from metadata hash in listing event
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct OnchainPackageMetadata {
|
||||
pub name: Option<String>,
|
||||
pub subtitle: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub image: Option<String>,
|
||||
pub version: Option<String>,
|
||||
pub license: Option<String>,
|
||||
pub website: Option<String>,
|
||||
pub screenshots: Option<Vec<String>>,
|
||||
pub mirrors: Option<Vec<NodeId>>,
|
||||
pub versions: Option<Vec<String>>,
|
||||
pub metadata: Option<kt::Erc721Metadata>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@ -86,13 +71,14 @@ pub struct PackageState {
|
||||
/// the version of the package we have downloaded
|
||||
pub our_version: String,
|
||||
pub installed: bool,
|
||||
pub verified: bool,
|
||||
pub caps_approved: bool,
|
||||
pub manifest_hash: Option<String>,
|
||||
/// are we serving this package to others?
|
||||
pub mirroring: bool,
|
||||
/// if we get a listing data update, will we try to download it?
|
||||
pub auto_update: bool,
|
||||
pub metadata: Option<OnchainPackageMetadata>,
|
||||
pub metadata: Option<kt::Erc721Metadata>,
|
||||
}
|
||||
|
||||
/// this process's saved state
|
||||
@ -318,6 +304,7 @@ impl State {
|
||||
mirrored_from: None,
|
||||
our_version,
|
||||
installed: true,
|
||||
verified: true, // implicity verified
|
||||
caps_approved: true, // since it's already installed this must be true
|
||||
manifest_hash: Some(generate_metadata_hash(&manifest_bytes)),
|
||||
mirroring: false,
|
||||
@ -421,6 +408,15 @@ impl State {
|
||||
|
||||
let metadata = fetch_metadata(&metadata_url, &metadata_hash).ok();
|
||||
|
||||
if let Some(metadata) = &metadata {
|
||||
if metadata.properties.publisher != publisher_name {
|
||||
return Err(anyhow::anyhow!(format!(
|
||||
"app store: metadata publisher name mismatch: got {}, expected {}",
|
||||
metadata.properties.publisher, publisher_name
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
let listing = match self.get_listing_with_hash_mut(&package_hash) {
|
||||
Some(current_listing) => {
|
||||
current_listing.name = package_name;
|
||||
@ -460,7 +456,15 @@ impl State {
|
||||
))?;
|
||||
|
||||
let metadata = match fetch_metadata(&metadata_url, &metadata_hash) {
|
||||
Ok(metadata) => Some(metadata),
|
||||
Ok(metadata) => {
|
||||
if metadata.properties.publisher != current_listing.publisher {
|
||||
return Err(anyhow::anyhow!(format!(
|
||||
"app store: metadata publisher name mismatch: got {}, expected {}",
|
||||
metadata.properties.publisher, current_listing.publisher
|
||||
)));
|
||||
}
|
||||
Some(metadata)
|
||||
}
|
||||
Err(e) => {
|
||||
crate::print_to_terminal(
|
||||
1,
|
||||
@ -583,10 +587,7 @@ fn dnswire_decode(wire_format_bytes: &[u8]) -> Result<String, std::string::FromU
|
||||
}
|
||||
|
||||
/// fetch metadata from metadata_url and verify it matches metadata_hash
|
||||
fn fetch_metadata(
|
||||
metadata_url: &str,
|
||||
metadata_hash: &str,
|
||||
) -> anyhow::Result<OnchainPackageMetadata> {
|
||||
fn fetch_metadata(metadata_url: &str, metadata_hash: &str) -> anyhow::Result<kt::Erc721Metadata> {
|
||||
let url = url::Url::parse(metadata_url)?;
|
||||
let _response = http::send_request_await_response(http::Method::GET, url, None, 5, vec![])?;
|
||||
let Some(body) = get_blob() else {
|
||||
@ -594,9 +595,7 @@ fn fetch_metadata(
|
||||
};
|
||||
let hash = generate_metadata_hash(&body.bytes);
|
||||
if &hash == metadata_hash {
|
||||
Ok(serde_json::from_slice::<OnchainPackageMetadata>(
|
||||
&body.bytes,
|
||||
)?)
|
||||
Ok(serde_json::from_slice::<kt::Erc721Metadata>(&body.bytes)?)
|
||||
} else {
|
||||
Err(anyhow::anyhow!(
|
||||
"metadata hash mismatch: got {hash}, expected {metadata_hash}"
|
||||
|
16
kinode/packages/app_store/metadata.json
Normal file
16
kinode/packages/app_store/metadata.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "App Store",
|
||||
"description": "A package manager + app store.",
|
||||
"image": "",
|
||||
"properties": {
|
||||
"package_name": "app_store",
|
||||
"current_version": "0.3.0",
|
||||
"publisher": "sys",
|
||||
"mirrors": [],
|
||||
"code_hashes": {
|
||||
"0.3.0": ""
|
||||
}
|
||||
},
|
||||
"external_url": "https://kinode.org",
|
||||
"animation_url": ""
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
{
|
||||
"package": "app_store",
|
||||
"publisher": "sys",
|
||||
"version": [
|
||||
0,
|
||||
2,
|
||||
0
|
||||
],
|
||||
"description": "A package manager + app store."
|
||||
}
|
90
kinode/packages/app_store/pkg/ui/assets/index-Wv-dWa0C.js
Normal file
90
kinode/packages/app_store/pkg/ui/assets/index-Wv-dWa0C.js
Normal file
File diff suppressed because one or more lines are too long
@ -18,7 +18,7 @@
|
||||
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1.00001, viewport-fit=cover"
|
||||
/>
|
||||
<link href='https://fonts.googleapis.com/css?family=Montserrat' rel='stylesheet'>
|
||||
<script type="module" crossorigin src="/main:app_store:sys/assets/index-A09g5OKk.js"></script>
|
||||
<script type="module" crossorigin src="/main:app_store:sys/assets/index-Wv-dWa0C.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/main:app_store:sys/assets/index-aUqPNadJ.css">
|
||||
</head>
|
||||
<body>
|
||||
|
16
kinode/packages/chess/metadata.json
Normal file
16
kinode/packages/chess/metadata.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "Chess by Kinode",
|
||||
"description": "A peer-to-peer chess game",
|
||||
"image": "",
|
||||
"properties": {
|
||||
"package_name": "chess",
|
||||
"current_version": "0.2.0",
|
||||
"publisher": "sys",
|
||||
"mirrors": [],
|
||||
"code_hashes": {
|
||||
"0.2.0": ""
|
||||
}
|
||||
},
|
||||
"external_url": "https://kinode.org",
|
||||
"animation_url": ""
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"package": "chess",
|
||||
"publisher": "sys",
|
||||
"version": [
|
||||
0,
|
||||
2,
|
||||
0
|
||||
]
|
||||
}
|
16
kinode/packages/homepage/metadata.json
Normal file
16
kinode/packages/homepage/metadata.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "Homepage",
|
||||
"description": "Homepage for Kinode OS",
|
||||
"image": "",
|
||||
"properties": {
|
||||
"package_name": "homepage",
|
||||
"current_version": "0.1.0",
|
||||
"publisher": "sys",
|
||||
"mirrors": [],
|
||||
"code_hashes": {
|
||||
"0.1.0": ""
|
||||
}
|
||||
},
|
||||
"external_url": "https://kinode.org",
|
||||
"animation_url": ""
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"package": "homepage",
|
||||
"publisher": "sys",
|
||||
"version": [
|
||||
0,
|
||||
1,
|
||||
0
|
||||
]
|
||||
}
|
16
kinode/packages/kns_indexer/metadata.json
Normal file
16
kinode/packages/kns_indexer/metadata.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "KNS Indexer",
|
||||
"description": "Kinode OS pki indexer",
|
||||
"image": "",
|
||||
"properties": {
|
||||
"package_name": "kns_indexer",
|
||||
"current_version": "0.1.0",
|
||||
"publisher": "sys",
|
||||
"mirrors": [],
|
||||
"code_hashes": {
|
||||
"0.1.0": ""
|
||||
}
|
||||
},
|
||||
"external_url": "https://kinode.org",
|
||||
"animation_url": ""
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"package": "kns_indexer",
|
||||
"publisher": "sys",
|
||||
"version": [
|
||||
0,
|
||||
1,
|
||||
0
|
||||
]
|
||||
}
|
16
kinode/packages/terminal/metadata.json
Normal file
16
kinode/packages/terminal/metadata.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "Terminal",
|
||||
"description": "Default script runner for Kinode OS",
|
||||
"image": "",
|
||||
"properties": {
|
||||
"package_name": "terminal",
|
||||
"current_version": "0.1.0",
|
||||
"publisher": "sys",
|
||||
"mirrors": [],
|
||||
"code_hashes": {
|
||||
"0.1.0": ""
|
||||
}
|
||||
},
|
||||
"external_url": "https://kinode.org",
|
||||
"animation_url": ""
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"package": "terminal",
|
||||
"publisher": "sys",
|
||||
"version": [
|
||||
0,
|
||||
1,
|
||||
0
|
||||
]
|
||||
}
|
16
kinode/packages/tester/metadata.json
Normal file
16
kinode/packages/tester/metadata.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "Tester",
|
||||
"description": "Package for testing other packages",
|
||||
"image": "",
|
||||
"properties": {
|
||||
"package_name": "tester",
|
||||
"current_version": "0.1.0",
|
||||
"publisher": "sys",
|
||||
"mirrors": [],
|
||||
"code_hashes": {
|
||||
"0.1.0": ""
|
||||
}
|
||||
},
|
||||
"external_url": "https://kinode.org",
|
||||
"animation_url": ""
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
{
|
||||
"package": "tester",
|
||||
"publisher": "sys",
|
||||
"version": [
|
||||
0,
|
||||
1,
|
||||
0
|
||||
]
|
||||
}
|
@ -389,7 +389,8 @@ async fn bootstrap(
|
||||
|
||||
let packages = get_zipped_packages().await;
|
||||
|
||||
for (package_name, mut package) in packages.clone() {
|
||||
for (package_metadata, mut package) in packages.clone() {
|
||||
let package_name = package_metadata.properties.package_name.as_str();
|
||||
// special case tester: only load it in if in simulation mode
|
||||
if package_name == "tester" {
|
||||
#[cfg(not(feature = "simulation-mode"))]
|
||||
@ -397,31 +398,7 @@ async fn bootstrap(
|
||||
}
|
||||
|
||||
println!("fs: handling package {package_name}...\r");
|
||||
// get and read metadata.json
|
||||
let Ok(mut package_metadata_zip) = package.by_name("metadata.json") else {
|
||||
println!(
|
||||
"fs: missing metadata for package {}, skipping",
|
||||
package_name
|
||||
);
|
||||
continue;
|
||||
};
|
||||
let mut metadata_content = Vec::new();
|
||||
package_metadata_zip
|
||||
.read_to_end(&mut metadata_content)
|
||||
.unwrap();
|
||||
drop(package_metadata_zip);
|
||||
let package_metadata: serde_json::Value =
|
||||
serde_json::from_slice(&metadata_content).expect("fs: metadata parse error");
|
||||
|
||||
// println!("fs: found package metadata: {:?}\r", package_metadata);
|
||||
|
||||
let package_name = package_metadata["package"]
|
||||
.as_str()
|
||||
.expect("fs: metadata parse error: bad package name");
|
||||
|
||||
let package_publisher = package_metadata["publisher"]
|
||||
.as_str()
|
||||
.expect("fs: metadata parse error: bad publisher name");
|
||||
let package_publisher = package_metadata.properties.publisher.as_str();
|
||||
|
||||
// create a new package in VFS
|
||||
let our_drive_name = [package_name, package_publisher].join(":");
|
||||
@ -630,7 +607,8 @@ async fn bootstrap(
|
||||
}
|
||||
// second loop: go and grant_capabilities to processes
|
||||
// can't do this in first loop because we need to have all processes in the map first
|
||||
for (package_name, mut package) in packages {
|
||||
for (package_metadata, mut package) in packages {
|
||||
let package_name = package_metadata.properties.package_name.as_str();
|
||||
// special case tester: only load it in if in simulation mode
|
||||
if package_name == "tester" {
|
||||
#[cfg(not(feature = "simulation-mode"))]
|
||||
@ -654,31 +632,7 @@ async fn bootstrap(
|
||||
let package_manifest = serde_json::from_str::<Vec<PackageManifestEntry>>(&package_manifest)
|
||||
.expect("fs: manifest parse error");
|
||||
|
||||
// get and read metadata.json
|
||||
let Ok(mut package_metadata_zip) = package.by_name("metadata.json") else {
|
||||
println!(
|
||||
"fs: missing metadata for package {}, skipping",
|
||||
package_name
|
||||
);
|
||||
continue;
|
||||
};
|
||||
let mut metadata_content = Vec::new();
|
||||
package_metadata_zip
|
||||
.read_to_end(&mut metadata_content)
|
||||
.unwrap();
|
||||
drop(package_metadata_zip);
|
||||
let package_metadata: serde_json::Value =
|
||||
serde_json::from_slice(&metadata_content).expect("fs: metadata parse error");
|
||||
|
||||
// println!("fs: found package metadata: {:?}\r", package_metadata);
|
||||
|
||||
let package_name = package_metadata["package"]
|
||||
.as_str()
|
||||
.expect("fs: metadata parse error: bad package name");
|
||||
|
||||
let package_publisher = package_metadata["publisher"]
|
||||
.as_str()
|
||||
.expect("fs: metadata parse error: bad publisher name");
|
||||
let package_publisher = package_metadata.properties.publisher.as_str();
|
||||
|
||||
// for each process-entry in manifest.json:
|
||||
for entry in package_manifest {
|
||||
@ -759,16 +713,24 @@ fn sign_cap(cap: Capability, keypair: Arc<signature::Ed25519KeyPair>) -> Vec<u8>
|
||||
}
|
||||
|
||||
/// read in `include!()`ed .zip package files
|
||||
async fn get_zipped_packages() -> Vec<(String, zip::ZipArchive<std::io::Cursor<&'static [u8]>>)> {
|
||||
async fn get_zipped_packages() -> Vec<(
|
||||
Erc721Metadata,
|
||||
zip::ZipArchive<std::io::Cursor<&'static [u8]>>,
|
||||
)> {
|
||||
// println!("fs: reading distro packages...\r");
|
||||
|
||||
let mut packages = Vec::new();
|
||||
|
||||
for (package_name, bytes) in BOOTSTRAPPED_PROCESSES.iter() {
|
||||
for (package_name, metadata_bytes, bytes) in BOOTSTRAPPED_PROCESSES.iter() {
|
||||
if let Ok(zip) = zip::ZipArchive::new(std::io::Cursor::new(*bytes)) {
|
||||
// add to list of packages
|
||||
// println!("fs: found package: {}\r", package_name);
|
||||
packages.push((package_name.to_string(), zip));
|
||||
if let Ok(metadata) = serde_json::from_slice::<Erc721Metadata>(metadata_bytes) {
|
||||
packages.push((metadata, zip));
|
||||
} else {
|
||||
println!(
|
||||
"fs: metadata for package {} is not valid Erc721Metadata",
|
||||
package_name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1042,17 +1042,47 @@ impl std::fmt::Display for PersistedProcess {
|
||||
}
|
||||
}
|
||||
|
||||
pub type PackageVersion = (u32, u32, u32);
|
||||
|
||||
/// the type that gets deserialized from `metadata.json` in a package
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct PackageMetadata {
|
||||
pub package: String,
|
||||
pub publisher: String,
|
||||
pub version: PackageVersion,
|
||||
pub wit_version: Option<(u32, u32, u32)>,
|
||||
/// Represents the metadata associated with a kinode package, which is an ERC721 compatible token.
|
||||
/// This is deserialized from the `metadata.json` file in a package.
|
||||
/// Fields:
|
||||
/// - `name`: An optional field representing the display name of the package. This does not have to be unique, and is not used for identification purposes.
|
||||
/// - `description`: An optional field providing a description of the package.
|
||||
/// - `image`: An optional field containing a URL to an image representing the package.
|
||||
/// - `external_url`: An optional field containing a URL for more information about the package. For example, a link to the github repository.
|
||||
/// - `animation_url`: An optional field containing a URL to an animation or video representing the package.
|
||||
/// - `properties`: A requried field containing important information about the package.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Erc721Metadata {
|
||||
pub name: Option<String>,
|
||||
pub description: Option<String>,
|
||||
pub website: Option<String>,
|
||||
pub image: Option<String>,
|
||||
pub external_url: Option<String>,
|
||||
pub animation_url: Option<String>,
|
||||
pub properties: Erc721Properties,
|
||||
}
|
||||
|
||||
/// Represents critical fields of a kinode package in an ERC721 compatible format.
|
||||
/// This follows the [ERC1155](https://github.com/ethereum/ercs/blob/master/ERCS/erc-1155.md#erc-1155-metadata-uri-json-schema) metadata standard.
|
||||
///
|
||||
/// Fields:
|
||||
/// - `package_name`: The unique name of the package, used in the `PackageId`, e.g. `package_name:publisher`.
|
||||
/// - `publisher`: The KNS identity of the package publisher used in the `PackageId`, e.g. `package_name:publisher`
|
||||
/// - `current_version`: A string representing the current version of the package, e.g. `1.0.0`.
|
||||
/// - `mirrors`: A list of NodeIds where the package can be found, providing redundancy.
|
||||
/// - `code_hashes`: A map from version names to their respective SHA-256 hashes.
|
||||
/// - `license`: An optional field containing the license of the package.
|
||||
/// - `screenshots`: An optional field containing a list of URLs to screenshots of the package.
|
||||
/// - `wit_version`: An optional field containing the version of the WIT standard that the package adheres to.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Erc721Properties {
|
||||
pub package_name: String,
|
||||
pub publisher: String,
|
||||
pub current_version: String,
|
||||
pub mirrors: Vec<NodeId>,
|
||||
pub code_hashes: HashMap<String, String>,
|
||||
pub license: Option<String>,
|
||||
pub screenshots: Option<Vec<String>>,
|
||||
pub wit_version: Option<(u32, u32, u32)>,
|
||||
}
|
||||
|
||||
/// the type that gets deserialized from each entry in the array in `manifest.json`
|
||||
|
@ -8,7 +8,7 @@ import zipfile
|
||||
def get_system_info():
|
||||
# Get OS and architecture information
|
||||
os_info = subprocess.run(["uname"], capture_output=True, text=True, check=True).stdout.strip().lower()
|
||||
arch_info = subprocess.run(["uname", "-p"], capture_output=True, text=True, check=True).stdout.strip().lower()
|
||||
arch_info = subprocess.run(["uname", "-m"], capture_output=True, text=True, check=True).stdout.strip().lower()
|
||||
|
||||
if os_info == "linux":
|
||||
os_info = "unknown-linux-gnu"
|
||||
|
Loading…
Reference in New Issue
Block a user