Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Essentially Rewrite HellPot + Fun Bonus Features #162

Closed
wants to merge 38 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
ef69b86
Add optional `-b`/`--book` flag to choose source file other than Niet…
ginger51011 Jan 18, 2024
ac77dcc
Remove globals from heffalump/*, add NewDefault{Heffalump,MarkovMap}()
ginger51011 Jan 19, 2024
1b8de3d
Add short flags to help, add `--help` flag
ginger51011 Jan 20, 2024
0a3cc6d
Rename --book to --grimoire, fix comments
ginger51011 Feb 2, 2024
6e183db
Merge pull request #131 from ginger51011/feat/add-file-flag
yunginnanet Apr 14, 2024
e016fba
add JSON hell, and enable more kinds of hell in the future
ShadowJonathan Jan 31, 2024
54e492c
fix plaintext
ShadowJonathan Jan 31, 2024
53afe56
Merge pull request #137 from ShadowJonathan/with-json
yunginnanet Apr 19, 2024
a06c356
Merge branch 'main' into development
yunginnanet Apr 19, 2024
b647b54
Feat[CI]: run release build matrix on github release creation
yunginnanet May 1, 2024
81e2fb3
Fix[CD]: run release build matrix on github release creation
yunginnanet May 1, 2024
a4ab0cb
Fix[CD]: run release build matrix on github release creation, workflo…
yunginnanet May 1, 2024
e63d81a
Fix[CD]: bump go version and don't package tar.gz in favor of just bin
yunginnanet May 1, 2024
cefb21b
Fix[CD]: bump go version and don't package tar.gz in favor of just bi…
yunginnanet May 1, 2024
c309667
Fix[CD]: try to fix go-release-action config
yunginnanet May 1, 2024
e8888b2
Merge branch 'main' into development
yunginnanet May 19, 2024
67877b7
Merge branch 'main' into development
yunginnanet Jun 19, 2024
20c41be
Merge branch 'main' into development
yunginnanet Jun 20, 2024
14ba022
Merge branch 'main' into development
yunginnanet Jun 21, 2024
cc7020f
TeeHee: Essentially rewrite HellPot :^)
yunginnanet Jun 21, 2024
3c2059a
Fix: build and vet errors
yunginnanet Jun 21, 2024
df5c936
Fix: Remove unused git stash lint
yunginnanet Jun 21, 2024
db0ec03
SAST: Resolve gosec G304
yunginnanet Jun 21, 2024
8519480
Fix: don't parse flags during unit tests
yunginnanet Jun 21, 2024
843d04a
Chore: prune deps
yunginnanet Jun 21, 2024
be9700a
Resolve https://github.com/yunginnanet/HellPot/pull/162#discussion_r1…
yunginnanet Jun 21, 2024
da2fadd
Fix: nil check on buffer pointer
yunginnanet Jun 21, 2024
ee11dd3
WIP rewrite progress, config loading broken atm
yunginnanet Jun 26, 2024
833b424
Fix: fix configuration file loading
yunginnanet Jun 26, 2024
317fd91
Security (logger): Resolve gosec G301 (CWE-276)
yunginnanet Jun 26, 2024
e9785d2
Security (logger): Resolve gosec G302 (CWE-276)
yunginnanet Jun 26, 2024
dfad295
Chore: Tidy up, split up files in main package
yunginnanet Jun 26, 2024
303aa0b
Chore: go mod tidy
yunginnanet Jun 26, 2024
362c1d3
Fix: cli arg, config, and logger fixes
yunginnanet Jun 26, 2024
888142b
Fix: Embolden main package test, improve default config warning
yunginnanet Jun 26, 2024
eac788b
Fix: add missing `util.go`
yunginnanet Jun 26, 2024
031e116
Revert "add JSON hell, and enable more kinds of hell in the future"
yunginnanet Jun 26, 2024
e5831c0
Revert "fix plaintext"
yunginnanet Jun 26, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Clients (hopefully bots) that disregard `robots.txt` and connect to your instanc

HellPot will send an infinite stream of data that is _just close enough_ to being a real website that they might just stick around until their soul is ripped apart and they cease to exist.

Under the hood of this eternal suffering is a markov engine that chucks bits and pieces of [The Birth of Tragedy (Hellenism and Pessimism)](https://www.gutenberg.org/files/51356/51356-h/51356-h.htm) by Friedrich Nietzsche at the client using [fasthttp](https://github.com/valyala/fasthttp).
Under the hood of this eternal suffering is a markov engine that chucks bits and pieces of [The Birth of Tragedy (Hellenism and Pessimism)](https://www.gutenberg.org/files/51356/51356-h/51356-h.htm) by Friedrich Nietzsche at the client~~~~ using [fasthttp](https://github.com/valyala/fasthttp), or optionally you may synchronize HellPot with your nightmares by using the `-g`/`--grimoire` flag

## Building From Source

Expand Down
54 changes: 11 additions & 43 deletions cmd/HellPot/HellPot.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,58 +2,26 @@ package main

import (
"os"
"os/signal"
"syscall"

"github.com/rs/zerolog"

"github.com/yunginnanet/HellPot/internal/config"
"github.com/yunginnanet/HellPot/internal/extra"
"github.com/yunginnanet/HellPot/internal/http"
)

var (
log zerolog.Logger
version string // set by linker
)

func init() {
if version != "" {
config.Version = version[1:]
}
config.Init()
if config.BannerOnly {
extra.Banner()
os.Exit(0)
}
func main() {
stopChan := make(chan os.Signal, 1)
log, _, resolvedConf, realConf, err := setup(stopChan)

switch config.DockerLogging {
case true:
config.CurrentLogFile = "/dev/stdout"
config.NoColor = true
log = config.StartLogger(false, os.Stdout)
default:
log = config.StartLogger(true)
if err != nil {
println("failed to start: " + err.Error())
os.Exit(1)
}

extra.Banner()

log.Info().Str("caller", "config").Str("file", config.Filename).Msg(config.Filename)
log.Info().Str("caller", "logger").Msg(config.CurrentLogFile)
log.Debug().Str("caller", "logger").Msg("debug enabled")
log.Trace().Str("caller", "logger").Msg("trace enabled")

}

func main() {
stopChan := make(chan os.Signal, 1)
signal.Notify(stopChan, syscall.SIGINT, syscall.SIGTERM)
printInfo(log, resolvedConf, realConf)

go func() {
log.Fatal().Err(http.Serve()).Msg("HTTP error")
log.Fatal().Err(http.Serve(realConf)).Msg("HTTP error")
}()

<-stopChan // wait for SIGINT
log.Warn().Msg("Shutting down server...")

sig := <-stopChan // wait for SIGINT
log.Warn().Interface("signal_received", sig).
Msg("Shutting down server...")
}
88 changes: 88 additions & 0 deletions cmd/HellPot/HellPot_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package main

import (
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"time"

"github.com/yunginnanet/HellPot/internal/config"
"github.com/yunginnanet/HellPot/internal/http"
)

func testMain(t *testing.T) (string, string, chan os.Signal, *config.Parameters, error) {
t.Helper()
stopChan := make(chan os.Signal, 1)

log, logFile, resolvedConf, realConfig, err := setup(stopChan)
if err == nil {
printInfo(log, resolvedConf, realConfig)
go func() {
terr := http.Serve(realConfig)
if terr != nil {
t.Error("failed to serve HTTP: " + terr.Error())
close(stopChan)
}
}()
}
//goland:noinspection GoNilness
return resolvedConf, logFile, stopChan, realConfig, err
}

func TestHellPot(t *testing.T) {
tDir := filepath.Join(t.TempDir(), strconv.Itoa(int(time.Now().Unix())))
logDir := filepath.Join(tDir, "logs")
if err := os.MkdirAll(logDir, 0755); err != nil {
t.Fatal(err)
}
confFile := filepath.Join(tDir, "HellPot_test.toml")
t.Setenv("HELLPOT_LOGGER_DIRECTORY", logDir)
t.Setenv("HELLPOT_CONFIG", confFile)

resolvedConf, logFile, stopChan, realConfig, err := testMain(t)
if err != nil {
t.Fatal(err)
}
if stopChan == nil {
t.Fatal("stopChan is nil")
}
if resolvedConf == "" {
t.Fatal("resolvedConf is empty")
}
if logFile == "" {
t.Fatal("logFile is empty")
}
if _, err = os.Stat(logFile); err != nil {
t.Fatal(err)
}
if resolvedConf != confFile {
t.Errorf("expected %s, got %s", confFile, resolvedConf)
}
if logFile != filepath.Join(logDir, "HellPot.log") {
t.Errorf("expected %s, got %s", filepath.Join(logDir, "HellPot.log"), logFile)
}
time.Sleep(25 * time.Millisecond) // sync maybe
logDat, err := os.ReadFile(logFile)
if err != nil {
t.Error(err)
}
if !strings.Contains(string(logDat), "🔥 Starting HellPot 🔥") {
t.Errorf("expected log to contain '🔥 Starting HellPot 🔥', got %s", logDat)
}
if !strings.Contains(string(logDat), logFile) {
t.Errorf("expected log to contain '%s'", logFile)
}
if !strings.Contains(string(logDat), resolvedConf) {
t.Errorf("expected log to contain '%s'", resolvedConf)
}
if !strings.Contains(string(logDat), "PID: "+strconv.Itoa(os.Getpid())) {
t.Errorf("expected log to contain 'PID: %d', got %s", os.Getpid(), logDat)
}
t.Log("resolvedConf: ", resolvedConf)
t.Log("logFile: ", logFile)
t.Log("realConfig: ", realConfig)
time.Sleep(100 * time.Millisecond)
stopChan <- os.Interrupt
}
214 changes: 214 additions & 0 deletions cmd/HellPot/boot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
package main

import (
"errors"
"flag"
"fmt"
"io"
"os"
"os/signal"
"path/filepath"
"strconv"
"syscall"
"time"

"github.com/rs/zerolog"

"github.com/yunginnanet/HellPot/internal/config"
"github.com/yunginnanet/HellPot/internal/extra"
"github.com/yunginnanet/HellPot/internal/logger"
)

const (
defaultConfigWarningDelaySecs = 10
red = "\033[31m"
reset = "\033[0m"
)

func writeConfig(target string) (*config.Parameters, bool) {
var f *os.File
var err error
f, err = os.Create(target) // #nosec G304 -- go home gosec, you're drunk
if err != nil {
println("failed to create config file: " + err.Error())
return nil, false
}
if _, err = io.Copy(f, config.Defaults.IO); err != nil {
println("failed to write default config to file: " + err.Error())
_ = f.Close()
return nil, false
}
if err = f.Sync(); err != nil {
panic(err)
}
println("wrote default config to " + target)
var newConf *config.Parameters
if newConf, err = config.Setup(f); err != nil {
println("failed to setup config with newly written file: " + err.Error())
_ = f.Close()
return nil, false
}
_ = f.Close()
newConf.UsingDefaults = true
return newConf, true
}

func searchConfig() string {
var resolvedConf string
uconf, _ := os.UserConfigDir()
if uconf == "" && os.Getenv("HOME") != "" {
uconf = filepath.Join(os.Getenv("HOME"), ".config")
}

for _, path := range []string{
"/etc/HellPot/config.toml",
"/usr/local/etc/HellPot/config.toml",
"./config.toml",
filepath.Join(uconf, "HellPot", "config.toml"),
} {
if _, err := os.Stat(path); err == nil {
resolvedConf = path
break
}
}
return resolvedConf
}

func readConfig(resolvedConf string) (*config.Parameters, error) {
var err error
var setupErr error
var f *os.File

if resolvedConf == "" {
return nil, fmt.Errorf("%w: provided config file is an empty string", io.EOF)
}

var runningConfig *config.Parameters

f, err = os.Open(resolvedConf) // #nosec G304 go home gosec, you're drunk
if err == nil {
runningConfig, setupErr = config.Setup(f)
}
switch {
case setupErr != nil:
println("failed to setup config: " + setupErr.Error())
if f != nil {
_ = f.Close()
}
err = setupErr
case err != nil:
println("failed to open config file for reading: " + err.Error())
println("trying to create it....")
newRunningConfig, wroteOK := writeConfig(resolvedConf)
if wroteOK {
return newRunningConfig, nil
}
println("failed to create config file, cannot continue")
return nil, fmt.Errorf("failed to create config file: %w", err)
case runningConfig != nil:
_ = f.Close()
}

return runningConfig, err
}

func resolveConfig() (runningConfig *config.Parameters, usingDefaults bool, resolvedConf string, err error) {
setIfPresent := func(confRoot *flag.Flag) (ok bool) {
if confRoot != nil && confRoot.Value.String() != "" {
resolvedConf = confRoot.Value.String()
return true
}
return false
}
if config.CLIFlags != nil {
confRoot := config.CLIFlags.Lookup("config")
if !setIfPresent(confRoot) {
confRoot = config.CLIFlags.Lookup("c")
setIfPresent(confRoot)
}
}

if resolvedConf == "" && os.Getenv("HELLPOT_CONFIG_FILE") != "" {
resolvedConf = os.Getenv("HELLPOT_CONFIG_FILE")
}

if resolvedConf == "" {
resolvedConf = searchConfig()
}

if runningConfig, err = readConfig(resolvedConf); err != nil && !errors.Is(err, io.EOF) {
return runningConfig, false, "", err
}

if runningConfig == nil {
if runningConfig, err = config.Setup(nil); err != nil || runningConfig == nil {
if err == nil {
err = errors.New("unknown failure resulting in missing configuration, cannot continue")
}
return runningConfig, false, "", err
}
return runningConfig, true, "", nil
}

return runningConfig, false, resolvedConf, nil
}

func setup(stopChan chan os.Signal) (log zerolog.Logger, logFile string,
resolvedConf string, realConf *config.Parameters, err error) {

config.InitCLI()

var usingDefaults bool
var runningConfig *config.Parameters

if runningConfig, usingDefaults, resolvedConf, err = resolveConfig(); err != nil {
return
}

if runningConfig == nil {
err = errors.New("running configuration is nil, cannot continue")
return
}

// TODO: jesus bro r u ok
realConf = runningConfig
if usingDefaults && !realConf.UsingDefaults {
realConf.UsingDefaults = true
}
if realConf.UsingDefaults && !usingDefaults {
usingDefaults = true
}

//goland:noinspection GoNilness // we check for nil above
if log, err = logger.New(runningConfig.Logger); err != nil {
return
}

logFile = runningConfig.Logger.ActiveLogFileName

if usingDefaults {
log.Warn().Msg("using default configuration!")
print(red + "continuing with default configuration in ")
for i := defaultConfigWarningDelaySecs; i > 0; i-- {
print(strconv.Itoa(i))
for i := 0; i < 5; i++ {
time.Sleep(200 * time.Millisecond)
print(".")
}
}
print(reset + "\n")
}

if //goland:noinspection GoNilness
!runningConfig.Logger.NoColor {
extra.Banner()
}

signal.Notify(stopChan, syscall.SIGINT, syscall.SIGTERM)

if absResolvedConf, err := filepath.Abs(resolvedConf); err == nil {
resolvedConf = absResolvedConf
}

return
}
Loading