2021-09-15 08:28:09 +00:00
package config
import (
"bytes"
"fmt"
"io/ioutil"
"os"
2021-09-15 14:04:16 +00:00
"runtime"
2021-09-15 08:28:09 +00:00
"github.com/rs/zerolog"
"github.com/spf13/viper"
)
const (
2021-09-15 14:04:16 +00:00
Version = "0.3"
Title = "HellPot"
2021-09-15 08:28:09 +00:00
)
2021-09-15 19:17:32 +00:00
var BannerOnly = false
2021-09-15 16:13:16 +00:00
// "http"
2021-09-15 08:28:09 +00:00
var (
// BindAddr is defined via our toml configuration file. It is the address that HellPot listens on.
BindAddr string
// BindPort is defined via our toml configuration file. It is the port that HellPot listens on.
BindPort string
// Paths are defined via our toml configuration file. These are the paths that HellPot will present for "robots.txt"
// These are also the paths that HellPot will respond for. Other paths will throw a warning and will serve a 404.
Paths [ ] string
2021-09-15 16:13:16 +00:00
UseUnixSocket bool
UnixSocketPath = ""
)
// "performance"
var (
RestrictConcurrency bool
2021-09-15 19:17:32 +00:00
MaxWorkers int
2021-09-15 16:13:16 +00:00
)
// "diception"
var (
// FakeServerName is our configured value for the "Server: " response header when serving HTTP clients
FakeServerName string
2021-09-15 08:28:09 +00:00
)
var (
// Filename returns the current location of our toml config file.
Filename string
)
var (
f * os . File
err error
2021-09-15 14:04:16 +00:00
NoColor bool
2021-09-15 08:28:09 +00:00
customconfig = false
home string
configLocations [ ] string
)
/ *
Opt represents our program options .
nitially the values that are defined in Opt will be used to define details .
Beyond that , default values will be replaced by options from our config file .
* /
var Opt map [ string ] map [ string ] interface { }
var (
// Debug is our global debug toggle
Debug bool
prefConfigLocation string
snek * viper . Viper
)
func init ( ) {
if home , err = os . UserHomeDir ( ) ; err != nil {
panic ( err )
}
2021-09-15 14:04:16 +00:00
prefConfigLocation = home + "/.config/" + Title
2021-09-15 08:28:09 +00:00
Opt = make ( map [ string ] map [ string ] interface { } )
snek = viper . New ( )
}
// Init will initialize our toml configuration engine and define our default configuration values which can be written to a new configuration file if desired
func Init ( ) {
snek . SetConfigType ( "toml" )
snek . SetConfigName ( "config" )
argParse ( )
if customconfig {
associate ( )
return
}
acquireClue ( )
setDefaults ( )
for _ , loc := range configLocations {
snek . AddConfigPath ( loc )
}
2021-09-15 14:04:16 +00:00
if err = snek . MergeInConfig ( ) ; err != nil && runtime . GOOS != "windows" {
2021-09-15 08:28:09 +00:00
if _ , err := os . Stat ( prefConfigLocation ) ; os . IsNotExist ( err ) {
if err = os . Mkdir ( prefConfigLocation , 0755 ) ; err != nil {
2021-09-15 13:43:01 +00:00
println ( "error writing new config: " + err . Error ( ) )
2021-09-15 08:28:09 +00:00
}
}
2021-09-15 14:04:16 +00:00
newconfig := prefConfigLocation + "/" + "config.toml"
if err = snek . SafeWriteConfigAs ( newconfig ) ; err != nil {
2021-09-15 08:28:09 +00:00
fmt . Println ( err . Error ( ) )
os . Exit ( 1 )
}
2021-09-15 14:04:16 +00:00
Filename = newconfig
2021-09-15 08:28:09 +00:00
}
2021-09-15 14:04:16 +00:00
if runtime . GOOS == "windows" {
newconfig := "hellpot-config"
snek . SetConfigName ( newconfig )
if err = snek . MergeInConfig ( ) ; err != nil {
if err = snek . SafeWriteConfigAs ( newconfig + ".toml" ) ; err != nil {
fmt . Println ( err . Error ( ) )
os . Exit ( 1 )
}
}
Filename = newconfig
}
if len ( Filename ) < 1 {
Filename = snek . ConfigFileUsed ( )
}
2021-09-15 08:28:09 +00:00
associate ( )
}
func setDefaults ( ) {
2021-09-15 14:04:16 +00:00
var (
2021-09-15 16:13:16 +00:00
configSections = [ ] string { "logger" , "http" , "performance" , "diception" }
2021-09-15 14:04:16 +00:00
deflogdir = home + "/.config/" + Title + "/logs/"
defNoColor = false
)
if runtime . GOOS == "windows" {
deflogdir = "logs/"
defNoColor = true
}
2021-09-15 08:28:09 +00:00
Opt [ "logger" ] = map [ string ] interface { } {
2021-09-15 14:04:16 +00:00
"debug" : true ,
"directory" : deflogdir ,
"nocolor" : defNoColor ,
"use_date_filename" : true ,
2021-09-15 08:28:09 +00:00
}
Opt [ "http" ] = map [ string ] interface { } {
2021-09-15 16:13:16 +00:00
"use_unix_socket" : false ,
"unix_socket" : "/var/run/hellpot" ,
"bind_addr" : "127.0.0.1" ,
"bind_port" : "8080" ,
2021-09-15 08:28:09 +00:00
"paths" : [ ] string {
"wp-login.php" ,
"wp-login" ,
} ,
}
2021-09-15 16:13:16 +00:00
Opt [ "performance" ] = map [ string ] interface { } {
"restrict_concurrency" : false ,
2021-09-15 19:17:32 +00:00
"max_workers" : 256 ,
2021-09-15 16:13:16 +00:00
}
Opt [ "diception" ] = map [ string ] interface { } {
"server_name" : "nginx" ,
}
2021-09-15 08:28:09 +00:00
for _ , def := range configSections {
snek . SetDefault ( def , Opt [ def ] )
}
}
func acquireClue ( ) {
configLocations = append ( configLocations , "./" )
2021-09-15 14:04:16 +00:00
if runtime . GOOS != "windows" {
configLocations = append ( configLocations , prefConfigLocation )
configLocations = append ( configLocations , "/etc/" + Title + "/" )
configLocations = append ( configLocations , "../" )
configLocations = append ( configLocations , "../../" )
}
2021-09-15 08:28:09 +00:00
}
func loadCustomConfig ( path string ) {
if f , err = os . Open ( path ) ; err != nil {
println ( "Error opening specified config file: " + path )
panic ( "config file open fatal error: " + err . Error ( ) )
}
buf , err := ioutil . ReadAll ( f )
err2 := snek . ReadConfig ( bytes . NewBuffer ( buf ) )
switch {
case err != nil :
fmt . Println ( "config file read fatal error: " , err . Error ( ) )
case err2 != nil :
fmt . Println ( "config file read fatal error: " , err2 . Error ( ) )
default :
break
}
customconfig = true
}
// TODO: should probably just make a proper CLI with flags or something
func argParse ( ) {
for i , arg := range os . Args {
switch arg {
2021-09-15 14:04:16 +00:00
case "-h" :
println ( "HellPot: use -c <file.toml> to specify config file." )
os . Exit ( 0 )
case "--config" :
fallthrough
2021-09-15 19:17:32 +00:00
case "--banner" :
BannerOnly = true
2021-09-15 08:28:09 +00:00
case "-c" :
if len ( os . Args ) <= i - 1 {
panic ( "syntax error! expected file after -c" )
}
loadCustomConfig ( os . Args [ i + 1 ] )
default :
continue
}
}
}
func associate ( ) {
var newOpt map [ string ] map [ string ] interface { }
newOpt = Opt
for category , opt := range Opt {
for optname , value := range opt {
if snek . IsSet ( category + "." + optname ) {
newOpt [ category ] [ optname ] = value
}
}
}
Opt = newOpt
Debug = snek . GetBool ( "logger.debug" )
logDir = snek . GetString ( "logger.directory" )
2021-09-15 14:04:16 +00:00
NoColor = snek . GetBool ( "logger.nocolor" )
2021-09-15 08:28:09 +00:00
BindAddr = snek . GetString ( "http.bind_addr" )
BindPort = snek . GetString ( "http.bind_port" )
Paths = snek . GetStringSlice ( "http.paths" )
2021-09-15 16:13:16 +00:00
UseUnixSocket = snek . GetBool ( "http.use_unix_socket" )
FakeServerName = snek . GetString ( "diception.server_name" )
RestrictConcurrency = snek . GetBool ( "performance.restrict_concurrency" )
MaxWorkers = snek . GetInt ( "performance.max_workers" )
if UseUnixSocket {
UnixSocketPath = snek . GetString ( "http.unix_socket_path" )
}
2021-09-15 08:28:09 +00:00
if Debug {
zerolog . SetGlobalLevel ( zerolog . DebugLevel )
}
}