dip/vendor/github.com/likexian/whois-parser/parser.go

276 lines
7.0 KiB
Go
Raw Normal View History

2019-12-22 18:20:45 +01:00
/*
2024-04-28 13:08:41 +02:00
* Copyright 2014-2024 Li Kexian
2019-12-22 18:20:45 +01:00
*
* 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.
*
2020-05-24 18:42:01 +02:00
* Go module for domain whois information parsing
2019-12-22 18:20:45 +01:00
* https://www.likexian.com/
*/
package whoisparser
import (
"regexp"
"strings"
"github.com/likexian/gokit/assert"
2020-05-24 18:42:01 +02:00
"github.com/likexian/gokit/xslice"
2020-12-04 20:58:53 +01:00
"golang.org/x/net/idna"
2019-12-22 18:20:45 +01:00
)
// Version returns package version
func Version() string {
2023-05-17 13:27:04 +02:00
return "1.24.8"
2019-12-22 18:20:45 +01:00
}
// 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
2021-11-12 12:28:10 +01:00
func Parse(text string) (whoisInfo WhoisInfo, err error) { //nolint:cyclop
2019-12-22 18:20:45 +01:00
name, extension := searchDomain(text)
if name == "" {
2021-11-12 12:28:10 +01:00
err = getDomainErrorType(text)
return
}
if extension != "" && isExtNotFoundDomain(text, extension) {
err = ErrNotFoundDomain
2019-12-22 18:20:45 +01:00
return
}
2020-05-24 18:42:01 +02:00
domain := &Domain{}
registrar := &Contact{}
registrant := &Contact{}
administrative := &Contact{}
technical := &Contact{}
billing := &Contact{}
2019-12-22 18:20:45 +01:00
2020-12-04 20:58:53 +01:00
domain.Name, _ = idna.ToASCII(name)
domain.Extension, _ = idna.ToASCII(extension)
2019-12-22 18:20:45 +01:00
2020-12-04 20:58:53 +01:00
whoisText, _ := Prepare(text, domain.Extension)
2019-12-22 18:20:45 +01:00
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:] == ":" {
2021-11-12 12:28:10 +01:00
i++
2019-12-22 18:20:45 +01:00
for ; i < len(whoisLines); i++ {
thisLine := strings.TrimSpace(whoisLines[i])
if strings.Contains(thisLine, ":") {
break
}
line += thisLine + ","
}
line = strings.Trim(line, ",")
2021-11-12 12:28:10 +01:00
i--
2019-12-22 18:20:45 +01:00
}
lines := strings.SplitN(line, ":", 2)
name := strings.TrimSpace(lines[0])
value := strings.TrimSpace(lines[1])
value = strings.TrimSpace(strings.Trim(value, ":"))
if value == "" {
continue
}
2021-11-12 12:28:10 +01:00
keyName := searchKeyName(name)
2019-12-22 18:20:45 +01:00
switch keyName {
case "domain_id":
domain.ID = value
case "domain_name":
2020-12-04 20:58:53 +01:00
if domain.Domain == "" {
2023-03-31 16:52:07 +02:00
if firstSpace := strings.IndexByte(value, ' '); firstSpace > 0 {
value = value[:firstSpace]
}
2020-12-04 20:58:53 +01:00
domain.Domain = strings.ToLower(value)
domain.Punycode, _ = idna.ToASCII(domain.Domain)
}
2019-12-22 18:20:45 +01:00
case "domain_status":
2020-05-24 18:42:01 +02:00
domain.Status = append(domain.Status, strings.Split(value, ",")...)
2019-12-22 18:20:45 +01:00
case "domain_dnssec":
2021-11-12 12:28:10 +01:00
if !domain.DNSSec {
domain.DNSSec = isDNSSecEnabled(value)
2019-12-22 18:20:45 +01:00
}
case "whois_server":
if domain.WhoisServer == "" {
domain.WhoisServer = value
}
case "name_servers":
2020-05-24 18:42:01 +02:00
domain.NameServers = append(domain.NameServers, strings.Split(value, ",")...)
2019-12-22 18:20:45 +01:00
case "created_date":
if domain.CreatedDate == "" {
domain.CreatedDate = value
if parsed, err := parseDateString(value); err == nil {
domain.CreatedDateInTime = &parsed
}
2019-12-22 18:20:45 +01:00
}
case "updated_date":
if domain.UpdatedDate == "" {
domain.UpdatedDate = value
if parsed, err := parseDateString(value); err == nil {
domain.UpdatedDateInTime = &parsed
}
2019-12-22 18:20:45 +01:00
}
case "expired_date":
if domain.ExpirationDate == "" {
domain.ExpirationDate = value
if parsed, err := parseDateString(value); err == nil {
domain.ExpirationDateInTime = &parsed
}
2019-12-22 18:20:45 +01:00
}
case "referral_url":
registrar.ReferralURL = value
default:
2021-11-12 12:28:10 +01:00
name = clearKeyName(name)
2019-12-22 18:20:45 +01:00
if !strings.Contains(name, " ") {
2021-11-12 12:28:10 +01:00
if name == "registrar" {
name += " name"
2024-04-28 13:08:41 +02:00
} else if domain.Extension == "dk" {
name = "registrant " + name
2021-11-12 12:28:10 +01:00
} else {
name += " organization"
}
2019-12-22 18:20:45 +01:00
}
ns := strings.SplitN(name, " ", 2)
name = strings.TrimSpace("registrant " + ns[1])
if ns[0] == "registrar" || ns[0] == "registration" {
2020-05-24 18:42:01 +02:00
parseContact(registrar, name, value)
2019-12-22 18:20:45 +01:00
} else if ns[0] == "registrant" || ns[0] == "holder" {
2020-05-24 18:42:01 +02:00
parseContact(registrant, name, value)
2019-12-22 18:20:45 +01:00
} else if ns[0] == "admin" || ns[0] == "administrative" {
2020-05-24 18:42:01 +02:00
parseContact(administrative, name, value)
2019-12-22 18:20:45 +01:00
} else if ns[0] == "tech" || ns[0] == "technical" {
2020-05-24 18:42:01 +02:00
parseContact(technical, name, value)
2019-12-22 18:20:45 +01:00
} else if ns[0] == "bill" || ns[0] == "billing" {
2020-05-24 18:42:01 +02:00
parseContact(billing, name, value)
2019-12-22 18:20:45 +01:00
}
}
}
2021-11-12 12:28:10 +01:00
domain.NameServers = fixNameServers(domain.NameServers)
domain.Status = fixDomainStatus(domain.Status)
2019-12-22 18:20:45 +01:00
2020-05-24 18:42:01 +02:00
domain.NameServers = xslice.Unique(domain.NameServers).([]string)
domain.Status = xslice.Unique(domain.Status).([]string)
2019-12-22 18:20:45 +01:00
whoisInfo.Domain = domain
2020-05-24 18:42:01 +02:00
if *registrar != (Contact{}) {
whoisInfo.Registrar = registrar
}
if *registrant != (Contact{}) {
whoisInfo.Registrant = registrant
}
if *administrative != (Contact{}) {
whoisInfo.Administrative = administrative
}
if *technical != (Contact{}) {
whoisInfo.Technical = technical
}
if *billing != (Contact{}) {
whoisInfo.Billing = billing
}
2019-12-22 18:20:45 +01:00
return
}
// parseContact do parse contact info
2020-05-24 18:42:01 +02:00
func parseContact(contact *Contact, name, value string) {
2021-11-12 12:28:10 +01:00
switch searchKeyName(name) {
2019-12-22 18:20:45 +01:00
case "registrant_id":
contact.ID = value
case "registrant_name":
2021-11-12 12:28:10 +01:00
if contact.Name == "" {
contact.Name = value
}
2019-12-22 18:20:45 +01:00
case "registrant_organization":
2021-11-12 12:28:10 +01:00
if contact.Organization == "" {
contact.Organization = value
}
2019-12-22 18:20:45 +01:00
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)
}
}
2023-03-17 13:19:17 +01:00
var searchDomainRx1 = regexp.MustCompile(`(?i)\[?domain\:?(\s*\_?name)?\]?[\s\.]*\:?` +
`\s*([^\s\,\;\(\)]+)\.([^\s\,\;\(\)\.]{2,})`)
var searchDomainRx2 = regexp.MustCompile(`(?i)\[?domain\:?(\s*\_?name)?\]?[\s\.]*\:?` +
`\s*([^\s\,\;\(\)\.]{2,})\n`)
2021-11-12 12:28:10 +01:00
// searchDomain finds domain name and extension from whois information
func searchDomain(text string) (name, extension string) {
2023-03-17 13:19:17 +01:00
m := searchDomainRx1.FindStringSubmatch(text)
2019-12-22 18:20:45 +01:00
if len(m) > 0 {
2023-03-17 13:19:17 +01:00
name = strings.TrimPrefix(strings.TrimSpace(m[2]), "\"")
extension = strings.TrimSuffix(strings.TrimSpace(m[3]), "\"")
2019-12-22 18:20:45 +01:00
}
2021-11-12 12:28:10 +01:00
if name == "" {
2023-03-17 13:19:17 +01:00
m := searchDomainRx2.FindStringSubmatch(text)
2021-11-12 12:28:10 +01:00
if len(m) > 0 {
name = strings.TrimSpace(m[2])
extension = ""
}
2019-12-22 18:20:45 +01:00
}
2021-11-12 12:28:10 +01:00
if name != "" {
name = strings.ToLower(name)
extension = strings.ToLower(extension)
}
return
2019-12-22 18:20:45 +01:00
}