60 lines
1.9 KiB
Go
60 lines
1.9 KiB
Go
// Package keys holds what the mesh's kept values of more than one domain share: the version a kept value carries and
|
|
// the escaping of a name into a key part (novox/hq ADR 0634 §1, §4; they were go/delivery's and are used by the
|
|
// Delivery, Placement and Identity and access domains alike). It names no seat and no module.
|
|
package keys
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
// Version is the version of every kept value that carries one and the only one its readers read.
|
|
const Version = 1
|
|
|
|
var nameOK = regexp.MustCompile(`^[-/_=a-zA-Z0-9]+$`)
|
|
|
|
// 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.
|
|
func EscapeName(name string) string {
|
|
var b strings.Builder
|
|
for i := 0; i < len(name); i++ {
|
|
c := name[i]
|
|
switch {
|
|
case c >= 'a' && c <= 'z', c >= 'A' && c <= 'Z', c >= '0' && c <= '9', c == '-', c == '/', c == '_':
|
|
b.WriteByte(c)
|
|
default:
|
|
fmt.Fprintf(&b, "=%02x", c)
|
|
}
|
|
}
|
|
return b.String()
|
|
}
|
|
|
|
// UnescapeName is the inverse of EscapeName; it refuses a part with a bare `=` or any character EscapeName leaves
|
|
// escaped.
|
|
func UnescapeName(part string) (string, error) {
|
|
var out []byte
|
|
for i := 0; i < len(part); i++ {
|
|
c := part[i]
|
|
if c != '=' {
|
|
if !nameOK.MatchString(string(c)) {
|
|
return "", fmt.Errorf("keys: %q holds %q, which a key part escapes", part, c)
|
|
}
|
|
out = append(out, c)
|
|
continue
|
|
}
|
|
if i+3 > len(part) {
|
|
return "", fmt.Errorf("keys: %q ends in an incomplete escape", part)
|
|
}
|
|
v, err := hex.DecodeString(part[i+1 : i+3])
|
|
if err != nil || part[i+1:i+3] != strings.ToLower(part[i+1:i+3]) {
|
|
return "", fmt.Errorf("keys: %q holds a malformed escape %q", part, part[i:i+3])
|
|
}
|
|
out = append(out, v[0])
|
|
i += 2
|
|
}
|
|
return string(out), nil
|
|
}
|