dip/vendor/github.com/likexian/whois-parser-go/parser.go
2019-12-22 18:20:45 +01:00

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 "", ""
}