summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/entity/user.rs36
-rw-r--r--src/server.rs5
-rw-r--r--src/server/routes.rs1
-rw-r--r--src/server/routes/users.rs6
-rw-r--r--src/server/routes/users/get_user.rs57
-rw-r--r--src/state.rs14
6 files changed, 99 insertions, 20 deletions
diff --git a/src/entity/user.rs b/src/entity/user.rs
index af27ea2..e136cb3 100644
--- a/src/entity/user.rs
+++ b/src/entity/user.rs
@@ -2,25 +2,27 @@ use activitypub_federation::{
config::Data,
fetch::object_id::ObjectId,
http_signatures::generate_actor_keypair,
+ kinds::actor::PersonType,
+ protocol::public_key::PublicKey,
traits::{Actor, Object},
};
use async_trait::async_trait;
-use serde::Deserialize;
+use serde::{Deserialize, Serialize};
use tracing::trace;
use url::Url;
use crate::{error::AppError, state::AppHandle};
#[derive(PartialEq, Clone, Debug)]
-pub(crate) struct LocalUser {
+pub(crate) struct User {
pub username: String,
- pub ap_id: ObjectId<LocalUser>,
+ pub ap_id: ObjectId<User>,
pub private_key: Option<String>,
pub public_key: String,
pub inbox: Url,
}
-impl LocalUser {
+impl User {
pub fn new(username: &str) -> Result<Self, AppError> {
trace!("creating a new user");
let keys = generate_actor_keypair()?;
@@ -36,17 +38,25 @@ impl LocalUser {
}
}
-#[derive(Deserialize)]
-pub struct User {}
+#[derive(Clone, Debug, Deserialize, Serialize)]
+#[serde(rename_all = "camelCase")]
+pub struct Person {
+ #[serde(rename = "type")]
+ kind: PersonType,
+ preferred_username: String,
+ id: ObjectId<User>,
+ inbox: Url,
+ public_key: PublicKey,
+}
#[async_trait]
-impl Object for LocalUser {
+impl Object for User {
#[doc = " App data type passed to handlers. Must be identical to"]
#[doc = " [crate::config::FederationConfigBuilder::app_data] type."]
type DataType = AppHandle;
#[doc = " The type of protocol struct which gets sent over network to federate this database struct."]
- type Kind = User;
+ type Kind = Person;
#[doc = " Error type returned by handler methods"]
type Error = AppError;
@@ -69,7 +79,13 @@ impl Object for LocalUser {
#[doc = " Called when a local object gets fetched by another instance over HTTP, or when an object"]
#[doc = " gets sent in an activity."]
async fn into_json(self, data: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error> {
- todo!()
+ Ok(Person {
+ preferred_username: self.username.clone(),
+ kind: Default::default(),
+ id: self.ap_id.clone(),
+ inbox: self.inbox.clone(),
+ public_key: self.public_key(),
+ })
}
#[doc = " Verifies that the received object is valid."]
@@ -94,7 +110,7 @@ impl Object for LocalUser {
}
}
-impl Actor for LocalUser {
+impl Actor for User {
fn public_key_pem(&self) -> &str {
&self.public_key
}
diff --git a/src/server.rs b/src/server.rs
index c6ce02c..bb2b4d0 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -1,4 +1,4 @@
-use activitypub_federation::config::FederationConfig;
+use activitypub_federation::config::{FederationConfig, FederationMiddleware};
use axum::{Router, routing::get};
use tower_http::trace::TraceLayer;
@@ -8,7 +8,8 @@ pub mod routes;
pub fn router(state: FederationConfig<AppHandle>) -> Router {
Router::new()
+ .merge(routes::users::users_router())
.route("/", get(health_check))
.layer(TraceLayer::new_for_http())
- .with_state(state)
+ .layer(FederationMiddleware::new(state))
}
diff --git a/src/server/routes.rs b/src/server/routes.rs
index 5814e0e..7751c95 100644
--- a/src/server/routes.rs
+++ b/src/server/routes.rs
@@ -1,3 +1,4 @@
+pub(super) mod users;
use axum::response::IntoResponse;
pub async fn health_check() -> impl IntoResponse {
diff --git a/src/server/routes/users.rs b/src/server/routes/users.rs
new file mode 100644
index 0000000..ad09c8e
--- /dev/null
+++ b/src/server/routes/users.rs
@@ -0,0 +1,6 @@
+pub mod get_user;
+use axum::{Router, routing::get};
+
+pub fn users_router() -> Router {
+ Router::new().route("/users/{usernme}", get(get_user::http_get_user))
+}
diff --git a/src/server/routes/users/get_user.rs b/src/server/routes/users/get_user.rs
new file mode 100644
index 0000000..8020923
--- /dev/null
+++ b/src/server/routes/users/get_user.rs
@@ -0,0 +1,57 @@
+use activitypub_federation::{
+ axum::json::FederationJson, config::Data, protocol::context::WithContext, traits::Object,
+};
+use axum::{debug_handler, extract::Path, http::StatusCode, response::IntoResponse};
+
+use crate::{error::AppError, state::AppHandle};
+
+#[debug_handler]
+pub async fn http_get_user(
+ Path(name): Path<String>,
+ data: Data<AppHandle>,
+) -> Result<impl IntoResponse, AppError> {
+ let read = data.users.read().await;
+ if let Some(a) = read
+ .iter()
+ .find(|value| value.username.eq(&name))
+ .map(ToOwned::to_owned)
+ {
+ let json_user = a.into_json(&data).await?;
+ Ok((
+ StatusCode::OK,
+ FederationJson(WithContext::new_default(json_user)),
+ )
+ .into_response())
+ } else {
+ Ok((StatusCode::NOT_FOUND, "").into_response())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use axum::{
+ body::Body,
+ http::{Request, StatusCode},
+ };
+ use tower::ServiceExt;
+
+ use crate::{server, state::AppState};
+
+ #[tokio::test]
+ async fn get_user() {
+ let state = AppState::new().await.unwrap();
+ let app = server::router(state);
+
+ let response = app
+ .oneshot(
+ Request::builder()
+ .uri("/users/sellershut")
+ .body(Body::empty())
+ .unwrap(),
+ )
+ .await
+ .unwrap();
+
+ assert_eq!(response.status(), StatusCode::OK);
+ }
+}
diff --git a/src/state.rs b/src/state.rs
index 64c2e7c..d7c9136 100644
--- a/src/state.rs
+++ b/src/state.rs
@@ -1,14 +1,12 @@
-use std::{
- ops::Deref,
- sync::{Arc, RwLock},
-};
+use std::{ops::Deref, sync::Arc};
use activitypub_federation::config::FederationConfig;
+use tokio::sync::RwLock;
-use crate::{entity::user::LocalUser, error::AppError};
+use crate::{entity::user::User, error::AppError};
#[derive(Clone)]
-pub struct AppHandle(pub Arc<AppState>);
+pub struct AppHandle(Arc<AppState>);
impl Deref for AppHandle {
type Target = Arc<AppState>;
@@ -19,12 +17,12 @@ impl Deref for AppHandle {
}
pub struct AppState {
- users: RwLock<Vec<LocalUser>>,
+ pub users: RwLock<Vec<User>>,
}
impl AppState {
pub async fn new() -> Result<FederationConfig<AppHandle>, AppError> {
- let user = LocalUser::new("sellershut")?;
+ let user = User::new("sellershut")?;
let domain = "localhost";
let config = FederationConfig::builder()