webfingerd/tests/test_tokens.rs

154 lines
5.2 KiB
Rust

mod common;
use axum_test::TestServer;
use serde_json::json;
use webfingerd::handler;
/// Helper: register a verified domain and return (id, owner_token).
/// Uses MockChallengeVerifier (injected in test state) so no manual DB manipulation needed.
async fn setup_verified_domain(
server: &TestServer,
_state: &webfingerd::state::AppState,
domain_name: &str,
) -> (String, String) {
let create_resp = server
.post("/api/v1/domains")
.json(&json!({"domain": domain_name, "challenge_type": "dns-01"}))
.await;
let body: serde_json::Value = create_resp.json();
let id = body["id"].as_str().unwrap().to_string();
let reg_secret = body["registration_secret"].as_str().unwrap().to_string();
// MockChallengeVerifier always succeeds
let verify_resp = server
.post(&format!("/api/v1/domains/{id}/verify"))
.json(&json!({"registration_secret": reg_secret}))
.await;
let owner_token = verify_resp.json::<serde_json::Value>()["owner_token"]
.as_str()
.unwrap()
.to_string();
(id, owner_token)
}
#[tokio::test]
async fn test_create_service_token() {
let state = common::test_state().await;
let app = handler::router(state.clone());
let server = TestServer::new(app);
let (id, owner_token) = setup_verified_domain(&server, &state, "example.com").await;
let response = server
.post(&format!("/api/v1/domains/{id}/tokens"))
.add_header("Authorization", format!("Bearer {owner_token}"))
.json(&json!({
"name": "oxifed",
"allowed_rels": ["self"],
"resource_pattern": "acct:*@example.com"
}))
.await;
response.assert_status(axum::http::StatusCode::CREATED);
let body: serde_json::Value = response.json();
assert!(body["id"].is_string());
assert!(body["token"].is_string());
assert_eq!(body["name"], "oxifed");
}
#[tokio::test]
async fn test_create_service_token_rejects_bad_pattern() {
let state = common::test_state().await;
let app = handler::router(state.clone());
let server = TestServer::new(app);
let (id, owner_token) = setup_verified_domain(&server, &state, "example.com").await;
// Pattern without @ or wrong domain
let response = server
.post(&format!("/api/v1/domains/{id}/tokens"))
.add_header("Authorization", format!("Bearer {owner_token}"))
.json(&json!({
"name": "evil",
"allowed_rels": ["self"],
"resource_pattern": "*"
}))
.await;
response.assert_status_bad_request();
}
#[tokio::test]
async fn test_list_service_tokens() {
let state = common::test_state().await;
let app = handler::router(state.clone());
let server = TestServer::new(app);
let (id, owner_token) = setup_verified_domain(&server, &state, "example.com").await;
server
.post(&format!("/api/v1/domains/{id}/tokens"))
.add_header("Authorization", format!("Bearer {owner_token}"))
.json(&json!({
"name": "oxifed",
"allowed_rels": ["self"],
"resource_pattern": "acct:*@example.com"
}))
.await;
let response = server
.get(&format!("/api/v1/domains/{id}/tokens"))
.add_header("Authorization", format!("Bearer {owner_token}"))
.await;
response.assert_status_ok();
let body: serde_json::Value = response.json();
let tokens = body.as_array().unwrap();
assert_eq!(tokens.len(), 1);
assert_eq!(tokens[0]["name"], "oxifed");
// Token hash should NOT be exposed
assert!(tokens[0].get("token_hash").is_none());
assert!(tokens[0].get("token").is_none());
}
// NOTE: test_revoke_service_token_deletes_links is in tests/test_links.rs (Task 10)
// because it depends on the link registration endpoint. It is tested there as part
// of the full link lifecycle, not here where the endpoint doesn't exist yet.
#[tokio::test]
async fn test_revoke_service_token() {
let state = common::test_state().await;
let app = handler::router(state.clone());
let server = TestServer::new(app);
let (id, owner_token) = setup_verified_domain(&server, &state, "example.com").await;
let create_resp = server
.post(&format!("/api/v1/domains/{id}/tokens"))
.add_header("Authorization", format!("Bearer {owner_token}"))
.json(&json!({
"name": "oxifed",
"allowed_rels": ["self"],
"resource_pattern": "acct:*@example.com"
}))
.await;
let body: serde_json::Value = create_resp.json();
let token_id = body["id"].as_str().unwrap().to_string();
// Revoke the token
let response = server
.delete(&format!("/api/v1/domains/{id}/tokens/{token_id}"))
.add_header("Authorization", format!("Bearer {owner_token}"))
.await;
response.assert_status(axum::http::StatusCode::NO_CONTENT);
// Token should no longer appear in list
let list_resp = server
.get(&format!("/api/v1/domains/{id}/tokens"))
.add_header("Authorization", format!("Bearer {owner_token}"))
.await;
let tokens = list_resp.json::<serde_json::Value>();
let tokens = tokens.as_array().unwrap();
assert!(tokens.is_empty());
}