Normalize covenant catalog lookups

This commit is contained in:
Virgil 2026-04-02 14:17:08 +00:00
parent 55fd86a33e
commit 91ec180a86
5 changed files with 58 additions and 10 deletions

View file

@ -44,6 +44,9 @@ var (
)
// HasLockedName reports whether the JS lockup table contains the name.
//
// Lookup is case-insensitive and accepts a canonical `.lthn` suffix in
// addition to bare labels.
func HasLockedName(name string) bool {
return DefaultLockedCatalog().HasByName(name)
}
@ -64,6 +67,9 @@ func HasLockedBinary(name []byte) bool {
}
// GetLockedName returns the locked-name entry for the provided label.
//
// The input is lower-cased before hashing, and canonical `.lthn` suffixes are
// stripped before lookup.
func GetLockedName(name string) (LockedName, bool) {
return DefaultLockedCatalog().GetByName(name)
}
@ -195,8 +201,8 @@ func (c *LockedCatalog) HasByName(name string) bool {
// GetByName returns the locked-name entry for the provided label.
//
// The lookup lower-cases ASCII input and hashes it directly, matching the JS
// reference helper's ASCII encoding behavior.
// The lookup lower-cases ASCII input, strips canonical `.lthn` suffixes, and
// hashes the normalized label directly.
func (c *LockedCatalog) GetByName(name string) (LockedName, bool) {
name, ok := asciiLowerName(name)
if !ok {

View file

@ -128,6 +128,19 @@ func TestLockedLookupStringAndBinaryAliases(t *testing.T) {
if !HasLockedByBinary([]byte("NEC")) {
t.Fatal("HasLockedByBinary should report locked catalog labels")
}
item, ok = GetLockedName("nec.lthn")
if !ok {
t.Fatal("GetLockedName should accept canonical .lthn names")
}
if item.Name != "nec" {
t.Fatalf("item.Name = %q, want %q", item.Name, "nec")
}
if !HasLockedName("nec.lthn") {
t.Fatal("HasLockedName should accept canonical .lthn names")
}
}
func TestLockedLookupHasByHashAlias(t *testing.T) {

View file

@ -2,11 +2,13 @@
package covenant
import "bytes"
// asciiLowerName lower-cases ASCII labels without performing Unicode
// case-folding. The JS reference uses ASCII encoding for these catalog lookups,
// so non-ASCII input is rejected instead of being hashed differently.
// case-folding. The helper also strips an optional canonical `.lthn` suffix so
// the catalog lookups accept the same normalized forms as the top-level LNS API.
func asciiLowerName(name string) (string, bool) {
if len(name) == 0 || len(name) > maxNameSize {
if len(name) == 0 {
return "", false
}
@ -26,5 +28,18 @@ func asciiLowerName(name string) (string, bool) {
buf[i] = ch
}
switch {
case bytes.HasSuffix(buf, []byte(".lthn.")):
buf = buf[:len(buf)-6]
case bytes.HasSuffix(buf, []byte(".lthn")):
buf = buf[:len(buf)-5]
case bytes.HasSuffix(buf, []byte(".")):
buf = buf[:len(buf)-1]
}
if len(buf) == 0 || len(buf) > maxNameSize {
return "", false
}
return string(buf), true
}

View file

@ -61,8 +61,8 @@ var (
// HasReservedName reports whether the JS reserved-name table contains the name.
//
// Lookup is case-insensitive and matches the reference table's lower-casing
// behaviour.
// Lookup is case-insensitive and accepts a canonical `.lthn` suffix in
// addition to bare labels.
func HasReservedName(name string) bool {
return DefaultReservedCatalog().HasByName(name)
}
@ -84,7 +84,8 @@ func HasReservedBinary(name []byte) bool {
// GetReservedName returns the reserved-name entry for the provided label.
//
// The input is lower-cased before hashing, matching the JS reference helper.
// The input is lower-cased before hashing, and canonical `.lthn` suffixes are
// stripped before lookup.
func GetReservedName(name string) (ReservedName, bool) {
return DefaultReservedCatalog().GetByName(name)
}
@ -258,8 +259,8 @@ func (c *ReservedCatalog) HasByName(name string) bool {
// GetByName returns the reserved-name entry for the provided label.
//
// The lookup lower-cases ASCII input and hashes it directly, matching the JS
// reference helper's ASCII encoding behavior.
// The lookup lower-cases ASCII input, strips canonical `.lthn` suffixes, and
// hashes the normalized label directly.
func (c *ReservedCatalog) GetByName(name string) (ReservedName, bool) {
name, ok := asciiLowerName(name)
if !ok {

View file

@ -132,6 +132,19 @@ func TestReservedLookupStringAndBinaryAliases(t *testing.T) {
if !HasReservedByBinary([]byte("RESERVED")) {
t.Fatal("HasReservedByBinary should report reserved catalog labels")
}
item, ok = GetReservedName("reserved.lthn")
if !ok {
t.Fatal("GetReservedName should accept canonical .lthn names")
}
if item.Name != "reserved" {
t.Fatalf("item.Name = %q, want %q", item.Name, "reserved")
}
if !HasReservedName("reserved.lthn") {
t.Fatal("HasReservedName should accept canonical .lthn names")
}
}
func TestReservedLookupHasByHashAlias(t *testing.T) {