~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/atlibs-socialweb-computer-requester

socialweb.computer market requester and policy modules for atlibs, with its web pages and lexicons

0
0
main
70 lines · 2.6 KB Raw History
use abi::records::exec::Attest;
use abi::repo::get_record;
use abi::{AtUri, Call, LexiconType, TypedLexicon, TypedStrongRef};

use crate::nsid::{BID, RECEIPT};
use serde::Serialize;
use serde_json::{Value, json};

use crate::input::strong;
use crate::nsid::ATTEST;

/// Attestations come from the host (com.fedfork.exec.attest); without a record
/// it answers with the host's did:key.
pub fn attest(me: &str, record: Option<&Value>) -> Call {
    Call::new("", ATTEST).input(json!(Attest { repository: me.into(), record: record.cloned() }))
}

pub fn typed<T: LexiconType + Serialize + PartialEq>(record: T) -> Value {
    json!(TypedLexicon::new(record))
}

/// The host's signed copy must be the record we asked for, plus signatures.
pub fn signed(result: Result<Value, String>, unsigned: &Value) -> Result<Value, String> {
    let record = result?["record"].take();
    let mut bare = record.clone();
    let signatures = bare.as_object_mut().and_then(|o| o.remove("signatures"));
    if !signatures.as_ref().and_then(Value::as_array).is_some_and(|s| !s.is_empty()) || &bare != unsigned {
        return Err("attest must return the record with signatures added".into());
    }
    Ok(record)
}

pub fn created(result: Result<Value, String>) -> Result<TypedStrongRef, String> {
    strong(&result?, "createRecord output")
}

/// A peer's public record, read from its own PDS.
pub fn read(uri: &AtUri) -> Call {
    get_record(uri).service(&uri.repo)
}

/// The winner keys its receipt by the accept: receipt-<hex(sha256("<uri>\n<cid>"))[0..32]>.
pub fn receipt_uri(bidder: &str, accept: &TypedStrongRef) -> AtUri {
    AtUri::new(bidder, RECEIPT, format!("receipt-{}", hex16(&format!("{}\n{}", accept.uri, accept.cid))))
}

/// A bidder keys its bid by the rfp: bid-<hex(sha256("<bidder>\0<uri>#<cid>"))[0..20]>.
pub fn bid_uri(bidder: &str, rfp: &TypedStrongRef) -> AtUri {
    AtUri::new(bidder, BID, format!("bid-{}", &hex(&format!("{bidder}\0{}#{}", rfp.uri, rfp.cid))[..20]))
}

pub fn hex16(key: &str) -> String {
    hex(key)[..32].to_string()
}

fn hex(key: &str) -> String {
    use sha2::{Digest, Sha256};
    Sha256::digest(key.as_bytes()).iter().map(|b| format!("{b:02x}")).collect()
}

/// base64url without padding (the webrtc:// and iroh:// URL refs).
pub fn b64url(bytes: &[u8]) -> String {
    const A: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
    let mut out = String::new();
    for chunk in bytes.chunks(3) {
        let n = chunk.iter().enumerate().fold(0u32, |n, (i, b)| n | u32::from(*b) << (16 - 8 * i));
        out.extend((0..=chunk.len()).map(|i| A[(n >> (18 - 6 * i) & 63) as usize] as char));
    }
    out
}