fedimovies/src/activitypub/actors/attachments.rs
2022-07-25 21:39:06 +00:00

174 lines
5.1 KiB
Rust

use uuid::Uuid;
use crate::activitypub::vocabulary::{
IDENTITY_PROOF,
LINK,
PROPERTY_VALUE,
};
use crate::errors::ValidationError;
use crate::ethereum::identity::{
ETHEREUM_EIP191_PROOF,
DidPkh,
verify_identity_proof,
};
use crate::frontend::get_subscription_page_url;
use crate::models::profiles::types::{
ExtraField,
IdentityProof,
PaymentOption,
PaymentType,
};
use super::types::ActorAttachment;
pub fn attach_identity_proof(
proof: IdentityProof,
) -> ActorAttachment {
ActorAttachment {
object_type: IDENTITY_PROOF.to_string(),
name: proof.issuer.to_string(),
value: None,
href: None,
signature_algorithm: Some(proof.proof_type),
signature_value: Some(proof.value),
}
}
pub fn parse_identity_proof(
actor_id: &str,
attachment: &ActorAttachment,
) -> Result<IdentityProof, ValidationError> {
if attachment.object_type != IDENTITY_PROOF {
return Err(ValidationError("invalid attachment type"));
};
let proof_type = attachment.signature_algorithm.as_ref()
.ok_or(ValidationError("missing proof type"))?;
if proof_type != ETHEREUM_EIP191_PROOF {
return Err(ValidationError("unknown proof type"));
};
let did = attachment.name.parse::<DidPkh>()
.map_err(|_| ValidationError("invalid did"))?;
let signature = attachment.signature_value.as_ref()
.ok_or(ValidationError("missing signature"))?;
verify_identity_proof(
actor_id,
&did,
signature,
).map_err(|_| ValidationError("invalid identity proof"))?;
let proof = IdentityProof {
issuer: did,
proof_type: proof_type.to_string(),
value: signature.to_string(),
};
Ok(proof)
}
pub fn attach_payment_option(
instance_url: &str,
user_id: &Uuid,
payment_option: PaymentOption,
) -> ActorAttachment {
match payment_option.payment_type {
PaymentType::Link => unimplemented!(),
PaymentType::EthereumSubscription => {
let name = format!("{:?}", payment_option.payment_type);
let subscription_page_url =
get_subscription_page_url(instance_url, user_id);
ActorAttachment {
object_type: LINK.to_string(),
name: name,
value: None,
href: Some(subscription_page_url),
signature_algorithm: None,
signature_value: None,
}
},
}
}
pub fn parse_payment_option(
attachment: &ActorAttachment,
) -> Result<PaymentOption, ValidationError> {
if attachment.object_type != LINK {
return Err(ValidationError("invalid attachment type"));
};
let payment_option = PaymentOption {
payment_type: PaymentType::Link,
name: Some(attachment.name.clone()),
href: attachment.href.clone(),
};
Ok(payment_option)
}
pub fn attach_extra_field(
field: ExtraField,
) -> ActorAttachment {
ActorAttachment {
object_type: PROPERTY_VALUE.to_string(),
name: field.name,
value: Some(field.value),
href: None,
signature_algorithm: None,
signature_value: None,
}
}
pub fn parse_extra_field(
attachment: &ActorAttachment,
) -> Result<ExtraField, ValidationError> {
if attachment.object_type != PROPERTY_VALUE {
return Err(ValidationError("invalid attachment type"));
};
let property_value = attachment.value.as_ref()
.ok_or(ValidationError("missing property value"))?;
let field = ExtraField {
name: attachment.name.clone(),
value: property_value.to_string(),
value_source: None,
};
Ok(field)
}
#[cfg(test)]
mod tests {
use crate::utils::id::new_uuid;
use super::*;
const INSTANCE_URL: &str = "https://example.com";
#[test]
fn test_extra_field() {
let field = ExtraField {
name: "test".to_string(),
value: "value".to_string(),
value_source: None,
};
let attachment = attach_extra_field(field.clone());
assert_eq!(attachment.object_type, PROPERTY_VALUE);
let parsed_field = parse_extra_field(&attachment).unwrap();
assert_eq!(parsed_field.name, field.name);
assert_eq!(parsed_field.value, field.value);
}
#[test]
fn test_payment_option() {
let user_id = new_uuid();
let payment_option = PaymentOption::subscription();
let subscription_page_url =
format!("https://example.com/profile/{}/subscription", user_id);
let attachment = attach_payment_option(
INSTANCE_URL,
&user_id,
payment_option,
);
assert_eq!(attachment.object_type, LINK);
assert_eq!(attachment.name, "EthereumSubscription");
assert_eq!(attachment.href.as_deref().unwrap(), subscription_page_url);
let parsed_option = parse_payment_option(&attachment).unwrap();
assert!(matches!(parsed_option.payment_type, PaymentType::Link));
assert_eq!(parsed_option.name.unwrap(), "EthereumSubscription");
assert_eq!(parsed_option.href.unwrap(), subscription_page_url);
}
}