11import { concat , hexlify } from "@ethersproject/bytes" ;
2- import { toUtf8Bytes } from "@ethersproject/strings" ;
2+ import { toUtf8Bytes , toUtf8String } from "@ethersproject/strings" ;
33import { keccak256 } from "@ethersproject/keccak256" ;
44
55import { Logger } from "@ethersproject/logger" ;
@@ -11,11 +11,59 @@ import { ens_normalize } from "./ens-normalize/lib";
1111const Zeros = new Uint8Array ( 32 ) ;
1212Zeros . fill ( 0 ) ;
1313
14- const Partition = new RegExp ( "^((.*)\\.)?([^.]+)$" ) ;
14+ function checkComponent ( comp : Uint8Array ) : Uint8Array {
15+ if ( comp . length === 0 ) { throw new Error ( "invalid ENS name; empty component" ) ; }
16+ let nonUnder = false ;
17+ let last = - 1 ;
18+ for ( let i = 0 ; i < comp . length ; i ++ ) {
19+ const c = comp [ i ] ;
20+
21+ // An underscore (i.e. "_"); only allows at the beginning
22+ if ( c === 0x5f ) {
23+ if ( nonUnder ) { throw new Error ( "invalid ENS name; non-prefix underscore" ) ; }
24+ } else {
25+ // A hyphen (i.e. "-"); only allows a single in a row
26+ if ( c === 0x2d && last === c ) {
27+ throw new Error ( "invalid ENS name; double-hyphen" ) ;
28+ }
29+ nonUnder = true ;
30+ }
31+ last = c ;
32+ }
33+ return comp ;
34+ }
35+
36+ function ensNameSplit ( name : string ) : Array < Uint8Array > {
37+ const bytes = toUtf8Bytes ( ens_normalize ( name ) ) ;
38+ const comps : Array < Uint8Array > = [ ] ;
39+
40+ if ( name . length === 0 ) { return comps ; }
41+
42+ let last = 0 ;
43+ for ( let i = 0 ; i < bytes . length ; i ++ ) {
44+ const d = bytes [ i ] ;
45+
46+ // A separator (i.e. "."); copy this component
47+ if ( d === 0x2e ) {
48+ comps . push ( checkComponent ( bytes . slice ( last , i ) ) ) ;
49+ last = i + 1 ;
50+ }
51+ }
52+
53+ // There was a stray separator at the end of the name
54+ if ( last >= bytes . length ) { throw new Error ( "invalid ENS name; empty component" ) ; }
55+
56+ comps . push ( checkComponent ( bytes . slice ( last ) ) ) ;
57+ return comps ;
58+ }
59+
60+ export function ensNormalize ( name : string ) : string {
61+ return ensNameSplit ( name ) . map ( ( comp ) => toUtf8String ( comp ) ) . join ( "." ) ;
62+ }
1563
1664export function isValidName ( name : string ) : boolean {
1765 try {
18- return ens_normalize ( name ) . length !== 0 ;
66+ return ( ensNameSplit ( name ) . length !== 0 ) ;
1967 } catch ( error ) { }
2068 return false ;
2169}
@@ -26,34 +74,28 @@ export function namehash(name: string): string {
2674 logger . throwArgumentError ( "invalid ENS name; not a string" , "name" , name ) ;
2775 }
2876
29- let current = ens_normalize ( name ) ;
3077 let result : string | Uint8Array = Zeros ;
31- while ( current . length ) {
32- const partition = current . match ( Partition ) ;
33- if ( partition == null || partition [ 2 ] === "" ) {
34- logger . throwArgumentError ( "invalid ENS address; missing component" , "name" , name ) ;
35- }
36- const label = toUtf8Bytes ( partition [ 3 ] ) ;
37- result = keccak256 ( concat ( [ result , keccak256 ( label ) ] ) ) ;
3878
39- current = partition [ 2 ] || "" ;
79+ const comps = ensNameSplit ( name ) ;
80+ while ( comps . length ) {
81+ result = keccak256 ( concat ( [ result , keccak256 ( comps . pop ( ) ) ] ) ) ;
4082 }
4183
4284 return hexlify ( result ) ;
4385}
4486
4587export function dnsEncode ( name : string ) : string {
46- name = ens_normalize ( name )
47- return hexlify ( concat ( name . split ( "." ) . map ( ( comp ) => {
48-
88+ return hexlify ( concat ( ensNameSplit ( name ) . map ( ( comp ) => {
4989 // DNS does not allow components over 63 bytes in length
50- if ( toUtf8Bytes ( comp ) . length > 63 ) {
90+ if ( comp . length > 63 ) {
5191 throw new Error ( "invalid DNS encoded entry; length exceeds 63 bytes" ) ;
5292 }
5393
54- // We jam in an _ prefix to fill in with the length later
55- const bytes = toUtf8Bytes ( "_" + comp ) ;
94+ const bytes = new Uint8Array ( comp . length + 1 ) ;
95+ bytes . set ( comp , 1 ) ;
5696 bytes [ 0 ] = bytes . length - 1 ;
5797 return bytes ;
98+
5899 } ) ) ) + "00" ;
59100}
101+
0 commit comments