Compare commits

...

3 commits

Author SHA1 Message Date
e7e8653ce2
chore: bump sea_orm to 1.0 2024-08-11 12:55:27 +02:00
2bbc1270a1
fix: add compat options to add target to likes
this is a nastier compat option: lemmy sends likes anonymously by design
(you can't see who upvoted/downvoted you). however mastodon likes are
intended to be seen (as mastodon shows every like as public on their
frontend). issue is: they both come with completely empty addressing!
thanks mastodon... so this compat option makes likes addressed to local
objects always address the object author. this restores mastodon likes
behavior but "leaks" lemmy votes. i don't know how to fix it: maybe do
some weird magic checking what is in `@context`??? disgusting but at
least i can stop leaking lemmy's likes...
2024-08-11 12:50:50 +02:00
77bf9d17a1
fix: add compat option to fix lemmy images
no clue why sometimes they come as bare links?? but it's images, they
show as images on lemmy's frontend... this is not really a good check as
we overrule remote decisions, but it's togglable so deployers can decide
if they care more about UX or spec consistency
2024-08-11 12:48:46 +02:00
13 changed files with 286 additions and 229 deletions

446
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -35,7 +35,7 @@ clap = { version = "4.5", features = ["derive"] }
signal-hook = "0.3" signal-hook = "0.3"
signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] } signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }
tokio = { version = "1.35", features = ["full"] } # TODO slim this down tokio = { version = "1.35", features = ["full"] } # TODO slim this down
sea-orm = { version = "0.12", features = ["sqlx-sqlite", "sqlx-postgres", "runtime-tokio-rustls"] } sea-orm = { version = "1.0", features = ["sqlx-sqlite", "sqlx-postgres", "runtime-tokio-rustls"] }
futures = "0.3" futures = "0.3"
upub = { path = "upub/core" } upub = { path = "upub/core" }

View file

@ -19,7 +19,7 @@ thiserror = "1"
paste = "1.0" paste = "1.0"
tracing = "0.1" tracing = "0.1"
serde_json = { version = "1", optional = true } serde_json = { version = "1", optional = true }
sea-orm = { version = "0.12", optional = true, default-features = false } sea-orm = { version = "1.0", optional = true, default-features = false }
reqwest = { version = "0.12", features = ["json"], optional = true } reqwest = { version = "0.12", features = ["json"], optional = true }
[features] [features]

View file

@ -97,7 +97,7 @@ macro_rules! strenum {
} }
fn column_type() -> sea_orm::sea_query::ColumnType { fn column_type() -> sea_orm::sea_query::ColumnType {
sea_orm::sea_query::ColumnType::String(Some(24)) sea_orm::sea_query::ColumnType::String(sea_orm::sea_query::table::StringLen::N(24))
} }
} }

View file

@ -20,6 +20,6 @@ uuid = { version = "1.8", features = ["v4"] }
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
openssl = "0.10" # TODO handle pubkeys with a smaller crate openssl = "0.10" # TODO handle pubkeys with a smaller crate
clap = { version = "4.5", features = ["derive"] } clap = { version = "4.5", features = ["derive"] }
sea-orm = "0.12" sea-orm = "1.0"
futures = "0.3" futures = "0.3"
mdhtml = { path = "../../utils/mdhtml/" } mdhtml = { path = "../../utils/mdhtml/" }

View file

@ -31,7 +31,7 @@ httpsign = { path = "../../utils/httpsign/" }
mdhtml = { path = "../../utils/mdhtml/" } mdhtml = { path = "../../utils/mdhtml/" }
jrd = "0.1" jrd = "0.1"
tracing = "0.1" tracing = "0.1"
sea-orm = { version = "0.12", features = ["macros"] } sea-orm = { version = "1.0", features = ["macros"] }
reqwest = { version = "0.12", features = ["json"] } reqwest = { version = "0.12", features = ["json"] }
apb = { path = "../../apb", features = ["unstructured", "orm", "did-core", "activitypub-miscellaneous-terms", "activitypub-fe", "activitypub-counters", "litepub", "ostatus", "toot"] } apb = { path = "../../apb", features = ["unstructured", "orm", "did-core", "activitypub-miscellaneous-terms", "activitypub-fe", "activitypub-counters", "litepub", "ostatus", "toot"] }
# nodeinfo = "0.0.2" # the version on crates.io doesn't re-export necessary types to build the struct!!! # nodeinfo = "0.0.2" # the version on crates.io doesn't re-export necessary types to build the struct!!!

