gourami

[UNMAINTAINED] Activitypub server in Rust
Log | Files | Refs | README | LICENSE

commit ba0c15f6ab5c855644153bdd2c9f86bae74abb07
parent c60cd003e82ae54752567786239674c41d3632a6
Author: alex wennerberg <alex@alexwennerberg.com>
Date:   Sun, 17 May 2020 10:04:01 -0500

cleanup some mastodon interop errors

Diffstat:
Mansible/playbook.yml | 8++++++++
Msrc/ap.rs | 24++++++++++++++----------
Msrc/routes.rs | 38++++++++++++++++----------------------
3 files changed, 38 insertions(+), 32 deletions(-)

diff --git a/ansible/playbook.yml b/ansible/playbook.yml @@ -17,6 +17,14 @@ src: ../target/release/gourami_social dest: /home/gourami/gourami_social # TODO template etc owner: gourami + - name: copy static files over + copy: + src: ../static + dest: /home/gourami + - name: copy migrations over + copy: + src: ../migrations + dest: /home/gourami - name: copy env over copy: src: prod_dotenv # distinguish dev/prod diff --git a/src/ap.rs b/src/ap.rs @@ -60,7 +60,7 @@ pub struct CreateNote { // Maybe use AP crate id: String, object: ApNote, - actor: Actor, + actor: String, // could be obj? } #[derive(Debug, Deserialize, Serialize)] @@ -173,9 +173,9 @@ pub fn server_actor_json() -> Actor { use url::Url; -pub fn check_domains_match(a: &str, b: &str) -> Result<String, Error> { - if Url::parse(a)?.domain() == Url::parse(b)?.domain() { - return Ok(Url::parse(a)?.domain().ok_or("No domain found")?.to_owned()); +pub fn check_domains_match(a: &str, b: &str) -> Result<(), Error> { + if Some(a) == Url::parse(b)?.domain() { + return Ok(()); } return Err(Error::MiscError("Domain Mismatch".to_owned())); } @@ -186,9 +186,10 @@ pub fn process_create_note(v: Value, domain: &str) -> Result<(), Error> { // let conn = &POOL.get()?; let create_note: CreateNote = serde_json::from_value(v)?; + // TODO cache this // do some domain verification - check_domains_match(domain, &create_note.actor.id)?; + check_domains_match(domain, &create_note.actor)?; check_domains_match(domain, &create_note.id)?; check_domains_match(domain, &create_note.object.id)?; check_domains_match(domain, &create_note.object.attributed_to)?; @@ -199,7 +200,7 @@ pub fn process_create_note(v: Value, domain: &str) -> Result<(), Error> { // if user not in db, insert // let ap_note = create_note.object; - if !should_accept(&ap_note.id) { + if !should_accept(&create_note.actor) { return Err(Error::MiscError("Not someone we are following".to_owned())); } let remote_username = ap_note @@ -380,7 +381,8 @@ fn generate_server_follow(remote_actor: &str, my_inbox_url: &str) -> Result<Valu actor_id: remote_actor.to_owned(), inbox_url: my_inbox_url.to_owned(), }) - .execute(conn)?; + .execute(conn) + .ok(); // TODO better error handling Ok(res) } @@ -539,9 +541,11 @@ pub async fn verify_ap_message( .set_expiration(Duration::seconds(3600)) .dont_use_created_field(); let unverified = config.begin_verify(method, path_and_query, headers)?; - let actor: Actor = get_remote_actor(unverified.key_id()).await?; - check_domains_match(unverified.key_id(), &actor.id)?; - let domain = check_domains_match(unverified.key_id(), &actor.public_key.owner)?; + let key_id = unverified.key_id(); + let actor: Actor = get_remote_actor(key_id).await?; + let domain = Url::parse(key_id)?.domain().ok_or("No domain")?.to_owned(); + check_domains_match(&domain, &actor.id)?; + check_domains_match(&domain, &actor.public_key.owner)?; let res = unverified.verify(|signature, signing_string| { let public_key: &[u8] = actor.public_key.public_key_pem.as_bytes(); let r = Rsa::public_key_from_pem(public_key).unwrap(); diff --git a/src/routes.rs b/src/routes.rs @@ -136,31 +136,25 @@ pub async fn run_server() { .and(warp::fs::dir("./static")) .or(robots); - // activityPub stuff - // This stuff should filter based on the application headers - // setup authentication - // POST - // TODO -- setup proper replies - // force content type to be application/ld+json; profile="https://www.w3.org/ns/activitystreams let post_server_inbox = path!("inbox") - .and(body::aggregate()) - .and( - header::exact_ignore_case( - "content-type", - r#"application/ld+json; profile="https://www.w3.org/ns/activitystreams""#, - ) - .or(header::exact_ignore_case( - "content-type", - r#"application/ld+json"#, - )) - .or(header::exact_ignore_case( - "content-type", - r#"profile="https://www.w3.org/ns/activitystreams""#, - )), - ) + .and(body::aggregate()) // TODO -- figure out whats going wrong with content type here from mastodon + // .and( + // header::exact_ignore_case( + // "content-type", + // r#"application/ld+json; profile="https://www.w3.org/ns/activitystreams""#, + // ) + // .or(header::exact_ignore_case( + // "content-type", + // r#"application/ld+json"#, + // )) + // .or(header::exact_ignore_case( + // "content-type", + // r#"profile="https://www.w3.org/ns/activitystreams""#, + // )), + // ) .and(header::headers_cloned()) - .and_then(|buf, _, headers| async move { post_inbox(buf, headers).await }); + .and_then(|buf, headers| async move { post_inbox(buf, headers).await }); let get_server_outbox = path!("outbox").map(get_outbox);