[#56] Add multi-level domain name support
Signed-off-by: Ekaterina Lebedeva <ekaterina.lebedeva@yadro.com>
This commit is contained in:
parent
897f538a3c
commit
4dcb575caa
2 changed files with 22 additions and 13 deletions
|
@ -219,7 +219,7 @@ func GetPrice() int {
|
||||||
|
|
||||||
// IsAvailable checks whether the provided domain name is available.
|
// IsAvailable checks whether the provided domain name is available.
|
||||||
func IsAvailable(name string) bool {
|
func IsAvailable(name string) bool {
|
||||||
fragments := splitAndCheck(name, false)
|
fragments := splitAndCheck(name)
|
||||||
if fragments == nil {
|
if fragments == nil {
|
||||||
panic("invalid domain name format")
|
panic("invalid domain name format")
|
||||||
}
|
}
|
||||||
|
@ -231,16 +231,19 @@ func IsAvailable(name string) bool {
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return parentExpired(ctx, 0, fragments)
|
if parentExpired(ctx, fragments) {
|
||||||
|
panic("parent does not exist or is expired")
|
||||||
|
}
|
||||||
|
return storage.Get(ctx, append([]byte{prefixName}, getTokenKey([]byte(name))...)) == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// parentExpired returns true if any domain from fragments doesn't exist or is expired.
|
// parentExpired returns true if any domain from fragments doesn't exist or is expired.
|
||||||
// first denotes the deepest subdomain to check.
|
// first denotes the deepest subdomain to check.
|
||||||
func parentExpired(ctx storage.Context, first int, fragments []string) bool {
|
func parentExpired(ctx storage.Context, fragments []string) bool {
|
||||||
now := int64(runtime.GetTime())
|
now := int64(runtime.GetTime())
|
||||||
last := len(fragments) - 1
|
last := len(fragments) - 1
|
||||||
name := fragments[last]
|
name := fragments[last]
|
||||||
for i := last; i >= first; i-- {
|
for i := last; i > 0; i-- {
|
||||||
if i != last {
|
if i != last {
|
||||||
name = fragments[i] + "." + name
|
name = fragments[i] + "." + name
|
||||||
}
|
}
|
||||||
|
@ -258,7 +261,7 @@ func parentExpired(ctx storage.Context, first int, fragments []string) bool {
|
||||||
|
|
||||||
// Register registers a new domain with the specified owner and name if it's available.
|
// Register registers a new domain with the specified owner and name if it's available.
|
||||||
func Register(name string, owner interop.Hash160, email string, refresh, retry, expire, ttl int) bool {
|
func Register(name string, owner interop.Hash160, email string, refresh, retry, expire, ttl int) bool {
|
||||||
fragments := splitAndCheck(name, true)
|
fragments := splitAndCheck(name)
|
||||||
if fragments == nil {
|
if fragments == nil {
|
||||||
panic("invalid domain name format")
|
panic("invalid domain name format")
|
||||||
}
|
}
|
||||||
|
@ -277,7 +280,7 @@ func Register(name string, owner interop.Hash160, email string, refresh, retry,
|
||||||
if tldBytes == nil {
|
if tldBytes == nil {
|
||||||
panic("TLD not found")
|
panic("TLD not found")
|
||||||
}
|
}
|
||||||
if parentExpired(ctx, 1, fragments) {
|
if parentExpired(ctx, fragments) {
|
||||||
panic("one of the parent domains is not registered")
|
panic("one of the parent domains is not registered")
|
||||||
}
|
}
|
||||||
parentKey := getTokenKey([]byte(name[len(fragments[0])+1:]))
|
parentKey := getTokenKey([]byte(name[len(fragments[0])+1:]))
|
||||||
|
@ -388,7 +391,7 @@ func checkBaseRecords(typ RecordType, data string) bool {
|
||||||
case A:
|
case A:
|
||||||
return checkIPv4(data)
|
return checkIPv4(data)
|
||||||
case CNAME:
|
case CNAME:
|
||||||
return splitAndCheck(data, true) != nil
|
return splitAndCheck(data) != nil
|
||||||
case TXT:
|
case TXT:
|
||||||
return len(data) <= maxTXTRecordLength
|
return len(data) <= maxTXTRecordLength
|
||||||
case AAAA:
|
case AAAA:
|
||||||
|
@ -508,7 +511,7 @@ func getNameState(ctx storage.Context, tokenID []byte) NameState {
|
||||||
tokenKey := getTokenKey(tokenID)
|
tokenKey := getTokenKey(tokenID)
|
||||||
ns := getNameStateWithKey(ctx, tokenKey)
|
ns := getNameStateWithKey(ctx, tokenKey)
|
||||||
fragments := std.StringSplit(string(tokenID), ".")
|
fragments := std.StringSplit(string(tokenID), ".")
|
||||||
if parentExpired(ctx, 1, fragments) {
|
if parentExpired(ctx, fragments) {
|
||||||
panic("parent domain has expired")
|
panic("parent domain has expired")
|
||||||
}
|
}
|
||||||
return ns
|
return ns
|
||||||
|
@ -716,16 +719,13 @@ func isAlNum(c uint8) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// splitAndCheck splits domain name into parts and validates it.
|
// splitAndCheck splits domain name into parts and validates it.
|
||||||
func splitAndCheck(name string, allowMultipleFragments bool) []string {
|
func splitAndCheck(name string) []string {
|
||||||
l := len(name)
|
l := len(name)
|
||||||
if l < minDomainNameLength || maxDomainNameLength < l {
|
if l < minDomainNameLength || maxDomainNameLength < l {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
fragments := std.StringSplit(name, ".")
|
fragments := std.StringSplit(name, ".")
|
||||||
l = len(fragments)
|
l = len(fragments)
|
||||||
if l > 2 && !allowMultipleFragments {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
for i := 0; i < l; i++ {
|
for i := 0; i < l; i++ {
|
||||||
if !checkFragment(fragments[i], i == l-1) {
|
if !checkFragment(fragments[i], i == l-1) {
|
||||||
return nil
|
return nil
|
||||||
|
@ -846,7 +846,7 @@ func checkIPv6(data string) bool {
|
||||||
|
|
||||||
// tokenIDFromName returns token ID (domain.root) from the provided name.
|
// tokenIDFromName returns token ID (domain.root) from the provided name.
|
||||||
func tokenIDFromName(name string) string {
|
func tokenIDFromName(name string) string {
|
||||||
fragments := splitAndCheck(name, true)
|
fragments := splitAndCheck(name)
|
||||||
if fragments == nil {
|
if fragments == nil {
|
||||||
panic("invalid domain name format")
|
panic("invalid domain name format")
|
||||||
}
|
}
|
||||||
|
|
|
@ -334,6 +334,15 @@ func TestNNSIsAvailable(t *testing.T) {
|
||||||
"myemail@frostfs.info", refresh, retry, expire, ttl)
|
"myemail@frostfs.info", refresh, retry, expire, ttl)
|
||||||
|
|
||||||
c.Invoke(t, false, "isAvailable", "domain.com")
|
c.Invoke(t, false, "isAvailable", "domain.com")
|
||||||
|
|
||||||
|
c.Invoke(t, true, "isAvailable", "dom.domain.com")
|
||||||
|
c.InvokeFail(t, "parent does not exist or is expired", "isAvailable", "dom.dom.domain.com")
|
||||||
|
|
||||||
|
c1.Invoke(t, true, "register",
|
||||||
|
"dom.domain.com", acc.ScriptHash(),
|
||||||
|
"myemail@frostfs.info", refresh, retry, expire, ttl)
|
||||||
|
c.Invoke(t, false, "isAvailable", "dom.domain.com")
|
||||||
|
c.Invoke(t, true, "isAvailable", "dom.dom.domain.com")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNNSRenew(t *testing.T) {
|
func TestNNSRenew(t *testing.T) {
|
||||||
|
|
Loading…
Reference in a new issue