mirror of
https://github.com/astro/buzzrelay.git
synced 2024-12-24 03:10:29 +00:00
relay can be followed
This commit is contained in:
parent
6260f4306e
commit
177051be52
5 changed files with 58 additions and 13 deletions
|
@ -26,8 +26,11 @@ pub struct ActorPublicKey {
|
|||
/// ActivityPub "activity"
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Action<O> {
|
||||
#[serde(rename = "@context")]
|
||||
pub jsonld_context: serde_json::Value,
|
||||
#[serde(rename = "type")]
|
||||
pub action_type: String,
|
||||
pub id: String,
|
||||
pub actor: String,
|
||||
pub to: Option<String>,
|
||||
pub object: Option<O>,
|
||||
|
|
|
@ -85,7 +85,6 @@ where
|
|||
// mastodon uses base64::alphabet::STANDARD, not base64::alphabet::URL_SAFE
|
||||
digest_header = digest_header.replace("+", "-")
|
||||
.replace("/", "_");
|
||||
dbg!(&digest_header);
|
||||
let digest: DigestHeader = digest_header.parse()
|
||||
.map_err(|e| (StatusCode::BAD_REQUEST, format!("Cannot parse Digest: header: {}", e)))?;
|
||||
// read body
|
||||
|
|
13
src/main.rs
13
src/main.rs
|
@ -17,6 +17,7 @@ pub use fetch::fetch;
|
|||
mod send;
|
||||
pub use send::send;
|
||||
mod activitypub;
|
||||
mod webfinger;
|
||||
mod endpoint;
|
||||
|
||||
const ACTOR_ID: &str = "https://relay.fedi.buzz/actor";
|
||||
|
@ -61,6 +62,7 @@ async fn handler(
|
|||
axum::extract::State(state): axum::extract::State<State>,
|
||||
endpoint: endpoint::Endpoint,
|
||||
) -> Response {
|
||||
dbg!(&endpoint);
|
||||
let action = match serde_json::from_value::<activitypub::Action<serde_json::Value>>(endpoint.payload.clone()) {
|
||||
Ok(action) => action,
|
||||
Err(e) => return (
|
||||
|
@ -68,29 +70,29 @@ async fn handler(
|
|||
format!("Bad action: {:?}", e)
|
||||
).into_response(),
|
||||
};
|
||||
dbg!(&action);
|
||||
|
||||
if action.action_type == "Follow" {
|
||||
let private_key = state.private_key.clone();
|
||||
let client = state.client.clone();
|
||||
tokio::spawn(async move {
|
||||
let accept = activitypub::Action {
|
||||
jsonld_context: serde_json::Value::String("https://www.w3.org/ns/activitystreams".to_string()),
|
||||
action_type: "Accept".to_string(),
|
||||
actor: ACTOR_ID.to_string(),
|
||||
to: Some(endpoint.actor.id),
|
||||
to: Some(endpoint.actor.id.clone()),
|
||||
id: action.id,
|
||||
object: Some(endpoint.payload),
|
||||
};
|
||||
dbg!(serde_json::to_string_pretty(&accept));
|
||||
send::send(
|
||||
client.as_ref(), &endpoint.actor.inbox,
|
||||
ACTOR_KEY,
|
||||
&private_key,
|
||||
accept,
|
||||
).await
|
||||
.map_err(|e| tracing::error!("post: {}", e));
|
||||
.map_err(|e| tracing::error!("post accept: {}", e));
|
||||
});
|
||||
|
||||
(StatusCode::CREATED,
|
||||
(StatusCode::ACCEPTED,
|
||||
[("content-type", "application/activity+json")],
|
||||
"{}"
|
||||
).into_response()
|
||||
|
@ -115,6 +117,7 @@ async fn main() {
|
|||
let app = Router::new()
|
||||
.route("/actor", get(actor))
|
||||
.route("/relay", post(handler))
|
||||
.route("/.well-known/webfinger", get(webfinger::webfinger))
|
||||
.with_state(State {
|
||||
client: Arc::new(reqwest::Client::new()),
|
||||
private_key, public_key,
|
||||
|
|
23
src/send.rs
23
src/send.rs
|
@ -1,3 +1,4 @@
|
|||
use http::StatusCode;
|
||||
use http_digest_headers::{DigestHeader, DigestMethod};
|
||||
use serde::Serialize;
|
||||
use sigh::{PrivateKey, SigningConfig, alg::RsaSha256};
|
||||
|
@ -14,11 +15,15 @@ pub enum SendError {
|
|||
HttpReq(#[from] http::Error),
|
||||
#[error("HTTP client error")]
|
||||
Http(#[from] reqwest::Error),
|
||||
#[error("Invalid URI")]
|
||||
InvalidUri,
|
||||
#[error("Error response from remote")]
|
||||
Response(String),
|
||||
}
|
||||
|
||||
pub async fn send<T: Serialize>(
|
||||
client: &reqwest::Client,
|
||||
url: &str,
|
||||
uri: &str,
|
||||
key_id: &str,
|
||||
private_key: &PrivateKey,
|
||||
body: T,
|
||||
|
@ -38,9 +43,12 @@ pub async fn send<T: Serialize>(
|
|||
&digest_header[7..].replace("-", "+").replace("_", "/")
|
||||
);
|
||||
|
||||
let url = reqwest::Url::parse(uri)
|
||||
.map_err(|_| SendError::InvalidUri)?;
|
||||
let mut req = http::Request::builder()
|
||||
.method("POST")
|
||||
.uri(url)
|
||||
.uri(uri)
|
||||
.header("host", format!("{}", url.host().ok_or(SendError::InvalidUri)?))
|
||||
.header("content-type", "application/activity+json")
|
||||
.header("date", chrono::Utc::now().to_rfc2822()
|
||||
.replace("+0000", "GMT"))
|
||||
|
@ -49,11 +57,12 @@ pub async fn send<T: Serialize>(
|
|||
.map_err(SendError::HttpReq)?;
|
||||
SigningConfig::new(RsaSha256, private_key, key_id)
|
||||
.sign(&mut req)?;
|
||||
dbg!(&req);
|
||||
let res = client.execute(req.try_into()?)
|
||||
.await?;
|
||||
dbg!(&res);
|
||||
dbg!(res.text().await);
|
||||
|
||||
Ok(())
|
||||
if res.status() >= StatusCode::OK && res.status() < StatusCode::MULTIPLE_CHOICES {
|
||||
Ok(())
|
||||
} else {
|
||||
let response = res.text().await?;
|
||||
Err(SendError::Response(response))
|
||||
}
|
||||
}
|
||||
|
|
31
src/webfinger.rs
Normal file
31
src/webfinger.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use axum::{
|
||||
async_trait,
|
||||
body::{Bytes, HttpBody},
|
||||
extract::{Query},
|
||||
http::{header::CONTENT_TYPE, Request, StatusCode},
|
||||
Json,
|
||||
response::{IntoResponse, Response},
|
||||
routing::post,
|
||||
Form, RequestExt, Router, BoxError,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
pub async fn webfinger(Query(params): Query<HashMap<String, String>>) -> Response {
|
||||
let resource = match params.get("resource") {
|
||||
Some(resource) => resource,
|
||||
None => return StatusCode::NOT_FOUND.into_response(),
|
||||
};
|
||||
Json(json!({
|
||||
"subject": &resource,
|
||||
"aliases": &[
|
||||
"https://relay.fedi.buzz/actor",
|
||||
],
|
||||
"links": &[json!({
|
||||
"rel": "self",
|
||||
"type": "application/activity+json",
|
||||
"href": "https://relay.fedi.buzz/actor",
|
||||
})],
|
||||
})).into_response()
|
||||
}
|
Loading…
Reference in a new issue