first commit
Agent Release / build (push) Has been cancelled
Server Deploy / deploy (push) Has been cancelled

This commit is contained in:
domrichardson
2026-06-15 13:58:45 +01:00
commit c9868b2108
55 changed files with 11076 additions and 0 deletions
+209
View File
@@ -0,0 +1,209 @@
package services
import (
"context"
"crypto/md5"
"encoding/base64"
"fmt"
"strings"
"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"
)
func computeFingerprint(pubKey string) string {
parts := strings.Fields(pubKey)
if len(parts) < 2 {
return ""
}
raw, err := base64.StdEncoding.DecodeString(parts[1])
if err != nil {
return ""
}
sum := md5.Sum(raw)
var pairs []string
for _, b := range sum {
pairs = append(pairs, fmt.Sprintf("%02x", b))
}
return "MD5:" + strings.Join(pairs, ":")
}
func CreateKey(label, publicKey, source, generatedByServerID string) (*models.Key, error) {
key := &models.Key{
KeyID: uuid.NewString(),
Label: label,
PublicKey: publicKey,
Fingerprint: computeFingerprint(publicKey),
Source: source,
GeneratedByServerID: generatedByServerID,
CreatedAt: time.Now(),
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err := db.Col("keys").InsertOne(ctx, key)
if err != nil {
return nil, err
}
return key, nil
}
func GetKey(keyID string) (*models.Key, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
var key models.Key
err := db.Col("keys").FindOne(ctx, bson.M{"key_id": keyID}).Decode(&key)
if err != nil {
return nil, err
}
return &key, nil
}
func ListKeys() ([]models.Key, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
cursor, err := db.Col("keys").Find(ctx, bson.M{})
if err != nil {
return nil, err
}
defer cursor.Close(ctx)
var keys []models.Key
if err := cursor.All(ctx, &keys); err != nil {
return nil, err
}
return keys, nil
}
func DeleteKey(keyID string) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err := db.Col("keys").DeleteOne(ctx, bson.M{"key_id": keyID})
return err
}
func AssignKey(keyID, serverID string) (*models.Assignment, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// Check if already assigned and active
var existing models.Assignment
err := db.Col("assignments").FindOne(ctx, bson.M{
"key_id": keyID,
"server_id": serverID,
"revoked_at": nil,
}).Decode(&existing)
if err == nil {
return &existing, nil
}
a := &models.Assignment{
KeyID: keyID,
ServerID: serverID,
AssignedAt: time.Now(),
}
_, err = db.Col("assignments").InsertOne(ctx, a)
if err != nil {
return nil, err
}
return a, nil
}
func RevokeAssignment(keyID, serverID string) error {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
now := time.Now()
_, err := db.Col("assignments").UpdateOne(ctx,
bson.M{"key_id": keyID, "server_id": serverID, "revoked_at": nil},
bson.M{"$set": bson.M{"revoked_at": now}},
)
return err
}
func GetAssignmentsForKey(keyID string) ([]models.Assignment, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
cursor, err := db.Col("assignments").Find(ctx, bson.M{"key_id": keyID, "revoked_at": nil})
if err != nil {
return nil, err
}
defer cursor.Close(ctx)
var assignments []models.Assignment
if err := cursor.All(ctx, &assignments); err != nil {
return nil, err
}
return assignments, nil
}
type AssignmentWithServer struct {
models.Assignment `bson:",inline"`
Server *models.Server `json:"server,omitempty"`
}
func GetAssignmentsWithServers(keyID string) ([]AssignmentWithServer, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
cursor, err := db.Col("assignments").Find(ctx, bson.M{"key_id": keyID})
if err != nil {
return nil, err
}
defer cursor.Close(ctx)
var assignments []models.Assignment
if err := cursor.All(ctx, &assignments); err != nil {
return nil, err
}
result := make([]AssignmentWithServer, 0, len(assignments))
for _, a := range assignments {
item := AssignmentWithServer{Assignment: a}
var srv models.Server
if err := db.Col("servers").FindOne(ctx, bson.M{"server_id": a.ServerID}).Decode(&srv); err == nil {
item.Server = &srv
}
result = append(result, item)
}
return result, nil
}
type AssignmentWithKey struct {
models.Assignment `bson:",inline"`
Key *models.Key `json:"key,omitempty"`
}
func GetAssignmentsWithKeysForServer(serverID string) ([]AssignmentWithKey, error) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
cursor, err := db.Col("assignments").Find(ctx, bson.M{"server_id": serverID})
if err != nil {
return nil, err
}
defer cursor.Close(ctx)
var assignments []models.Assignment
if err := cursor.All(ctx, &assignments); err != nil {
return nil, err
}
result := make([]AssignmentWithKey, 0, len(assignments))
for _, a := range assignments {
item := AssignmentWithKey{Assignment: a}
var key models.Key
if err := db.Col("keys").FindOne(ctx, bson.M{"key_id": a.KeyID}).Decode(&key); err == nil {
item.Key = &key
}
result = append(result, item)
}
return result, nil
}