package release import ( "bytes" "crypto/ed25519" "encoding/base64" "encoding/json" "errors" "net/url" "github.com/carlosframework/platform/internal/controlname" "github.com/carlosframework/platform/internal/maintenanceguard" ) const MaxWorkerControlBytes = 32 << 10 var ErrWorkerControl = errors.New("worker control record refused") type WorkerHead struct { Schema int `json:"schema"` Kind string `json:"kind"` Deployment string `json:"deployment"` Account string `json:"account"` Box string `json:"box"` PhysicalIdentity string `json:"physical_identity"` Generation int64 `json:"generation"` Revision int64 `json:"revision"` TokenHash string `json:"token_hash"` Status string `json:"status"` Placement string `json:"placement"` Candidate maintenanceguard.Reference `json:"candidate"` Open []maintenanceguard.Reference `json:"open"` } type WorkerAssignmentIdentity struct { Assignment maintenanceguard.Reference `json:"assignment"` Deployment string `json:"deployment"` Box string `json:"box"` Generation int64 `json:"generation"` Account string `json:"account"` App string `json:"app"` Host string `json:"host"` Operation string `json:"operation"` Request string `json:"request"` Attempt string `json:"attempt"` } type WorkerAssignmentState struct { Schema int `json:"schema"` Kind string `json:"kind"` Identity WorkerAssignmentIdentity `json:"identity"` Revision int64 `json:"revision"` Disabled bool `json:"disabled"` Expires int64 `json:"expires_at"` Preflight *maintenanceguard.Reference `json:"preflight,omitempty"` Compatibility *maintenanceguard.Reference `json:"compatibility,omitempty"` Execution *maintenanceguard.Reference `json:"execution,omitempty"` Resume *maintenanceguard.Reference `json:"resume,omitempty"` } func workerOrigin(s string) bool { u, e := url.Parse(s) return e == nil && u.Scheme == "https" && u.User == nil && controlname.ValidHostShape(u.Host) && s == "https://"+u.Host } func workerRef(r maintenanceguard.Reference) bool { return maintenanceguard.ValidID(r.ID) && maintenanceguard.ValidDigest(r.Digest) } func (h WorkerHead) Valid() bool { if h.Schema != 1 || h.Kind != "maintenance-worker" || !workerOrigin(h.Deployment) || !controlname.ValidAccount(h.Account) || !controlname.ValidApp(h.Box) || !maintenanceguard.ValidDigest(h.PhysicalIdentity) || h.Generation <= 0 || h.Revision <= 0 || !maintenanceguard.ValidDigest(h.TokenHash) || (h.Status != "active" && h.Status != "revoking" && h.Status != "detached") || (h.Placement != "" && !controlname.ValidApp(h.Placement)) || !workerRef(h.Candidate) || h.Open == nil || len(h.Open) > 8 || (h.Status == "detached" && len(h.Open) != 0) { return false } seen := map[string]bool{} for _, ref := range h.Open { if !workerRef(ref) || seen[ref.ID] { return false } seen[ref.ID] = true } return true } func (i WorkerAssignmentIdentity) Valid() bool { return workerRef(i.Assignment) && workerOrigin(i.Deployment) && controlname.ValidApp(i.Box) && i.Generation > 0 && controlname.ValidAccount(i.Account) && controlname.ValidApp(i.App) && controlname.ValidHostShape(i.Host) && maintenanceguard.ValidID(i.Operation) && maintenanceguard.ValidID(i.Request) && maintenanceguard.ValidID(i.Attempt) } func (s WorkerAssignmentState) Valid() bool { if s.Schema != 1 || s.Kind != "maintenance-assignment" || !s.Identity.Valid() || s.Revision <= 0 || s.Expires <= 0 { return false } if (s.Compatibility != nil || s.Execution != nil) && s.Preflight == nil || s.Resume != nil && s.Execution == nil { return false } for _, r := range []*maintenanceguard.Reference{s.Preflight, s.Compatibility, s.Execution, s.Resume} { if r != nil && !workerRef(*r) { return false } } return true } // Canonical encoding is part of this new internal wire version. Comparing typed // encoding rejects aliases, duplicate/unknown fields and missing false fields. func decodeWorkerCanonical(raw []byte, dst any) error { if len(raw) == 0 || len(raw) > MaxWorkerControlBytes { return ErrWorkerControl } if json.Unmarshal(raw, dst) != nil { return ErrWorkerControl } canonical, err := json.Marshal(dst) if err != nil { return ErrWorkerControl } var compact bytes.Buffer if json.Compact(&compact, raw) != nil || !bytes.Equal(compact.Bytes(), canonical) { return ErrWorkerControl } return nil } func signRootPayload(sg Signer, payload []byte) ([]byte, error) { if sg.usable() != nil || sg.scope != nil || sg.grant != nil { return nil, ErrWorkerControl } b64 := base64.StdEncoding.EncodeToString(payload) signature := ed25519.Sign(sg.key, []byte(b64)) return json.MarshalIndent(signedWrapper{Payload: b64, Sig: base64.StdEncoding.EncodeToString(signature)}, "", " ") } func verifyWorkerPayload(pub ed25519.PublicKey, wire []byte) ([]byte, error) { var wrapper signedWrapper if decodeWorkerCanonical(wire, &wrapper) != nil || wrapper.Grant != nil || len(pub) != ed25519.PublicKeySize { return nil, ErrWorkerControl } signature, err := base64.StdEncoding.Strict().DecodeString(wrapper.Sig) if err != nil || base64.StdEncoding.EncodeToString(signature) != wrapper.Sig || len(signature) != ed25519.SignatureSize || !ed25519.Verify(pub, []byte(wrapper.Payload), signature) { return nil, ErrWorkerControl } raw, err := base64.StdEncoding.Strict().DecodeString(wrapper.Payload) if err != nil || len(raw) > MaxWorkerControlBytes/2 || base64.StdEncoding.EncodeToString(raw) != wrapper.Payload { return nil, ErrWorkerControl } return raw, nil } func SignWorkerHead(sg Signer, h WorkerHead) ([]byte, error) { if !h.Valid() { return nil, ErrWorkerControl } raw, err := json.Marshal(h) if err != nil { return nil, ErrWorkerControl } return signRootPayload(sg, raw) } func VerifyWorkerHead(pub ed25519.PublicKey, wire []byte) (WorkerHead, error) { var h WorkerHead raw, err := verifyWorkerPayload(pub, wire) if err != nil || decodeWorkerCanonical(raw, &h) != nil || !h.Valid() { return WorkerHead{}, ErrWorkerControl } return h, nil } func SignWorkerAssignment(sg Signer, s WorkerAssignmentState) ([]byte, error) { if !s.Valid() { return nil, ErrWorkerControl } raw, err := json.Marshal(s) if err != nil { return nil, ErrWorkerControl } return signRootPayload(sg, raw) } func VerifyWorkerAssignment(pub ed25519.PublicKey, wire []byte) (WorkerAssignmentState, error) { var s WorkerAssignmentState raw, err := verifyWorkerPayload(pub, wire) if err != nil || decodeWorkerCanonical(raw, &s) != nil || !s.Valid() { return WorkerAssignmentState{}, ErrWorkerControl } return s, nil }