package api import ( "encoding/base64" "net/http" "github.com/gin-gonic/gin" "github.com/google/uuid" "github.com/stef/pkiapi/internal/pki" "github.com/stef/pkiapi/internal/storage" ) // CreateCertificateRequest représente la requête de création de certificat type CreateCertificateRequest struct { Subject string `json:"subject" binding:"required"` ValidityDays int `json:"validity_days" binding:"required,min=1,max=3650"` } // CertificateResponse représente la réponse avec les données du certificat type CertificateResponse struct { ID string `json:"id"` Subject string `json:"subject"` Issuer string `json:"issuer"` NotBefore string `json:"not_before"` NotAfter string `json:"not_after"` SerialNumber string `json:"serial_number"` Certificate string `json:"certificate"` // Base64 encoded Revoked bool `json:"revoked"` } // certificateStore est un store global pour les certificats var certificateStore storage.CertificateStore // InitCertificateStore initialise le store pour les certificats func InitCertificateStore(store storage.CertificateStore) { certificateStore = store } // CreateCertificate crée un nouveau certificat auto-signé func CreateCertificate(c *gin.Context) { var req CreateCertificateRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // Générer le certificat cert, err := pki.GenerateCertificate(req.Subject, req.ValidityDays) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "erreur génération certificat"}) return } // Générer un ID unique certID := uuid.New().String() cert.ID = certID // Sauvegarder le certificat if err := certificateStore.SaveCertificate(certID, cert); err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "erreur sauvegarde certificat"}) return } // Récupérer l'utilisateur depuis le contexte JWT userID, _ := c.Get("user_id") // Retourner la réponse response := CertificateResponse{ ID: certID, Subject: cert.Subject, Issuer: cert.Issuer, NotBefore: cert.NotBefore.Format("2006-01-02T15:04:05Z"), NotAfter: cert.NotAfter.Format("2006-01-02T15:04:05Z"), Revoked: false, } if cert.Cert != nil { response.SerialNumber = cert.Cert.SerialNumber.String() response.Certificate = base64.StdEncoding.EncodeToString(cert.Cert.Raw) } c.JSON(http.StatusCreated, gin.H{ "certificate": response, "created_by": userID, }) } // ListCertificates retourne tous les certificats func ListCertificates(c *gin.Context) { certs := certificateStore.ListCertificates() var responses []CertificateResponse for _, cert := range certs { response := CertificateResponse{ ID: cert.ID, Subject: cert.Subject, Issuer: cert.Issuer, NotBefore: cert.NotBefore.Format("2006-01-02T15:04:05Z"), NotAfter: cert.NotAfter.Format("2006-01-02T15:04:05Z"), Revoked: cert.Revoked, } if cert.Cert != nil { response.SerialNumber = cert.Cert.SerialNumber.String() } responses = append(responses, response) } c.JSON(http.StatusOK, gin.H{"certificates": responses}) } // GetCertificate retourne un certificat par ID func GetCertificate(c *gin.Context) { id := c.Param("id") cert, err := certificateStore.GetCertificate(id) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "certificat non trouvé"}) return } response := CertificateResponse{ ID: cert.ID, Subject: cert.Subject, Issuer: cert.Issuer, NotBefore: cert.NotBefore.Format("2006-01-02T15:04:05Z"), NotAfter: cert.NotAfter.Format("2006-01-02T15:04:05Z"), Revoked: cert.Revoked, } if cert.Cert != nil { response.SerialNumber = cert.Cert.SerialNumber.String() response.Certificate = base64.StdEncoding.EncodeToString(cert.Cert.Raw) } c.JSON(http.StatusOK, gin.H{"certificate": response}) } // RevokeCertificate révoque un certificat func RevokeCertificate(c *gin.Context) { var req struct { CertificateID string `json:"certificate_id" binding:"required"` Reason string `json:"reason"` } if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } cert, err := certificateStore.GetCertificate(req.CertificateID) if err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "certificat non trouvé"}) return } cert.Revoked = true certificateStore.SaveCertificate(req.CertificateID, cert) c.JSON(http.StatusOK, gin.H{ "message": "certificat révoqué", "id": req.CertificateID, "reason": req.Reason, }) } // GetCRL retourne la liste de révocation func GetCRL(c *gin.Context) { certs := certificateStore.ListCertificates() var revokedCerts []gin.H for _, cert := range certs { if cert.Revoked && cert.Cert != nil { revokedCerts = append(revokedCerts, gin.H{ "serial_number": cert.Cert.SerialNumber.String(), "subject": cert.Subject, }) } } c.JSON(http.StatusOK, gin.H{ "crl": revokedCerts, "version": 1, }) }