use base64::engine::general_purpose::STANDARD as BASE64;
use base64::Engine;
use sha2::{Digest, Sha256};
const TURTLE_BODY: &str = r#"@prefix ex: <https://example.org/> .
ex:demo a ex:Note ; ex:content "hello nip-98" .
"#;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let url = std::env::args()
.nth(1)
.unwrap_or_else(|| "http://127.0.0.1:8765/notes/demo.ttl".to_string());
let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(10))
.build()?;
let body = TURTLE_BODY.as_bytes();
let put_header = build_nip98_header(&url, "PUT", Some(body));
println!("PUT {url}");
println!(" Authorization: {put_header}");
let resp = client
.put(&url)
.header(reqwest::header::AUTHORIZATION, &put_header)
.header(reqwest::header::CONTENT_TYPE, "text/turtle")
.body(body.to_vec())
.send()
.await?;
let status = resp.status();
let etag = resp
.headers()
.get(reqwest::header::ETAG)
.and_then(|v| v.to_str().ok())
.unwrap_or("<none>")
.to_string();
println!(" status: {status}");
println!(" etag: {etag}");
let get_header = build_nip98_header(&url, "GET", None);
println!("GET {url}");
let resp = client
.get(&url)
.header(reqwest::header::AUTHORIZATION, &get_header)
.send()
.await?;
let status = resp.status();
let text = resp.text().await.unwrap_or_default();
println!(" status: {status}");
println!(" body:");
println!("{text}");
Ok(())
}
fn build_nip98_header(url: &str, method: &str, body: Option<&[u8]>) -> String {
let created_at = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(0);
let mut tags = vec![
vec!["u".to_string(), url.to_string()],
vec!["method".to_string(), method.to_string()],
];
if let Some(b) = body {
if !b.is_empty() {
tags.push(vec![
"payload".to_string(),
hex::encode(Sha256::digest(b)),
]);
}
}
let event = serde_json::json!({
"id": "0".repeat(64),
"pubkey": "a".repeat(64),
"created_at": created_at,
"kind": 27235,
"tags": tags,
"content": "",
"sig": "0".repeat(128),
});
let token = BASE64.encode(serde_json::to_string(&event).unwrap_or_default());
format!("Nostr {token}")
}