summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrtkay123 <dev@kanjala.com>2025-07-19 23:31:41 +0200
committerrtkay123 <dev@kanjala.com>2025-07-19 23:31:41 +0200
commit5bfbeb8e843adf1e949f71074dac22be0c720644 (patch)
treee9c69a3ab64880c333ff9783b77aa9c18bf08a43
parent4616c62bcd899a76062c611b96b13833f782f51e (diff)
downloadsellershut-5bfbeb8e843adf1e949f71074dac22be0c720644.tar.bz2
sellershut-5bfbeb8e843adf1e949f71074dac22be0c720644.zip
feat: dynamic read
-rw-r--r--crates/sellershut/src/entity/user.rs6
-rw-r--r--crates/sellershut/src/server/activities/follow.rs5
-rw-r--r--crates/sellershut/src/server/middleware/sign_request.rs124
-rw-r--r--crates/sellershut/src/server/middleware/sign_request/signature.rs15
4 files changed, 114 insertions, 36 deletions
diff --git a/crates/sellershut/src/entity/user.rs b/crates/sellershut/src/entity/user.rs
index 1abf50f..b420682 100644
--- a/crates/sellershut/src/entity/user.rs
+++ b/crates/sellershut/src/entity/user.rs
@@ -213,6 +213,12 @@ pub struct Person {
image: Option<Url>,
}
+impl Person {
+ pub fn public_id(&self) -> &str {
+ &self.public_key.id
+ }
+}
+
#[async_trait]
impl Object for User {
#[doc = " App data type passed to handlers. Must be identical to"]
diff --git a/crates/sellershut/src/server/activities/follow.rs b/crates/sellershut/src/server/activities/follow.rs
index f0df0d9..e39b81e 100644
--- a/crates/sellershut/src/server/activities/follow.rs
+++ b/crates/sellershut/src/server/activities/follow.rs
@@ -118,10 +118,7 @@ mod tests {
"http://localhost:{}/activity/follow/1",
config.application.port
);
- let actor = format!(
- "http://localhost/users/{}",
- hut_config.instance_name
- );
+ let actor = format!("http://localhost/users/{}", hut_config.instance_name);
let app = server::router(state);
diff --git a/crates/sellershut/src/server/middleware/sign_request.rs b/crates/sellershut/src/server/middleware/sign_request.rs
index 889984f..4eb3bd3 100644
--- a/crates/sellershut/src/server/middleware/sign_request.rs
+++ b/crates/sellershut/src/server/middleware/sign_request.rs
@@ -1,20 +1,21 @@
mod signature;
-use activitypub_federation::config::FederationConfig;
+use activitypub_federation::{config::FederationConfig, traits::Object};
use axum::{
body::Body,
extract::Request,
- http::HeaderValue,
+ http::{HeaderValue, StatusCode},
response::Response,
};
use futures_util::future::BoxFuture;
-use std::{
- task::{Context, Poll},
-};
+use std::task::{Context, Poll};
use tower::{Layer, Service};
+use tracing::trace;
-use crate::{server::middleware::sign_request::signature::Signature, state::AppHandle};
-
+use crate::{
+ server::{middleware::sign_request::signature::Signature, routes::users::get_user::read_user},
+ state::AppHandle,
+};
#[derive(Clone)]
pub struct SignRequestLayer {
@@ -62,30 +63,105 @@ where
fn call(&mut self, request: Request) -> Self::Future {
let mut inner = self.inner.clone();
+ let uri = request.uri().clone();
let (parts, body) = request.into_parts();
+ let state = self.state.to_request_data();
+ let domain = self.state.domain().to_owned();
Box::pin(async move {
- let bytes = axum::body::to_bytes(body, usize::MAX).await.unwrap();
-
- let signature = Signature::create(
- ""
- .as_bytes(),
- bytes,
- )
- .unwrap();
+ let ok_500 = || {
+ let mut response = axum::response::Response::default();
+ *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
+ Ok(response)
+ };
+ let bytes = match axum::body::to_bytes(body, usize::MAX).await {
+ Ok(b) => b,
+ Err(e) => {
+ trace!("could not decode response body: {e:?}");
+ return ok_500();
+ }
+ };
+
+ // Get user
+ let user = match read_user("sellershut", &state).await {
+ Ok(Some(u)) => u,
+ Ok(None) => {
+ trace!("user not found");
+ return ok_500();
+ }
+ Err(e) => {
+ trace!("failed to read user: {e:?}");
+ return ok_500();
+ }
+ };
+
+ let pk = user.private_key.clone().unwrap_or_default();
+
+ let json_user = match user.into_json(&state).await {
+ Ok(j) => j,
+ Err(e) => {
+ trace!("failed to serialise user: {e:?}");
+ return ok_500();
+ }
+ };
+
+ // Sign the body
+ let signature = match Signature::new(pk.as_bytes(), bytes, uri, &domain) {
+ Ok(sig) => sig,
+ Err(e) => {
+ trace!("signature creation failed: {e:?}");
+ return ok_500();
+ }
+ };
let mut new_request = Request::from_parts(parts, Body::from(signature.body));
let head = new_request.headers_mut();
- let header = format!(
- "keyId=\"http://localhost/users/sellershut#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest\",signature=\"{}\"",
- signature.signature,
- );
- println!("{header}");
- head.insert("Host", HeaderValue::from_str(&signature.host).unwrap());
- head.insert("Date", HeaderValue::from_str(&signature.date).unwrap());
- head.insert("Digest", HeaderValue::from_str(&signature.digest).unwrap());
- head.insert("Signature", HeaderValue::from_str(&header).unwrap());
+
+ let header = [
+ format!("keyId=\"{}\"", json_user.public_id()),
+ "algorithm=rsa-sha256".to_string(),
+ "headers=\"(request-target) host date digest\"".to_string(),
+ format!("signature=\"{}\"", signature.signature),
+ ]
+ .join(",");
+
+ let host = match HeaderValue::from_str(&signature.host) {
+ Ok(value) => value,
+ Err(e) => {
+ trace!(name = "host",value = ?signature.host, "header creation failed: {e:?}");
+ return ok_500();
+ }
+ };
+
+ let date = match HeaderValue::from_str(&signature.date) {
+ Ok(value) => value,
+ Err(e) => {
+ trace!(name = "date",value = ?signature.date, "header creation failed: {e:?}");
+ return ok_500();
+ }
+ };
+
+ let digest = match HeaderValue::from_str(&signature.digest) {
+ Ok(value) => value,
+ Err(e) => {
+ trace!(name = "digest",value = ?signature.digest, "header creation failed: {e:?}");
+ return ok_500();
+ }
+ };
+
+ let signature = match HeaderValue::from_str(&header) {
+ Ok(value) => value,
+ Err(e) => {
+ trace!(name = "signature", "header creation failed: {e:?}");
+ return ok_500();
+ }
+ };
+
+ head.insert("Host", host);
+ head.insert("Date", date);
+ head.insert("Digest", digest);
+ head.insert("Signature", signature);
inner.call(new_request).await
})
diff --git a/crates/sellershut/src/server/middleware/sign_request/signature.rs b/crates/sellershut/src/server/middleware/sign_request/signature.rs
index 18e62c0..06a1037 100644
--- a/crates/sellershut/src/server/middleware/sign_request/signature.rs
+++ b/crates/sellershut/src/server/middleware/sign_request/signature.rs
@@ -1,4 +1,4 @@
-use axum::body::Bytes;
+use axum::{body::Bytes, http::Uri};
use base64::{Engine, engine::general_purpose};
use openssl::{pkey::PKey, rsa::Rsa, sign::Signer};
use sha2::{Digest, Sha256};
@@ -13,11 +13,11 @@ pub struct Signature {
pub date: String,
pub digest: String,
pub signature: String,
- pub body: Bytes
+ pub body: Bytes,
}
impl Signature {
- pub fn create(key: &[u8], body: Bytes) -> Result<Self, AppError> {
+ pub fn new(key: &[u8], body: Bytes, uri: Uri, domain: &str) -> Result<Self, AppError> {
let mut hasher = Sha256::new();
hasher.update(&body);
@@ -26,12 +26,11 @@ impl Signature {
let digest_hash = general_purpose::STANDARD.encode(result);
let digest = format!("SHA-256={digest_hash}");
- let inbox_path = "/users/sellershut/inbox";
let now = OffsetDateTime::now_utc().format(&Rfc2822)?;
let signing_string = [
- format!("(request-target): post {inbox_path}"),
- "host: localhost:2210".to_owned(),
+ format!("(request-target): post {uri}"),
+ format!("host: {domain}"),
format!("date: {now}"),
format!("digest: {digest}"),
]
@@ -48,8 +47,8 @@ impl Signature {
let signature = signer.sign_to_vec()?;
let result = general_purpose::STANDARD.encode(signature);
- Ok(Self{
- host: "localhost:2210".to_string(),
+ Ok(Self {
+ host: domain.to_owned(),
date: now,
digest,
signature: result,