+9
Cargo.lock
+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
+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
-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
+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>> {