Code sync, security fixes
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
// Package ids generates and validates the identifiers used across Relata.
|
||||
//
|
||||
// Every persisted record uses a UUIDv4 string primary key. Chunk IDs are used
|
||||
// verbatim as Qdrant point IDs, which Qdrant accepts in UUID form; that removes
|
||||
// any need for a separate ID mapping table.
|
||||
package ids
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// New returns a random UUIDv4 string.
|
||||
func New() string { return uuid.NewString() }
|
||||
|
||||
// Valid reports whether s is a well-formed UUID. Used to reject client-supplied
|
||||
// identifiers before they reach a database query.
|
||||
func Valid(s string) bool {
|
||||
if len(s) != 36 {
|
||||
return false
|
||||
}
|
||||
_, err := uuid.Parse(s)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// Token returns a URL-safe random string with n bytes of entropy, used for
|
||||
// session and CSRF tokens.
|
||||
func Token(n int) (string, error) {
|
||||
b := make([]byte, n)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.RawURLEncoding.EncodeToString(b), nil
|
||||
}
|
||||
|
||||
// HashToken returns the hex SHA-256 of a token. Sessions store this rather than
|
||||
// the token itself so that database contents cannot be replayed as credentials.
|
||||
func HashToken(tok string) string {
|
||||
sum := sha256.Sum256([]byte(tok))
|
||||
return hex.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
// Deterministic derives a stable UUID from parts, used for idempotency keys and
|
||||
// dedupe keys so that reprocessing replaces rather than duplicates records.
|
||||
func Deterministic(parts ...string) string {
|
||||
h := sha256.New()
|
||||
for _, p := range parts {
|
||||
h.Write([]byte(p))
|
||||
h.Write([]byte{0}) // separator prevents ("ab","c") colliding with ("a","bc")
|
||||
}
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// DeterministicUUID derives a stable UUIDv5-shaped identifier from parts. Used
|
||||
// where a UUID is structurally required (Qdrant point IDs) but the value must be
|
||||
// reproducible across runs.
|
||||
func DeterministicUUID(parts ...string) string {
|
||||
h := sha256.New()
|
||||
for _, p := range parts {
|
||||
h.Write([]byte(p))
|
||||
h.Write([]byte{0})
|
||||
}
|
||||
sum := h.Sum(nil)
|
||||
var u uuid.UUID
|
||||
copy(u[:], sum[:16])
|
||||
u[6] = (u[6] & 0x0f) | 0x50 // version 5
|
||||
u[8] = (u[8] & 0x3f) | 0x80 // RFC 4122 variant
|
||||
return u.String()
|
||||
}
|
||||
Reference in New Issue
Block a user