use actix_web::{HttpResponse, web}; use crate::api::response::{ApiErrorResponse, ApiResponse}; use crate::error::AppError; use crate::models::users::UserSshKey; use crate::service::AppService; use crate::service::user::keys::AddSshKeyParams; use crate::session::Session; /// Add an SSH key /// /// Registers a new SSH public key for the authenticated user. /// Requires authentication. /// /// Parameters: /// - title: Human-readable label for the key (e.g., "Work Laptop") /// - public_key: SSH public key string (supports RSA, Ed25519, ECDSA, DSA) /// - key_type: Key algorithm type ("rsa", "ed25519", "ecdsa", "dsa") /// - expires_at: Optional expiration date for the key /// /// Effects: /// - Key fingerprint is computed and stored /// - Key is immediately usable for Git operations /// - Duplicate keys are rejected /// /// Returns the created SSH key with fingerprint and metadata. #[utoipa::path( post, path = "/api/v1/user/keys/ssh", tag = "User", operation_id = "userAddSshKey", request_body( content = AddSshKeyParams, description = "SSH key creation parameters", content_type = "application/json" ), responses( (status = 201, description = "SSH key added successfully. Returns the created key with fingerprint and metadata.", body = ApiResponse), (status = 400, description = "Invalid parameters: invalid key format, unsupported key type, or type mismatch", body = ApiErrorResponse), (status = 401, description = "Authentication required or session expired", body = ApiErrorResponse), (status = 409, description = "SSH key with this fingerprint already exists", body = ApiErrorResponse), (status = 500, description = "Internal server error", body = ApiErrorResponse), ), security( ("session_cookie" = []) ) )] pub async fn add_ssh_key( service: web::Data, session: Session, params: web::Json, ) -> Result { let key = service .user .user_add_ssh_key(&session, params.into_inner()) .await?; Ok(HttpResponse::Created().json(ApiResponse::new(key))) }