fedimovies/src/webfinger/views.rs

123 lines
3.7 KiB
Rust
Raw Normal View History

2021-04-09 00:22:17 +00:00
use actix_web::{get, web, HttpResponse};
2022-10-01 16:56:57 +00:00
use crate::activitypub::constants::AP_MEDIA_TYPE;
use crate::activitypub::identifiers::{
local_actor_id,
local_instance_actor_id,
parse_local_actor_id,
};
use crate::config::{Config, Instance};
use crate::database::{get_database_client, DatabaseClient, DbPool};
2021-11-13 17:37:31 +00:00
use crate::errors::{HttpError, ValidationError};
2021-04-09 00:22:17 +00:00
use crate::models::users::queries::is_registered_user;
use super::types::{
ActorAddress,
2021-04-09 00:22:17 +00:00
Link,
JsonResourceDescriptor,
WebfingerQueryParams,
JRD_CONTENT_TYPE,
2021-04-09 00:22:17 +00:00
};
// https://datatracker.ietf.org/doc/html/rfc7565#section-7
fn parse_acct_uri(uri: &str) -> Result<ActorAddress, ValidationError> {
let actor_address = uri.strip_prefix("acct:")
.ok_or(ValidationError("invalid query target"))?
.parse()?;
Ok(actor_address)
}
2023-01-12 21:38:36 +00:00
async fn get_jrd(
db_client: &impl DatabaseClient,
instance: Instance,
2023-01-12 21:38:36 +00:00
resource: &str,
2021-04-09 00:22:17 +00:00
) -> Result<JsonResourceDescriptor, HttpError> {
let actor_address = if resource.starts_with("acct:") {
parse_acct_uri(resource)?
} else {
// Actor ID? (reverse webfinger)
let username = parse_local_actor_id(
&instance.url(),
resource,
)?;
ActorAddress { username, hostname: instance.hostname() }
};
if actor_address.hostname != instance.hostname() {
// Wrong instance
2021-04-09 00:22:17 +00:00
return Err(HttpError::NotFoundError("user"));
};
let actor_id = if actor_address.username == instance.hostname() {
local_instance_actor_id(&instance.url())
2021-11-18 00:51:56 +00:00
} else {
if !is_registered_user(db_client, &actor_address.username).await? {
2021-11-18 00:51:56 +00:00
return Err(HttpError::NotFoundError("user"));
};
local_actor_id(&instance.url(), &actor_address.username)
2021-11-18 00:51:56 +00:00
};
2021-04-09 00:22:17 +00:00
let link = Link {
rel: "self".to_string(),
2022-10-01 16:56:57 +00:00
link_type: Some(AP_MEDIA_TYPE.to_string()),
href: Some(actor_id),
2021-04-09 00:22:17 +00:00
};
let jrd = JsonResourceDescriptor {
subject: format!("acct:{}", actor_address),
2021-04-09 00:22:17 +00:00
links: vec![link],
};
Ok(jrd)
}
#[get("/.well-known/webfinger")]
2023-01-12 21:38:36 +00:00
pub async fn webfinger_view(
2021-04-09 00:22:17 +00:00
config: web::Data<Config>,
2022-12-03 21:23:52 +00:00
db_pool: web::Data<DbPool>,
2021-04-09 00:22:17 +00:00
query_params: web::Query<WebfingerQueryParams>,
) -> Result<HttpResponse, HttpError> {
let db_client = &**get_database_client(&db_pool).await?;
2023-01-12 21:38:36 +00:00
let jrd = get_jrd(
db_client,
config.instance(),
2023-01-12 21:38:36 +00:00
&query_params.resource,
).await?;
2021-04-09 00:22:17 +00:00
let response = HttpResponse::Ok()
.content_type(JRD_CONTENT_TYPE)
.json(jrd);
Ok(response)
}
#[cfg(test)]
mod tests {
2023-01-12 21:38:36 +00:00
use serial_test::serial;
use crate::database::test_utils::create_test_database;
use crate::models::users::{
queries::create_user,
types::UserCreateData,
};
use super::*;
#[test]
fn test_parse_acct_uri() {
let uri = "acct:user_1@example.com";
let actor_address = parse_acct_uri(uri).unwrap();
assert_eq!(actor_address.username, "user_1");
assert_eq!(actor_address.hostname, "example.com");
}
2023-01-12 21:38:36 +00:00
#[tokio::test]
#[serial]
async fn test_get_jrd() {
let db_client = &mut create_test_database().await;
let instance = Instance::for_test("https://example.com");
let user_data = UserCreateData {
username: "test".to_string(),
..Default::default()
};
create_user(db_client, user_data).await.unwrap();
let resource = "acct:test@example.com";
let jrd = get_jrd(db_client, instance, resource).await.unwrap();
assert_eq!(jrd.subject, resource);
assert_eq!(
jrd.links[0].href.as_ref().unwrap(),
"https://example.com/users/test",
);
}
}