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 (
|
import (
|
||||||
core "dappco.re/go/core"
|
core "dappco.re/go/core"
|
||||||
|
"dappco.re/go/lns/internal/nameutil"
|
||||||
"dappco.re/go/lns/pkg/covenant"
|
"dappco.re/go/lns/pkg/covenant"
|
||||||
"dappco.re/go/lns/pkg/primitives"
|
"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.
|
// ResolveString returns the canonical hash for a .lthn name supplied as a string.
|
||||||
func (s *Service) ResolveString(name string) (primitives.Hash, error) {
|
func (s *Service) ResolveString(name string) (primitives.Hash, error) {
|
||||||
normalized, ok := canonicalizeName(name)
|
normalized, ok := nameutil.Canonicalize(name)
|
||||||
if !ok {
|
if !ok {
|
||||||
return primitives.Hash{}, core.E("lns.Service.ResolveString", "invalid name", nil)
|
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.
|
// ResolveBinary returns the canonical hash for a .lthn name supplied as bytes.
|
||||||
func (s *Service) ResolveBinary(name []byte) (primitives.Hash, error) {
|
func (s *Service) ResolveBinary(name []byte) (primitives.Hash, error) {
|
||||||
normalized, ok := canonicalizeName(name)
|
normalized, ok := nameutil.Canonicalize(name)
|
||||||
if !ok {
|
if !ok {
|
||||||
return primitives.Hash{}, core.E("lns.Service.ResolveBinary", "invalid name", nil)
|
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")
|
// ok := svc.VerifyString("example.lthn")
|
||||||
func (s *Service) VerifyString(name string) bool {
|
func (s *Service) VerifyString(name string) bool {
|
||||||
normalized, ok := canonicalizeName(name)
|
normalized, ok := nameutil.Canonicalize(name)
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -224,7 +225,7 @@ func (s *Service) VerifyString(name string) bool {
|
||||||
//
|
//
|
||||||
// ok := svc.VerifyBinary([]byte("example.lthn"))
|
// ok := svc.VerifyBinary([]byte("example.lthn"))
|
||||||
func (s *Service) VerifyBinary(name []byte) bool {
|
func (s *Service) VerifyBinary(name []byte) bool {
|
||||||
normalized, ok := canonicalizeName(name)
|
normalized, ok := nameutil.Canonicalize(name)
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -270,7 +271,7 @@ func (s *Service) GetReserved(name any) (covenant.ReservedName, bool) {
|
||||||
// svc := c.Service("lns").(*lns.Service)
|
// svc := c.Service("lns").(*lns.Service)
|
||||||
// item, ok := svc.GetReservedName("reserved")
|
// item, ok := svc.GetReservedName("reserved")
|
||||||
func (s *Service) GetReservedName(name any) (covenant.ReservedName, bool) {
|
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 {
|
if item, ok := covenant.GetReservedName(label); ok {
|
||||||
return item, true
|
return item, true
|
||||||
}
|
}
|
||||||
|
|
@ -433,7 +434,7 @@ func (s *Service) GetLocked(name any) (covenant.LockedName, bool) {
|
||||||
// svc := c.Service("lns").(*lns.Service)
|
// svc := c.Service("lns").(*lns.Service)
|
||||||
// item, ok := svc.GetLockedName("nec")
|
// item, ok := svc.GetLockedName("nec")
|
||||||
func (s *Service) GetLockedName(name any) (covenant.LockedName, bool) {
|
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 {
|
if item, ok := covenant.GetLockedName(label); ok {
|
||||||
return item, true
|
return item, true
|
||||||
}
|
}
|
||||||
|
|
@ -791,58 +792,3 @@ func (s *Service) LockedValues() []covenant.LockedName {
|
||||||
func (s *Service) GetLockedValues() []covenant.LockedName {
|
func (s *Service) GetLockedValues() []covenant.LockedName {
|
||||||
return s.LockedValues()
|
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 (
|
import (
|
||||||
core "dappco.re/go/core"
|
core "dappco.re/go/core"
|
||||||
|
"dappco.re/go/lns/internal/nameutil"
|
||||||
"dappco.re/go/lns/pkg/covenant"
|
"dappco.re/go/lns/pkg/covenant"
|
||||||
"dappco.re/go/lns/pkg/primitives"
|
"dappco.re/go/lns/pkg/primitives"
|
||||||
)
|
)
|
||||||
|
|
@ -60,7 +61,7 @@ func WithCore(c *core.Core) ServiceOption {
|
||||||
// svc := dns.NewService()
|
// svc := dns.NewService()
|
||||||
// hash, err := svc.Resolve("example.lthn")
|
// hash, err := svc.Resolve("example.lthn")
|
||||||
func (s *Service) Resolve(name any) (primitives.Hash, error) {
|
func (s *Service) Resolve(name any) (primitives.Hash, error) {
|
||||||
normalized, ok := canonicalizeName(name)
|
normalized, ok := nameutil.Canonicalize(name)
|
||||||
if !ok {
|
if !ok {
|
||||||
return primitives.Hash{}, core.E("dns.Service.Resolve", "invalid name type", nil)
|
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()
|
// svc := dns.NewService()
|
||||||
// ok := svc.Verify("example.lthn")
|
// ok := svc.Verify("example.lthn")
|
||||||
func (s *Service) Verify(name any) bool {
|
func (s *Service) Verify(name any) bool {
|
||||||
normalized, ok := canonicalizeName(name)
|
normalized, ok := nameutil.Canonicalize(name)
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -150,7 +151,7 @@ func (s *Service) ResolveString(name string) (primitives.Hash, error) {
|
||||||
// svc := dns.NewService()
|
// svc := dns.NewService()
|
||||||
// hash, err := svc.ResolveBinary([]byte("example.lthn"))
|
// hash, err := svc.ResolveBinary([]byte("example.lthn"))
|
||||||
func (s *Service) ResolveBinary(name []byte) (primitives.Hash, error) {
|
func (s *Service) ResolveBinary(name []byte) (primitives.Hash, error) {
|
||||||
normalized, ok := canonicalizeName(name)
|
normalized, ok := nameutil.Canonicalize(name)
|
||||||
if !ok {
|
if !ok {
|
||||||
return primitives.Hash{}, core.E("dns.Service.ResolveBinary", "invalid name type", nil)
|
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()
|
// svc := dns.NewService()
|
||||||
// ok := svc.VerifyBinary([]byte("example.lthn"))
|
// ok := svc.VerifyBinary([]byte("example.lthn"))
|
||||||
func (s *Service) VerifyBinary(name []byte) bool {
|
func (s *Service) VerifyBinary(name []byte) bool {
|
||||||
normalized, ok := canonicalizeName(name)
|
normalized, ok := nameutil.Canonicalize(name)
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -240,29 +241,3 @@ func (s *Service) HashByName(name any) (primitives.Hash, error) {
|
||||||
func (s *Service) VerifyByName(name any) bool {
|
func (s *Service) VerifyByName(name any) bool {
|
||||||
return s.VerifyName(name)
|
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