View file

@ -12,6 +12,9 @@ pub struct Config {
#[serde(default)] #[serde(default)]
pub security: SecurityConfig, pub security: SecurityConfig,
#[serde(default)]
pub compat: CompatibilityConfig,
// TODO should i move app keys here? // TODO should i move app keys here?
} }
@ -96,6 +99,15 @@ pub struct SecurityConfig {
pub reinsertion_attempt_limit: u32, pub reinsertion_attempt_limit: u32,
} }
#[serde_inline_default::serde_inline_default]
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize, serde_default::DefaultFromSerde)]
pub struct CompatibilityConfig {
#[serde(default)]
pub fix_attachment_images_media_type: bool,
#[serde(default)]
pub add_explicit_target_to_likes_if_local: bool,
}
impl Config { impl Config {
pub fn load(path: Option<&std::path::PathBuf>) -> Self { pub fn load(path: Option<&std::path::PathBuf>) -> Self {

View file

@ -12,7 +12,8 @@ where
T::Model : Sync, T::Model : Sync,
{ {
async fn any(self, db: &impl ConnectionTrait) -> Result<bool, sea_orm::DbErr> { async fn any(self, db: &impl ConnectionTrait) -> Result<bool, sea_orm::DbErr> {
Ok(self.count(db).await? > 0) // TODO ConnectionTrait became an iterator?? self.count(db) gives error now
Ok(PaginatorTrait::count(self, db).await? > 0)
} }
} }

View file

@ -80,14 +80,6 @@ impl Normalizer for crate::Context {
tracing::warn!("ignoring array-in-array while processing attachments"); tracing::warn!("ignoring array-in-array while processing attachments");
continue continue
}, },
Node::Link(l) => crate::model::attachment::ActiveModel {
internal: sea_orm::ActiveValue::NotSet,
url: Set(self.cloaked(l.href().unwrap_or_default())),
object: Set(object_model.internal),
document_type: Set(apb::DocumentType::Page),
name: Set(l.name().str()),
media_type: Set(l.media_type().unwrap_or("link").to_string()),
},
Node::Object(o) => { Node::Object(o) => {
let mut model = AP::attachment_q(o.as_document()?, object_model.internal, None)?; let mut model = AP::attachment_q(o.as_document()?, object_model.internal, None)?;
if let Set(u) | Unchanged(u) = model.url { if let Set(u) | Unchanged(u) = model.url {
@ -95,6 +87,28 @@ impl Normalizer for crate::Context {
} }
model model
}, },
Node::Link(l) => {
let url = l.href().unwrap_or_default();
let mut media_type = l.media_type().unwrap_or("link").to_string();
let mut document_type = apb::DocumentType::Page;
if self.cfg().compat.fix_attachment_images_media_type
&& [".jpg", ".jpeg", ".png", ".webp", ".bmp"] // TODO more image types???
.iter()
.any(|x| url.ends_with(x))
{
document_type = apb::DocumentType::Image;
media_type = format!("image/{}", url.split('.').last().unwrap_or_default());
}
crate::model::attachment::ActiveModel {
internal: sea_orm::ActiveValue::NotSet,
url: Set(self.cloaked(url)),
object: Set(object_model.internal),
document_type: Set(document_type),
name: Set(l.name().str()),
media_type: Set(media_type),
}
},
}; };
crate::model::attachment::Entity::insert(attachment_model) crate::model::attachment::Entity::insert(attachment_model)
.exec(tx) .exec(tx)

View file

@ -98,6 +98,7 @@ pub async fn create(ctx: &crate::Context, activity: impl apb::Activity, tx: &Dat
pub async fn like(ctx: &crate::Context, activity: impl apb::Activity, tx: &DatabaseTransaction) -> Result<(), ProcessorError> { pub async fn like(ctx: &crate::Context, activity: impl apb::Activity, tx: &DatabaseTransaction) -> Result<(), ProcessorError> {
let actor = ctx.fetch_user(activity.actor().id()?, tx).await?; let actor = ctx.fetch_user(activity.actor().id()?, tx).await?;
let obj = ctx.fetch_object(activity.object().id()?, tx).await?; let obj = ctx.fetch_object(activity.object().id()?, tx).await?;
let likes_local_object = obj.attributed_to.as_ref().map(|x| ctx.is_local(x)).unwrap_or_default();
if crate::model::like::Entity::find_by_uid_oid(actor.internal, obj.internal) if crate::model::like::Entity::find_by_uid_oid(actor.internal, obj.internal)
.any(tx) .any(tx)
.await? .await?
@ -120,8 +121,11 @@ pub async fn like(ctx: &crate::Context, activity: impl apb::Activity, tx: &Datab
.await?; .await?;
// likes without addressing are "silent likes", process them but dont store activity or notify // likes without addressing are "silent likes", process them but dont store activity or notify
if !activity.addressed().is_empty() { if likes_local_object || !activity.addressed().is_empty() {
let activity_model = ctx.insert_activity(activity, tx).await?; let mut activity_model = ctx.insert_activity(activity, tx).await?;
if likes_local_object {
activity_model.to.0.push(obj.attributed_to.clone().unwrap_or_default());
}
ctx.address((Some(&activity_model), None), tx).await?; ctx.address((Some(&activity_model), None), tx).await?;
// TODO check that object author is in this like addressing!!! otherwise skip notification // TODO check that object author is in this like addressing!!! otherwise skip notification

View file

@ -11,4 +11,4 @@ readme = "README.md"
[lib] [lib]
[dependencies] [dependencies]
sea-orm-migration = "0.12" sea-orm-migration = "1.0"

View file

@ -27,7 +27,7 @@ tower-http = { version = "0.5", features = ["cors", "trace"] }
httpsign = { path = "../../utils/httpsign/", features = ["axum"] } httpsign = { path = "../../utils/httpsign/", features = ["axum"] }
apb = { path = "../../apb", features = ["unstructured", "orm", "activitypub-fe", "activitypub-counters", "litepub", "ostatus", "toot", "jsonld"] } apb = { path = "../../apb", features = ["unstructured", "orm", "activitypub-fe", "activitypub-counters", "litepub", "ostatus", "toot", "jsonld"] }
uriproxy = { path = "../../utils/uriproxy" } uriproxy = { path = "../../utils/uriproxy" }
sea-orm = { version = "0.12", features = ["macros", "sqlx-sqlite", "runtime-tokio-rustls"] } sea-orm = "1.0"
# nodeinfo = "0.0.2" # the version on crates.io doesn't re-export necessary types to build the struct!!! # nodeinfo = "0.0.2" # the version on crates.io doesn't re-export necessary types to build the struct!!!
nodeinfo = { git = "https://codeberg.org/thefederationinfo/nodeinfo-rs", rev = "e865094804" } nodeinfo = { git = "https://codeberg.org/thefederationinfo/nodeinfo-rs", rev = "e865094804" }
# mastodon # mastodon

View file

@ -15,7 +15,7 @@ thiserror = "1"
tracing = "0.1" tracing = "0.1"
async-trait = "0.1" async-trait = "0.1"
serde_json = "1" serde_json = "1"
sea-orm = "0.12" sea-orm = "1.0"
regex = "1.10" regex = "1.10"
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
tokio = { version = "1.35", features = ["full"] } # TODO slim this down tokio = { version = "1.35", features = ["full"] } # TODO slim this down