// Package kept holds what the layouts of the Delivery domain's kept values share: the version check on reading one, the // rule a name must keep to be a key part, and the form of a digest. It names no seat and no module (ADR 0634 ยง2). The // version itself (keys.Version) and the escaping of a name (keys.EscapeName) are mesh-sdk's, since more than one domain uses // them. package kept import ( "encoding/json" "errors" "fmt" "regexp" "git.novox.be/novox/mesh-sdk/go/keys" ) // ErrUnknownVersion is what Decode returns for a value whose version is missing or not keys.Version. Test it with errors.Is. var ErrUnknownVersion = errors.New("kept: unknown value version") var nameOK = regexp.MustCompile(`^[-/_=a-zA-Z0-9]+$`) // CheckName refuses a name that is empty or holds a dot, a wildcard, whitespace or a character a bus key refuses. func CheckName(kind, name string) error { if name == "" { return fmt.Errorf("kept: the %s name is empty", kind) } if !nameOK.MatchString(name) { return fmt.Errorf("kept: the %s name %q holds a dot, a wildcard, whitespace or a character a key refuses", kind, name) } return nil } var hex64 = regexp.MustCompile(`^[0-9a-f]{64}$`) // IsHex64 says whether s is 64 lowercase hex digits. func IsHex64(s string) bool { return hex64.MatchString(s) } // CheckVersion refuses a value with no version or one this reader does not read. func CheckVersion(data []byte) error { var probe struct { V *int `json:"v"` } if err := json.Unmarshal(data, &probe); err != nil { return fmt.Errorf("kept: value is not JSON: %w", err) } if probe.V == nil { return fmt.Errorf("%w: no version in the value, this reader reads %d", ErrUnknownVersion, keys.Version) } if *probe.V != keys.Version { return fmt.Errorf("%w: the value is version %d, this reader reads %d", ErrUnknownVersion, *probe.V, keys.Version) } return nil } // Decode reads data into into after CheckVersion. func Decode(data []byte, into any) error { if err := CheckVersion(data); err != nil { return err } if err := json.Unmarshal(data, into); err != nil { return fmt.Errorf("kept: value does not fit its shape: %w", err) } return nil } var digestForm = regexp.MustCompile(`^sha256:[0-9a-f]{64}$`) // CheckDigest refuses a digest that is not sha256:<64 lowercase hex digits>, saying what it is of. func CheckDigest(digest, of string) error { if !digestForm.MatchString(digest) { return fmt.Errorf("kept: %s %q is not sha256:<64 lowercase hex digits>", of, digest) } return nil }