refactor: share LNS name normalization
This commit is contained in:
parent
f03fc28ae0
commit
f987dde471
3 changed files with 80 additions and 91 deletions
68
internal/nameutil/name.go
Normal file
68
internal/nameutil/name.go
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// SPDX-License-Identifier: EUPL-1.2
|
||||
|
||||
package nameutil
|
||||
|
||||
import core "dappco.re/go/core"
|
||||
|
||||
// CatalogLabel converts string and byte inputs into a raw catalog label.
|
||||
//
|
||||
// It accepts the same input types as the public service helpers and preserves
|
||||
// the bytes exactly, without applying canonical name suffix trimming.
|
||||
func CatalogLabel(name any) (string, bool) {
|
||||
switch v := name.(type) {
|
||||
case string:
|
||||
return v, true
|
||||
case []byte:
|
||||
return string(v), true
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
|
||||
// Canonicalize normalizes string and byte inputs into a lowercased LNS label.
|
||||
//
|
||||
// The helper rejects non-ASCII input, lowercases ASCII letters, and strips the
|
||||
// optional trailing `.lthn` or trailing dot suffix used by service callers.
|
||||
func Canonicalize(name any) (string, bool) {
|
||||
var value []byte
|
||||
|
||||
switch v := name.(type) {
|
||||
case string:
|
||||
value = []byte(v)
|
||||
case []byte:
|
||||
value = append([]byte(nil), v...)
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
|
||||
if len(value) == 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
for i := range value {
|
||||
if value[i]&0x80 != 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
if value[i] >= 'A' && value[i] <= 'Z' {
|
||||
value[i] += 'a' - 'A'
|
||||
}
|
||||
}
|
||||
|
||||
str := string(value)
|
||||
|
||||
switch {
|
||||
case core.HasSuffix(str, ".lthn."):
|
||||
str = core.TrimSuffix(str, ".lthn.")
|
||||
case core.HasSuffix(str, ".lthn"):
|
||||
str = core.TrimSuffix(str, ".lthn")
|
||||
case core.HasSuffix(str, "."):
|
||||
str = core.TrimSuffix(str, ".")
|
||||
}
|
||||
|
||||
if len(str) == 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
return str, true
|
||||
}
|
||||
68
lns.go
68
lns.go
|
|
@ -14,6 +14,7 @@ package lns
|
|||
|
||||
import (
|
||||
core "dappco.re/go/core"
|
||||
"dappco.re/go/lns/internal/nameutil"
|
||||
"dappco.re/go/lns/pkg/covenant"
|
||||
"dappco.re/go/lns/pkg/primitives"
|
||||
)
|
||||
|
|
@ -136,7 +137,7 @@ func (s *Service) HashByBinary(name []byte) (primitives.Hash, error) {
|
|||
|
||||
// ResolveString returns the canonical hash for a .lthn name supplied as a string.
|
||||
func (s *Service) ResolveString(name string) (primitives.Hash, error) {
|
||||
normalized, ok := canonicalizeName(name)
|
||||
normalized, ok := nameutil.Canonicalize(name)
|
||||
if !ok {
|
||||
return primitives.Hash{}, core.E("lns.Service.ResolveString", "invalid name", nil)
|
||||
}
|
||||
|
|
@ -146,7 +147,7 @@ func (s *Service) ResolveString(name string) (primitives.Hash, error) {
|
|||
|
||||
// ResolveBinary returns the canonical hash for a .lthn name supplied as bytes.
|
||||
func (s *Service) ResolveBinary(name []byte) (primitives.Hash, error) {
|
||||
normalized, ok := canonicalizeName(name)
|
||||
normalized, ok := nameutil.Canonicalize(name)
|
||||
if !ok {
|
||||
return primitives.Hash{}, core.E("lns.Service.ResolveBinary", "invalid name", nil)
|
||||
}
|
||||
|
|
@ -212,7 +213,7 @@ func (s *Service) VerifyByName(name any) bool {
|
|||
//
|
||||
// ok := svc.VerifyString("example.lthn")
|
||||
func (s *Service) VerifyString(name string) bool {
|
||||
normalized, ok := canonicalizeName(name)
|
||||
normalized, ok := nameutil.Canonicalize(name)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
|
@ -224,7 +225,7 @@ func (s *Service) VerifyString(name string) bool {
|
|||
//
|
||||
// ok := svc.VerifyBinary([]byte("example.lthn"))
|
||||
func (s *Service) VerifyBinary(name []byte) bool {
|
||||
normalized, ok := canonicalizeName(name)
|
||||
normalized, ok := nameutil.Canonicalize(name)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
|
@ -270,7 +271,7 @@ func (s *Service) GetReserved(name any) (covenant.ReservedName, bool) {
|
|||
// svc := c.Service("lns").(*lns.Service)
|
||||
// item, ok := svc.GetReservedName("reserved")
|
||||
func (s *Service) GetReservedName(name any) (covenant.ReservedName, bool) {
|
||||
if label, ok := catalogLabel(name); ok {
|
||||
if label, ok := nameutil.CatalogLabel(name); ok {
|
||||
if item, ok := covenant.GetReservedName(label); ok {
|
||||
return item, true
|
||||
}
|
||||
|
|
@ -433,7 +434,7 @@ func (s *Service) GetLocked(name any) (covenant.LockedName, bool) {
|
|||
// svc := c.Service("lns").(*lns.Service)
|
||||
// item, ok := svc.GetLockedName("nec")
|
||||
func (s *Service) GetLockedName(name any) (covenant.LockedName, bool) {
|
||||
if label, ok := catalogLabel(name); ok {
|
||||
if label, ok := nameutil.CatalogLabel(name); ok {
|
||||
if item, ok := covenant.GetLockedName(label); ok {
|
||||
return item, true
|
||||
}
|
||||
|
|
@ -791,58 +792,3 @@ func (s *Service) LockedValues() []covenant.LockedName {
|
|||
func (s *Service) GetLockedValues() []covenant.LockedName {
|
||||
return s.LockedValues()
|
||||
}
|
||||
|
||||
func catalogLabel(name any) (string, bool) {
|
||||
switch v := name.(type) {
|
||||
case string:
|
||||
return v, true
|
||||
case []byte:
|
||||
return string(v), true
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
}
|
||||
|
||||
func canonicalizeName(name any) (string, bool) {
|
||||
var value []byte
|
||||
|
||||
switch v := name.(type) {
|
||||
case string:
|
||||
value = []byte(v)
|
||||
case []byte:
|
||||
value = append([]byte(nil), v...)
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
|
||||
if len(value) == 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
for i := range value {
|
||||
if value[i]&0x80 != 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
if value[i] >= 'A' && value[i] <= 'Z' {
|
||||
value[i] += 'a' - 'A'
|
||||
}
|
||||
}
|
||||
|
||||
str := string(value)
|
||||
|
||||
switch {
|
||||
case core.HasSuffix(str, ".lthn."):
|
||||
str = core.TrimSuffix(str, ".lthn.")
|
||||
case core.HasSuffix(str, ".lthn"):
|
||||
str = core.TrimSuffix(str, ".lthn")
|
||||
case core.HasSuffix(str, "."):
|
||||
str = core.TrimSuffix(str, ".")
|
||||
}
|
||||
|
||||
if len(str) == 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
return str, true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ package dns
|
|||
|
||||
import (
|
||||
core "dappco.re/go/core"
|
||||
"dappco.re/go/lns/internal/nameutil"
|
||||
"dappco.re/go/lns/pkg/covenant"
|
||||
"dappco.re/go/lns/pkg/primitives"
|
||||
)
|
||||
|
|
@ -60,7 +61,7 @@ func WithCore(c *core.Core) ServiceOption {
|
|||
// svc := dns.NewService()
|
||||
// hash, err := svc.Resolve("example.lthn")
|
||||
func (s *Service) Resolve(name any) (primitives.Hash, error) {
|
||||
normalized, ok := canonicalizeName(name)
|
||||
normalized, ok := nameutil.Canonicalize(name)
|
||||
if !ok {
|
||||
return primitives.Hash{}, core.E("dns.Service.Resolve", "invalid name type", nil)
|
||||
}
|
||||
|
|
@ -87,7 +88,7 @@ func (s *Service) Hash(name any) (primitives.Hash, error) {
|
|||
// svc := dns.NewService()
|
||||
// ok := svc.Verify("example.lthn")
|
||||
func (s *Service) Verify(name any) bool {
|
||||
normalized, ok := canonicalizeName(name)
|
||||
normalized, ok := nameutil.Canonicalize(name)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
|
@ -150,7 +151,7 @@ func (s *Service) ResolveString(name string) (primitives.Hash, error) {
|
|||
// svc := dns.NewService()
|
||||
// hash, err := svc.ResolveBinary([]byte("example.lthn"))
|
||||
func (s *Service) ResolveBinary(name []byte) (primitives.Hash, error) {
|
||||
normalized, ok := canonicalizeName(name)
|
||||
normalized, ok := nameutil.Canonicalize(name)
|
||||
if !ok {
|
||||
return primitives.Hash{}, core.E("dns.Service.ResolveBinary", "invalid name type", nil)
|
||||
}
|
||||
|
|
@ -188,7 +189,7 @@ func (s *Service) VerifyString(name string) bool {
|
|||
// svc := dns.NewService()
|
||||
// ok := svc.VerifyBinary([]byte("example.lthn"))
|
||||
func (s *Service) VerifyBinary(name []byte) bool {
|
||||
normalized, ok := canonicalizeName(name)
|
||||
normalized, ok := nameutil.Canonicalize(name)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
|
@ -240,29 +241,3 @@ func (s *Service) HashByName(name any) (primitives.Hash, error) {
|
|||
func (s *Service) VerifyByName(name any) bool {
|
||||
return s.VerifyName(name)
|
||||
}
|
||||
|
||||
func canonicalizeName(name any) (string, bool) {
|
||||
var value string
|
||||
|
||||
switch v := name.(type) {
|
||||
case string:
|
||||
value = v
|
||||
case []byte:
|
||||
value = string(v)
|
||||
default:
|
||||
return "", false
|
||||
}
|
||||
|
||||
value = core.Lower(value)
|
||||
|
||||
switch {
|
||||
case core.HasSuffix(value, ".lthn."):
|
||||
value = core.TrimSuffix(value, ".lthn.")
|
||||
case core.HasSuffix(value, ".lthn"):
|
||||
value = core.TrimSuffix(value, ".lthn")
|
||||
case core.HasSuffix(value, "."):
|
||||
value = core.TrimSuffix(value, ".")
|
||||
}
|
||||
|
||||
return value, true
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue