fix(auth): repair persistence layer and stop storing plaintext keys
- Store SHA-256 digests (key_hash + key_preview) instead of raw keys, in both the in-memory store and Postgres; migrate legacy plaintext rows in place and drop the plaintext column. - Fix TEXT[] scans that failed at runtime (missing pq.Array) in GetKey/ListKeys/LoadAllKeys. - Load persisted keys at startup (InitializeFromDatabase was never called) and fall back to the database on cache miss, so issued keys survive restarts. - Make HybridKeyStore.CreateKey genuinely write-through: cache is only updated after a successful DB write. - Guard nil database backend (auth enabled without DB previously panicked on key creation) and degrade to in-memory operation. - Persist bootstrap admin keys when a database is configured. - Record real audit-log details as JSON and log audit failures instead of silently dropping them; add DB pool limits and ping timeout. - Sentinel errors matched with errors.Is; unit tests for hashing, write-through ordering, DB fallback, and nil-DB operation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+3
-3
@@ -2,10 +2,10 @@ package rest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
@@ -173,7 +173,7 @@ func (h *KeyManagementHandler) ListKeys(w http.ResponseWriter, r *http.Request)
|
||||
keyInfos := make([]*KeyInfo, len(keys))
|
||||
for i, key := range keys {
|
||||
keyInfos[i] = &KeyInfo{
|
||||
Key: "nk_" + key.Key[len(key.Key)-4:], // Show only last 4 chars
|
||||
Key: key.KeyPreview, // non-sensitive preview, e.g. "nk_…ab12"
|
||||
Name: key.Name,
|
||||
ClientID: key.ClientID,
|
||||
Roles: key.Roles,
|
||||
@@ -214,7 +214,7 @@ func (h *KeyManagementHandler) RevokeKey(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
err := h.keyStore.DeactivateKeyByName(ctx, keyName, authCtx.ClientID)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "not found") {
|
||||
if errors.Is(err, auth.ErrKeyNotFound) {
|
||||
h.respondError(w, http.StatusNotFound, "Key not found", "")
|
||||
} else {
|
||||
h.logger.Errorf("Failed to revoke API key: %v", err)
|
||||
|
||||
Reference in New Issue
Block a user