Sign a NIP-98 HTTP auth event (kind:27235) and return the Authorization header value. The event includes: - `u` tag: the full request URL - `method` tag: HTTP method (GET, POST, PUT, DELETE) - `payload` tag: SHA-256 hex of the request body (if present)
(
keys: &Keys,
method: &str,
url: &str,
body: Option<&[u8]>,
)
| 81 | /// - `method` tag: HTTP method (GET, POST, PUT, DELETE) |
| 82 | /// - `payload` tag: SHA-256 hex of the request body (if present) |
| 83 | fn sign_nip98( |
| 84 | keys: &Keys, |
| 85 | method: &str, |
| 86 | url: &str, |
| 87 | body: Option<&[u8]>, |
| 88 | ) -> Result<String, CliError> { |
| 89 | let mut tags = vec![ |
| 90 | Tag::parse(["u", url]).map_err(|e| CliError::Other(format!("tag error: {e}")))?, |
| 91 | Tag::parse(["method", method]).map_err(|e| CliError::Other(format!("tag error: {e}")))?, |
| 92 | // Nonce prevents replay rejection for rapid-fire requests with identical bodies. |
| 93 | Tag::parse(["nonce", &uuid::Uuid::new_v4().to_string()]) |
| 94 | .map_err(|e| CliError::Other(format!("tag error: {e}")))?, |
| 95 | ]; |
| 96 | if let Some(b) = body { |
| 97 | let hash = hex::encode(Sha256::digest(b)); |
| 98 | tags.push( |
| 99 | Tag::parse(["payload", &hash]) |
| 100 | .map_err(|e| CliError::Other(format!("tag error: {e}")))?, |
| 101 | ); |
| 102 | } |
| 103 | let event = EventBuilder::new(Kind::Custom(27235), "") |
| 104 | .tags(tags) |
| 105 | .sign_with_keys(keys) |
| 106 | .map_err(|e| CliError::Other(format!("NIP-98 signing failed: {e}")))?; |
| 107 | let json = event.as_json(); |
| 108 | Ok(format!("Nostr {}", B64.encode(json.as_bytes()))) |
| 109 | } |
| 110 | |
| 111 | pub struct BuzzClient { |
| 112 | http: reqwest::Client, |
no test coverage detected