From e1e9851d5c8d6c7fe6791ffe7afd6e49cfd03b5e Mon Sep 17 00:00:00 2001 From: silverpill Date: Tue, 21 Feb 2023 21:39:42 +0000 Subject: [PATCH] Make media URLs in Mastodon API responses relative to current origin --- CHANGELOG.md | 1 + mitra-utils/src/urls.rs | 3 ++ src/http.rs | 16 +++++++++- src/mastodon_api/accounts/types.rs | 11 +++++-- src/mastodon_api/accounts/views.rs | 42 +++++++++++++++++++++++-- src/mastodon_api/custom_emojis/types.rs | 4 +-- src/mastodon_api/custom_emojis/views.rs | 17 ++++++---- src/mastodon_api/directory/views.rs | 12 ++++++- src/mastodon_api/media/types.rs | 4 +-- src/mastodon_api/notifications/types.rs | 4 ++- src/mastodon_api/notifications/views.rs | 16 ++++++++-- src/mastodon_api/search/views.rs | 13 +++++++- src/mastodon_api/settings/views.rs | 14 ++++++++- src/mastodon_api/statuses/helpers.rs | 6 ++-- src/mastodon_api/statuses/types.rs | 10 +++--- src/mastodon_api/statuses/views.rs | 37 ++++++++++++++++++++-- src/mastodon_api/subscriptions/views.rs | 12 ++++++- src/mastodon_api/timelines/views.rs | 15 ++++++++- 18 files changed, 204 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7225362..9354f1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Fixed actor object JSON-LD validation errors. - Fixed activity JSON-LD validation errors. +- Make media URLs in Mastodon API responses relative to current origin. ## [1.13.1] - 2023-02-09 diff --git a/mitra-utils/src/urls.rs b/mitra-utils/src/urls.rs index 2b7559a..919682f 100644 --- a/mitra-utils/src/urls.rs +++ b/mitra-utils/src/urls.rs @@ -14,6 +14,9 @@ pub fn get_hostname(url: &str) -> Result { } pub fn guess_protocol(hostname: &str) -> &'static str { + if hostname == "localhost" { + return "http"; + }; let maybe_ipv4_address = hostname.parse::(); if let Ok(_ipv4_address) = maybe_ipv4_address { return "http"; diff --git a/src/http.rs b/src/http.rs index 68261a5..0cbb1ee 100644 --- a/src/http.rs +++ b/src/http.rs @@ -1,6 +1,6 @@ use actix_web::{ body::{BodySize, BoxBody, MessageBody}, - dev::ServiceResponse, + dev::{ConnectionInfo, ServiceResponse}, error::{Error, JsonPayloadError}, http::StatusCode, middleware::{ErrorHandlerResponse, ErrorHandlers}, @@ -10,6 +10,8 @@ use actix_web::{ }; use serde_json::json; +use mitra_utils::urls::guess_protocol; + use crate::errors::HttpError; pub type FormOrJson = Either, Json>; @@ -46,3 +48,15 @@ pub fn json_error_handler( other_error => other_error.into(), } } + +pub fn get_request_base_url(connection_info: ConnectionInfo) -> String { + // TODO: HTTP server should set X-Forwarded-Proto header + // let scheme = connection_info.scheme(); + let host = connection_info.host(); + let scheme = if let Some((hostname, _port)) = host.split_once(':') { + guess_protocol(hostname) + } else { + guess_protocol(host) + }; + format!("{}://{}", scheme, host) +} diff --git a/src/mastodon_api/accounts/types.rs b/src/mastodon_api/accounts/types.rs index 2477d93..b1f3a6a 100644 --- a/src/mastodon_api/accounts/types.rs +++ b/src/mastodon_api/accounts/types.rs @@ -117,14 +117,15 @@ pub struct Account { impl Account { pub fn from_profile( + base_url: &str, instance_url: &str, profile: DbActorProfile, ) -> Self { let profile_url = profile.actor_url(instance_url); let avatar_url = profile.avatar - .map(|image| get_file_url(instance_url, &image.file_name)); + .map(|image| get_file_url(base_url, &image.file_name)); let header_url = profile.banner - .map(|image| get_file_url(instance_url, &image.file_name)); + .map(|image| get_file_url(base_url, &image.file_name)); let is_locked = profile.actor_json .map(|actor| actor.manually_approves_followers) .unwrap_or(false); @@ -207,6 +208,7 @@ impl Account { } pub fn from_user( + base_url: &str, instance_url: &str, user: User, ) -> Self { @@ -224,6 +226,7 @@ impl Account { }; let role = ApiRole::from_db(user.role); let mut account = Self::from_profile( + base_url, instance_url, user.profile, ); @@ -502,10 +505,12 @@ pub struct ApiSubscription { impl ApiSubscription { pub fn from_subscription( + base_url: &str, instance_url: &str, subscription: Subscription, ) -> Self { let sender = Account::from_profile( + base_url, instance_url, subscription.sender, ); @@ -545,6 +550,7 @@ mod tests { ..Default::default() }; let account = Account::from_profile( + INSTANCE_URL, INSTANCE_URL, profile, ); @@ -570,6 +576,7 @@ mod tests { ..Default::default() }; let account = Account::from_user( + INSTANCE_URL, INSTANCE_URL, user, ); diff --git a/src/mastodon_api/accounts/views.rs b/src/mastodon_api/accounts/views.rs index 892e5cb..dd744e9 100644 --- a/src/mastodon_api/accounts/views.rs +++ b/src/mastodon_api/accounts/views.rs @@ -1,6 +1,12 @@ use actix_web::{ - get, patch, post, web, - HttpRequest, HttpResponse, Scope, + dev::ConnectionInfo, + get, + patch, + post, + web, + HttpRequest, + HttpResponse, + Scope, }; use actix_web_httpauth::extractors::bearer::BearerAuth; use uuid::Uuid; @@ -33,6 +39,7 @@ use crate::ethereum::{ gate::is_allowed_user, identity::verify_eip191_identity_proof, }; +use crate::http::get_request_base_url; use crate::identity::{ claims::create_identity_claim, did::Did, @@ -110,6 +117,7 @@ use super::types::{ #[post("")] pub async fn create_account( + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, maybe_blockchain: web::Data>, @@ -195,6 +203,7 @@ pub async fn create_account( }; log::warn!("created user {}", user.id); let account = Account::from_user( + &get_request_base_url(connection_info), &config.instance_url(), user, ); @@ -204,12 +213,14 @@ pub async fn create_account( #[get("/verify_credentials")] async fn verify_credentials( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, ) -> Result { let db_client = &**get_database_client(&db_pool).await?; let user = get_current_user(db_client, auth.token()).await?; let account = Account::from_user( + &get_request_base_url(connection_info), &config.instance_url(), user, ); @@ -219,6 +230,7 @@ async fn verify_credentials( #[patch("/update_credentials")] async fn update_credentials( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, account_data: web::Json, @@ -246,6 +258,7 @@ async fn update_credentials( ).await?.enqueue(db_client).await?; let account = Account::from_user( + &get_request_base_url(connection_info), &config.instance_url(), current_user, ); @@ -278,6 +291,7 @@ async fn get_unsigned_update( #[post("/send_activity")] async fn send_signed_activity( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, data: web::Json, @@ -323,6 +337,7 @@ async fn send_signed_activity( outgoing_activity.enqueue(db_client).await?; let account = Account::from_user( + &get_request_base_url(connection_info), &config.instance_url(), current_user, ); @@ -363,6 +378,7 @@ async fn get_identity_claim( #[post("/identity_proof")] async fn create_identity_proof( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, proof_data: web::Json, @@ -441,6 +457,7 @@ async fn create_identity_proof( ).await?.enqueue(db_client).await?; let account = Account::from_user( + &get_request_base_url(connection_info), &config.instance_url(), current_user, ); @@ -465,6 +482,7 @@ async fn get_relationships_view( #[get("/lookup")] async fn lookup_acct( + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, query_params: web::Query, @@ -472,6 +490,7 @@ async fn lookup_acct( let db_client = &**get_database_client(&db_pool).await?; let profile = get_profile_by_acct(db_client, &query_params.acct).await?; let account = Account::from_profile( + &get_request_base_url(connection_info), &config.instance_url(), profile, ); @@ -480,6 +499,7 @@ async fn lookup_acct( #[get("/search")] async fn search_by_acct( + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, query_params: web::Query, @@ -490,9 +510,11 @@ async fn search_by_acct( &query_params.q, query_params.limit.inner(), ).await?; + let base_url = get_request_base_url(connection_info); let instance_url = config.instance().url(); let accounts: Vec = profiles.into_iter() .map(|profile| Account::from_profile( + &base_url, &instance_url, profile, )) @@ -502,6 +524,7 @@ async fn search_by_acct( #[get("/search_did")] async fn search_by_did( + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, query_params: web::Query, @@ -510,9 +533,11 @@ async fn search_by_did( let did: Did = query_params.did.parse() .map_err(|_| ValidationError("invalid DID"))?; let profiles = search_profiles_by_did(db_client, &did, false).await?; + let base_url = get_request_base_url(connection_info); let instance_url = config.instance().url(); let accounts: Vec = profiles.into_iter() .map(|profile| Account::from_profile( + &base_url, &instance_url, profile, )) @@ -522,6 +547,7 @@ async fn search_by_did( #[get("/{account_id}")] async fn get_account( + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, account_id: web::Path, @@ -529,6 +555,7 @@ async fn get_account( let db_client = &**get_database_client(&db_pool).await?; let profile = get_profile_by_id(db_client, &account_id).await?; let account = Account::from_profile( + &get_request_base_url(connection_info), &config.instance_url(), profile, ); @@ -608,6 +635,7 @@ async fn unfollow_account( #[get("/{account_id}/statuses")] async fn get_account_statuses( auth: Option, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, account_id: web::Path, @@ -636,6 +664,7 @@ async fn get_account_statuses( ).await?; let statuses = build_status_list( db_client, + &get_request_base_url(connection_info), &config.instance_url(), maybe_current_user.as_ref(), posts, @@ -646,6 +675,7 @@ async fn get_account_statuses( #[get("/{account_id}/followers")] async fn get_account_followers( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, account_id: web::Path, @@ -668,9 +698,11 @@ async fn get_account_followers( ).await?; let max_index = usize::from(query_params.limit.inner().saturating_sub(1)); let maybe_last_id = followers.get(max_index).map(|item| item.relationship_id); + let base_url = get_request_base_url(connection_info); let instance_url = config.instance().url(); let accounts: Vec = followers.into_iter() .map(|item| Account::from_profile( + &base_url, &instance_url, item.profile, )) @@ -687,6 +719,7 @@ async fn get_account_followers( #[get("/{account_id}/following")] async fn get_account_following( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, account_id: web::Path, @@ -709,9 +742,11 @@ async fn get_account_following( ).await?; let max_index = usize::from(query_params.limit.inner().saturating_sub(1)); let maybe_last_id = following.get(max_index).map(|item| item.relationship_id); + let base_url = get_request_base_url(connection_info); let instance_url = config.instance().url(); let accounts: Vec = following.into_iter() .map(|item| Account::from_profile( + &base_url, &instance_url, item.profile, )) @@ -728,6 +763,7 @@ async fn get_account_following( #[get("/{account_id}/subscribers")] async fn get_account_subscribers( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, account_id: web::Path, @@ -741,6 +777,7 @@ async fn get_account_subscribers( let subscriptions: Vec = vec![]; return Ok(HttpResponse::Ok().json(subscriptions)); }; + let base_url = get_request_base_url(connection_info); let instance_url = config.instance_url(); let subscriptions: Vec = get_incoming_subscriptions( db_client, @@ -751,6 +788,7 @@ async fn get_account_subscribers( .await? .into_iter() .map(|subscription| ApiSubscription::from_subscription( + &base_url, &instance_url, subscription, )) diff --git a/src/mastodon_api/custom_emojis/types.rs b/src/mastodon_api/custom_emojis/types.rs index ef2fe9d..3b9478b 100644 --- a/src/mastodon_api/custom_emojis/types.rs +++ b/src/mastodon_api/custom_emojis/types.rs @@ -13,8 +13,8 @@ pub struct CustomEmoji { } impl CustomEmoji { - pub fn from_db(instance_url: &str, emoji: DbEmoji) -> Self { - let image_url = get_file_url(instance_url, &emoji.image.file_name); + pub fn from_db(base_url: &str, emoji: DbEmoji) -> Self { + let image_url = get_file_url(base_url, &emoji.image.file_name); Self { shortcode: emoji.emoji_name, url: image_url.clone(), diff --git a/src/mastodon_api/custom_emojis/views.rs b/src/mastodon_api/custom_emojis/views.rs index 57f08a0..0eead3d 100644 --- a/src/mastodon_api/custom_emojis/views.rs +++ b/src/mastodon_api/custom_emojis/views.rs @@ -1,23 +1,28 @@ -use actix_web::{get, web, HttpResponse, Scope}; - -use mitra_config::Config; +use actix_web::{ + dev::ConnectionInfo, + get, + web, + HttpResponse, + Scope, +}; use crate::database::{get_database_client, DbPool}; use crate::errors::HttpError; +use crate::http::get_request_base_url; use crate::models::emojis::queries::get_local_emojis; use super::types::CustomEmoji; /// https://docs.joinmastodon.org/methods/custom_emojis/ #[get("")] async fn custom_emoji_list( - config: web::Data, + connection_info: ConnectionInfo, db_pool: web::Data, ) -> Result { let db_client = &**get_database_client(&db_pool).await?; - let instance = config.instance(); + let base_url = get_request_base_url(connection_info); let emojis: Vec = get_local_emojis(db_client).await? .into_iter() - .map(|db_emoji| CustomEmoji::from_db(&instance.url(), db_emoji)) + .map(|db_emoji| CustomEmoji::from_db(&base_url, db_emoji)) .collect(); Ok(HttpResponse::Ok().json(emojis)) } diff --git a/src/mastodon_api/directory/views.rs b/src/mastodon_api/directory/views.rs index 8b39678..8aec698 100644 --- a/src/mastodon_api/directory/views.rs +++ b/src/mastodon_api/directory/views.rs @@ -1,11 +1,18 @@ /// https://docs.joinmastodon.org/methods/instance/directory/ -use actix_web::{get, web, HttpResponse, Scope}; +use actix_web::{ + dev::ConnectionInfo, + get, + web, + HttpResponse, + Scope, +}; use actix_web_httpauth::extractors::bearer::BearerAuth; use mitra_config::Config; use crate::database::{get_database_client, DbPool}; use crate::errors::HttpError; +use crate::http::get_request_base_url; use crate::mastodon_api::{ accounts::types::Account, oauth::auth::get_current_user, @@ -16,6 +23,7 @@ use super::types::DirectoryQueryParams; #[get("")] async fn profile_directory( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, query_params: web::Query, @@ -28,10 +36,12 @@ async fn profile_directory( query_params.offset, query_params.limit.inner(), ).await?; + let base_url = get_request_base_url(connection_info); let instance_url = config.instance().url(); let accounts: Vec = profiles .into_iter() .map(|profile| Account::from_profile( + &base_url, &instance_url, profile, )) diff --git a/src/mastodon_api/media/types.rs b/src/mastodon_api/media/types.rs index 4d331aa..de8a387 100644 --- a/src/mastodon_api/media/types.rs +++ b/src/mastodon_api/media/types.rs @@ -26,7 +26,7 @@ pub struct Attachment { } impl Attachment { - pub fn from_db(instance_url: &str, db_attachment: DbMediaAttachment) -> Self { + pub fn from_db(base_url: &str, db_attachment: DbMediaAttachment) -> Self { let attachment_type = AttachmentType::from_media_type(db_attachment.media_type); let attachment_type_mastodon = match attachment_type { @@ -35,7 +35,7 @@ impl Attachment { AttachmentType::Video => "video", }; let attachment_url = get_file_url( - instance_url, + base_url, &db_attachment.file_name, ); Self { diff --git a/src/mastodon_api/notifications/types.rs b/src/mastodon_api/notifications/types.rs index eeb16e6..cb3b8f2 100644 --- a/src/mastodon_api/notifications/types.rs +++ b/src/mastodon_api/notifications/types.rs @@ -35,15 +35,17 @@ pub struct ApiNotification { impl ApiNotification { pub fn from_db( + base_url: &str, instance_url: &str, notification: Notification, ) -> Self { let account = Account::from_profile( + base_url, instance_url, notification.sender, ); let status = notification.post.map(|post| { - Status::from_post(instance_url, post) + Status::from_post(base_url, instance_url, post) }); let event_type_mastodon = match notification.event_type { EventType::Follow => "follow", diff --git a/src/mastodon_api/notifications/views.rs b/src/mastodon_api/notifications/views.rs index b2ca767..49be79a 100644 --- a/src/mastodon_api/notifications/views.rs +++ b/src/mastodon_api/notifications/views.rs @@ -1,6 +1,8 @@ /// https://docs.joinmastodon.org/methods/notifications/ use actix_web::{ - get, web, + dev::ConnectionInfo, + get, + web, HttpRequest, HttpResponse, Scope as ActixScope, }; @@ -10,6 +12,7 @@ use mitra_config::Config; use crate::database::{get_database_client, DbPool}; use crate::errors::HttpError; +use crate::http::get_request_base_url; use crate::mastodon_api::{ oauth::auth::get_current_user, pagination::get_paginated_response, @@ -20,6 +23,7 @@ use super::types::{ApiNotification, NotificationQueryParams}; #[get("")] async fn get_notifications_view( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, query_params: web::Query, @@ -27,6 +31,8 @@ async fn get_notifications_view( ) -> Result { let db_client = &**get_database_client(&db_pool).await?; let current_user = get_current_user(db_client, auth.token()).await?; + let base_url = get_request_base_url(connection_info); + let instance = config.instance(); let notifications: Vec = get_notifications( db_client, ¤t_user.id, @@ -34,13 +40,17 @@ async fn get_notifications_view( query_params.limit.inner(), ).await? .into_iter() - .map(|item| ApiNotification::from_db(&config.instance_url(), item)) + .map(|item| ApiNotification::from_db( + &base_url, + &instance.url(), + item, + )) .collect(); let max_index = usize::from(query_params.limit.inner().saturating_sub(1)); let maybe_last_id = notifications.get(max_index) .map(|item| item.id.clone()); let response = get_paginated_response( - &config.instance_url(), + &instance.url(), request.uri().path(), notifications, maybe_last_id, diff --git a/src/mastodon_api/search/views.rs b/src/mastodon_api/search/views.rs index 751f025..8bf6f55 100644 --- a/src/mastodon_api/search/views.rs +++ b/src/mastodon_api/search/views.rs @@ -1,11 +1,18 @@ /// https://docs.joinmastodon.org/methods/search/ -use actix_web::{get, web, HttpResponse, Scope}; +use actix_web::{ + dev::ConnectionInfo, + get, + web, + HttpResponse, + Scope, +}; use actix_web_httpauth::extractors::bearer::BearerAuth; use mitra_config::Config; use crate::database::{get_database_client, DbPool}; use crate::errors::HttpError; +use crate::http::get_request_base_url; use crate::mastodon_api::{ accounts::types::Account, oauth::auth::get_current_user, @@ -18,6 +25,7 @@ use super::types::{SearchQueryParams, SearchResults}; #[get("")] async fn search_view( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, query_params: web::Query, @@ -31,15 +39,18 @@ async fn search_view( query_params.q.trim(), query_params.limit.inner(), ).await?; + let base_url = get_request_base_url(connection_info); let instance_url = config.instance().url(); let accounts: Vec = profiles.into_iter() .map(|profile| Account::from_profile( + &base_url, &instance_url, profile, )) .collect(); let statuses = build_status_list( db_client, + &base_url, &instance_url, Some(¤t_user), posts, diff --git a/src/mastodon_api/settings/views.rs b/src/mastodon_api/settings/views.rs index 8d4107e..9c6ca74 100644 --- a/src/mastodon_api/settings/views.rs +++ b/src/mastodon_api/settings/views.rs @@ -1,4 +1,11 @@ -use actix_web::{get, post, web, HttpResponse, Scope}; +use actix_web::{ + dev::ConnectionInfo, + get, + post, + web, + HttpResponse, + Scope, +}; use actix_web_httpauth::extractors::bearer::BearerAuth; use mitra_config::Config; @@ -12,6 +19,7 @@ use crate::activitypub::{ }; use crate::database::{get_database_client, DatabaseError, DbPool}; use crate::errors::{HttpError, ValidationError}; +use crate::http::get_request_base_url; use crate::mastodon_api::{ accounts::types::Account, oauth::auth::get_current_user, @@ -37,6 +45,7 @@ use super::types::{ #[post("/change_password")] async fn change_password_view( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, request_data: web::Json, @@ -47,6 +56,7 @@ async fn change_password_view( .map_err(|_| HttpError::InternalError)?; set_user_password(db_client, ¤t_user.id, password_hash).await?; let account = Account::from_user( + &get_request_base_url(connection_info), &config.instance_url(), current_user, ); @@ -117,6 +127,7 @@ async fn import_follows_view( #[post("/move_followers")] async fn move_followers( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, request_data: web::Json, @@ -194,6 +205,7 @@ async fn move_followers( ).enqueue(db_client).await?; let account = Account::from_user( + &get_request_base_url(connection_info), &instance.url(), current_user, ); diff --git a/src/mastodon_api/statuses/helpers.rs b/src/mastodon_api/statuses/helpers.rs index a3eb656..53f058d 100644 --- a/src/mastodon_api/statuses/helpers.rs +++ b/src/mastodon_api/statuses/helpers.rs @@ -75,6 +75,7 @@ pub async fn parse_microsyntaxes( /// Load related objects and build status for API response pub async fn build_status( db_client: &impl DatabaseClient, + base_url: &str, instance_url: &str, user: Option<&User>, mut post: Post, @@ -83,12 +84,13 @@ pub async fn build_status( if let Some(user) = user { add_user_actions(db_client, &user.id, vec![&mut post]).await?; }; - let status = Status::from_post(instance_url, post); + let status = Status::from_post(base_url, instance_url, post); Ok(status) } pub async fn build_status_list( db_client: &impl DatabaseClient, + base_url: &str, instance_url: &str, user: Option<&User>, mut posts: Vec, @@ -99,7 +101,7 @@ pub async fn build_status_list( }; let statuses: Vec = posts .into_iter() - .map(|post| Status::from_post(instance_url, post)) + .map(|post| Status::from_post(base_url, instance_url, post)) .collect(); Ok(statuses) } diff --git a/src/mastodon_api/statuses/types.rs b/src/mastodon_api/statuses/types.rs index 3d25fb9..0203d1e 100644 --- a/src/mastodon_api/statuses/types.rs +++ b/src/mastodon_api/statuses/types.rs @@ -85,12 +85,13 @@ pub struct Status { impl Status { pub fn from_post( + base_url: &str, instance_url: &str, post: Post, ) -> Self { let object_id = post.object_id(instance_url); let attachments: Vec = post.attachments.into_iter() - .map(|item| Attachment::from_db(instance_url, item)) + .map(|item| Attachment::from_db(base_url, item)) .collect(); let mentions: Vec = post.mentions.into_iter() .map(|item| Mention::from_profile(instance_url, item)) @@ -99,20 +100,21 @@ impl Status { .map(|tag_name| Tag::from_tag_name(instance_url, tag_name)) .collect(); let emojis: Vec = post.emojis.into_iter() - .map(|emoji| CustomEmoji::from_db(instance_url, emoji)) + .map(|emoji| CustomEmoji::from_db(base_url, emoji)) .collect(); let account = Account::from_profile( + base_url, instance_url, post.author, ); let reblog = if let Some(repost_of) = post.repost_of { - let status = Status::from_post(instance_url, *repost_of); + let status = Status::from_post(base_url, instance_url, *repost_of); Some(Box::new(status)) } else { None }; let links = post.linked.into_iter().map(|post| { - Status::from_post(instance_url, post) + Status::from_post(base_url, instance_url, post) }).collect(); let visibility = match post.visibility { Visibility::Public => "public", diff --git a/src/mastodon_api/statuses/views.rs b/src/mastodon_api/statuses/views.rs index 3085835..c89fa77 100644 --- a/src/mastodon_api/statuses/views.rs +++ b/src/mastodon_api/statuses/views.rs @@ -1,5 +1,13 @@ /// https://docs.joinmastodon.org/methods/statuses/ -use actix_web::{delete, get, post, web, HttpResponse, Scope}; +use actix_web::{ + delete, + dev::ConnectionInfo, + get, + post, + web, + HttpResponse, + Scope, +}; use actix_web_httpauth::extractors::bearer::BearerAuth; use chrono::Utc; use uuid::Uuid; @@ -21,7 +29,7 @@ use crate::activitypub::builders::{ use crate::database::{get_database_client, DatabaseError, DbPool}; use crate::errors::{HttpError, ValidationError}; use crate::ethereum::nft::create_mint_signature; -use crate::http::FormOrJson; +use crate::http::{get_request_base_url, FormOrJson}; use crate::ipfs::{ store as ipfs_store, posts::PostMetadata, @@ -69,6 +77,7 @@ use super::types::{ #[post("")] async fn create_status( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, status_data: FormOrJson, @@ -190,7 +199,11 @@ async fn create_status( prepare_create_note(db_client, &instance, ¤t_user, &post) .await?.enqueue(db_client).await?; - let status = Status::from_post(&instance.url(), post); + let status = Status::from_post( + &get_request_base_url(connection_info), + &instance.url(), + post, + ); Ok(HttpResponse::Ok().json(status)) } @@ -232,6 +245,7 @@ async fn preview_status( #[get("/{status_id}")] async fn get_status( auth: Option, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, status_id: web::Path, @@ -247,6 +261,7 @@ async fn get_status( }; let status = build_status( db_client, + &get_request_base_url(connection_info), &config.instance_url(), maybe_current_user.as_ref(), post, @@ -285,6 +300,7 @@ async fn delete_status( #[get("/{status_id}/context")] async fn get_context( auth: Option, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, status_id: web::Path, @@ -301,6 +317,7 @@ async fn get_context( ).await?; let statuses = build_status_list( db_client, + &get_request_base_url(connection_info), &config.instance_url(), maybe_current_user.as_ref(), posts, @@ -327,6 +344,7 @@ async fn get_context( async fn get_thread_view( auth: Option, config: web::Data, + connection_info: ConnectionInfo, db_pool: web::Data, status_id: web::Path, ) -> Result { @@ -342,6 +360,7 @@ async fn get_thread_view( ).await?; let statuses = build_status_list( db_client, + &get_request_base_url(connection_info), &config.instance_url(), maybe_current_user.as_ref(), posts, @@ -352,6 +371,7 @@ async fn get_thread_view( #[post("/{status_id}/favourite")] async fn favourite( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, status_id: web::Path, @@ -386,6 +406,7 @@ async fn favourite( let status = build_status( db_client, + &get_request_base_url(connection_info), &config.instance_url(), Some(¤t_user), post, @@ -396,6 +417,7 @@ async fn favourite( #[post("/{status_id}/unfavourite")] async fn unfavourite( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, status_id: web::Path, @@ -427,6 +449,7 @@ async fn unfavourite( let status = build_status( db_client, + &get_request_base_url(connection_info), &config.instance_url(), Some(¤t_user), post, @@ -437,6 +460,7 @@ async fn unfavourite( #[post("/{status_id}/reblog")] async fn reblog( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, status_id: web::Path, @@ -465,6 +489,7 @@ async fn reblog( let status = build_status( db_client, + &get_request_base_url(connection_info), &config.instance_url(), Some(¤t_user), repost, @@ -475,6 +500,7 @@ async fn reblog( #[post("/{status_id}/unreblog")] async fn unreblog( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, status_id: web::Path, @@ -502,6 +528,7 @@ async fn unreblog( let status = build_status( db_client, + &get_request_base_url(connection_info), &config.instance_url(), Some(¤t_user), post, @@ -512,6 +539,7 @@ async fn unreblog( #[post("/{status_id}/make_permanent")] async fn make_permanent( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, status_id: web::Path, @@ -561,6 +589,7 @@ async fn make_permanent( let status = build_status( db_client, + &get_request_base_url(connection_info), &config.instance_url(), Some(¤t_user), post, @@ -605,6 +634,7 @@ async fn get_signature( #[post("/{status_id}/token_minted")] async fn token_minted( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, status_id: web::Path, @@ -625,6 +655,7 @@ async fn token_minted( let status = build_status( db_client, + &get_request_base_url(connection_info), &config.instance_url(), Some(¤t_user), post, diff --git a/src/mastodon_api/subscriptions/views.rs b/src/mastodon_api/subscriptions/views.rs index d42980b..5ffaa49 100644 --- a/src/mastodon_api/subscriptions/views.rs +++ b/src/mastodon_api/subscriptions/views.rs @@ -1,4 +1,11 @@ -use actix_web::{get, post, web, HttpResponse, Scope}; +use actix_web::{ + dev::ConnectionInfo, + get, + post, + web, + HttpResponse, + Scope, +}; use actix_web_httpauth::extractors::bearer::BearerAuth; use uuid::Uuid; @@ -15,6 +22,7 @@ use crate::ethereum::{ is_registered_recipient, }, }; +use crate::http::get_request_base_url; use crate::mastodon_api::{ accounts::types::Account, oauth::auth::get_current_user, @@ -92,6 +100,7 @@ async fn get_subscription_options( #[post("/options")] pub async fn register_subscription_option( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, maybe_blockchain: web::Data>, @@ -166,6 +175,7 @@ pub async fn register_subscription_option( }; let account = Account::from_user( + &get_request_base_url(connection_info), &config.instance_url(), current_user, ); diff --git a/src/mastodon_api/timelines/views.rs b/src/mastodon_api/timelines/views.rs index 7d3f5d6..27d1194 100644 --- a/src/mastodon_api/timelines/views.rs +++ b/src/mastodon_api/timelines/views.rs @@ -1,11 +1,18 @@ /// https://docs.joinmastodon.org/methods/timelines/ -use actix_web::{get, web, HttpResponse, Scope}; +use actix_web::{ + dev::ConnectionInfo, + get, + web, + HttpResponse, + Scope, +}; use actix_web_httpauth::extractors::bearer::BearerAuth; use mitra_config::Config; use crate::database::{get_database_client, DbPool}; use crate::errors::HttpError; +use crate::http::get_request_base_url; use crate::mastodon_api::{ oauth::auth::get_current_user, statuses::helpers::build_status_list, @@ -20,6 +27,7 @@ use super::types::TimelineQueryParams; #[get("/home")] async fn home_timeline( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, query_params: web::Query, @@ -34,6 +42,7 @@ async fn home_timeline( ).await?; let statuses = build_status_list( db_client, + &get_request_base_url(connection_info), &config.instance_url(), Some(¤t_user), posts, @@ -45,6 +54,7 @@ async fn home_timeline( #[get("/public")] async fn public_timeline( auth: BearerAuth, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, query_params: web::Query, @@ -59,6 +69,7 @@ async fn public_timeline( ).await?; let statuses = build_status_list( db_client, + &get_request_base_url(connection_info), &config.instance_url(), Some(¤t_user), posts, @@ -69,6 +80,7 @@ async fn public_timeline( #[get("/tag/{hashtag}")] async fn hashtag_timeline( auth: Option, + connection_info: ConnectionInfo, config: web::Data, db_pool: web::Data, hashtag: web::Path, @@ -88,6 +100,7 @@ async fn hashtag_timeline( ).await?; let statuses = build_status_list( db_client, + &get_request_base_url(connection_info), &config.instance_url(), maybe_current_user.as_ref(), posts,