gourami

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

commit 2b01812000d12cacf755222c465e61bf1ffcf16e
parent 4bac24e3f3fb5f73bf8610fc39af507a6b632e88
Author: alex wennerberg <alex@alexwennerberg.com>
Date:   Tue, 21 Apr 2020 20:46:57 -0500

Start on AP parsing

Diffstat:
MCargo.lock | 86+++++--------------------------------------------------------------------------
MCargo.toml | 2+-
MTODO | 2++
Msrc/ap.rs | 34+++++++++++++++++++++++++++-------
Msrc/db/note.rs | 31++++++++++++-------------------
Msrc/db/user.rs | 1-
Msrc/lib.rs | 5++---
7 files changed, 49 insertions(+), 112 deletions(-)

diff --git a/Cargo.lock b/Cargo.lock @@ -2,24 +2,24 @@ # It is not intended for manual editing. [[package]] name = "activitystreams" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4e772dec49451dc7192521318c39e64332457496366252180f095c7c3caca4" +checksum = "ae98a55a86fc3150f278b225644cd46b5359f4d75067eae6dc3a52b409c537fb" dependencies = [ "activitystreams-derive", "chrono", "mime 0.3.16", "serde", + "serde_json", "thiserror", - "typetag", "url", ] [[package]] name = "activitystreams-derive" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a49213d92701b6b3d582da94ad5506fbe7049c6281ac56031e5c218a9be74bf" +checksum = "20d0384ae423a1df266f216e351ce9b40e8d369467d9242c086121154b4327dd" dependencies = [ "proc-macro2 1.0.10", "quote 1.0.3", @@ -287,16 +287,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" [[package]] -name = "ctor" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47c5e5ac752e18207b12e16b10631ae5f7f68f8805f335f9b817ead83d9ffce1" -dependencies = [ - "quote 1.0.3", - "syn 1.0.17", -] - -[[package]] name = "diesel" version = "1.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -363,15 +353,6 @@ dependencies = [ ] [[package]] -name = "erased-serde" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d88b6d1705e16a4d62e05ea61cc0496c2bd190f4fa8e5c1f11ce747be6bcf3d1" -dependencies = [ - "serde", -] - -[[package]] name = "fake-simd" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -542,17 +523,6 @@ dependencies = [ ] [[package]] -name = "ghost" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a36606a68532b5640dc86bb1f33c64b45c4682aad4c50f3937b317ea387f3d6" -dependencies = [ - "proc-macro2 1.0.10", - "quote 1.0.3", - "syn 1.0.17", -] - -[[package]] name = "gourami_social" version = "0.1.0" dependencies = [ @@ -753,28 +723,6 @@ dependencies = [ ] [[package]] -name = "inventory" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d3f4b90287725c97b17478c60dda0c6324e7c84ee1ed72fb9179d0fdf13956" -dependencies = [ - "ctor", - "ghost", - "inventory-impl", -] - -[[package]] -name = "inventory-impl" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9092a4fefc9d503e9287ef137f03180a6e7d1b04c419563171ee14947c5e80ec" -dependencies = [ - "proc-macro2 1.0.10", - "quote 1.0.3", - "syn 1.0.17", -] - -[[package]] name = "iovec" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2076,30 +2024,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d2783fe2d6b8c1101136184eb41be8b1ad379e4657050b8aaff0c79ee7575f9" [[package]] -name = "typetag" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ebb2c484029d695fb68a06d80e1536c68d491b3e0cf874c66abed255e831cfe" -dependencies = [ - "erased-serde", - "inventory", - "lazy_static", - "serde", - "typetag-impl", -] - -[[package]] -name = "typetag-impl" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b63fd4799e4d0ec5cf0b055ebb8e2c3a657bbf76a84f6edc77ca60780e000204" -dependencies = [ - "proc-macro2 1.0.10", - "quote 1.0.3", - "syn 1.0.17", -] - -[[package]] name = "unicase" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml @@ -5,7 +5,7 @@ authors = ["alex wennerberg <alex@alexwennerberg.com>"] edition = "2018" [dependencies] -activitystreams = "0.4.0" +activitystreams = "0.5.0" askama = "0.8" bcrypt = "0.7" cookie = "0.13" diff --git a/TODO b/TODO @@ -1,5 +1,7 @@ sanitize on write to db +send notes as cleartext and html? + understand fn vs async fn in tokio marketing tagline: diff --git a/src/ap.rs b/src/ap.rs @@ -1,16 +1,36 @@ -use serde_json::value::Value; +use log::{debug, info}; +use serde_json::{Result, Value}; +use std::error::Error; +use activitystreams::activity::{Create, Activity}; -fn process_ap_activity(message: Value) { - // profiles +fn parse_unstructured_ap(message: &str) -> impl Activity { + // try and serialize in a few different ways + let object: Create = serde_json::from_str(message).unwrap(); + object +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn test_empty_string() { + parse_unstructured_ap("1"); + } +} + + + // Err("Message not an activity"); +// let object = message.get("object")?.get("type")?; +// profiles // follow // accept / reject // statuses "Notes" // match message.get("type").lower() { // "create" => Some(1), - // "delete" => Some(1), - // Announce? - // _ => None +// "delete" => Some(1), +// Announce? +// _ => None // }; // main type: Note // simple https://docs.joinmastodon.org/spec/activitypub/ @@ -21,7 +41,7 @@ fn process_ap_activity(message: Value) { // // "get" -> list all jsons. // match these to notifications -} + pub fn post_user_inbox(user_name: String, message: Value) { } diff --git a/src/db/note.rs b/src/db/note.rs @@ -1,6 +1,5 @@ use chrono; use std::collections::HashSet; -use activitystreams::object::streams; use diesel::sqlite::SqliteConnection; use maplit::hashset; use diesel::deserialize::{Queryable}; @@ -47,7 +46,7 @@ pub fn sanitize_remote_content(html_string: &str) -> String { html_clean } -/// used for user-inpul +/// used for user-input /// Parse links -- stolen from https://git.cypr.io/oz/autolink-rust/src/branch/master/src/lib.rs pub fn parse_note_text(text: &str) -> String { // dont hack me @@ -55,9 +54,10 @@ pub fn parse_note_text(text: &str) -> String { if text.len() == 0 { return String::new(); } + // this regex has to function after html parsing has happened. very weird. let re = Regex::new( r"(?ix) - \b(([\w-]+:&\#48;&\#47;?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/))) + \b(([\w-]+:&\#47;&\#47;?|www[.])[^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|&\#47))) ", ) .unwrap(); @@ -73,6 +73,7 @@ pub fn parse_note_text(text: &str) -> String { let replace_str = "<a href=\"/user/$2\">$0</a>"; let people_parsed = person_regex.replace_all(&notes_parsed, &replace_str as &str).to_string(); // TODO get mentions too + println!("{}", people_parsed); return people_parsed; } @@ -85,22 +86,23 @@ mod tests { assert!(parse_note_text("") == "") } + #[test] fn test_escape_html() { - assert!(parse_note_text("<script>haxxor</script>hi>") == "hi") + let example = "<script>haxxor</script>hi>"; + assert!(parse_note_text(example) == ammonia::clean_text(example)); } #[test] fn test_string_without_urls() { let src = "<p>Some HTML</p>"; - assert!(parse_note_text(src) == "Some HTML") + assert!(parse_note_text(src) == ammonia::clean_text(src)); } #[test] fn test_string_with_http_urls() { let src = "Check this out: https://doc.rust-lang.org/\n https://fr.wikipedia.org/wiki/Caf%C3%A9ine"; - let linked = "Check this out: <a href=\"https://doc.rust-lang.org/\">https://doc.rust-lang.org/</a>\n - <a href=\"https://fr.wikipedia.org/wiki/Caf%C3%A9ine\">https://fr.wikipedia.org/wiki/Caf%C3%A9ine</a>"; + let linked = "Check&#32;this&#32;out:&#32;<a href=\"https:&#47;&#47;doc.rust-lang.org&#47;&#10;&#10;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;https:&#47;&#47;fr.wikipedia.org&#47;wiki&#47;Caf%C3%A9ine\">https:&#47;&#47;doc.rust-lang.org&#47;&#10;&#10;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;https:&#47;&#47;fr.wikipedia.org&#47;wiki&#47;Caf%C3%A9ine</a>"; assert!(parse_note_text(src) == linked) } @@ -109,30 +111,21 @@ mod tests { let src = "Send spam to mailto://oz@cypr.io"; assert!( parse_note_text(src) - == "Send spam to <a href=\"mailto://oz@cypr.io\">mailto://oz@cypr.io</a>" + == "Send&#32;spam&#32;to&#32;<a href=\"mailto:&#47;&#47;oz@cypr.io\">mailto:&#47;&#47;oz@cypr.io</a>" ) } #[test] - fn test_string_with_trailing_chars() { - let src = "I love https://cat-bounce.com!\n - Have you seen https://en.wikipedia.org/wiki/Cat_(disambiguation)?"; - let linked = "I love <a href=\"https://cat-bounce.com\">https://cat-bounce.com</a>!\n - Have you seen <a href=\"https://en.wikipedia.org/wiki/Cat_(disambiguation)\">https://en.wikipedia.org/wiki/Cat_(disambiguation)</a>?"; - assert!(parse_note_text(src) == linked) - } - - #[test] fn test_user_replace() { let src = "@joe whats up @sally"; - let linked = "<a href=\"/user/joe\">@joe</a> whats up <a href=\"/user/sally\">@sally</a>"; + let linked = "<a href=\"/user/joe\">@joe</a>&#32;whats&#32;up&#32;<a href=\"/user/sally\">@sally</a>"; assert!(parse_note_text(src) == linked) } #[test] fn test_note_replace() { let src = "📝123 cool post >>456"; - let linked = "<a href=\"/note/123\">📝123</a> cool post <a href=\"/note/456\">&gt;&gt;456</a>"; + let linked = "<a href=\"/note/123\">📝123</a>&#32;cool&#32;post&#32;<a href=\"/note/456\">&gt;&gt;456</a>"; assert!(parse_note_text(src) == linked) } } diff --git a/src/db/user.rs b/src/db/user.rs @@ -1,4 +1,3 @@ -use activitystreams::object::streams; use diesel::sqlite::SqliteConnection; use diesel::deserialize::{Queryable}; use super::schema::users; diff --git a/src/lib.rs b/src/lib.rs @@ -411,9 +411,8 @@ pub async fn run_server() { let user_followers = path!("user" / String / "followers.json" ) .map(ap::user_followers); - let user_following = session_filter() - .and(path!("user" / String / "following.json" )) - .map(user_inbox); + let user_following = path!("user" / String / "following.json" ) + .map(ap::user_following); // https://github.com/seanmonstar/warp/issues/42 -- how to set up diesel // TODO set content length limit