Create /api/v1/accounts/aliases/all API endpoint

This commit is contained in:
silverpill 2023-04-03 20:16:16 +00:00
parent 59e5f12016
commit 13df9e0478
8 changed files with 143 additions and 28 deletions

View file

@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added ### Added
- Support calling `/api/v1/accounts/search` with `resolve` parameter. - Support calling `/api/v1/accounts/search` with `resolve` parameter.
- Created `/api/v1/accounts/aliases/all` API endpoint.
### Changed ### Changed

View file

@ -550,23 +550,6 @@ paths:
$ref: '#/components/schemas/Subscription' $ref: '#/components/schemas/Subscription'
404: 404:
description: Profile not found 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: /api/v1/accounts/{account_id}/follow:
post: post:
summary: Follow the given actor. summary: Follow the given actor.
@ -613,6 +596,37 @@ paths:
$ref: '#/components/schemas/Relationship' $ref: '#/components/schemas/Relationship'
404: 404:
description: Profile not found 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: /api/v1/apps:
post: post:
summary: Create a new application to obtain OAuth2 credentials. summary: Create a new application to obtain OAuth2 credentials.
@ -1476,6 +1490,19 @@ components:
type: string type: string
enum: enum:
- update - 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: Application:
type: object type: object
properties: properties:

View file

