first commit
This commit is contained in:
@@ -0,0 +1,193 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/mrhid6/keymanager/server/internal/db"
|
||||
"github.com/mrhid6/keymanager/server/internal/models"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
"go.mongodb.org/mongo-driver/v2/mongo/options"
|
||||
)
|
||||
|
||||
func generateToken(n int) (string, error) {
|
||||
b := make([]byte, n)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(b), nil
|
||||
}
|
||||
|
||||
func HashToken(token string) string {
|
||||
sum := sha256.Sum256([]byte(token))
|
||||
return hex.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
func CreateServer() (*models.Server, string, error) {
|
||||
token, err := generateToken(32)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
expires := time.Now().Add(time.Hour)
|
||||
s := &models.Server{
|
||||
ServerID: uuid.NewString(),
|
||||
PreRegToken: token,
|
||||
PreRegExpires: &expires,
|
||||
Status: "pending",
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
_, err = db.Col("servers").InsertOne(ctx, s)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
return s, token, nil
|
||||
}
|
||||
|
||||
func GetServer(serverID string) (*models.Server, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
var s models.Server
|
||||
err := db.Col("servers").FindOne(ctx, bson.M{"server_id": serverID}).Decode(&s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &s, nil
|
||||
}
|
||||
|
||||
func GetServerByPreRegToken(token string) (*models.Server, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
var s models.Server
|
||||
err := db.Col("servers").FindOne(ctx, bson.M{
|
||||
"pre_reg_token": token,
|
||||
"pre_reg_expires": bson.M{"$gt": time.Now()},
|
||||
}).Decode(&s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &s, nil
|
||||
}
|
||||
|
||||
func RegisterServer(serverID, preRegToken, hostname, ipAddress, osInfo string) (string, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
var s models.Server
|
||||
err := db.Col("servers").FindOne(ctx, bson.M{
|
||||
"server_id": serverID,
|
||||
"pre_reg_token": preRegToken,
|
||||
"pre_reg_expires": bson.M{"$gt": time.Now()},
|
||||
}).Decode(&s)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("invalid or expired pre-registration token")
|
||||
}
|
||||
|
||||
agentToken, err := generateToken(32)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
tokenHash := HashToken(agentToken)
|
||||
now := time.Now()
|
||||
|
||||
_, err = db.Col("servers").UpdateOne(ctx,
|
||||
bson.M{"server_id": serverID},
|
||||
bson.M{"$set": bson.M{
|
||||
"hostname": hostname,
|
||||
"ip_address": ipAddress,
|
||||
"os_info": osInfo,
|
||||
"agent_token_hash": tokenHash,
|
||||
"status": "active",
|
||||
"last_seen": now,
|
||||
"pre_reg_token": "",
|
||||
"pre_reg_expires": nil,
|
||||
}},
|
||||
)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return agentToken, nil
|
||||
}
|
||||
|
||||
func ValidateAgentToken(serverID, agentToken string) (*models.Server, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
tokenHash := HashToken(agentToken)
|
||||
var s models.Server
|
||||
err := db.Col("servers").FindOne(ctx, bson.M{
|
||||
"server_id": serverID,
|
||||
"agent_token_hash": tokenHash,
|
||||
}).Decode(&s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid agent token")
|
||||
}
|
||||
return &s, nil
|
||||
}
|
||||
|
||||
func UpdateServerLastSeen(serverID string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
now := time.Now()
|
||||
_, err := db.Col("servers").UpdateOne(ctx,
|
||||
bson.M{"server_id": serverID},
|
||||
bson.M{"$set": bson.M{"last_seen": now, "status": "active"}},
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func ListServers() ([]models.Server, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
opts := options.Find().SetSort(bson.D{{Key: "created_at", Value: -1}})
|
||||
cursor, err := db.Col("servers").Find(ctx, bson.M{}, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer cursor.Close(ctx)
|
||||
|
||||
var servers []models.Server
|
||||
if err := cursor.All(ctx, &servers); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
func DeleteServer(serverID string) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
_, err := db.Col("servers").DeleteOne(ctx, bson.M{"server_id": serverID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Also remove assignments
|
||||
_, err = db.Col("assignments").DeleteMany(ctx, bson.M{"server_id": serverID})
|
||||
return err
|
||||
}
|
||||
|
||||
func MarkOfflineServers(threshold time.Duration) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
cutoff := time.Now().Add(-threshold)
|
||||
_, err := db.Col("servers").UpdateMany(ctx,
|
||||
bson.M{
|
||||
"status": "active",
|
||||
"last_seen": bson.M{"$lt": cutoff},
|
||||
},
|
||||
bson.M{"$set": bson.M{"status": "offline"}},
|
||||
)
|
||||
return err
|
||||
}
|
||||
Reference in New Issue
Block a user