sign_plc_operation: new_plc_did

+1
.gitignore
··· 1 1 target/ 2 2 cli/history.txt 3 + cli/operation.json
+9
Cargo.lock
··· 136 136 checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" 137 137 138 138 [[package]] 139 + name = "base32" 140 + version = "0.5.1" 141 + source = "registry+https://github.com/rust-lang/crates.io-index" 142 + checksum = "022dfe9eb35f19ebbcb51e0b40a5ab759f46ad60cadf7297e0bd085afb50e076" 143 + 144 + [[package]] 139 145 name = "base58" 140 146 version = "0.2.0" 141 147 source = "registry+https://github.com/rust-lang/crates.io-index" ··· 1618 1624 name = "vnd-atproto-cli" 1619 1625 version = "0.0.1" 1620 1626 dependencies = [ 1627 + "base32", 1621 1628 "base58", 1622 1629 "base64", 1623 1630 "clap", ··· 1625 1632 "ledger-transport-hid", 1626 1633 "rustyline", 1627 1634 "serde", 1635 + "serde_ipld_dagcbor", 1628 1636 "serde_json", 1637 + "sha2", 1629 1638 "shellwords", 1630 1639 "tokio", 1631 1640 "vnd-atproto-client",
+3
cli/Cargo.toml
··· 5 5 6 6 [dependencies] 7 7 base58 = "0.2.0" 8 + base32 = "0.5.1" 8 9 base64 = "0.22.1" 10 + sha2 = "0.10.8" 9 11 client = { package = "vnd-atproto-client", path = "../client"} 10 12 clap = { version = "4.5.31", features = ["derive"] } 11 13 rustyline = "15.0.0" 12 14 shellwords = "1.1.0" 13 15 hidapi = "2.6.3" 14 16 ledger-transport-hid = "0.11.0" 17 + serde_ipld_dagcbor = { git = "http://github.com/edouardparis/serde_ipld_dagcbor", branch = "scopeguard-no-default-features", default-features = false } 15 18 serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } 16 19 serde_json = { version = "1.0", default-features = false, features = ["alloc"] } 17 20 tokio = { version = "1.38.1", features = ["io-util", "macros", "net", "rt", "rt-multi-thread", "sync"] }
-19
cli/operation.json
··· 1 - { 2 - "type": "plc_operation", 3 - "services": { 4 - "atproto_pds": { 5 - "type": "AtprotoPersonalDataServer", 6 - "endpoint": "https://bsky.social" 7 - } 8 - }, 9 - "alsoKnownAs": [ 10 - "at://atproto.com" 11 - ], 12 - "rotationKeys": [ 13 - "did:key:zQ3shhCGUqDKjStzuDxPkTxN6ujddP4RkEKJJouJGRRkaLGbg", 14 - "did:key:zQ3shpKnbdPx3g3CmPf5cRVTPe1HtSwVn5ish3wSnDPQCbLJK" 15 - ], 16 - "verificationMethods": { 17 - "atproto": "did:key:zQ3shXjHeiBuRCKmM36cuYnm7YEMzhGnCmCyW92sRJ9pribSF" 18 - } 19 - }
+22 -7
cli/src/main.rs
··· 7 7 use rustyline::hint::Hinter; 8 8 use rustyline::validate::{ValidationContext, ValidationResult, Validator}; 9 9 use rustyline::{Context, Editor, Helper}; 10 + use sha2::Digest; 10 11 11 12 use hidapi::HidApi; 12 13 use ledger_transport_hid::TransportNativeHID; ··· 17 18 AtprotoAppClient, 18 19 }; 19 20 20 - use serde::Deserialize; 21 + use serde::{Deserialize, Serialize}; 21 22 use std::borrow::Cow; 22 23 use std::fs::File; 23 24 use std::io::Read; ··· 48 49 /// Path to previous operation json file 49 50 #[clap(long)] 50 51 previous: Option<String>, 52 + #[clap(long, default_missing_value = "true", num_args = 0..=1)] 53 + new_plc_did: bool, 51 54 }, 52 55 Exit, 53 56 } ··· 204 207 key_index, 205 208 operation, 206 209 previous, 210 + new_plc_did, 207 211 } => { 208 212 let operation = read_operation_file(&operation)?; 209 213 let previous = if let Some(path) = previous { ··· 212 216 None 213 217 }; 214 218 let sig = app_client 215 - .sign_plc_operation(key_index.unwrap_or(0), operation, previous) 216 - .await?; 217 - println!( 218 - "sig: {}", 219 - base64::prelude::BASE64_URL_SAFE_NO_PAD.encode(sig) 220 - ); 219 + .sign_plc_operation(key_index.unwrap_or(0), operation.clone(), previous) 220 + .await 221 + .map(|s| base64::prelude::BASE64_URL_SAFE_NO_PAD.encode(s))?; 222 + println!("sig: {}", sig); 223 + if *new_plc_did { 224 + let b = serde_ipld_dagcbor::to_vec(&SignedPlcOperation { operation, sig }).unwrap(); 225 + let hash = sha2::Sha256::digest(b); 226 + let s = base32::encode(base32::Alphabet::Rfc4648Lower { padding: true }, &hash); 227 + eprintln!("did:plc:{}", &s[..24]); 228 + } 221 229 } 222 230 CliCommand::Exit => { 223 231 app_client.exit().await?; ··· 225 233 } 226 234 } 227 235 Ok(()) 236 + } 237 + 238 + #[derive(Serialize)] 239 + pub struct SignedPlcOperation { 240 + #[serde(flatten)] 241 + operation: client::PlcOperation, 242 + sig: String, 228 243 } 229 244 230 245 fn read_operation_file(path: &str) -> Result<client::PlcOperation, Box<dyn std::error::Error>> {