install.sh + frontend: use external URL dsbmueller.spdns.org:8443, configurable via RMM_BACKEND env
This commit is contained in:
@@ -182,6 +182,15 @@ func (d *Database) migrate() error {
|
||||
// Indices fuer Metrics
|
||||
d.db.Exec(`CREATE INDEX IF NOT EXISTS idx_metrics_agent_metric ON metrics(agent_id, metric, time DESC)`)
|
||||
|
||||
// API-Keys Tabelle
|
||||
d.db.Exec(`CREATE TABLE IF NOT EXISTS api_keys (
|
||||
id SERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
key TEXT NOT NULL UNIQUE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
last_used TIMESTAMPTZ
|
||||
)`)
|
||||
|
||||
// Retention Policy (90 Tage)
|
||||
d.setupRetention()
|
||||
|
||||
@@ -954,3 +963,96 @@ func (d *Database) GetAgentStatus(agentID string) string {
|
||||
}
|
||||
return models.CalculateAgentStatus(&lastHB.Time)
|
||||
}
|
||||
|
||||
// ==================== API-Keys ====================
|
||||
|
||||
type APIKey struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
LastUsed *time.Time `json:"last_used,omitempty"`
|
||||
}
|
||||
|
||||
func (d *Database) ListAPIKeys() ([]APIKey, error) {
|
||||
rows, err := d.db.Query("SELECT id, name, key, created_at, last_used FROM api_keys ORDER BY created_at")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var keys []APIKey
|
||||
for rows.Next() {
|
||||
var k APIKey
|
||||
var lastUsed sql.NullTime
|
||||
if err := rows.Scan(&k.ID, &k.Name, &k.Key, &k.CreatedAt, &lastUsed); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if lastUsed.Valid {
|
||||
k.LastUsed = &lastUsed.Time
|
||||
}
|
||||
keys = append(keys, k)
|
||||
}
|
||||
if keys == nil {
|
||||
keys = []APIKey{}
|
||||
}
|
||||
return keys, rows.Err()
|
||||
}
|
||||
|
||||
func (d *Database) CreateAPIKey(name, key string) (*APIKey, error) {
|
||||
var k APIKey
|
||||
err := d.db.QueryRow(
|
||||
"INSERT INTO api_keys (name, key) VALUES ($1, $2) RETURNING id, name, key, created_at",
|
||||
name, key,
|
||||
).Scan(&k.ID, &k.Name, &k.Key, &k.CreatedAt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &k, nil
|
||||
}
|
||||
|
||||
func (d *Database) DeleteAPIKey(id int) error {
|
||||
result, err := d.db.Exec("DELETE FROM api_keys WHERE id = $1", id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rows, _ := result.RowsAffected()
|
||||
if rows == 0 {
|
||||
return fmt.Errorf("API-Key nicht gefunden")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Database) GetAllAPIKeys() ([]string, error) {
|
||||
rows, err := d.db.Query("SELECT key FROM api_keys")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var keys []string
|
||||
for rows.Next() {
|
||||
var k string
|
||||
if err := rows.Scan(&k); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return keys, rows.Err()
|
||||
}
|
||||
|
||||
func (d *Database) UpdateAPIKeyLastUsed(key string) {
|
||||
d.db.Exec("UPDATE api_keys SET last_used = NOW() WHERE key = $1", key)
|
||||
}
|
||||
|
||||
// MigrateConfigAPIKeys migriert API-Keys aus der Config in die DB (einmalig)
|
||||
func (d *Database) MigrateConfigAPIKeys(configKeys []string) {
|
||||
for _, key := range configKeys {
|
||||
var exists bool
|
||||
d.db.QueryRow("SELECT EXISTS(SELECT 1 FROM api_keys WHERE key = $1)", key).Scan(&exists)
|
||||
if !exists {
|
||||
d.db.Exec("INSERT INTO api_keys (name, key) VALUES ($1, $2)", "Default (migriert)", key)
|
||||
log.Printf("API-Key aus Config migriert: %s...", key[:8])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user