235 lines
6.0 KiB
Go
235 lines
6.0 KiB
Go
/*
|
|
* Copyright 2014-2019 Li Kexian
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
* Go module for domain whois info parse
|
|
* https://www.likexian.com/
|
|
*/
|
|
|
|
package whoisparser
|
|
|
|
import (
|
|
"errors"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/likexian/gokit/assert"
|
|
)
|
|
|
|
// Domain info error and replacer variables
|
|
var (
|
|
ErrDomainNotFound = errors.New("Domain is not found.")
|
|
ErrDomainInvalidData = errors.New("Domain whois data invalid.")
|
|
ErrDomainLimitExceed = errors.New("Domain query limit exceeded.")
|
|
)
|
|
|
|
// Version returns package version
|
|
func Version() string {
|
|
return "1.10.1"
|
|
}
|
|
|
|
// Author returns package author
|
|
func Author() string {
|
|
return "[Li Kexian](https://www.likexian.com/)"
|
|
}
|
|
|
|
// License returns package license
|
|
func License() string {
|
|
return "Licensed under the Apache License 2.0"
|
|
}
|
|
|
|
// Parse returns parsed whois info
|
|
func Parse(text string) (whoisInfo WhoisInfo, err error) {
|
|
name, extension := searchDomain(text)
|
|
if name == "" {
|
|
err = ErrDomainInvalidData
|
|
if IsNotFound(text) {
|
|
err = ErrDomainNotFound
|
|
} else if IsLimitExceeded(text) {
|
|
err = ErrDomainLimitExceed
|
|
}
|
|
return
|
|
}
|
|
|
|
var domain Domain
|
|
var registrar Contact
|
|
var registrant Contact
|
|
var administrative Contact
|
|
var technical Contact
|
|
var billing Contact
|
|
|
|
domain.Name = name
|
|
domain.Extension = extension
|
|
|
|
whoisText, _ := Prepare(text, extension)
|
|
whoisLines := strings.Split(whoisText, "\n")
|
|
for i := 0; i < len(whoisLines); i++ {
|
|
line := strings.TrimSpace(whoisLines[i])
|
|
if len(line) < 5 || !strings.Contains(line, ":") {
|
|
continue
|
|
}
|
|
|
|
fChar := line[:1]
|
|
if assert.IsContains([]string{"-", "*", "%", ">", ";"}, fChar) {
|
|
continue
|
|
}
|
|
|
|
if line[len(line)-1:] == ":" {
|
|
i += 1
|
|
for ; i < len(whoisLines); i++ {
|
|
thisLine := strings.TrimSpace(whoisLines[i])
|
|
if strings.Contains(thisLine, ":") {
|
|
break
|
|
}
|
|
line += thisLine + ","
|
|
}
|
|
line = strings.Trim(line, ",")
|
|
i -= 1
|
|
}
|
|
|
|
lines := strings.SplitN(line, ":", 2)
|
|
name := strings.TrimSpace(lines[0])
|
|
value := strings.TrimSpace(lines[1])
|
|
value = strings.TrimSpace(strings.Trim(value, ":"))
|
|
|
|
if value == "" {
|
|
continue
|
|
}
|
|
|
|
keyName := FindKeyName(name)
|
|
switch keyName {
|
|
case "domain_id":
|
|
domain.ID = value
|
|
case "domain_name":
|
|
domain.Domain = value
|
|
case "domain_status":
|
|
domain.Status += value + ","
|
|
case "domain_dnssec":
|
|
if domain.DNSSEC == "" {
|
|
domain.DNSSEC = value
|
|
}
|
|
case "whois_server":
|
|
if domain.WhoisServer == "" {
|
|
domain.WhoisServer = value
|
|
}
|
|
case "name_servers":
|
|
domain.NameServers += value + ","
|
|
case "created_date":
|
|
if domain.CreatedDate == "" {
|
|
domain.CreatedDate = value
|
|
}
|
|
case "updated_date":
|
|
if domain.UpdatedDate == "" {
|
|
domain.UpdatedDate = value
|
|
}
|
|
case "expired_date":
|
|
if domain.ExpirationDate == "" {
|
|
domain.ExpirationDate = value
|
|
}
|
|
case "referral_url":
|
|
registrar.ReferralURL = value
|
|
default:
|
|
name = ClearName(name)
|
|
if !strings.Contains(name, " ") {
|
|
name += " name"
|
|
}
|
|
ns := strings.SplitN(name, " ", 2)
|
|
name = strings.TrimSpace("registrant " + ns[1])
|
|
if ns[0] == "registrar" || ns[0] == "registration" {
|
|
registrar = parseContact(registrar, name, value)
|
|
} else if ns[0] == "registrant" || ns[0] == "holder" {
|
|
registrant = parseContact(registrant, name, value)
|
|
} else if ns[0] == "admin" || ns[0] == "administrative" {
|
|
administrative = parseContact(administrative, name, value)
|
|
} else if ns[0] == "tech" || ns[0] == "technical" {
|
|
technical = parseContact(technical, name, value)
|
|
} else if ns[0] == "bill" || ns[0] == "billing" {
|
|
billing = parseContact(billing, name, value)
|
|
}
|
|
}
|
|
}
|
|
|
|
domain.NameServers = FixNameServers(strings.ToLower(domain.NameServers))
|
|
domain.Status = FixDomainStatus(strings.ToLower(domain.Status))
|
|
|
|
domain.NameServers = RemoveDuplicateField(domain.NameServers)
|
|
domain.Status = RemoveDuplicateField(domain.Status)
|
|
|
|
whoisInfo.Domain = domain
|
|
whoisInfo.Registrar = registrar
|
|
whoisInfo.Registrant = registrant
|
|
whoisInfo.Administrative = administrative
|
|
whoisInfo.Technical = technical
|
|
whoisInfo.Billing = billing
|
|
|
|
return
|
|
}
|
|
|
|
// parseContact do parse contact info
|
|
func parseContact(contact Contact, name, value string) Contact {
|
|
keyName := FindKeyName(name)
|
|
|
|
switch keyName {
|
|
case "registrant_id":
|
|
contact.ID = value
|
|
case "registrant_name":
|
|
contact.Name = value
|
|
case "registrant_organization":
|
|
contact.Organization = value
|
|
case "registrant_street":
|
|
if contact.Street == "" {
|
|
contact.Street = value
|
|
} else {
|
|
contact.Street += ", " + value
|
|
}
|
|
case "registrant_city":
|
|
contact.City = value
|
|
case "registrant_state_province":
|
|
contact.Province = value
|
|
case "registrant_postal_code":
|
|
contact.PostalCode = value
|
|
case "registrant_country":
|
|
contact.Country = value
|
|
case "registrant_phone":
|
|
contact.Phone = value
|
|
case "registrant_phone_ext":
|
|
contact.PhoneExt = value
|
|
case "registrant_fax":
|
|
contact.Fax = value
|
|
case "registrant_fax_ext":
|
|
contact.FaxExt = value
|
|
case "registrant_email":
|
|
contact.Email = strings.ToLower(value)
|
|
}
|
|
|
|
return contact
|
|
}
|
|
|
|
// searchDomain find domain from whois info
|
|
func searchDomain(text string) (string, string) {
|
|
r := regexp.MustCompile(`(?i)\[?domain(\s*\_?name)?\]?\s*\:?\s*([a-z0-9\-\.]+)\.([a-z]{2,})`)
|
|
m := r.FindStringSubmatch(text)
|
|
if len(m) > 0 {
|
|
return strings.ToLower(strings.TrimSpace(m[2])), strings.ToLower(strings.TrimSpace(m[3]))
|
|
}
|
|
|
|
r = regexp.MustCompile(`(?i)\[?domain(\s*\_?name)?\]?\s*\:?\s*([a-z]{2,})\n`)
|
|
m = r.FindStringSubmatch(text)
|
|
if len(m) > 0 {
|
|
return strings.ToLower(strings.TrimSpace(m[2])), ""
|
|
}
|
|
|
|
return "", ""
|
|
}
|