hostpital

package
v0.1.0-beta2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 10, 2024 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package hostpital provides functions to assist in the maintenance of hosts files.

## Usage

```go import "github.com/KEINOS/go-hostpital/hostpital" ```

## Example Usage

- [Package examples](https://pkg.go.dev/github.com/KEINOS/go-hostpital/hostpital#pkg-examples) | godoc @ pkg.go.dev

Index

Examples

Constants

View Source
const (
	// DelimComnt is the delimiter for comments.
	DelimComnt = '#'
	// DelimDNS is the delimiter for DNS labels.
	DelimDNS = '.'
	// LF is the line feed, "\n".
	LF = int32(0x0a)
	// CR is the carriage return, "\r".
	CR = int32(0x0d)
	// Cutset is the set of characters for trimming white spaces.
	Cutset = "\t\n\v\f\r "
)

Variables

This section is empty.

Functions

func FileExists

func FileExists(path string) bool

FileExists returns true if the file exists and is not a directory.

Example
package main

import (
	"fmt"
	"os"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	// FileExists returns true if the file exists.
	if ok := hostpital.FileExists("examples_test.go"); ok {
		fmt.Println("given path exists and is a file")
	}

	// FileExists returns false if the path is a directory even if the path exists.
	if ok := hostpital.FileExists(os.TempDir()); !ok {
		fmt.Println("given path is a directory")
	}

	// FileExists returns false if the path does not exist.
	if ok := hostpital.FileExists("unknown.txt"); !ok {
		fmt.Println("given path does not exist")
	}
}
Output:

given path exists and is a file
given path is a directory
given path does not exist

func FindFile

func FindFile(patternFile, pathDirSearch string) ([]string, error)

FindFile returns a list of file paths found under the given directory. It will not include directories even if it matches. If no files are found, it will return an fs.ErrNotExist error.

e.g. FindFile("hosts*", "/home/user") will return:

["/home/user/.ssh/hosts", "/home/user/.ssh/hosts.deny", "/home/user/.ssh/hosts.allow"]
Example
package main

import (
	"fmt"
	"log"
	"path/filepath"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	patternSearch := "hosts*"
	pathDirSearch := filepath.Join("testdata", "search_me")

	foundFiles, err := hostpital.FindFile(patternSearch, pathDirSearch)
	if err != nil {
		log.Fatalf("failed to find files: %v", err)
	}

	for _, file := range foundFiles {
		fmt.Println(filepath.ToSlash(file))
	}

}
Output:

testdata/search_me/dir1/hosts
testdata/search_me/dir2/hosts.txt
testdata/search_me/dir2/subdir2/hosts
testdata/search_me/hosts/hosts

func IsCommentLine

func IsCommentLine(line string) bool

IsCommentLine returns true if the given line is a comment line.

Example
package main

import (
	"fmt"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	for index, line := range []string{
		"# This is a comment line",
		"           # This is a comment line with spaces.",
		"\t\t\t# This is a comment line with tabs.", // white spaces are trimmed
		"example.com # This is an in-line comment.", // has a non-comment info
	} {
		// IsCommentLine returns true if the line is a single comment line.
		// It returns false if the line contains a non-comment info.
		fmt.Printf("#%d: %v\n", index+1, hostpital.IsCommentLine(line))
	}
}
Output:

#1: true
#2: true
#3: true
#4: false

func IsCompatibleIDNA2008

func IsCompatibleIDNA2008(hostName string) bool

IsCompatibleIDNA2008 returns true if the given hostName is properly formatted for registration and is in ASCII/Punycode. False if it contains hosts or labels in Unicode or not IDNA2008 compatible.

Use TransformASCII() to convert raw punycode to IDNA2008 compatible ASCII.

Note that this function returns false if the label (host name or part of the subdomain) contains "_" (underscore).

Example
package main

import (
	"fmt"
	"log"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	for index, sample := range []struct {
		input string
		want  bool
	}{
		// Golden cases
		{input: "example.com", want: true},
		{input: "0.0.0.0", want: true},
		{input: "xn--fa-hia.com", want: true},    // IDNA2008 compatible and is ASCII/punycoded
		{input: "xn--gpher-jua.com", want: true}, // same as above
		// Wrong cases
		{input: "27--m01police.55fifayellow.com", want: false}, // Double hyphen with mal-formed punycode is not allowed
		{input: "my_host1.example.com", want: false},           // Host contains under score
		{input: "faß.com", want: false},                        // Must be in punycode/ASCII. Use TransformToASCII()
		{input: "www.аррӏе.com", want: false},                  // Same as above
		{input: "*.faß.com", want: false},                      // Wildcard is not allowed. Use IsCompatibleRFC6125Pattern()
		{input: ".example.com", want: false},                   // Must not start with a dot
	} {
		// True if host name is ready for registration. False if it is a raw
		// punycode or not IDNA2008 compatible.
		got := hostpital.IsCompatibleIDNA2008(sample.input)

		if got != sample.want {
			log.Fatalf("failed test #%d. input: %s, want: %v, got: %v",
				index+1, sample.input, sample.want, got)
		}

		fmt.Printf("IsCompatibleIDNA2008(%#v) --> %v\n", sample.input, sample.want)
	}
}
Output:

IsCompatibleIDNA2008("example.com") --> true
IsCompatibleIDNA2008("0.0.0.0") --> true
IsCompatibleIDNA2008("xn--fa-hia.com") --> true
IsCompatibleIDNA2008("xn--gpher-jua.com") --> true
IsCompatibleIDNA2008("27--m01police.55fifayellow.com") --> false
IsCompatibleIDNA2008("my_host1.example.com") --> false
IsCompatibleIDNA2008("faß.com") --> false
IsCompatibleIDNA2008("www.аррӏе.com") --> false
IsCompatibleIDNA2008("*.faß.com") --> false
IsCompatibleIDNA2008(".example.com") --> false

func IsCompatibleRFC6125

func IsCompatibleRFC6125(host string) bool

IsCompatibleRFC6125 returns true if the given host name can be matched or matched against according to RFC 6125 2.2, with some leniency to accommodate legacy values.

Note: This function is a copy of the internal function from the crypto/x509 package under BSD-3-Clause license. Please see the source code in "is_valid_hostname.go" for more information.

Example
package main

import (
	"fmt"
	"log"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	for index, test := range []struct {
		host string
		want bool
	}{
		// Golden cases
		{host: "example.com", want: true},
		{host: "eXample123-.com", want: true},
		{host: "example.com.", want: true},
		{host: "exa_mple.com", want: true},
		{host: "127.0.0.1", want: true},
		// Wrong cases
		{host: "0.0.0.0 example.com", want: false}, // no space allowed
		{host: "-eXample123-.com", want: false},
		{host: "", want: false},
		{host: ".", want: false},
		{host: "example..com", want: false},
		{host: ".example.com", want: false},
		{host: "*.example.com.", want: false},
		{host: "*foo.example.com", want: false},
		{host: "foo.*.example.com", want: false},
		{host: "foo,bar", want: false},
		{host: "project-dev:us-central1:main", want: false},
	} {
		got := hostpital.IsCompatibleRFC6125(test.host)

		if got != test.want {
			log.Fatalf("failed test #%d: IsCompatibleRFC6125(%#v) --> %v, want: %v",
				index+1, test.host, got, test.want)
		}
	}

	fmt.Println("OK")
}
Output:

OK

func IsCompatibleRFC6125Pattern

func IsCompatibleRFC6125Pattern(host string) bool

IsCompatibleRFC6125Pattern is similar to IsValidHostname but it also allows wildcard patterns.

Note: This function is a copy of the internal function from the crypto/x509 package under BSD-3-Clause license. Please see the source code in "is_valid_hostname.go" for more information.

Example
package main

import (
	"fmt"
	"log"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	for index, test := range []struct {
		host string
		want bool
	}{
		// Golden cases
		{host: "example.com", want: true},
		{host: "eXample123-.com", want: true},
		{host: "exa_mple.com", want: true},
		{host: "127.0.0.1", want: true},
		{host: "*.example.com", want: true}, // wildcard is allowed
		// Wrong cases
		{host: "0.0.0.0 example.com", want: false}, // no space allowed
		{host: "example.com.", want: false},        // dot at the end is not allowed
		{host: "-eXample123-.com", want: false},
		{host: "", want: false},
		{host: ".", want: false},
		{host: "example..com", want: false},
		{host: ".example.com", want: false},
		{host: "*.example.com.", want: false},
		{host: "*foo.example.com", want: false},
		{host: "foo.*.example.com", want: false},
		{host: "foo,bar", want: false},
		{host: "project-dev:us-central1:main", want: false},
	} {
		got := hostpital.IsCompatibleRFC6125Pattern(test.host)

		if got != test.want {
			log.Fatalf("failed test #%d: IsCompatibleRFC6125Pattern(%#v) --> %v, want: %v",
				index+1, test.host, got, test.want)
		}
	}

	fmt.Println("OK")
}
Output:

OK

func IsExistingFile

func IsExistingFile(path string) bool

IsExistingFile returns true if the path is an existing file. It returns false if the path is a directory or does not exist.

Example
package main

import (
	"fmt"
	"log"
	"path/filepath"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	for index, sample := range []struct {
		nameFile string
		want     bool
	}{
		{nameFile: "hosts.txt", want: true},
		{nameFile: "hosts_not_exists.txt", want: false},
		{nameFile: "", want: false}, // is directory
	} {
		pathFile := filepath.Join("testdata", sample.nameFile)

		got := hostpital.IsExistingFile(pathFile)

		if got != sample.want {
			log.Fatalf("failed test #%d. input: %s, want: %v, got: %v",
				index+1, pathFile, sample.want, got)
		}
	}

	fmt.Println("OK")
}
Output:

OK

func IsIPAddress

func IsIPAddress(hostName string) bool

IsIPAddress returns true if the given string is a valid IPv4 or IPv6 address. Note that white spaces are not allowed.

Example
package main

import (
	"fmt"
	"log"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	for index, test := range []struct {
		input string
		want  bool
	}{
		// Golden cases
		{input: "0.0.0.0", want: true},
		{input: "::", want: true},
		// Wrong cases
		{input: "0.0.0.0.0", want: false},
	} {
		// Detects IP address (IPV4 and IPV6)
		got := hostpital.IsIPAddress(test.input)
		if got != test.want {
			log.Fatalf("test #%v failed. IsIPAddress(%#v) --> %v (want: %v)",
				index+1, test.input, got, test.want)
		}

		fmt.Printf("IsIPAddress(%#v) --> %v\n", test.input, got)
	}
}
Output:

IsIPAddress("0.0.0.0") --> true
IsIPAddress("::") --> true
IsIPAddress("0.0.0.0.0") --> false

func PickRandom

func PickRandom(items []string) string

PickRandom returns a random item from the given slice.

Example
package main

import (
	"fmt"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	items := []string{
		"one.example.com",
		"two.example.com",
		"three.example.com",
		"four.example.com",
		"five.example.com",
	}

	changed := false
	picked1st := hostpital.PickRandom(items)

	// Pick 10 times since the number of items is too few.
	for i := 0; i < 10; i++ {
		// Sleep for a random time from 0 to 999 milliseconds to avoid the same
		// seed for the random number generator. The CI server is too fast.
		hostpital.SleepRandom(1)

		pickedCurr := hostpital.PickRandom(items)

		if pickedCurr != picked1st {
			changed = true
		}
	}

	fmt.Println("changed:", changed)
}
Output:

changed: true

func ReverseDNS

func ReverseDNS(hostName string) string

ReverseDNS converts the DNS labels in the reverse order.

For example, "www.google.com" will be converted to "com.google.www".

Example
package main

import (
	"fmt"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	// ReverseDNS reverses the order of the labels in a domain name.
	// Useful for grouping hosts by domain name.
	fmt.Println(hostpital.ReverseDNS("www.example.com"))
	fmt.Println(hostpital.ReverseDNS("com.example.www"))
}
Output:

com.example.www
www.example.com

func SleepRandom

func SleepRandom(secMax int)

SleepRandom sleeps for a random amount of time. If secMax is 0 or 1, it sleeps for a random amount of time between 0 and 999 milliseconds.

func TransformToASCII

func TransformToASCII(hostName string) (string, error)

TransformToASCII converts the given hostName in UNICODE to ASCII/punycode.

It does the opposite of TransformToUnicode().

Example
package main

import (
	"fmt"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	// Unicode --> ASCII/Punycode conversion.
	// For the opposite, see TransformToUnicode().
	hostASCII, err := hostpital.TransformToASCII("göpher.com")
	fmt.Println("TransformToASCII(\"göpher.com\") -->", hostASCII, err)
}
Output:

TransformToASCII("göpher.com") --> xn--gpher-jua.com <nil>

func TransformToUnicode

func TransformToUnicode(hostASCII string) (string, error)

TransformToUnicode converts the given punycoded host name in ASCII to UNICODE format.

It does the opposite of TransformToASCII().

Example
package main

import (
	"fmt"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	// ASCII/Punycode --> Unicode conversion. It will error if the input is not
	// convertable to Unicode. For the opposite, see TransformToASCII().
	hostPunycode, err := hostpital.TransformToUnicode("xn--gpher-jua.com")
	fmt.Println("TransformToUnicode(\"xn--gpher-jua.com\") -->", hostPunycode, err)
}
Output:

TransformToUnicode("xn--gpher-jua.com") --> göpher.com <nil>

func TrimComment

func TrimComment(line string) (string, error)

TrimComment removes hash ("#") comments from the given string and trailing spaces.

This function expects the given string to be a line from a hosts file and will error if the given line contains a line break.

Example
package main

import (
	"fmt"
	"log"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	line := "127.0.0.0 localhost # this is a line comment"

	// Trim a comment from a line
	hostTrimmed, err := hostpital.TrimComment(line)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(hostTrimmed)
}
Output:

127.0.0.0 localhost

func TrimDNSByLevel

func TrimDNSByLevel(host string, level int) string

TrimDNSByLevel returns the host name with the specified number of DNS levels.

E.g.

TrimDNSByLevel("www.example.com", 0) returns "com". Such as the top level domain.
TrimDNSByLevel("www.example.com", 1) returns "example.com". Such as the second level domain.
TrimDNSByLevel("www.example.com", 5) returns "www.example.com". As is.
Example
package main

import (
	"fmt"
	"log"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	for index, test := range []struct {
		host  string
		want  string
		level int
	}{
		{host: "www.example.com", level: 0, want: "com"},
		{host: "www.example.com", level: 1, want: "example.com"},
		{host: "www.example.com", level: 2, want: "www.example.com"},
		{host: "www.example.com", level: 5, want: "www.example.com"},
	} {
		got := hostpital.TrimDNSByLevel(test.host, test.level)
		if got != test.want {
			log.Fatalf("failed test #%d: host: %s, level: %d, want: %s, got: %s",
				index, test.host, test.level, test.want, got)
		}

		fmt.Printf("Level %d: %s --> %s\n", test.level, test.host, got)
	}
}
Output:

Level 0: www.example.com --> com
Level 1: www.example.com --> example.com
Level 2: www.example.com --> www.example.com
Level 5: www.example.com --> www.example.com

func TrimIPAdd

func TrimIPAdd(line string) string

TrimIPAdd removes the leading IP address from the given string.

Note that this function expects the given string to be a line from a hosts file. e.g. "0.0.0.0 example.com".

Example
package main

import (
	"fmt"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	for index, line := range []struct {
		input string
		want  string
	}{
		{"", ""},
		{" ", ""},
		{"123.123.123.123", ""},
		{"example.com", "example.com"},
		{"\texample.com", "example.com"},
		{"      example.com", "example.com"},
		{"123.123.123.123 example.com ", "example.com"},
		{"123.123.123.123       example.com ", "example.com"},
		{"123.123.123.123\texample.com ", "example.com"},
		{
			"123.123.123.123    0.0.0.0    sub1.example.com    sub2.example.com",
			"sub1.example.com sub2.example.com",
		},
	} {
		expect := line.want
		actual := hostpital.TrimIPAdd(line.input)

		fmt.Printf("#%d: %q --> %q ... ", index+1, line.input, actual)

		if actual != expect {
			fmt.Printf("FAIL (want: %q, got: %q)\n", expect, actual)
		} else {
			fmt.Println("PASS")
		}
	}
}
Output:

#1: "" --> "" ... PASS
#2: " " --> "" ... PASS
#3: "123.123.123.123" --> "" ... PASS
#4: "example.com" --> "example.com" ... PASS
#5: "\texample.com" --> "example.com" ... PASS
#6: "      example.com" --> "example.com" ... PASS
#7: "123.123.123.123 example.com " --> "example.com" ... PASS
#8: "123.123.123.123       example.com " --> "example.com" ... PASS
#9: "123.123.123.123\texample.com " --> "example.com" ... PASS
#10: "123.123.123.123    0.0.0.0    sub1.example.com    sub2.example.com" --> "sub1.example.com sub2.example.com" ... PASS

func TrimWordGaps

func TrimWordGaps(input string) string

TrimWordGaps reduces redundant and repetitive whitespace in the input string. It removes the line breaks, tabs, leading and trailing spaces as well.

Example
package main

import (
	"fmt"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	for index, input := range []string{
		"0.0.0.0                  example.com",
		"0.0.0.0\texample.com",
		" \t\n\t 127.0.0.1\texample.com\n\n\t#    inline     comment",
		"127.0.0.1\t              example.com      # inline\tcomment",
	} {
		result := hostpital.TrimWordGaps(input)

		fmt.Printf("#%d: %q\n", index+1, result)
	}
}
Output:

#1: "0.0.0.0 example.com"
#2: "0.0.0.0 example.com"
#3: "127.0.0.1 example.com # inline comment"
#4: "127.0.0.1 example.com # inline comment"

Types

type Parser

type Parser struct {
	UseIPAddress string // If not empty and 'TrimIPAddress' is true, use this IP address instead (default: "").

	IDNACompatible    bool // If true, punycode is converted to IDNA2008 compatible (default: true).
	OmitEmptyLine     bool // If true, empty lines are omitted (default: true).
	SortAfterParse    bool // If true, sort the lines after parsing (default: false).
	SortAsReverseDNS  bool // If true, sort the lines as reversed DNS hosts (default: false).
	TrimComment       bool // If true, comment is trimmed (default: true).
	TrimIPAddress     bool // If true, leading IP address is trimmed (default: true).
	TrimLeadingSpace  bool // If true, leading spaces are trimmed (default: true).
	TrimTrailingSpace bool // If true, trailing spaces are trimmed (default: true).
	// contains filtered or unexported fields
}

Parser holds the settings and the rules for the parsing. To simply validate the hostfile, use the methods in the Validator type instead.

Example

This example parses the hosts file as a DNS sinkhole. Which all the hosts will point to 0.0.0.0 and will not be able to connect to the Internet.

package main

import (
	"fmt"
	"log"
	"path/filepath"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	pathFile := filepath.Join("testdata", "default.txt")

	// For the default settings, see the NewValidator() example.
	parser := hostpital.NewParser()

	// Set the IP address to use for all the hosts.
	parser.UseIPAddress = "0.0.0.0"

	parsed, err := parser.ParseFile(pathFile)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(parsed)
}
Output:

0.0.0.0 dummy1.example.com
0.0.0.0 dummy2.example.com
0.0.0.0 dummy3.example.com
0.0.0.0 dummy4.example.com
0.0.0.0 dummy5.example.com dummy6.example.com

func NewParser

func NewParser() *Parser

NewParser returns a new Parser instance with the default values.

func (*Parser) CountLines

func (p *Parser) CountLines(pathFile string) (int, error)

CountLines counts the number of lines in the file.

func (*Parser) ParseFile

func (p *Parser) ParseFile(pathFile string) (string, error)

ParseFile reads the file from pathFile and returns the parsed lines as a string according to the settings in the Parser.

func (*Parser) ParseFileTo

func (p *Parser) ParseFileTo(pathFileIn string, fileOut io.Writer) error

ParseFileTo reads the file from pathFileIn and writes the parsed lines to fileOut.

Example
package main

import (
	"bytes"
	"fmt"
	"log"
	"path/filepath"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	pathFile := filepath.Join("testdata", "default.txt")

	parser := hostpital.NewParser()

	// Set property to sort after parsing
	parser.SortAfterParse = true

	// Create a buffer to store the parsed hosts file
	var buf bytes.Buffer

	// Execute ParseFileTo
	if err := parser.ParseFileTo(pathFile, &buf); err != nil {
		log.Fatal(err)
	}

	fmt.Println(buf.String())
}
Output:

dummy1.example.com
dummy2.example.com
dummy3.example.com
dummy4.example.com
dummy5.example.com dummy6.example.com

func (*Parser) ParseLine

func (p *Parser) ParseLine(line string) (string, bool)

ParseLine parses the given line and returns the parsed line as a string according to the settings in the Parser.

func (*Parser) ParseString

func (p *Parser) ParseString(input string) string

ParseString parses the given string and returns the parsed lines as a string according to the settings in the Parser.

Example
package main

import (
	"fmt"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	hosts := `# this is a comment
badboy5.example.com      badboy6.example.com

# this is another comment
123.123.123.120 badboy4.example.com
123.123.123.121 badboy3.example.com
123.123.123.122 badboy2.example.com
123.123.123.123 badboy1.example.com
`

	parser := hostpital.NewParser()

	// Set property for user custom settings
	parser.SortAfterParse = true
	parser.UseIPAddress = "0.0.0.0"

	parsed := parser.ParseString(hosts)

	fmt.Println(parsed)
}
Output:

0.0.0.0 badboy1.example.com
0.0.0.0 badboy2.example.com
0.0.0.0 badboy3.example.com
0.0.0.0 badboy4.example.com
0.0.0.0 badboy5.example.com badboy6.example.com

type Validator

type Validator struct {
	AllowComment       bool // If true, the line can be a comment (default: false).
	AllowEmptyLine     bool // If true, empty line returns true (default: true).
	AllowHyphen        bool // If true, the label can begin with hyphen (default: false).
	AllowHyphenDouble  bool // If true, unconvertable punycode with double hyphen is allowed (default: false).
	AllowIndent        bool // If true, the line can be indented (default: false).
	AllowIPAddressOnly bool // If true, the line can be only an IP address (default: false).
	AllowTrailingSpace bool // If true, the line can have trailing spaces (default: false).
	AllowUnderscore    bool // If true, the label can have underscore (default: false).
	IDNACompatible     bool // If true, the host must be compatible to IDNA2008 and false to RFC 6125 2.2 (default: true).
	// contains filtered or unexported fields
}

Validator holds the settings and the rules for the validation. To clean up the hostfile, use the methods in the Parser type instead.

It is recommended to use NewValidator() to create a new Validator due to the default values.

Example
package main

import (
	"fmt"

	"github.com/Code-Hex/dd"
	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	validator := hostpital.NewValidator()

	// Print default settings
	fmt.Println(dd.Dump(validator))

}
Output:

&hostpital.Validator{
  mutx: sync.Mutex{
    state: 0,
    sema: 0,
  },
  AllowComment: false,
  AllowEmptyLine: true,
  AllowHyphen: false,
  AllowHyphenDouble: false,
  AllowIndent: false,
  AllowIPAddressOnly: false,
  AllowTrailingSpace: false,
  AllowUnderscore: false,
  IDNACompatible: true,
  isInitialized: true,
}

func NewValidator

func NewValidator() *Validator

NewValidator returns a new Validator instance with the default values.

func (*Validator) ValidateFile

func (v *Validator) ValidateFile(pathFile string) bool

ValidateFile returns true if the file is valid according to the settings.

Example
package main

import (
	"fmt"
	"path/filepath"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	// Validator with default settings
	validator := hostpital.NewValidator()

	// Want RFC 6125 2.2 compatibility. If true, IDNA2008 compatible.
	validator.IDNACompatible = false
	// Allow comment lines in the hostfile.
	validator.AllowComment = true
	// Allow labels to begin with hyphen.
	// This setting is useful to manage hosts file for DNS sinkhole. "traditional
	// domain name" does not allow hyphen in the first character position of
	// their labels. Such as "m.-www99a.abc.example.com" for example. Usually
	// it is blocked by the client side's router, browser, etc. However, some
	// malicious domains owns their name server configured to resolve it to find
	// out web clients who doesn't care about it.
	validator.AllowHyphen = true

	// Validate a file
	pathFile := filepath.Join("testdata", "hosts.txt")

	if validator.ValidateFile(pathFile) {
		fmt.Println("The hostfile is valid.")
	}

}
Output:

The hostfile is valid.

func (*Validator) ValidateLine

func (v *Validator) ValidateLine(line string) error

ValidateLine returns nil if the line is valid according to the settings.

Example
package main

import (
	"fmt"

	"github.com/KEINOS/go-hostpital/hostpital"
)

func main() {
	// Validator with default settings
	//   AllowComment: false
	//   AllowEmptyLine: true
	//   AllowHyphen: false
	//   AllowHyphenDouble: false
	//   AllowIndent: false
	//   AllowIPAddressOnly: false
	//   AllowTrailingSpace: false
	//   AllowUnderscore: false
	//   IDNACompatible: true
	validator := hostpital.NewValidator()

	// User custom settings
	validator.AllowTrailingSpace = true

	for index, line := range []string{
		// Valid cases according to the settings.
		"example.com",
		"example.com           ",
		"",
		// Invalid cases according to the settings.
		"           example.com",
		"123.123.123.123",
		"# This is a comment line",
		"example.com # This is an in-line comment",
		"         ", // false. Empty line is allowed but indent is not allowed.
	} {
		err := validator.ValidateLine(line)
		fmt.Printf("#%d: %v\n", index+1, err)
	}
}
Output:

#1: <nil>
#2: <nil>
#3: <nil>
#4: failed to trim line: indent is not allowed
#5: IP address only line is not allowed
#6: failed to validate chunk/part of line: "#" is not IDNA2008 compatible: idna: disallowed rune U+0023
#7: failed to validate chunk/part of line: "#" is not IDNA2008 compatible: idna: disallowed rune U+0023
#8: failed to trim line: indent is not allowed

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL