torrust-actix 4.2.3

A rich, fast and efficient Bittorrent Tracker.
use crate::api::api::{
    api_service_token,
    api_validation
};
use crate::api::structs::certificate_reload_error::CertificateReloadError;
use crate::api::structs::certificate_reload_request::CertificateReloadRequest;
use crate::api::structs::certificate_reload_result::CertificateReloadResult;
use crate::api::structs::certificate_status_item::CertificateStatusItem;
use crate::api::structs::api_service_data::ApiServiceData;
use crate::api::structs::query_token::QueryToken;
use crate::ssl::enums::server_identifier::ServerIdentifier;
use actix_web::http::header::ContentType;
use actix_web::web::Data;
use actix_web::{
    web,
    HttpRequest,
    HttpResponse
};
use serde_json::json;
use std::sync::Arc;

pub async fn api_service_certificate_reload(
    request: HttpRequest,
    data: Data<Arc<ApiServiceData>>,
    body: Option<web::Json<CertificateReloadRequest>>,
) -> HttpResponse {
    if let Some(error_return) = api_validation(&request, &data).await {
        return error_return;
    }
    let params = web::Query::<QueryToken>::from_query(request.query_string()).unwrap();
    if let Some(response) = api_service_token(params.token.clone(), Arc::clone(&data.torrent_tracker.config)).await {
        return response;
    }
    let certificate_store = &data.torrent_tracker.certificate_store;
    let (server_type_filter, bind_address_filter) = match body {
        Some(req) => (req.server_type.clone(), req.bind_address.clone()),
        None => (None, None),
    };
    let certificates_to_reload: Vec<ServerIdentifier> = {
        let certificates = certificate_store.get_all_certificates();
        certificates
            .into_iter()
            .filter(|(server_id, _)| {
                if let Some(ref filter) = server_type_filter
                    && server_id.server_type() != filter.to_lowercase()
                {
                    return false;
                }
                if let Some(ref filter) = bind_address_filter
                    && server_id.bind_address() != filter
                {
                    return false;
                }
                true
            })
            .map(|(server_id, _)| server_id)
            .collect()
    };
    if certificates_to_reload.is_empty() {
        return HttpResponse::Ok().content_type(ContentType::json()).json(json!({
            "status": "no_certificates",
            "message": "No SSL certificates found to reload"
        }));
    }
    let mut reloaded: Vec<CertificateReloadResult> = Vec::with_capacity(certificates_to_reload.len());
    let mut errors: Vec<CertificateReloadError> = Vec::new();
    for server_id in certificates_to_reload {
        match certificate_store.reload_certificate(&server_id) {
            Ok(()) => {
                let loaded_at = certificate_store
                    .get_certificate(&server_id).map_or_else(|| "unknown".to_string(), |bundle| bundle.loaded_at.to_rfc3339());
                reloaded.push(CertificateReloadResult {
                    server_type: server_id.server_type().to_string(),
                    bind_address: server_id.bind_address().to_string(),
                    loaded_at,
                });
            }
            Err(e) => {
                errors.push(CertificateReloadError {
                    server_type: server_id.server_type().to_string(),
                    bind_address: server_id.bind_address().to_string(),
                    error: e.to_string(),
                });
            }
        }
    }
    let status = if errors.is_empty() {
        "ok"
    } else if reloaded.is_empty() {
        "failed"
    } else {
        "partial"
    };
    HttpResponse::Ok().content_type(ContentType::json()).json(json!({
        "status": status,
        "reloaded": reloaded,
        "errors": errors
    }))
}

pub async fn api_service_certificate_status(
    request: HttpRequest,
    data: Data<Arc<ApiServiceData>>,
) -> HttpResponse {
    if let Some(error_return) = api_validation(&request, &data).await {
        return error_return;
    }
    let params = web::Query::<QueryToken>::from_query(request.query_string()).unwrap();
    if let Some(response) = api_service_token(params.token.clone(), Arc::clone(&data.torrent_tracker.config)).await {
        return response;
    }
    let certificate_store = &data.torrent_tracker.certificate_store;
    let certificates = certificate_store.get_all_certificates();
    let status_items: Vec<CertificateStatusItem> = certificates
        .into_iter()
        .map(|(server_id, bundle)| {
            CertificateStatusItem {
                server_type: server_id.server_type().to_string(),
                bind_address: server_id.bind_address().to_string(),
                cert_path: bundle.cert_path.clone(),
                key_path: bundle.key_path.clone(),
                loaded_at: bundle.loaded_at.to_rfc3339(),
            }
        })
        .collect();
    HttpResponse::Ok().content_type(ContentType::json()).json(json!({
        "status": "ok",
        "certificates": status_items
    }))
}