@ -1,9 +1,32 @@
use crate::database::{DatabaseClient, DatabaseError}; 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; use super::types::DbActorProfile;
pub async fn find_aliases( pub async fn find_declared_aliases(
db_client: &impl DatabaseClient,
profile: &DbActorProfile,
) -> Result<Vec<DbActorProfile>, 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, db_client: &impl DatabaseClient,
profile: &DbActorProfile, profile: &DbActorProfile,
) -> Result<Vec<DbActorProfile>, DatabaseError> { ) -> Result<Vec<DbActorProfile>, DatabaseError> {

View file

@ -5,7 +5,7 @@ use mitra_config::Config;
use mitra_models::{ use mitra_models::{
database::{DatabaseClient, DatabaseError}, database::{DatabaseClient, DatabaseError},
notifications::queries::create_move_notification, notifications::queries::create_move_notification,
profiles::helpers::find_aliases, profiles::helpers::find_verified_aliases,
relationships::queries::{ relationships::queries::{
create_follow_request, create_follow_request,
get_followers, get_followers,
@ -75,8 +75,8 @@ pub async fn handle_move(
let new_actor = new_profile.actor_json.as_ref() let new_actor = new_profile.actor_json.as_ref()
.expect("target should be a remote actor"); .expect("target should be a remote actor");
// Find aliases by DIDs (signed) // Find aliases by DIDs (verified)
let mut aliases = find_aliases(db_client, &new_profile).await? let mut aliases = find_verified_aliases(db_client, &new_profile).await?
.into_iter() .into_iter()
.map(|profile| profile_actor_id(&instance.url(), &profile)) .map(|profile| profile_actor_id(&instance.url(), &profile))
.collect::<Vec<_>>(); .collect::<Vec<_>>();

View file

@ -3,6 +3,10 @@ use uuid::Uuid;
use mitra_config::Instance; use mitra_config::Instance;
use mitra_models::{ use mitra_models::{
database::{DatabaseClient, DatabaseError}, database::{DatabaseClient, DatabaseError},
profiles::helpers::{
find_declared_aliases,
find_verified_aliases,
},
profiles::types::DbActorProfile, profiles::types::DbActorProfile,
relationships::queries::{ relationships::queries::{
create_follow_request, create_follow_request,
@ -15,7 +19,7 @@ use mitra_models::{
use crate::activitypub::builders::follow::prepare_follow; use crate::activitypub::builders::follow::prepare_follow;
use super::types::RelationshipMap; use super::types::{Account, Aliases, RelationshipMap};
pub async fn follow_or_create_request( pub async fn follow_or_create_request(
db_client: &mut impl DatabaseClient, db_client: &mut impl DatabaseClient,
@ -95,6 +99,32 @@ pub async fn get_relationship(
Ok(relationship_map) Ok(relationship_map)
} }
pub async fn get_aliases(
db_client: &impl DatabaseClient,
base_url: &str,
instance_url: &str,
profile: &DbActorProfile,
) -> Result<Aliases, DatabaseError> {
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)] #[cfg(test)]
mod tests { mod tests {
use serial_test::serial; use serial_test::serial;

View file

@ -546,6 +546,12 @@ impl ApiSubscription {
} }
} }
#[derive(Serialize)]
pub struct Aliases {
pub declared: Vec<Account>,
pub verified: Vec<Account>,
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use mitra_models::profiles::types::ProfileImage; use mitra_models::profiles::types::ProfileImage;

View file

@ -15,7 +15,7 @@ use mitra_config::{Config, DefaultRole, RegistrationType};
use mitra_models::{ use mitra_models::{
database::{get_database_client, DatabaseError, DbPool}, database::{get_database_client, DatabaseError, DbPool},
posts::queries::get_posts_by_author, posts::queries::get_posts_by_author,
profiles::helpers::find_aliases, profiles::helpers::find_verified_aliases,
profiles::queries::{ profiles::queries::{
get_profile_by_acct, get_profile_by_acct,
get_profile_by_id, get_profile_by_id,
@ -100,7 +100,11 @@ use crate::mastodon_api::{
statuses::types::Status, statuses::types::Status,
}; };
use crate::validators::profiles::clean_profile_update_data; 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::{ use super::types::{
Account, Account,
AccountCreateData, AccountCreateData,
@ -832,7 +836,7 @@ async fn get_account_aliases(
) -> Result<HttpResponse, MastodonError> { ) -> Result<HttpResponse, MastodonError> {
let db_client = &**get_database_client(&db_pool).await?; let db_client = &**get_database_client(&db_pool).await?;
let profile = get_profile_by_id(db_client, &account_id).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 base_url = get_request_base_url(connection_info);
let instance_url = config.instance_url(); let instance_url = config.instance_url();
let accounts: Vec<Account> = aliases.into_iter() let accounts: Vec<Account> = aliases.into_iter()
@ -845,6 +849,26 @@ async fn get_account_aliases(
Ok(HttpResponse::Ok().json(accounts)) Ok(HttpResponse::Ok().json(accounts))
} }
#[get("/{account_id}/aliases/all")]
async fn get_all_account_aliases(
connection_info: ConnectionInfo,
config: web::Data<Config>,
db_pool: web::Data<DbPool>,
account_id: web::Path<Uuid>,
) -> Result<HttpResponse, MastodonError> {
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 { pub fn account_api_scope() -> Scope {
web::scope("/api/v1/accounts") web::scope("/api/v1/accounts")
// Routes without account ID // Routes without account ID
@ -868,4 +892,5 @@ pub fn account_api_scope() -> Scope {
.service(get_account_following) .service(get_account_following)
.service(get_account_subscribers) .service(get_account_subscribers)
.service(get_account_aliases) .service(get_account_aliases)
.service(get_all_account_aliases)
} }

View file

@ -11,7 +11,7 @@ use actix_web_httpauth::extractors::bearer::BearerAuth;
use mitra_config::Config; use mitra_config::Config;
use mitra_models::{ use mitra_models::{
database::{get_database_client, DatabaseError, DbPool}, database::{get_database_client, DatabaseError, DbPool},
profiles::helpers::find_aliases, profiles::helpers::find_verified_aliases,
profiles::queries::get_profile_by_remote_actor_id, profiles::queries::get_profile_by_remote_actor_id,
users::queries::set_user_password, users::queries::set_user_password,
}; };
@ -149,7 +149,10 @@ async fn move_followers(
}; };
if maybe_from_profile.is_some() { if maybe_from_profile.is_some() {
// Find known aliases of the current user // Find known aliases of the current user
let mut aliases = find_aliases(db_client, &current_user.profile).await? let mut aliases = find_verified_aliases(
db_client,
&current_user.profile,
).await?
.into_iter() .into_iter()
.map(|profile| profile_actor_id(&instance.url(), &profile)); .map(|profile| profile_actor_id(&instance.url(), &profile));
if !aliases.any(|actor_id| actor_id == request_data.from_actor_id) { if !aliases.any(|actor_id| actor_id == request_data.from_actor_id) {