Initial commit
This commit is contained in:
98
helpers/config.go
Normal file
98
helpers/config.go
Normal file
@@ -0,0 +1,98 @@
|
||||
// Package helpers provides useful helper structures for KermaGo
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
ipAddress = "3.126.74.45"
|
||||
port = 18018
|
||||
connTimeout = 10
|
||||
storeBaseDir = "/var/local/badkerma"
|
||||
peerListStore = "peers.json"
|
||||
blockStore = "blocks.json"
|
||||
transactionStore = "transactions.json"
|
||||
privateKeyFile = "private.pem"
|
||||
listenAddr = "0.0.0.0"
|
||||
initialPeerList = ""
|
||||
)
|
||||
|
||||
/*
|
||||
A Config is a helper used for storing and obtaining the application configuration.
|
||||
Supported configuration includes:
|
||||
- IPAddress
|
||||
- Port
|
||||
- ListenAddr - address to listen on
|
||||
- ConnTimeout - timeout for the client connections
|
||||
- PeerListStore - filename for the peer list store
|
||||
- BlockStore - filename for the blockchain store
|
||||
- TransactionStore - filename for the transaction store
|
||||
- PrivateKeyFile - filename for the private key
|
||||
- InitialPeerList - initial peer list for building up
|
||||
*/
|
||||
type Config struct {
|
||||
IPAddress string
|
||||
Port int
|
||||
PeerListStore string
|
||||
ConnTimeout int
|
||||
PrivateKeyFile string
|
||||
BlockStore string
|
||||
TransactionStore string
|
||||
ListenAddr string
|
||||
InitialPeerList string
|
||||
}
|
||||
|
||||
/*
|
||||
Construct fetches the configuration from the KERMA_* environment variables or sets sensible defaults
|
||||
*/
|
||||
func (c *Config) Construct() {
|
||||
c.IPAddress = ipAddress
|
||||
c.Port = port
|
||||
c.PeerListStore = peerListStore
|
||||
c.ConnTimeout = connTimeout
|
||||
c.PrivateKeyFile = privateKeyFile
|
||||
c.BlockStore = blockStore
|
||||
c.TransactionStore = transactionStore
|
||||
c.InitialPeerList = initialPeerList
|
||||
|
||||
baseDir := storeBaseDir
|
||||
|
||||
if os.Getenv("KERMA_IP_ADDR") != "" {
|
||||
c.IPAddress = os.Getenv("KERMA_IP_ADDR")
|
||||
}
|
||||
if os.Getenv("KERMA_PORT") != "" {
|
||||
c.Port, _ = strconv.Atoi(os.Getenv("KERMA_PORT"))
|
||||
}
|
||||
if os.Getenv("KERMA_CONN_TIMEOUT") != "" {
|
||||
c.ConnTimeout, _ = strconv.Atoi(os.Getenv("KERMA_CONN_TIMEOUT"))
|
||||
}
|
||||
if os.Getenv("KERMA_INITIAL_PEER_LIST") != "" {
|
||||
c.InitialPeerList = os.Getenv("KERMA_INITIAL_PEER_LIST")
|
||||
}
|
||||
if os.Getenv("KERMA_STORE_BASE_DIR") != "" {
|
||||
baseDir = os.Getenv("KERMA_STORE_BASE_DIR")
|
||||
baseDir = strings.TrimSuffix(baseDir, "/")
|
||||
}
|
||||
if os.Getenv("KERMA_PEER_LIST_STORE") != "" {
|
||||
c.PeerListStore = os.Getenv("KERMA_PEER_LIST_STORE")
|
||||
}
|
||||
if os.Getenv("KERMA_BLOCK_STORE") != "" {
|
||||
c.BlockStore = os.Getenv("KERMA_BLOCK_STORE")
|
||||
}
|
||||
if os.Getenv("KERMA_TRANSACTION_STORE") != "" {
|
||||
c.TransactionStore = os.Getenv("KERMA_TRANSACTION_STORE")
|
||||
}
|
||||
if os.Getenv("KERMA_PRIVATE_KEY_FILE") != "" {
|
||||
c.PrivateKeyFile = os.Getenv("KERMA_PRIVATE_KEY_FILE")
|
||||
}
|
||||
|
||||
c.PeerListStore = baseDir + "/" + c.PeerListStore
|
||||
c.BlockStore = baseDir + "/" + c.BlockStore
|
||||
c.TransactionStore = baseDir + "/" + c.TransactionStore
|
||||
c.PrivateKeyFile = baseDir + "/" + c.PrivateKeyFile
|
||||
c.ListenAddr = listenAddr + ":" + fmt.Sprint(c.Port)
|
||||
}
|
57
helpers/logger.go
Normal file
57
helpers/logger.go
Normal file
@@ -0,0 +1,57 @@
|
||||
// Package helpers provides useful helper structures for KermaGo
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
/*
|
||||
A Logger is a helper used for logging messages to stdout and stderr
|
||||
*/
|
||||
type Logger struct{}
|
||||
|
||||
/*
|
||||
Debug logs a debug message to stdout if the KERMA_DEBUG environment variable is set to true
|
||||
*/
|
||||
func (l *Logger) Debug(msg string) {
|
||||
if os.Getenv("KERMA_DEBUG") == "true" {
|
||||
t := time.Now()
|
||||
_, _ = fmt.Fprintln(os.Stdout, t.Format(time.RFC1123)+" [DEBUG] "+msg)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Info logs an info message to stdout
|
||||
*/
|
||||
func (l *Logger) Info(msg string) {
|
||||
t := time.Now()
|
||||
_, _ = fmt.Fprintln(os.Stdout, t.Format(time.RFC1123)+" [INFO] "+msg)
|
||||
}
|
||||
|
||||
/*
|
||||
Warn logs a warning message to stderr
|
||||
*/
|
||||
func (l *Logger) Warn(msg string) {
|
||||
t := time.Now()
|
||||
_, _ = fmt.Fprintln(os.Stderr, t.Format(time.RFC1123)+" [WARN] "+msg)
|
||||
}
|
||||
|
||||
/*
|
||||
Error logs an error message to stderr
|
||||
*/
|
||||
func (l *Logger) Error(msg string) {
|
||||
t := time.Now()
|
||||
_, _ = fmt.Fprintln(os.Stderr, t.Format(time.RFC1123)+" [ERROR] "+msg)
|
||||
}
|
||||
|
||||
/*
|
||||
Fatal logs a fatal message to stderr and terminates the application
|
||||
*/
|
||||
func (l *Logger) Fatal(msg string) {
|
||||
t := time.Now()
|
||||
_, _ = fmt.Fprintln(os.Stderr, t.Format(time.RFC1123)+" [FATAL] "+msg)
|
||||
os.Exit(1)
|
||||
}
|
91
helpers/tests/validator_test.go
Normal file
91
helpers/tests/validator_test.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"kerma/helpers"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestValidator(t *testing.T) {
|
||||
Convey("Given a new validator", t, func() {
|
||||
var validator helpers.Validator
|
||||
validator.Construct()
|
||||
|
||||
Convey("When the IsValidFQDN method is called", func() {
|
||||
Convey("When the input is an invalid FQDN, 'false' should be returned", func() {
|
||||
So(validator.IsValidFQDN("!!!$"), ShouldEqual, false)
|
||||
})
|
||||
|
||||
Convey("When the input is a valid FQDN, 'true' should be returned", func() {
|
||||
So(validator.IsValidFQDN("example.com"), ShouldEqual, true)
|
||||
So(validator.IsValidFQDN("sub.example.com"), ShouldEqual, true)
|
||||
So(validator.IsValidFQDN("sub1.example.com"), ShouldEqual, true)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When the IsValidIP method is called", func() {
|
||||
Convey("When the input is an invalid IP, 'false' should be returned", func() {
|
||||
So(validator.IsValidIP("!!!$"), ShouldEqual, false)
|
||||
So(validator.IsValidIP("example.com"), ShouldEqual, false)
|
||||
So(validator.IsValidIP("127.0.0.1"), ShouldEqual, false)
|
||||
So(validator.IsValidIP(validator.Config.IPAddress), ShouldEqual, false)
|
||||
})
|
||||
|
||||
Convey("When the input is a valid FQDN, 'true' should be returned", func() {
|
||||
So(validator.IsValidIP("1.1.1.1"), ShouldEqual, true)
|
||||
So(validator.IsValidIP("172.16.2.1"), ShouldEqual, true)
|
||||
So(validator.IsValidIP("192.168.150.2"), ShouldEqual, true)
|
||||
So(validator.IsValidIP("10.11.231.2"), ShouldEqual, true)
|
||||
So(validator.IsValidIP("254.254.252.251"), ShouldEqual, true)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When the IsValidPort method is called", func() {
|
||||
Convey("When the input is an invalid port, 'false' should be returned", func() {
|
||||
So(validator.IsValidPort("-1"), ShouldEqual, false)
|
||||
So(validator.IsValidPort("123456"), ShouldEqual, false)
|
||||
So(validator.IsValidPort("0"), ShouldEqual, false)
|
||||
So(validator.IsValidPort("example.com"), ShouldEqual, false)
|
||||
})
|
||||
|
||||
Convey("When the input is a valid port, 'true' should be returned", func() {
|
||||
So(validator.IsValidPort("18018"), ShouldEqual, true)
|
||||
So(validator.IsValidPort("65535"), ShouldEqual, true)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When the IsValidPeerName method is called", func() {
|
||||
Convey("When the input is an invalid peer name, 'false' should be returned", func() {
|
||||
So(validator.IsValidPeerName("192.168.150.2:-1"), ShouldEqual, false)
|
||||
So(validator.IsValidPeerName("172.16.2.1:123456"), ShouldEqual, false)
|
||||
So(validator.IsValidPeerName("127.0.0.1:18018"), ShouldEqual, false)
|
||||
So(validator.IsValidPeerName("example.com:111111"), ShouldEqual, false)
|
||||
})
|
||||
|
||||
Convey("When the input is a valid peer name, 'true' should be returned", func() {
|
||||
So(validator.IsValidPeerName("example.com:18018"), ShouldEqual, true)
|
||||
So(validator.IsValidPeerName("sub.example.com:11111"), ShouldEqual, true)
|
||||
So(validator.IsValidPeerName("172.16.2.1:18018"), ShouldEqual, true)
|
||||
So(validator.IsValidPeerName("192.168.150.2:18018"), ShouldEqual, true)
|
||||
So(validator.IsValidPeerName("10.11.231.2:18018"), ShouldEqual, true)
|
||||
So(validator.IsValidPeerName("254.254.252.251:18018"), ShouldEqual, true)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When the CheckIfFileExists method is called", func() {
|
||||
Convey("When the input is a non-existent file, 'false' should be returned", func() {
|
||||
So(validator.CheckIfFileExists("nonexisting.test"), ShouldEqual, false)
|
||||
})
|
||||
|
||||
Convey("When the input is an existing file, 'true' should be returned", func() {
|
||||
buff := make([]byte, 100)
|
||||
ioutil.WriteFile("existing.test", buff, 0666)
|
||||
So(validator.CheckIfFileExists("existing.test"), ShouldEqual, true)
|
||||
os.Remove("existing.test")
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
83
helpers/validator.go
Normal file
83
helpers/validator.go
Normal file
@@ -0,0 +1,83 @@
|
||||
// Package helpers provides useful helper structures for KermaGo
|
||||
package helpers
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
/*
|
||||
A Validator is a helper used to validate inputs based on a specified config
|
||||
*/
|
||||
type Validator struct {
|
||||
Config Config
|
||||
}
|
||||
|
||||
/*
|
||||
Construct creates a new validator
|
||||
*/
|
||||
func (v *Validator) Construct() {
|
||||
v.Config.Construct()
|
||||
}
|
||||
|
||||
/*
|
||||
IsValidFQDN checks if the string provided corresponds to a valid domain name
|
||||
*/
|
||||
func (v *Validator) IsValidFQDN(fqdn string) bool {
|
||||
// see: https://www.socketloop.com/tutorials/golang-use-regular-expression-to-validate-domain-name
|
||||
RegExp := regexp.MustCompile(`^(([a-zA-Z]{1})|([a-zA-Z]{1}[a-zA-Z]{1})|([a-zA-Z]{1}[0-9]{1})|([0-9]{1}[a-zA-Z]{1})|([a-zA-Z0-9][a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]))\.([a-zA-Z]{2,6}|[a-zA-Z0-9-]{2,30}\.[a-zA-Z
|
||||
]{2,3})$`)
|
||||
|
||||
return RegExp.MatchString(fqdn)
|
||||
}
|
||||
|
||||
/*
|
||||
IsValidPeerName checks if the string provided is a valid peer name. This includes valid domain + port combinations, valid IP + port combinations as well as only domains and IPs with default port 18018
|
||||
*/
|
||||
func (v *Validator) IsValidPeerName(peerName string) bool {
|
||||
addr := ""
|
||||
port := ""
|
||||
|
||||
if strings.Contains(peerName, ":") {
|
||||
buf := strings.Split(peerName, ":")
|
||||
addr = buf[0]
|
||||
port = buf[1]
|
||||
} else {
|
||||
addr = peerName
|
||||
port = "18018"
|
||||
}
|
||||
|
||||
if !v.IsValidIP(addr) {
|
||||
return v.IsValidFQDN(addr) && v.IsValidPort(port)
|
||||
}
|
||||
return v.IsValidPort(port)
|
||||
}
|
||||
|
||||
/*
|
||||
IsValidPort checks if the string provided is a port in the valid port range
|
||||
*/
|
||||
func (v *Validator) IsValidPort(port string) bool {
|
||||
portInt, err := strconv.ParseInt(port, 10, 32)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return portInt > 0 && portInt <= 65535
|
||||
}
|
||||
|
||||
/*
|
||||
IsValidIP checks if the string provided is a valid IP address. Valid IP addresses exclude 127.0.0.1 and the configured listen address
|
||||
*/
|
||||
func (v *Validator) IsValidIP(ip string) bool {
|
||||
return net.ParseIP(ip) != nil && ip != "127.0.0.1" && ip != v.Config.IPAddress
|
||||
}
|
||||
|
||||
/*
|
||||
CheckIfFileExists checks if the path specified is an existing file
|
||||
*/
|
||||
func (v *Validator) CheckIfFileExists(path string) bool {
|
||||
_, err := os.Stat(path)
|
||||
return err == nil
|
||||
}
|
Reference in New Issue
Block a user