Create Api Key added
This commit is contained in:
@ -1,7 +1,11 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"backend/models"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
@ -10,3 +14,52 @@ func (r *NodeHandler) LoginHandler(c *gin.Context) {
|
||||
log.Println("trying to login")
|
||||
r.Repo.LoginHandler(c)
|
||||
}
|
||||
|
||||
func GenerateSecureKey() (string, error) {
|
||||
bytes := make([]byte, 32) // 256 bits
|
||||
if _, err := rand.Read(bytes); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(bytes), nil
|
||||
}
|
||||
|
||||
func (r *NodeHandler) CreateApiKeyHandler(c *gin.Context) {
|
||||
|
||||
log.Println("trying to create key")
|
||||
newApiKey, err := GenerateSecureKey()
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Generate API key error: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "key creation error"})
|
||||
return
|
||||
}
|
||||
|
||||
var key models.CreateApiKeyResponse
|
||||
|
||||
key, err = r.Repo.CreateApiKeyHandler(c, newApiKey)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("CreateApiKeyHandler error: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "insert new api key error"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, key)
|
||||
}
|
||||
|
||||
func (h *NodeHandler) HandleRetrieveApiKeys(c *gin.Context) {
|
||||
|
||||
log.Println("All nodes retrieved request")
|
||||
|
||||
registeredNodes, err := h.Repo.RetriveNodeList()
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Request error on retrieving all nodes: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Impossible de récupérer la liste des nœuds"})
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("nb nodes: %v", len(registeredNodes))
|
||||
|
||||
c.JSON(http.StatusOK, registeredNodes)
|
||||
}
|
||||
|
||||
@ -38,6 +38,27 @@ func SeedAdmin(db *sqlx.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NodeAuthMiddleware(repo *repositories.NodeRepository) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
key := c.GetHeader("X-Node-API-Key")
|
||||
|
||||
if key == "" {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "Clé API manquante"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
isValid, err := repo.IsApiKeyValid(key)
|
||||
if err != nil || !isValid {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"error": "Clé API invalide"})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func AuthRequired(c *gin.Context) {
|
||||
session := sessions.Default(c)
|
||||
userID := session.Get("user_id")
|
||||
@ -92,15 +113,23 @@ func main() {
|
||||
{
|
||||
api.POST("/login", nodeHandler.LoginHandler)
|
||||
|
||||
api.POST("/register", nodeHandler.HandleRegisterNode)
|
||||
api.POST("/registerService", nodeHandler.HandleRegisterService)
|
||||
api.POST("/updateServiceStatus", nodeHandler.HandleUpdateServiceStatus)
|
||||
|
||||
protected := api.Group("/")
|
||||
protected.Use(AuthRequired)
|
||||
{
|
||||
protected.DELETE("/deleteService", nodeHandler.HandleDeleteService)
|
||||
|
||||
protected.POST("/createApiKey", nodeHandler.CreateApiKeyHandler)
|
||||
|
||||
protected.GET("/retrieveNodeList", nodeHandler.HandleRetrieveNodeList)
|
||||
protected.GET("/retrieveApiKeys", nodeHandler.HandleRetrieveApiKeys)
|
||||
}
|
||||
|
||||
nodes := api.Group("/")
|
||||
nodes.Use(NodeAuthMiddleware(nodeRepo))
|
||||
{
|
||||
nodes.POST("/register", nodeHandler.HandleRegisterNode)
|
||||
nodes.POST("/registerService", nodeHandler.HandleRegisterService)
|
||||
nodes.POST("/updateServiceStatus", nodeHandler.HandleUpdateServiceStatus)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
7
backend/migrations/000003_api_keys.up.sql
Normal file
7
backend/migrations/000003_api_keys.up.sql
Normal file
@ -0,0 +1,7 @@
|
||||
CREATE TABLE node_api_keys (
|
||||
id SERIAL PRIMARY KEY,
|
||||
key_name VARCHAR(100),
|
||||
key_value VARCHAR(64) UNIQUE NOT NULL,
|
||||
is_active BOOLEAN DEFAULT true,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
@ -9,3 +9,13 @@ type LoginResponse struct {
|
||||
Message string `json:"message"`
|
||||
Role string `json:"role"`
|
||||
}
|
||||
|
||||
type CreateApiKeyRequest struct {
|
||||
KeyName string `json:"key_name"`
|
||||
}
|
||||
|
||||
type CreateApiKeyResponse struct {
|
||||
Id int `json:"id" db:"id"`
|
||||
KeyName string `json:"key_name" db:"key_name"`
|
||||
Key string `json:"key" db:"key_value"`
|
||||
}
|
||||
|
||||
@ -11,6 +11,29 @@ import (
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func (r *NodeRepository) IsApiKeyValid(key string) (bool, error) {
|
||||
var exists bool
|
||||
query := "SELECT exists(SELECT 1 FROM node_api_keys WHERE key_value=$1 AND is_active=true)"
|
||||
err := r.DB.Get(&exists, query, key)
|
||||
return exists, err
|
||||
}
|
||||
|
||||
func (r *NodeRepository) CreateApiKeyHandler(c *gin.Context, newKey string) (models.CreateApiKeyResponse, error) {
|
||||
|
||||
var key models.CreateApiKeyResponse
|
||||
|
||||
var req models.CreateApiKeyRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Format invalide"})
|
||||
return key, err
|
||||
}
|
||||
|
||||
query := "INSERT INTO node_api_keys (key_value, key_name) VALUES ($1, $2) RETURNING id, key_name, key_value;"
|
||||
err := r.DB.Get(&key, query, newKey, req.KeyName)
|
||||
|
||||
return key, err
|
||||
}
|
||||
|
||||
func (r *NodeRepository) LoginHandler(c *gin.Context) {
|
||||
var req models.LoginRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user