SpruceID
Search…
Implementing New Witness Flows
Witness flows are built on top of schemas. They are more complex because they require defining a struct that implements Statement and a struct (sometimes the same as first) that implements Proof and Statement.
Once those two traits are implemented, a Generator<Proof, Schema> must also be implemented. One of the simplest is DNS:
// src/witness/dns
#[derive(Deserialize, Serialize)]
pub struct Claim {
pub domain: String,
pub prefix: String,
pub key_type: SignerDID,
}
​
impl Statement for Claim {
fn signer_type(&self) -> Result<SignerTypes, SignerError> {
SignerTypes::new(&self.key_type)
}
​
fn generate_statement(&self) -> Result<String, WitnessError> {
let signer_type = self.signer_type()?;
​
Ok(format!(
"{} is linked to {}",
self.domain,
signer_type.statement_id()?
))
}
​
fn delimitor(&self) -> String {
"=".to_string()
}
}
​
impl Proof for Claim {}
​
pub struct Schema {
pub domain: String,
pub key_type: SignerDID,
}
​
impl SchemaType for Schema {
// ...
}
Then the DNS generator is implemented like so:
impl Generator<Claim, Schema> for ClaimGenerator {
async fn locate_post(&self, proof: &Claim) -> Result<String, WitnessError> {
let client = reqwest::Client::new();
let request_url = format!(
"https://cloudflare-dns.com/dns-query?name={}&type=txt",
proof.domain
);
​
let res: DnsResponse = client
.get(Url::parse(&request_url).map_err(|e| WitnessError::BadLookup(e.to_string()))?)
.header("accept", "application/dns-json")
.send()
.await
.map_err(|e| WitnessError::BadLookup(e.to_string()))?
.json()
.await
.map_err(|e| WitnessError::BadLookup(e.to_string()))?;
​
let mut sig = String::new();
for answer in res.answer {
let mut trimmed_signature: &str = &answer.data;
if trimmed_signature.starts_with('"') && trimmed_signature.ends_with('"') {
trimmed_signature = &answer.data[1..answer.data.len() - 1];
}
if trimmed_signature.starts_with(&proof.prefix) {
sig = trimmed_signature.to_owned();
break;
}
}
​
// NOTE: We intercept the post and change it to match the <statement>=<signature>
// style format.
Ok(format!("{}={}", proof.generate_statement()?, sig))
}
​
fn _unchecked_to_schema(
&self,
proof: &Claim,
_statement: &str,
_signature: &str,
) -> Result<Schema, WitnessError> {
Ok(Schema {
domain: proof.domain.clone(),
key_type: proof.key_type.clone(),
})
}
}
A more complex generator is found in src/witness/twitter where an api_key is used to make the lookup. Once the Generator is implemented, it can be added to the WitnessGenerator in src/witness/generator and the generator will then support the new witness flow with no change to the calling applications.
Copy link