Compare commits
No commits in common. "fafe5307c5bd7d91c3f67f1d8c13503568031763" and "799b958543498360ace342013ccb51b3c07e0dbd" have entirely different histories.
fafe5307c5
...
799b958543
17 changed files with 265 additions and 303 deletions
370
Cargo.lock
generated
370
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -9,7 +9,7 @@ members = [
|
|||
"web",
|
||||
"utils/httpsign",
|
||||
"utils/mdhtml",
|
||||
"utils/uriproxy",
|
||||
"utils/uriproxy"
|
||||
]
|
||||
|
||||
[package]
|
||||
|
@ -31,11 +31,11 @@ path = "main.rs"
|
|||
toml = "0.8"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = "0.3"
|
||||
sea-orm = "0.12"
|
||||
clap = { version = "4.5", features = ["derive"] }
|
||||
signal-hook = "0.3"
|
||||
signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }
|
||||
tokio = { version = "1.35", features = ["full"] } # TODO slim this down
|
||||
sea-orm = { version = "0.12", features = ["sqlx-sqlite", "sqlx-postgres", "runtime-tokio-rustls"] }
|
||||
futures = "0.3"
|
||||
|
||||
upub = { path = "upub/core" }
|
||||
|
|
|
@ -18,6 +18,7 @@ chrono = { version = "0.4", features = ["serde"] }
|
|||
thiserror = "1"
|
||||
paste = "1.0"
|
||||
tracing = "0.1"
|
||||
async-trait = "0.1"
|
||||
serde_json = { version = "1", optional = true }
|
||||
sea-orm = { version = "0.12", optional = true, default-features = false }
|
||||
reqwest = { version = "0.12", features = ["json"], optional = true }
|
||||
|
|
|
@ -20,6 +20,6 @@ uuid = { version = "1.8", features = ["v4"] }
|
|||
chrono = { version = "0.4", features = ["serde"] }
|
||||
openssl = "0.10" # TODO handle pubkeys with a smaller crate
|
||||
clap = { version = "4.5", features = ["derive"] }
|
||||
sea-orm = "0.12"
|
||||
sea-orm = { version = "0.12", features = ["macros", "sqlx-sqlite", "runtime-tokio-rustls"] }
|
||||
futures = "0.3"
|
||||
mdhtml = { path = "../../utils/mdhtml/" }
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use upub::{ext::JsonVec, model::{activity, actor, addressing, config, credential, object}};
|
||||
use upub::model::{addressing, config, credential, activity, object, actor, Audience};
|
||||
use openssl::rsa::Rsa;
|
||||
use sea_orm::{ActiveValue::NotSet, IntoActiveModel};
|
||||
|
||||
|
@ -21,8 +21,8 @@ pub async fn faker(ctx: upub::Context, count: i64) -> Result<(), sea_orm::DbErr>
|
|||
followers: None,
|
||||
followers_count: 0,
|
||||
statuses_count: count as i32,
|
||||
fields: JsonVec::default(),
|
||||
also_known_as: JsonVec::default(),
|
||||
fields: vec![],
|
||||
also_known_as: vec![],
|
||||
moved_to: None,
|
||||
icon: Some("https://cdn.alemi.dev/social/circle-square.png".to_string()),
|
||||
image: Some("https://cdn.alemi.dev/social/someriver-xs.jpg".to_string()),
|
||||
|
@ -90,10 +90,10 @@ pub async fn faker(ctx: upub::Context, count: i64) -> Result<(), sea_orm::DbErr>
|
|||
likes: Set(0),
|
||||
announces: Set(0),
|
||||
audience: Set(None),
|
||||
to: Set(JsonVec(vec![apb::target::PUBLIC.to_string()])),
|
||||
bto: Set(JsonVec::default()),
|
||||
cc: Set(JsonVec(vec![])),
|
||||
bcc: Set(JsonVec::default()),
|
||||
to: Set(Audience(vec![apb::target::PUBLIC.to_string()])),
|
||||
bto: Set(Audience::default()),
|
||||
cc: Set(Audience(vec![])),
|
||||
bcc: Set(Audience::default()),
|
||||
url: Set(None),
|
||||
sensitive: Set(false),
|
||||
}).exec(db).await?;
|
||||
|
@ -106,10 +106,10 @@ pub async fn faker(ctx: upub::Context, count: i64) -> Result<(), sea_orm::DbErr>
|
|||
object: Set(Some(format!("{domain}/objects/{oid}"))),
|
||||
target: Set(None),
|
||||
published: Set(chrono::Utc::now() - std::time::Duration::from_secs(60*i as u64)),
|
||||
to: Set(JsonVec(vec![apb::target::PUBLIC.to_string()])),
|
||||
bto: Set(JsonVec::default()),
|
||||
cc: Set(JsonVec(vec![])),
|
||||
bcc: Set(JsonVec::default()),
|
||||
to: Set(Audience(vec![apb::target::PUBLIC.to_string()])),
|
||||
bto: Set(Audience::default()),
|
||||
cc: Set(Audience(vec![])),
|
||||
bcc: Set(Audience::default()),
|
||||
}).exec(db).await?;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ openssl = "0.10" # TODO handle pubkeys with a smaller crate
|
|||
base64 = "0.22"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
uuid = { version = "1.8", features = ["v4"] }
|
||||
regex = "1.10"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
serde_default = "0.1"
|
||||
|
@ -28,10 +29,10 @@ serde-inline-default = "0.2"
|
|||
toml = "0.8"
|
||||
uriproxy = { path = "../../utils/uriproxy" }
|
||||
httpsign = { path = "../../utils/httpsign/" }
|
||||
jsonvec = { path = "../../utils/jsonvec/" }
|
||||
jrd = "0.1"
|
||||
tracing = "0.1"
|
||||
sea-orm = { version = "0.12", features = ["macros"] }
|
||||
tokio = { version = "1.35", features = ["full"] } # TODO slim this down
|
||||
sea-orm = { version = "0.12", features = ["macros", "sqlx-sqlite", "sqlx-postgres", "runtime-tokio-rustls"] }
|
||||
reqwest = { version = "0.12", features = ["json"] }
|
||||
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!!!
|
||||
|
|
|
@ -48,66 +48,3 @@ impl<T, E: std::error::Error> LoggableError for Result<T, E> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct JsonVec<T>(pub Vec<T>);
|
||||
|
||||
impl<T> From<Vec<T>> for JsonVec<T> {
|
||||
fn from(value: Vec<T>) -> Self {
|
||||
JsonVec(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for JsonVec<T> {
|
||||
fn default() -> Self {
|
||||
JsonVec(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: serde::de::DeserializeOwned> sea_orm::TryGetableFromJson for JsonVec<T> {}
|
||||
|
||||
impl<T: serde::ser::Serialize> std::convert::From<JsonVec<T>> for sea_orm::Value {
|
||||
fn from(source: JsonVec<T>) -> Self {
|
||||
sea_orm::Value::Json(serde_json::to_value(&source).ok().map(std::boxed::Box::new))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: serde::de::DeserializeOwned + TypeName> sea_orm::sea_query::ValueType for JsonVec<T> {
|
||||
fn try_from(v: sea_orm::Value) -> Result<Self, sea_orm::sea_query::ValueTypeErr> {
|
||||
match v {
|
||||
sea_orm::Value::Json(Some(json)) => Ok(
|
||||
serde_json::from_value(*json).map_err(|_| sea_orm::sea_query::ValueTypeErr)?,
|
||||
),
|
||||
sea_orm::Value::Json(None) => Ok(JsonVec::default()),
|
||||
_ => Err(sea_orm::sea_query::ValueTypeErr),
|
||||
}
|
||||
}
|
||||
|
||||
fn type_name() -> String {
|
||||
format!("JsonVec_{}", T::type_name())
|
||||
}
|
||||
|
||||
fn array_type() -> sea_orm::sea_query::ArrayType {
|
||||
sea_orm::sea_query::ArrayType::Json
|
||||
}
|
||||
|
||||
fn column_type() -> sea_orm::sea_query::ColumnType {
|
||||
sea_orm::sea_query::ColumnType::Json
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> sea_orm::sea_query::Nullable for JsonVec<T> {
|
||||
fn null() -> sea_orm::Value {
|
||||
sea_orm::Value::Json(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TypeName {
|
||||
fn type_name() -> String;
|
||||
}
|
||||
|
||||
impl TypeName for String {
|
||||
fn type_name() -> String {
|
||||
"String".to_string()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use openssl::rsa::Rsa;
|
||||
use sea_orm::{ActiveValue::{NotSet, Set}, DatabaseConnection, EntityTrait};
|
||||
|
||||
use crate::{ext::JsonVec, model};
|
||||
use crate::model;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum InitError {
|
||||
|
@ -34,9 +34,9 @@ pub async fn application(
|
|||
domain: Set(domain.clone()),
|
||||
preferred_username: Set(domain.clone()),
|
||||
actor_type: Set(apb::ActorType::Application),
|
||||
also_known_as: Set(JsonVec::default()),
|
||||
also_known_as: Set(vec![]),
|
||||
moved_to: Set(None),
|
||||
fields: Set(JsonVec::default()), // TODO we could put some useful things here actually
|
||||
fields: Set(vec![]), // TODO we could put some useful things here actually
|
||||
private_key: Set(Some(privk)),
|
||||
public_key: Set(pubk),
|
||||
following: Set(None),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use apb::{ActivityMut, ActivityType, BaseMut, ObjectMut};
|
||||
use sea_orm::{entity::prelude::*, QuerySelect, SelectColumns};
|
||||
|
||||
use crate::ext::JsonVec;
|
||||
use crate::model::Audience;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "activities")]
|
||||
|
@ -14,10 +14,10 @@ pub struct Model {
|
|||
pub actor: String,
|
||||
pub object: Option<String>,
|
||||
pub target: Option<String>,
|
||||
pub to: JsonVec<String>,
|
||||
pub bto: JsonVec<String>,
|
||||
pub cc: JsonVec<String>,
|
||||
pub bcc: JsonVec<String>,
|
||||
pub to: Audience,
|
||||
pub bto: Audience,
|
||||
pub cc: Audience,
|
||||
pub bcc: Audience,
|
||||
pub published: ChronoDateTimeUtc,
|
||||
}
|
||||
|
||||
|
|
|
@ -2,9 +2,7 @@ use sea_orm::{entity::prelude::*, QuerySelect, SelectColumns};
|
|||
|
||||
use apb::{field::OptionalString, ActorMut, ActorType, BaseMut, DocumentMut, EndpointsMut, ObjectMut, PublicKeyMut};
|
||||
|
||||
use crate::ext::{JsonVec, TypeName};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, sea_orm::FromJsonQueryResult)]
|
||||
pub struct Field {
|
||||
pub name: String,
|
||||
pub content: String,
|
||||
|
@ -14,12 +12,6 @@ pub struct Field {
|
|||
pub field_type: String,
|
||||
}
|
||||
|
||||
impl TypeName for Field {
|
||||
fn type_name() -> String {
|
||||
"Field".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: apb::Object> From<T> for Field {
|
||||
fn from(value: T) -> Self {
|
||||
Field {
|
||||
|
@ -45,7 +37,7 @@ pub struct Model {
|
|||
pub image: Option<String>,
|
||||
pub icon: Option<String>,
|
||||
pub preferred_username: String,
|
||||
pub fields: JsonVec<Field>,
|
||||
pub fields: Vec<Field>,
|
||||
pub inbox: Option<String>,
|
||||
pub shared_inbox: Option<String>,
|
||||
pub outbox: Option<String>,
|
||||
|
@ -58,7 +50,7 @@ pub struct Model {
|
|||
pub private_key: Option<String>,
|
||||
pub published: ChronoDateTimeUtc,
|
||||
pub updated: ChronoDateTimeUtc,
|
||||
pub also_known_as: JsonVec<String>,
|
||||
pub also_known_as: Vec<String>,
|
||||
pub moved_to: Option<String>,
|
||||
}
|
||||
|
||||
|
@ -216,7 +208,7 @@ impl Model {
|
|||
.set_url(apb::Node::link(i.clone()))
|
||||
)))
|
||||
.set_attachment(apb::Node::array(
|
||||
self.fields.0
|
||||
self.fields
|
||||
.into_iter()
|
||||
.filter_map(|x| serde_json::to_value(x).ok())
|
||||
.collect()
|
||||
|
@ -241,7 +233,7 @@ impl Model {
|
|||
apb::new()
|
||||
.set_shared_inbox(self.shared_inbox.as_deref())
|
||||
))
|
||||
.set_also_known_as(apb::Node::links(self.also_known_as.0))
|
||||
.set_also_known_as(apb::Node::links(self.also_known_as))
|
||||
.set_moved_to(apb::Node::maybe_link(self.moved_to))
|
||||
.set_discoverable(Some(true))
|
||||
}
|
||||
|
|
|
@ -19,3 +19,23 @@ pub mod dislike;
|
|||
pub mod hashtag;
|
||||
pub mod mention;
|
||||
pub mod attachment;
|
||||
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, sea_orm::FromJsonQueryResult)]
|
||||
pub struct Audience(pub Vec<String>);
|
||||
|
||||
impl<T: apb::Base> From<apb::Node<T>> for Audience {
|
||||
fn from(value: apb::Node<T>) -> Self {
|
||||
use apb::field::OptionalString;
|
||||
|
||||
Audience(
|
||||
match value {
|
||||
apb::Node::Empty => vec![],
|
||||
apb::Node::Link(l) => l.href().map(|x| vec![x.to_string()]).unwrap_or_default(),
|
||||
apb::Node::Object(o) => if let Ok(id) = o.id() { vec![id.to_string()] } else { vec![] },
|
||||
apb::Node::Array(arr) => arr.into_iter().filter_map(|l| l.id().str()).collect(),
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use apb::{BaseMut, CollectionMut, DocumentMut, ObjectMut, ObjectType};
|
||||
use sea_orm::{entity::prelude::*, QuerySelect, SelectColumns};
|
||||
|
||||
use crate::ext::JsonVec;
|
||||
use super::Audience;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)]
|
||||
#[sea_orm(table_name = "objects")]
|
||||
|
@ -24,10 +24,10 @@ pub struct Model {
|
|||
pub announces: i32,
|
||||
pub replies: i32,
|
||||
pub context: Option<String>,
|
||||
pub to: JsonVec<String>,
|
||||
pub bto: JsonVec<String>,
|
||||
pub cc: JsonVec<String>,
|
||||
pub bcc: JsonVec<String>,
|
||||
pub to: Audience,
|
||||
pub bto: Audience,
|
||||
pub cc: Audience,
|
||||
pub bcc: Audience,
|
||||
pub published: ChronoDateTimeUtc,
|
||||
pub updated: ChronoDateTimeUtc,
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
use sea_orm::{ActiveValue::{NotSet, Set}, DbErr, EntityTrait};
|
||||
|
||||
use crate::ext::JsonVec;
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait Administrable {
|
||||
async fn register_user(
|
||||
|
@ -37,13 +35,13 @@ impl Administrable for crate::Context {
|
|||
domain: Set(domain),
|
||||
summary: Set(summary),
|
||||
preferred_username: Set(username.clone()),
|
||||
fields: Set(JsonVec::default()),
|
||||
fields: Set(vec![]),
|
||||
following: Set(None),
|
||||
following_count: Set(0),
|
||||
followers: Set(None),
|
||||
followers_count: Set(0),
|
||||
statuses_count: Set(0),
|
||||
also_known_as: Set(JsonVec::default()),
|
||||
also_known_as: Set(vec![]),
|
||||
moved_to: Set(None),
|
||||
icon: Set(avatar_url),
|
||||
image: Set(banner_url),
|
||||
|
|
|
@ -203,10 +203,10 @@ impl AP {
|
|||
object: activity.object().id().str(),
|
||||
target: activity.target().id().str(),
|
||||
published: activity.published().unwrap_or(chrono::Utc::now()),
|
||||
to: activity.to().all_ids().into(),
|
||||
bto: activity.bto().all_ids().into(),
|
||||
cc: activity.cc().all_ids().into(),
|
||||
bcc: activity.bcc().all_ids().into(),
|
||||
to: activity.to().into(),
|
||||
bto: activity.bto().into(),
|
||||
cc: activity.cc().into(),
|
||||
bcc: activity.bcc().into(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -287,10 +287,10 @@ impl AP {
|
|||
announces: object.shares().get()
|
||||
.map_or(0, |x| x.total_items().unwrap_or(0)) as i32,
|
||||
audience: object.audience().id().str(),
|
||||
to: object.to().all_ids().into(),
|
||||
bto: object.bto().all_ids().into(),
|
||||
cc: object.cc().all_ids().into(),
|
||||
bcc: object.bcc().all_ids().into(),
|
||||
to: object.to().into(),
|
||||
bto: object.bto().into(),
|
||||
cc: object.cc().into(),
|
||||
bcc: object.bcc().into(),
|
||||
|
||||
sensitive: object.sensitive().unwrap_or(false),
|
||||
})
|
||||
|
@ -333,12 +333,13 @@ impl AP {
|
|||
summary: actor.summary().str(),
|
||||
icon: actor.icon().get().and_then(|x| x.url().id().str()),
|
||||
image: actor.image().get().and_then(|x| x.url().id().str()),
|
||||
fields: actor.attachment().flat().into_iter().filter_map(|x| Some(crate::model::actor::Field::from(x.extract()?))).collect(),
|
||||
inbox: actor.inbox().id().str(),
|
||||
outbox: actor.outbox().id().str(),
|
||||
shared_inbox: actor.endpoints().get().and_then(|x| x.shared_inbox().str()),
|
||||
followers: actor.followers().id().str(),
|
||||
following: actor.following().id().str(),
|
||||
also_known_as: actor.also_known_as().flat().into_iter().filter_map(|x| x.id().str()).collect::<Vec<String>>().into(),
|
||||
also_known_as: actor.also_known_as().flat().into_iter().filter_map(|x| x.id().str()).collect(),
|
||||
moved_to: actor.moved_to().id().str(),
|
||||
published: actor.published().unwrap_or(chrono::Utc::now()),
|
||||
updated: chrono::Utc::now(),
|
||||
|
@ -347,12 +348,6 @@ impl AP {
|
|||
statuses_count: actor.statuses_count().unwrap_or(0) as i32,
|
||||
public_key: actor.public_key().get().ok_or(apb::FieldErr("publicKey"))?.public_key_pem().to_string(),
|
||||
private_key: None, // there's no way to transport privkey over AP json, must come from DB
|
||||
fields: actor.attachment()
|
||||
.flat()
|
||||
.into_iter()
|
||||
.filter_map(|x| Some(crate::model::actor::Field::from(x.extract()?)))
|
||||
.collect::<Vec<crate::model::actor::Field>>()
|
||||
.into(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,10 @@ readme = "README.md"
|
|||
[dependencies]
|
||||
thiserror = "1"
|
||||
rand = "0.8"
|
||||
sha2 = "0.10"
|
||||
sha256 = "1.5" # TODO ughhh
|
||||
hmac = "0.12"
|
||||
base64 = "0.22"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
|
|
|
@ -16,10 +16,12 @@ tracing = "0.1"
|
|||
async-trait = "0.1"
|
||||
serde_json = "1"
|
||||
sea-orm = "0.12"
|
||||
jrd = "0.1"
|
||||
regex = "1.10"
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
tokio = { version = "1.35", features = ["full"] } # TODO slim this down
|
||||
reqwest = { version = "0.12", features = ["json"] }
|
||||
apb = { path = "../../apb", features = ["unstructured", "orm", "activitypub-fe", "activitypub-counters", "litepub", "ostatus", "toot"] }
|
||||
httpsign = { path = "../../utils/httpsign/" }
|
||||
mdhtml = { path = "../../utils/mdhtml/" }
|
||||
upub = { path = "../core/" }
|
||||
|
|
|
@ -12,6 +12,7 @@ repository = "https://git.alemi.dev/upub.git"
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
async-trait = "0.1"
|
||||
lazy_static = "1.4"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = "0.3"
|
||||
|
|
Loading…
Reference in a new issue