122 lines
3.2 KiB
Go
122 lines
3.2 KiB
Go
package handlers
|
|
|
|
import (
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
|
|
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/repository"
|
|
"gitea.d3m0k1d.ru/d3m0k1d/HellreigN/backend/internal/utils"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
type AgentRegistrationGroup struct {
|
|
*Handlers
|
|
certBundle *utils.CertBundle
|
|
}
|
|
|
|
func NewAgentRegistrationGroup(h *Handlers) *AgentRegistrationGroup {
|
|
certDir := getCertDir()
|
|
bundle, err := utils.LoadCertBundle(certDir)
|
|
if err != nil {
|
|
log.Printf("[agent-reg] WARNING: cert bundle load failed: %v", err)
|
|
}
|
|
return &AgentRegistrationGroup{
|
|
Handlers: h,
|
|
certBundle: bundle,
|
|
}
|
|
}
|
|
|
|
// CreateRegistrationToken — админ создаёт токен для агента
|
|
// @Summary Create registration token
|
|
// @Tags agents
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body repository.RegistrationRequest true "Label"
|
|
// @Success 200 {object} map[string]string
|
|
// @Security Bearer
|
|
// @Router /agents/register-token [post]
|
|
func (arg *AgentRegistrationGroup) CreateRegistrationToken(c *gin.Context) {
|
|
var req repository.RegistrationRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
token, err := arg.Repo.CreateRegistrationToken(req.Label)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create token"})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, gin.H{"token": token})
|
|
}
|
|
|
|
// Register — агент шлёт CSR + token, получает сертификаты
|
|
// @Summary Register agent
|
|
// @Tags agents
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body RegisterRequest true "CSR + token"
|
|
// @Success 200 {object} RegisterResponse
|
|
// @Router /agents/register [post]
|
|
func (arg *AgentRegistrationGroup) Register(c *gin.Context) {
|
|
var req RegisterRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
if arg.certBundle == nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "certificate bundle not available"})
|
|
return
|
|
}
|
|
|
|
regToken, err := arg.Repo.GetRegistrationToken(req.Token)
|
|
if err != nil {
|
|
if err == repository.ErrNotFound {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid registration token"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to verify token"})
|
|
return
|
|
}
|
|
|
|
if regToken.Used {
|
|
c.JSON(http.StatusGone, gin.H{"error": "registration token already used"})
|
|
return
|
|
}
|
|
|
|
clientCertPEM, err := arg.certBundle.SignCSR([]byte(req.CSR), regToken.Label)
|
|
if err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "failed to sign CSR: " + err.Error()})
|
|
return
|
|
}
|
|
|
|
if err := arg.Repo.MarkRegistrationTokenUsed(req.Token); err != nil {
|
|
log.Printf("[agent-reg] WARNING: failed to mark token used: %v", err)
|
|
}
|
|
|
|
c.JSON(http.StatusOK, RegisterResponse{
|
|
CACert: string(arg.certBundle.GetCACertPEM()),
|
|
ClientCert: string(clientCertPEM),
|
|
})
|
|
}
|
|
|
|
type RegisterRequest struct {
|
|
CSR string `json:"csr" binding:"required"`
|
|
Token string `json:"token" binding:"required"`
|
|
}
|
|
|
|
type RegisterResponse struct {
|
|
CACert string `json:"ca_cert"`
|
|
ClientCert string `json:"client_cert"`
|
|
}
|
|
|
|
func getCertDir() string {
|
|
if d := os.Getenv("SSL_CERT_DIR"); d != "" {
|
|
return d
|
|
}
|
|
return "/var/lib/hellreign/ssl"
|
|
}
|