69 lines
2.3 KiB
Go
69 lines
2.3 KiB
Go
package machine_identity
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/ed25519"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"errors"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
type registryDocument struct {
|
|
Version string `json:"version"`
|
|
Audience string `json:"audience"`
|
|
Principals []registryPrincipal `json:"principals"`
|
|
}
|
|
|
|
type registryPrincipal struct {
|
|
PrincipalID string `json:"principal_id"`
|
|
Enabled bool `json:"enabled"`
|
|
Keys []registryKey `json:"keys"`
|
|
}
|
|
|
|
type registryKey struct {
|
|
KeyID string `json:"kid"`
|
|
PublicKey string `json:"public_key_base64url"`
|
|
Status string `json:"status"`
|
|
Scopes []string `json:"scopes"`
|
|
}
|
|
|
|
func LoadRegistry(filePath, expectedAudience string) (*Registry, error) {
|
|
if strings.TrimSpace(filePath) == "" || !validAudiences[expectedAudience] {
|
|
return nil, errors.New("machine principal registry path and audience are required")
|
|
}
|
|
raw, err := os.ReadFile(filePath)
|
|
if err != nil {
|
|
return nil, errors.New("read machine principal registry")
|
|
}
|
|
decoder := json.NewDecoder(bytes.NewReader(raw))
|
|
decoder.DisallowUnknownFields()
|
|
var document registryDocument
|
|
if err = decoder.Decode(&document); err != nil {
|
|
return nil, errors.New("invalid machine principal registry")
|
|
}
|
|
if err = decoder.Decode(&struct{}{}); !errors.Is(err, io.EOF) {
|
|
return nil, errors.New("invalid machine principal registry")
|
|
}
|
|
if document.Version != "yovision.machine-principal-registry/v1" || document.Audience != expectedAudience || len(document.Principals) == 0 {
|
|
return nil, errors.New("invalid machine principal registry")
|
|
}
|
|
records := make([]KeyRecord, 0)
|
|
for _, principal := range document.Principals {
|
|
if len(principal.Keys) == 0 {
|
|
return nil, errors.New("invalid machine principal registry")
|
|
}
|
|
for _, key := range principal.Keys {
|
|
publicKey, decodeErr := base64.RawURLEncoding.Strict().DecodeString(key.PublicKey)
|
|
if decodeErr != nil || len(publicKey) != ed25519.PublicKeySize || (key.Status != "active" && key.Status != "revoked") {
|
|
return nil, errors.New("invalid machine principal registry")
|
|
}
|
|
records = append(records, KeyRecord{Principal: principal.PrincipalID, KeyID: key.KeyID, PublicKey: ed25519.PublicKey(publicKey), Audience: document.Audience,
|
|
Scopes: key.Scopes, Enabled: principal.Enabled, Revoked: key.Status == "revoked"})
|
|
}
|
|
}
|
|
return NewRegistry(records...)
|
|
}
|