keys: the version check, CheckName and IsHex64 move here from the Delivery domain's kept package, since Delivery and Identity and access share them (ADR 0634 §1, §4; issue 1966)
Claude-Session: https://claude.ai/code/session_01NcbgfFSnn24M3GcqttoU7i
This commit is contained in:
@@ -5,6 +5,8 @@ package keys
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -15,6 +17,43 @@ const Version = 1
|
||||
|
||||
var nameOK = regexp.MustCompile(`^[-/_=a-zA-Z0-9]+$`)
|
||||
|
||||
// ErrUnknownVersion is what CheckVersion returns for a value whose version is missing or not Version. Test it with
|
||||
// errors.Is.
|
||||
var ErrUnknownVersion = errors.New("keys: unknown value version")
|
||||
|
||||
// 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("keys: value is not JSON: %w", err)
|
||||
}
|
||||
if probe.V == nil {
|
||||
return fmt.Errorf("%w: no version in the value, this reader reads %d", ErrUnknownVersion, Version)
|
||||
}
|
||||
if *probe.V != Version {
|
||||
return fmt.Errorf("%w: the value is version %d, this reader reads %d", ErrUnknownVersion, *probe.V, Version)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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("keys: the %s name is empty", kind)
|
||||
}
|
||||
if !nameOK.MatchString(name) {
|
||||
return fmt.Errorf("keys: 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) }
|
||||
|
||||
// EscapeName is name as a key part: a character outside letters, digits, `-`, `/` and `_` is written `=` and its
|
||||
// two lowercase hex digits per byte, and `=` itself is escaped, so any non-empty name keys and a name of allowed
|
||||
// characters only keys as it is. UnescapeName is its inverse.
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package keys
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@@ -27,3 +28,23 @@ func TestNamesEscapeIntoKeyPartsAndBack(t *testing.T) {
|
||||
t.Errorf("Version = %d: a kept value's readers read the one version", Version)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAKeptValueIsReadOnlyAtItsVersionAndAKeyPartOnlyOfKeyCharacters(t *testing.T) {
|
||||
for data, ok := range map[string]bool{`{"v":1}`: true, `{"v":2}`: false, `{}`: false} {
|
||||
err := CheckVersion([]byte(data))
|
||||
if (err == nil) != ok || (!ok && !errors.Is(err, ErrUnknownVersion)) {
|
||||
t.Errorf("CheckVersion(%s) = %v", data, err)
|
||||
}
|
||||
}
|
||||
if CheckVersion([]byte(`nope`)) == nil {
|
||||
t.Error("a value that is no JSON is read")
|
||||
}
|
||||
for name, ok := range map[string]bool{"a-b_c/d=": true, "": false, "a.b": false, "a b": false, "a*": false} {
|
||||
if (CheckName("module", name) == nil) != ok {
|
||||
t.Errorf("CheckName(%q) = %v", name, CheckName("module", name))
|
||||
}
|
||||
}
|
||||
if !IsHex64(strings.Repeat("a", 64)) || IsHex64(strings.Repeat("A", 64)) || IsHex64("a") {
|
||||
t.Error("IsHex64 reads a wrong form")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user