Multi-host phase 1: API tokens, auto TLS with pinned fingerprints, hub-side node manager + reverse proxy (WebSockets included), machine switcher in the rail, Machines page
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
fc42675e9f
commit
7dcdb5dc98
@@ -3,6 +3,7 @@ package auth
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
@@ -59,6 +60,35 @@ func VerifyPassword(hash, pw string) bool {
|
||||
return subtle.ConstantTimeCompare(got, want) == 1
|
||||
}
|
||||
|
||||
// ---- API tokens (hub → node) ----
|
||||
|
||||
// NewToken returns a random bearer token and its SHA-256 hex, which is what gets stored.
|
||||
func NewToken() (token, hash string, err error) {
|
||||
b := make([]byte, 32)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
token = base64.RawURLEncoding.EncodeToString(b)
|
||||
return token, HashToken(token), nil
|
||||
}
|
||||
|
||||
func HashToken(token string) string {
|
||||
sum := sha256.Sum256([]byte(token))
|
||||
return hex.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
// TokenMatches compares a presented token against stored hashes in constant time.
|
||||
func TokenMatches(token string, hashes []string) bool {
|
||||
h := []byte(HashToken(token))
|
||||
ok := false
|
||||
for _, want := range hashes {
|
||||
if subtle.ConstantTimeCompare(h, []byte(want)) == 1 {
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
return ok
|
||||
}
|
||||
|
||||
// Sessions is a token store backed by the state file. Expiry is sliding.
|
||||
type Sessions struct {
|
||||
st *store.Store
|
||||
|
||||
Reference in New Issue
Block a user