155 lines
4.0 KiB
Go
155 lines
4.0 KiB
Go
|
|
package whois
|
||
|
|
|
||
|
|
import "strings"
|
||
|
|
|
||
|
|
var notFoundTokens = []string{
|
||
|
|
"no object found",
|
||
|
|
"domain not found",
|
||
|
|
"no match for",
|
||
|
|
"no match",
|
||
|
|
"no data found",
|
||
|
|
"no entries found",
|
||
|
|
"no matching record",
|
||
|
|
"no found",
|
||
|
|
"query returned 0 objects",
|
||
|
|
"does not have any data for",
|
||
|
|
"domain unknown",
|
||
|
|
"domain has not been registered",
|
||
|
|
"the domain name is not available",
|
||
|
|
"domain name is not available",
|
||
|
|
"reserved name",
|
||
|
|
"reserved domain name",
|
||
|
|
"cannot be registered",
|
||
|
|
"can not be registered",
|
||
|
|
"the queried object does not exist",
|
||
|
|
}
|
||
|
|
|
||
|
|
var accessDeniedTokens = []string{
|
||
|
|
"this tld has no whois server",
|
||
|
|
"requests of this client are not permitted",
|
||
|
|
"restricted to specifically qualified registrants",
|
||
|
|
"ip address used to perform the query is not authorised",
|
||
|
|
"ip address used to perform the query is not authorised",
|
||
|
|
}
|
||
|
|
|
||
|
|
func isNotFoundLine(line string) bool {
|
||
|
|
return isStrictNotFoundLine(line) || isAccessDeniedLine(line)
|
||
|
|
}
|
||
|
|
|
||
|
|
func isStrictNotFoundLine(line string) bool {
|
||
|
|
l := strings.ToLower(strings.TrimSpace(line))
|
||
|
|
if l == "" {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
for _, t := range notFoundTokens {
|
||
|
|
if strings.Contains(l, t) {
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func isAccessDeniedLine(line string) bool {
|
||
|
|
l := strings.ToLower(strings.TrimSpace(line))
|
||
|
|
if l == "" {
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
for _, t := range accessDeniedTokens {
|
||
|
|
if strings.Contains(l, t) {
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func rawHasNotFound(raw string) bool {
|
||
|
|
for _, line := range strings.Split(raw, "\n") {
|
||
|
|
if isStrictNotFoundLine(line) {
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func rawHasAccessDenied(raw string) bool {
|
||
|
|
for _, line := range strings.Split(raw, "\n") {
|
||
|
|
if isAccessDeniedLine(line) {
|
||
|
|
return true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return false
|
||
|
|
}
|
||
|
|
|
||
|
|
func splitKV(line string) (key, val string, ok bool) {
|
||
|
|
if i := strings.Index(line, ":"); i > 0 {
|
||
|
|
key = strings.TrimSpace(line[:i])
|
||
|
|
if key == "" || strings.Contains(key, "://") {
|
||
|
|
return "", "", false
|
||
|
|
}
|
||
|
|
return key, strings.TrimSpace(line[i+1:]), true
|
||
|
|
}
|
||
|
|
return "", "", false
|
||
|
|
}
|
||
|
|
|
||
|
|
func normalizeKey(k string) string {
|
||
|
|
k = strings.ToLower(strings.TrimSpace(k))
|
||
|
|
if k == "" {
|
||
|
|
return ""
|
||
|
|
}
|
||
|
|
|
||
|
|
for strings.Contains(k, "..") {
|
||
|
|
k = strings.ReplaceAll(k, "..", ".")
|
||
|
|
}
|
||
|
|
k = strings.Trim(k, ". ")
|
||
|
|
|
||
|
|
replacer := strings.NewReplacer(
|
||
|
|
".", " ",
|
||
|
|
"\t", " ",
|
||
|
|
"_", " ",
|
||
|
|
"-", " ",
|
||
|
|
"/", " ",
|
||
|
|
)
|
||
|
|
k = replacer.Replace(k)
|
||
|
|
k = strings.Join(strings.Fields(k), " ")
|
||
|
|
return k
|
||
|
|
}
|
||
|
|
|
||
|
|
func canonicalKey(k string) string {
|
||
|
|
n := normalizeKey(k)
|
||
|
|
switch n {
|
||
|
|
case "domain", "domain name", "domainname", "nom de domaine":
|
||
|
|
return "domain"
|
||
|
|
case "registry domain id", "domain id", "roid":
|
||
|
|
return "domain_id"
|
||
|
|
case "updated date", "last modified", "domain record last updated", "changed", "record last updated on", "last updated":
|
||
|
|
return "updated_at"
|
||
|
|
case "creation date", "registration time", "registered", "domain record activated", "created", "record created", "domain created":
|
||
|
|
return "created_at"
|
||
|
|
case "registry expiry date", "registrar registration expiration date", "expiration time", "domain expires", "expire", "expires", "record expires on", "renewal date":
|
||
|
|
return "expired_at"
|
||
|
|
case "registrar", "sponsoring registrar", "registrar name", "registration service provider", "current registar", "registar created", "registrar handle":
|
||
|
|
return "registrar"
|
||
|
|
case "status", "domain status", "registration status", "domain state", "domaintype":
|
||
|
|
return "status"
|
||
|
|
case "name server", "name servers", "name server information", "nameserver", "nameservers", "nserver", "primary server", "secondary server":
|
||
|
|
return "nameserver"
|
||
|
|
case "dnssec", "ds records":
|
||
|
|
return "dnssec"
|
||
|
|
}
|
||
|
|
|
||
|
|
if strings.Contains(n, "modification") && strings.Contains(n, "derni") {
|
||
|
|
return "updated_at"
|
||
|
|
}
|
||
|
|
if strings.Contains(n, "date d expiration") || strings.Contains(n, "date de expiration") {
|
||
|
|
return "expired_at"
|
||
|
|
}
|
||
|
|
if strings.Contains(n, "date de c") && strings.Contains(n, "ation") {
|
||
|
|
return "created_at"
|
||
|
|
}
|
||
|
|
if strings.HasPrefix(n, "name server") || strings.HasPrefix(n, "nameserver") || strings.HasPrefix(n, "name servers in") {
|
||
|
|
return "nameserver"
|
||
|
|
}
|
||
|
|
|
||
|
|
return n
|
||
|
|
}
|