From 13df9e04783928813043dd4d6d6bdcb150a1b702 Mon Sep 17 00:00:00 2001 From: silverpill Date: Mon, 3 Apr 2023 20:16:16 +0000 Subject: [PATCH] Create /api/v1/accounts/aliases/all API endpoint --- CHANGELOG.md | 1 + docs/openapi.yaml | 61 ++++++++++++++++++++-------- mitra-models/src/profiles/helpers.rs | 27 +++++++++++- src/activitypub/handlers/move.rs | 6 +-- src/mastodon_api/accounts/helpers.rs | 32 ++++++++++++++- src/mastodon_api/accounts/types.rs | 6 +++ src/mastodon_api/accounts/views.rs | 31 ++++++++++++-- src/mastodon_api/settings/views.rs | 7 +++- 8 files changed, 143 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1737117..c4d6912 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Added - Support calling `/api/v1/accounts/search` with `resolve` parameter. +- Created `/api/v1/accounts/aliases/all` API endpoint. ### Changed diff --git a/docs/openapi.yaml b/docs/openapi.yaml index 813a35e..79ecb4e 100644 --- a/docs/openapi.yaml +++ b/docs/openapi.yaml @@ -550,23 +550,6 @@ paths: $ref: '#/components/schemas/Subscription' 404: description: Profile not found - /api/v1/accounts/{account_id}/aliases: - get: - summary: Get actor's aliases. - parameters: - - $ref: '#/components/parameters/account_id' - responses: - 200: - description: Successful operation - content: - application/json: - schema: - description: Profile list - type: array - items: - $ref: '#/components/schemas/Account' - 404: - description: Profile not found /api/v1/accounts/{account_id}/follow: post: summary: Follow the given actor. @@ -613,6 +596,37 @@ paths: $ref: '#/components/schemas/Relationship' 404: description: Profile not found + /api/v1/accounts/{account_id}/aliases: + get: + summary: Get actor's verified aliases. + parameters: + - $ref: '#/components/parameters/account_id' + responses: + 200: + description: Successful operation + content: + application/json: + schema: + description: Profile list + type: array + items: + $ref: '#/components/schemas/Account' + 404: + description: Profile not found + /api/v1/accounts/{account_id}/aliases/all: + get: + summary: Get actor's aliases. + parameters: + - $ref: '#/components/parameters/account_id' + responses: + 200: + description: Successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/Aliases' + 404: + description: Profile not found /api/v1/apps: post: summary: Create a new application to obtain OAuth2 credentials. @@ -1476,6 +1490,19 @@ components: type: string enum: - update + Aliases: + type: object + properties: + declared: + description: Aliases declared by user. + type: array + items: + $ref: '#/components/schemas/Account' + verified: + description: Cryptographically verified aliases. + type: array + items: + $ref: '#/components/schemas/Account' Application: type: object properties: diff --git a/mitra-models/src/profiles/helpers.rs b/mitra-models/src/profiles/helpers.rs index 9273d5f..45f280e 100644 --- a/mitra-models/src/profiles/helpers.rs +++ b/mitra-models/src/profiles/helpers.rs @@ -1,9 +1,32 @@ use crate::database::{DatabaseClient, DatabaseError}; -use super::queries::search_profiles_by_did_only; +use super::queries::{ + get_profile_by_remote_actor_id, + search_profiles_by_did_only, +}; use super::types::DbActorProfile; -pub async fn find_aliases( +pub async fn find_declared_aliases( + db_client: &impl DatabaseClient, + profile: &DbActorProfile, +) -> Result, DatabaseError> { + let mut results = vec![]; + for actor_id in profile.aliases.clone().into_actor_ids() { + let alias = match get_profile_by_remote_actor_id( + db_client, + &actor_id, + ).await { + Ok(profile) => profile, + // Ignore unknown profiles + Err(DatabaseError::NotFound(_)) => continue, + Err(other_error) => return Err(other_error), + }; + results.push(alias); + }; + Ok(results) +} + +pub async fn find_verified_aliases( db_client: &impl DatabaseClient, profile: &DbActorProfile, ) -> Result, DatabaseError> { diff --git a/src/activitypub/handlers/move.rs b/src/activitypub/handlers/move.rs index bbdb90f..aaad1e7 100644 --- a/src/activitypub/handlers/move.rs +++ b/src/activitypub/handlers/move.rs @@ -5,7 +5,7 @@ use mitra_config::Config; use mitra_models::{ database::{DatabaseClient, DatabaseError}, notifications::queries::create_move_notification, - profiles::helpers::find_aliases, + profiles::helpers::find_verified_aliases, relationships::queries::{ create_follow_request, get_followers, @@ -75,8 +75,8 @@ pub async fn handle_move( let new_actor = new_profile.actor_json.as_ref() .expect("target should be a remote actor"); - // Find aliases by DIDs (signed) - let mut aliases = find_aliases(db_client, &new_profile).await? + // Find aliases by DIDs (verified) + let mut aliases = find_verified_aliases(db_client, &new_profile).await? .into_iter() .map(|profile| profile_actor_id(&instance.url(), &profile)) .collect::>(); diff --git a/src/mastodon_api/accounts/helpers.rs b/src/mastodon_api/accounts/helpers.rs index 8938b02..01ea7fa 100644 --- a/src/mastodon_api/accounts/helpers.rs +++ b/src/mastodon_api/accounts/helpers.rs @@ -3,6 +3,10 @@ use uuid::Uuid; use mitra_config::Instance; use mitra_models::{ database::{DatabaseClient, DatabaseError}, + profiles::helpers::{ + find_declared_aliases, + find_verified_aliases, + }, profiles::types::DbActorProfile, relationships::queries::{ create_follow_request, @@ -15,7 +19,7 @@ use mitra_models::{ use crate::activitypub::builders::follow::prepare_follow; -use super::types::RelationshipMap; +use super::types::{Account, Aliases, RelationshipMap}; pub async fn follow_or_create_request( db_client: &mut impl DatabaseClient, @@ -95,6 +99,32 @@ pub async fn get_relationship( Ok(relationship_map) } +pub async fn get_aliases( + db_client: &impl DatabaseClient, + base_url: &str, + instance_url: &str, + profile: &DbActorProfile, +) -> Result { + let declared = find_declared_aliases(db_client, profile).await? + .into_iter() + .map(|profile| Account::from_profile( + base_url, + instance_url, + profile, + )) + .collect(); + let verified = find_verified_aliases(db_client, profile).await? + .into_iter() + .map(|profile| Account::from_profile( + base_url, + instance_url, + profile, + )) + .collect(); + let aliases = Aliases { declared, verified }; + Ok(aliases) +} + #[cfg(test)] mod tests { use serial_test::serial; diff --git a/src/mastodon_api/accounts/types.rs b/src/mastodon_api/accounts/types.rs index 681d356..977aea4 100644 --- a/src/mastodon_api/accounts/types.rs +++ b/src/mastodon_api/accounts/types.rs @@ -546,6 +546,12 @@ impl ApiSubscription { } } +#[derive(Serialize)] +pub struct Aliases { + pub declared: Vec, + pub verified: Vec, +} + #[cfg(test)] mod tests { use mitra_models::profiles::types::ProfileImage; diff --git a/src/mastodon_api/accounts/views.rs b/src/mastodon_api/accounts/views.rs index 4baf3e1..729c650 100644 --- a/src/mastodon_api/accounts/views.rs +++ b/src/mastodon_api/accounts/views.rs @@ -15,7 +15,7 @@ use mitra_config::{Config, DefaultRole, RegistrationType}; use mitra_models::{ database::{get_database_client, DatabaseError, DbPool}, posts::queries::get_posts_by_author, - profiles::helpers::find_aliases, + profiles::helpers::find_verified_aliases, profiles::queries::{ get_profile_by_acct, get_profile_by_id, @@ -100,7 +100,11 @@ use crate::mastodon_api::{ statuses::types::Status, }; use crate::validators::profiles::clean_profile_update_data; -use super::helpers::{follow_or_create_request, get_relationship}; +use super::helpers::{ + follow_or_create_request, + get_aliases, + get_relationship, +}; use super::types::{ Account, AccountCreateData, @@ -832,7 +836,7 @@ async fn get_account_aliases( ) -> Result { let db_client = &**get_database_client(&db_pool).await?; let profile = get_profile_by_id(db_client, &account_id).await?; - let aliases = find_aliases(db_client, &profile).await?; + let aliases = find_verified_aliases(db_client, &profile).await?; let base_url = get_request_base_url(connection_info); let instance_url = config.instance_url(); let accounts: Vec = aliases.into_iter() @@ -845,6 +849,26 @@ async fn get_account_aliases( Ok(HttpResponse::Ok().json(accounts)) } +#[get("/{account_id}/aliases/all")] +async fn get_all_account_aliases( + connection_info: ConnectionInfo, + config: web::Data, + db_pool: web::Data, + account_id: web::Path, +) -> Result { + let db_client = &**get_database_client(&db_pool).await?; + let profile = get_profile_by_id(db_client, &account_id).await?; + let base_url = get_request_base_url(connection_info); + let instance_url = config.instance_url(); + let aliases = get_aliases( + db_client, + &base_url, + &instance_url, + &profile, + ).await?; + Ok(HttpResponse::Ok().json(aliases)) +} + pub fn account_api_scope() -> Scope { web::scope("/api/v1/accounts") // Routes without account ID @@ -868,4 +892,5 @@ pub fn account_api_scope() -> Scope { .service(get_account_following) .service(get_account_subscribers) .service(get_account_aliases) + .service(get_all_account_aliases) } diff --git a/src/mastodon_api/settings/views.rs b/src/mastodon_api/settings/views.rs index 4e62d63..01ca5e1 100644 --- a/src/mastodon_api/settings/views.rs +++ b/src/mastodon_api/settings/views.rs @@ -11,7 +11,7 @@ use actix_web_httpauth::extractors::bearer::BearerAuth; use mitra_config::Config; use mitra_models::{ database::{get_database_client, DatabaseError, DbPool}, - profiles::helpers::find_aliases, + profiles::helpers::find_verified_aliases, profiles::queries::get_profile_by_remote_actor_id, users::queries::set_user_password, }; @@ -149,7 +149,10 @@ async fn move_followers( }; if maybe_from_profile.is_some() { // Find known aliases of the current user - let mut aliases = find_aliases(db_client, ¤t_user.profile).await? + let mut aliases = find_verified_aliases( + db_client, + ¤t_user.profile, + ).await? .into_iter() .map(|profile| profile_actor_id(&instance.url(), &profile)); if !aliases.any(|actor_id| actor_id == request_data.from_actor_id) {