From cd9ea77cec8e5f99b0ddac095f5bebd67686f66f Mon Sep 17 00:00:00 2001 From: Buffrr Date: Thu, 6 Aug 2026 13:19:46 +0200 Subject: [PATCH 1/3] fix(test-rig): bind certrelay on all interfaces It defaulted to loopback, so the relay was unreachable from another machine or a container while subs itself listened on 0.0.0.0. --- subs/src/testrig.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/subs/src/testrig.rs b/subs/src/testrig.rs index 739eebd..48d789d 100644 --- a/subs/src/testrig.rs +++ b/subs/src/testrig.rs @@ -221,6 +221,11 @@ impl TestRigHandle { self.spaced_rpc_url.replace("://", "://user:pass@"), "--port".to_string(), port.to_string(), + // Reachable off-box, matching the subs listener. certrelay binds + // loopback by default, which leaves it unusable from another + // machine or a container. + "--bind".to_string(), + "0.0.0.0".to_string(), "--self-url".to_string(), url.clone(), "--is-bootstrap".to_string(), From e85f16914acd7b96215d18015afb6df97d1d1b4b Mon Sep 17 00:00:00 2001 From: Buffrr Date: Thu, 20 Aug 2026 13:17:53 +0200 Subject: [PATCH 2/3] chore(deps): spaces 0.3.0, libveritas 0.4.2, fabric 0.2.9 --- Cargo.lock | 162 +++++++++++++++++++++++++++-------------------------- Cargo.toml | 14 ++--- 2 files changed, 89 insertions(+), 87 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1041533..c4ec967 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1275,9 +1275,9 @@ dependencies = [ [[package]] name = "borsh_utils" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a9716bbbca7bd5eb81c46151ef82ce10ebcf428f63397371284b2b705c28cb9" +checksum = "afe6e88b898c9baea16d8f01a67b948c3816e48e96f779afd4a7932b03d1cac1" dependencies = [ "bitcoin", "borsh", @@ -1285,8 +1285,8 @@ dependencies = [ [[package]] name = "borsh_utils" -version = "0.2.1" -source = "git+https://github.com/spacesprotocol/spaces.git?branch=subspaces#744e75a7625f98dbe5e3a484f962769e506c5381" +version = "0.3.0" +source = "git+https://github.com/spacesprotocol/spaces.git?branch=subspaces#5eedbb096aca38127b0d02f85e58ccee24c9bbd5" dependencies = [ "bitcoin", "borsh", @@ -2279,9 +2279,9 @@ dependencies = [ [[package]] name = "fabric-resolver" -version = "0.2.7" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa0e6bdf85df8e2cddc911d311dc748251f6aa78adb8e61884bcc73c4851277" +checksum = "d99a126b02399edc6aee4e787ead2b6eea7fff21bdbf7a6accbc003f517b269f" dependencies = [ "borsh", "dashmap", @@ -2289,17 +2289,18 @@ dependencies = [ "libveritas", "rand 0.9.5", "reqwest", + "secp256k1", "serde", "serde_json", "sha2", - "spaces_nums 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_nums 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio", ] [[package]] name = "fabric-resolver" -version = "0.2.7" -source = "git+https://github.com/spacesprotocol/certrelay.git#e680aff03be1b87778f22b8c4f284da52b443333" +version = "0.2.9" +source = "git+https://github.com/spacesprotocol/certrelay.git#7138296dcada419ad2e210891c84741f3b09687a" dependencies = [ "borsh", "dashmap", @@ -2308,7 +2309,7 @@ dependencies = [ "serde", "serde_json", "sha2", - "spaces_nums 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_nums 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3622,9 +3623,9 @@ dependencies = [ [[package]] name = "libveritas" -version = "0.3.3" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a640a4f8a32bfc381e67d80ae0ac8e6e7b139073dba53556474d18ab81fe33b8" +checksum = "1860beafc30c88b2ad698483376e6cc6f437de34ec4536b6db6d185e604154bc" dependencies = [ "base64 0.22.1", "borsh", @@ -3633,10 +3634,10 @@ dependencies = [ "risc0-zkvm", "serde", "serde_json", - "sip7 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sip7 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "spacedb", - "spaces_nums 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "spaces_protocol 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_nums 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_protocol 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4917,8 +4918,8 @@ dependencies = [ [[package]] name = "relay" -version = "0.2.7" -source = "git+https://github.com/spacesprotocol/certrelay.git#e680aff03be1b87778f22b8c4f284da52b443333" +version = "0.2.9" +source = "git+https://github.com/spacesprotocol/certrelay.git#7138296dcada419ad2e210891c84741f3b09687a" dependencies = [ "anyhow", "axum 0.8.3", @@ -4927,21 +4928,22 @@ dependencies = [ "borsh", "clap", "env_logger", - "fabric-resolver 0.2.7 (git+https://github.com/spacesprotocol/certrelay.git)", + "fabric-resolver 0.2.9 (git+https://github.com/spacesprotocol/certrelay.git)", "governor", "hex", "libveritas", "rand 0.9.5", "reqwest", "rusqlite", + "secp256k1", "serde", "serde_json", "sha2", "spacedb", "spaces_checkpoint", - "spaces_client 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "spaces_nums 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "spaces_protocol 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_client 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_nums 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_protocol 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio", "toml", "tower-http", @@ -6013,25 +6015,25 @@ checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" [[package]] name = "sip7" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ed9b8980298850d71acd2c96f55bef13a4e4d28d2976c503a86c69c791fd34" +checksum = "b1c60c754d3958120c272c963e2333f4ea2f142f9832e5ffdd4cc04caa9ab946" dependencies = [ "base64 0.22.1", "hex", "serde", - "spaces_protocol 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_protocol 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sip7" -version = "0.2.1" -source = "git+https://github.com/spacesprotocol/spaces.git?branch=subspaces#744e75a7625f98dbe5e3a484f962769e506c5381" +version = "0.3.0" +source = "git+https://github.com/spacesprotocol/spaces.git?branch=subspaces#5eedbb096aca38127b0d02f85e58ccee24c9bbd5" dependencies = [ "base64 0.22.1", "hex", "serde", - "spaces_protocol 0.2.1 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", + "spaces_protocol 0.3.0 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", ] [[package]] @@ -6084,9 +6086,9 @@ dependencies = [ [[package]] name = "spacedb" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50025cab5ea890c2ddbfbd0ecd46694d6ac0090caa21d74da3b80104b6ef4a8" +checksum = "cf14a3d14c3dcc6b87d837e246d9de73ef24b0d83796a294ceaa82e8acf4e8c9" dependencies = [ "bincode 2.0.1", "borsh", @@ -6098,9 +6100,9 @@ dependencies = [ [[package]] name = "spaces_checkpoint" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611add09bc1b52a4739a71bb15bcbdb162449c668bf0c74f8c4a48835c4e5c60" +checksum = "c1ab25dcb0d99385d0f6ca9213c6ed0ec182625d794ed2051fa1568b81270700" dependencies = [ "anyhow", "clap", @@ -6110,7 +6112,7 @@ dependencies = [ "serde_json", "sha2", "spacedb", - "spaces_protocol 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_protocol 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tar", "tracing", "ureq", @@ -6118,14 +6120,14 @@ dependencies = [ [[package]] name = "spaces_client" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27ec4e8bc75f0f2e87beb778702149efd341a0b10efe42493b3de32a670d64c" +checksum = "534384e03c6d0bf1196466d9a7e20cebb1c5b425b926834a673439b214ce0815" dependencies = [ "anyhow", "base64 0.22.1", "borsh", - "borsh_utils 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "borsh_utils 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap", "colored", "directories 5.0.1", @@ -6141,11 +6143,11 @@ dependencies = [ "schemars 0.8.22", "serde", "serde_json", - "sip7 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "sip7 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "spacedb", - "spaces_nums 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "spaces_protocol 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "spaces_wallet 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_nums 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_protocol 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_wallet 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "tabled", "threadpool", "tokio", @@ -6154,13 +6156,13 @@ dependencies = [ [[package]] name = "spaces_client" -version = "0.2.1" -source = "git+https://github.com/spacesprotocol/spaces.git?branch=subspaces#744e75a7625f98dbe5e3a484f962769e506c5381" +version = "0.3.0" +source = "git+https://github.com/spacesprotocol/spaces.git?branch=subspaces#5eedbb096aca38127b0d02f85e58ccee24c9bbd5" dependencies = [ "anyhow", "base64 0.22.1", "borsh", - "borsh_utils 0.2.1 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", + "borsh_utils 0.3.0 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", "clap", "colored", "directories 5.0.1", @@ -6175,11 +6177,11 @@ dependencies = [ "rusqlite", "serde", "serde_json", - "sip7 0.2.1 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", + "sip7 0.3.0 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", "spacedb", - "spaces_nums 0.2.1 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", - "spaces_protocol 0.2.1 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", - "spaces_wallet 0.2.1 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", + "spaces_nums 0.3.0 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", + "spaces_protocol 0.3.0 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", + "spaces_wallet 0.3.0 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", "tabled", "threadpool", "tokio", @@ -6188,62 +6190,62 @@ dependencies = [ [[package]] name = "spaces_nums" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b842f5b10f200e3c9548489657da4e889897183c72d35673f27d20c2ecb3be" +checksum = "7995b967a9e479b52f11e4b6f165f3b0c07b58f3aa109234332a2a9fdbab4716" dependencies = [ "bech32", "bitcoin", "borsh", - "borsh_utils 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "borsh_utils 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex", "log", "serde", - "spaces_protocol 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_protocol 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "spaces_nums" -version = "0.2.1" -source = "git+https://github.com/spacesprotocol/spaces.git?branch=subspaces#744e75a7625f98dbe5e3a484f962769e506c5381" +version = "0.3.0" +source = "git+https://github.com/spacesprotocol/spaces.git?branch=subspaces#5eedbb096aca38127b0d02f85e58ccee24c9bbd5" dependencies = [ "bech32", "bitcoin", "borsh", - "borsh_utils 0.2.1 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", + "borsh_utils 0.3.0 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", "hex", "log", "serde", - "spaces_protocol 0.2.1 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", + "spaces_protocol 0.3.0 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", ] [[package]] name = "spaces_protocol" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f412ceb3e0a1ce5ca00a8cc7bb875cd614ba7ac809e4085502ec397e354a4a" +checksum = "592c235dc5872d4d28564fa59e0c4035255042a60d0c77f3732df527f4485100" dependencies = [ "bitcoin", "borsh", - "borsh_utils 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "borsh_utils 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde", ] [[package]] name = "spaces_protocol" -version = "0.2.1" -source = "git+https://github.com/spacesprotocol/spaces.git?branch=subspaces#744e75a7625f98dbe5e3a484f962769e506c5381" +version = "0.3.0" +source = "git+https://github.com/spacesprotocol/spaces.git?branch=subspaces#5eedbb096aca38127b0d02f85e58ccee24c9bbd5" dependencies = [ "bitcoin", "borsh", - "borsh_utils 0.2.1 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", + "borsh_utils 0.3.0 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", "serde", ] [[package]] name = "spaces_testutil" -version = "0.2.1" -source = "git+https://github.com/spacesprotocol/spaces.git?branch=subspaces#744e75a7625f98dbe5e3a484f962769e506c5381" +version = "0.3.0" +source = "git+https://github.com/spacesprotocol/spaces.git?branch=subspaces#5eedbb096aca38127b0d02f85e58ccee24c9bbd5" dependencies = [ "anyhow", "assert_cmd", @@ -6252,17 +6254,17 @@ dependencies = [ "hex", "serde_json", "spacedb", - "spaces_client 0.2.1 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", - "spaces_protocol 0.2.1 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", + "spaces_client 0.3.0 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", + "spaces_protocol 0.3.0 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", "tokio", "zip 0.6.6", ] [[package]] name = "spaces_wallet" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6ba9c85e7685c47229c8430cb9496c67799af42b7c9bc64f12e15245a601aa2" +checksum = "5d340b0780e3246915db18f4a4b7f6a7aa96af429d75fb4bc622b31b7cb5e878" dependencies = [ "anyhow", "bdk_wallet_backport", @@ -6272,14 +6274,14 @@ dependencies = [ "secp256k1", "serde", "serde_json", - "spaces_nums 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "spaces_protocol 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_nums 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_protocol 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "spaces_wallet" -version = "0.2.1" -source = "git+https://github.com/spacesprotocol/spaces.git?branch=subspaces#744e75a7625f98dbe5e3a484f962769e506c5381" +version = "0.3.0" +source = "git+https://github.com/spacesprotocol/spaces.git?branch=subspaces#5eedbb096aca38127b0d02f85e58ccee24c9bbd5" dependencies = [ "anyhow", "bdk_wallet_backport", @@ -6289,8 +6291,8 @@ dependencies = [ "secp256k1", "serde", "serde_json", - "spaces_nums 0.2.1 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", - "spaces_protocol 0.2.1 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", + "spaces_nums 0.3.0 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", + "spaces_protocol 0.3.0 (git+https://github.com/spacesprotocol/spaces.git?branch=subspaces)", ] [[package]] @@ -6398,10 +6400,10 @@ dependencies = [ "rusqlite", "serde", "serde_json", - "spaces_client 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "spaces_protocol 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_client 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_protocol 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "spaces_testutil", - "spaces_wallet 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_wallet 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "subs-core", "subs-types", "tokio", @@ -6418,7 +6420,7 @@ dependencies = [ "bitcoin", "borsh", "env_logger", - "fabric-resolver 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "fabric-resolver 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "hex", "libveritas", "libveritas_zk", @@ -6428,11 +6430,11 @@ dependencies = [ "serde", "serde_json", "spacedb", - "spaces_client 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "spaces_nums 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "spaces_protocol 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_client 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_nums 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_protocol 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "spaces_testutil", - "spaces_wallet 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spaces_wallet 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "subs-prover", "subs-types", "tempfile", diff --git a/Cargo.toml b/Cargo.toml index 05cb984..45e5d9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,20 +9,20 @@ subs-prover = { path = "prover" } subs-core = { path = "core" } # libveritas / fabric / spacedb / relay -libveritas = { version = "=0.3.3", features = ["elf"] } +libveritas = { version = "=0.4.2", features = ["elf"] } libveritas_zk = "=0.1.1" -libveritas_testutil = "=0.3.3" +libveritas_testutil = "=0.4.2" # hash-idx builds a sidecar index that speeds up .prove(); it is not a default # feature and pulls in rusqlite, which we already depend on. spacedb = { version = "0.1.3", features = ["hash-idx"] } relay = { git = "https://github.com/spacesprotocol/certrelay.git" } -fabric = { package = "fabric-resolver", version = "=0.2.7" } +fabric = { package = "fabric-resolver", version = "=0.2.9" } # Spaces protocol crates -spaces_protocol = { version = "0.2.1", features = ["std"] } -spaces_nums = { version = "0.2.1", features = ["std"] } -spaces_client = { version = "0.2.1" } -spaces_wallet = "0.2.1" +spaces_protocol = { version = "0.3.0", features = ["std"] } +spaces_nums = { version = "0.3.0", features = ["std"] } +spaces_client = { version = "0.3.0" } +spaces_wallet = "0.3.0" spaces_testutil = { git = "https://github.com/spacesprotocol/spaces.git", branch = "subspaces" } # Common third-party deps From a97f4d25bff4116bd47aac31731e371c5f9d3398 Mon Sep 17 00:00:00 2001 From: Buffrr Date: Thu, 20 Aug 2026 13:18:14 +0200 Subject: [PATCH 3/3] feat(ui): download the publish message for a handle A debugging aid: GET /certs/:handle/message returns the exact bytes submit_certs would broadcast, reachable from a button on the handle page. --- subs/src/routes/certs.rs | 56 ++++++++++++++++++++++++++++++++++++-- subs/src/routes/mod.rs | 1 + subs/templates/handle.html | 26 ++++++++++++++++++ 3 files changed, 81 insertions(+), 2 deletions(-) diff --git a/subs/src/routes/certs.rs b/subs/src/routes/certs.rs index 989f40d..1cba759 100644 --- a/subs/src/routes/certs.rs +++ b/subs/src/routes/certs.rs @@ -2,9 +2,9 @@ use axum::{ extract::{Path, State}, - http::StatusCode, + http::{header, StatusCode}, Json, - response::Response, + response::{IntoResponse, Response}, }; use base64::Engine; use serde::Serialize; @@ -58,3 +58,55 @@ pub async fn issue_cert( })) } +/// GET /certs/:handle/message - The exact bytes publishing this handle would +/// broadcast. +/// +/// A debugging aid: this is what `submit_certs` builds and hands to the relay, +/// so it can be inspected or replayed without going through a publish. +/// +/// Nothing is recorded. Publishing tracks message sizes to size the next batch, +/// and marks handles published — an export that did either would perturb the +/// state it exists to inspect. +/// +/// The bytes are only meaningful against the chain tip they were built at: +/// build_message fetches a fresh chain proof, so this is a snapshot rather than +/// a durable artifact. It needs an RPC but no fabric, since nothing is sent. +pub async fn export_message( + State(state): State, + Path(handle): Path, +) -> Result { + use spaces_protocol::sname::SName; + + let handle: SName = handle + .parse() + .map_err(|e| json_error(StatusCode::BAD_REQUEST, format!("invalid handle: {}", e)))?; + + let filename = format!("{}.message.bin", handle.to_string().replace(['@', '/'], "_")); + + let certs = state + .operator + .issue_certs(vec![handle]) + .await + .map_err(|e| json_error(StatusCode::INTERNAL_SERVER_ERROR, e))?; + + let message = state + .operator + .build_message(certs) + .await + .map_err(|e| json_error(StatusCode::INTERNAL_SERVER_ERROR, e))?; + + let bytes = message.to_bytes(); + + Ok(( + [ + (header::CONTENT_TYPE, "application/octet-stream".to_string()), + ( + header::CONTENT_DISPOSITION, + format!("attachment; filename=\"{}\"", filename), + ), + ], + bytes, + ) + .into_response()) +} + diff --git a/subs/src/routes/mod.rs b/subs/src/routes/mod.rs index e9e3cfb..22d83dd 100644 --- a/subs/src/routes/mod.rs +++ b/subs/src/routes/mod.rs @@ -70,6 +70,7 @@ pub fn router() -> Router { .route("/query/anchors", get(query::export_anchors)) // API: Certificates .route("/certs/:handle", get(certs::issue_cert)) + .route("/certs/:handle/message", get(certs::export_message)) // API: RPC Console .route("/rpc/endpoints", get(console::get_endpoints)) .route("/rpc/spaced", post(console::proxy_spaced)) diff --git a/subs/templates/handle.html b/subs/templates/handle.html index 63aaacb..875ff94 100644 --- a/subs/templates/handle.html +++ b/subs/templates/handle.html @@ -156,6 +156,7 @@

Fabric Query

const pubLabel = h.publish_status ? 'Re-publish Certificate' : 'Publish Certificate'; btns += ``; btns += ``; + btns += ``; btns += ``; actions.innerHTML = btns; } @@ -241,6 +242,31 @@

Fabric Query

} } +// The exact bytes publishing this handle would broadcast. Downloaded rather +// than shown: it is binary, and the root certificate alone is ~224 KB. +async function downloadMessage() { + try { + const r = await fetch(`/certs/${encodeURIComponent(fullHandle)}/message`); + if (!r.ok) { + const j = await r.json().catch(() => ({})); + showResult(j.error || 'Failed to build message', false); + return; + } + const blob = await r.blob(); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = `${handle}${space}.message.bin`; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + showResult(`Message downloaded (${blob.size.toLocaleString()} bytes)`, true); + } catch (e) { + showResult(e.message, false); + } +} + async function queryHandle() { const card = document.getElementById('queryCard'); const result = document.getElementById('queryResult');