use serde::{Deserialize, Serialize};
use url::Url;
use crate::value::UrlOr;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Multikey {
pub id: Url,
#[serde(rename = "type")]
pub kind: String,
pub controller: Url,
pub public_key_multibase: String,
}
impl Multikey {
pub const TYPE: &'static str = "Multikey";
#[must_use]
pub fn new(id: Url, controller: Url, public_key_multibase: impl Into<String>) -> Self {
Self {
id,
kind: Self::TYPE.to_owned(),
controller,
public_key_multibase: public_key_multibase.into(),
}
}
}
pub type AssertionMethod = UrlOr<Multikey>;
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use serde_json::json;
use super::*;
#[test]
fn inline_multikey_roundtrips() {
let raw = json!({
"id": "https://example.com/users/alice#ed25519-key",
"type": "Multikey",
"controller": "https://example.com/users/alice",
"publicKeyMultibase": "z6MkrJVnaZkeFzdQyMZu1cgjg7k1pZZ6pvBQ7XJPt4swbTQ2"
});
let key: Multikey = serde_json::from_value(raw.clone()).unwrap();
assert_eq!(key.kind, Multikey::TYPE);
assert!(key.public_key_multibase.starts_with('z'));
let back = serde_json::to_value(&key).unwrap();
assert_eq!(back, raw);
}
#[test]
fn assertion_method_accepts_bare_url_form() {
let raw = json!("https://example.com/users/alice#main-key");
let am: AssertionMethod = serde_json::from_value(raw.clone()).unwrap();
assert!(matches!(am, AssertionMethod::Url(_)));
let back = serde_json::to_value(&am).unwrap();
assert_eq!(back, raw);
}
#[test]
fn assertion_method_accepts_inlined_multikey_form() {
let raw = json!({
"id": "https://example.com/users/alice#main-key",
"type": "Multikey",
"controller": "https://example.com/users/alice",
"publicKeyMultibase": "z6Mk…"
});
let am: AssertionMethod = serde_json::from_value(raw.clone()).unwrap();
assert!(matches!(am, AssertionMethod::Object(_)));
let back = serde_json::to_value(&am).unwrap();
assert_eq!(back, raw);
}
}