/
config.go
190 lines (153 loc) · 5 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
package config
import (
"bufio"
"fmt"
"net/url"
"os"
"strings"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
type Settings struct {
Verbose int
Logger *zap.Logger
ProxyParam string
BatchParam bool
NoCheck bool
}
var GlobalConfig Settings
var ConfigFile map[string]string
var homeDir = os.Getenv("HOME")
var BaseDirectory = homeDir + "/.local/htb-cli"
const HostHackTheBox = "labs.hackthebox.com"
const BaseHackTheBoxAPIURL = "https://" + HostHackTheBox + "/api/v4"
const StatusURL = "https://status.hackthebox.com/api/v2/status.json"
const Version = "v1.6.0"
func ConfigureLogger() error {
var logLevel zapcore.Level
switch GlobalConfig.Verbose {
case 0:
logLevel = zap.ErrorLevel
case 1:
logLevel = zap.InfoLevel
case 2:
logLevel = zap.DebugLevel
default:
logLevel = zap.DebugLevel
}
encoderConfig := zap.NewDevelopmentEncoderConfig()
encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder // Ajoute des couleurs pour les niveaux de log
cfg := zap.Config{
Level: zap.NewAtomicLevelAt(logLevel),
Development: true,
Encoding: "console",
EncoderConfig: encoderConfig,
OutputPaths: []string{"stdout"},
ErrorOutputPaths: []string{"stderr"},
}
var err error
GlobalConfig.Logger, err = cfg.Build()
if err != nil {
return fmt.Errorf("logger configuration error: %v", err)
}
zap.ReplaceGlobals(GlobalConfig.Logger)
return nil
}
// LoadConfig reads a configuration file from a specified filepath and returns a map of key-value pairs.
func LoadConfig(filepath string) (map[string]string, error) {
config := make(map[string]string)
file, err := os.Open(filepath)
if err != nil {
return nil, err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
if line == "" || strings.HasPrefix(line, "#") {
continue
}
parts := strings.SplitN(line, "=", 2)
if len(parts) != 2 {
return nil, fmt.Errorf("incorrectly formatted line in configuration file: %s", line)
}
key := strings.TrimSpace(parts[0])
value := strings.TrimSpace(parts[1])
if err := validateConfig(key, value); err != nil {
return nil, err
}
config[key] = value
}
if err := scanner.Err(); err != nil {
return nil, err
}
return config, nil
}
// validateConfig checks if the provided key-value pairs in the configuration are valid.
func validateConfig(key, value string) error {
switch key {
case "Logging", "Batch":
if value != "True" && value != "False" {
return fmt.Errorf("the value for '%s' must be 'True' or 'False', got : %s", key, value)
}
case "Proxy":
if value != "False" && !isValidHTTPorHTTPSURL(value) {
return fmt.Errorf("the URL for '%s' must be a valid URL starting with http or https, got : %s", key, value)
}
case "Discord":
if value != "False" && !isValidDiscordWebhook(value) {
return fmt.Errorf("the Discord webhook URL is invalid : %s", value)
}
}
return nil
}
// isValidDiscordWebhook checks if a given URL is a valid Discord webhook.
func isValidDiscordWebhook(u string) bool {
parsedURL, err := url.Parse(u)
return err == nil && parsedURL.Scheme == "https" && strings.Contains(parsedURL.Host, "discord.com") && strings.Contains(parsedURL.Path, "/api/webhooks/")
}
// isValidHTTPorHTTPSURL checks if a given URL is valid and uses either the HTTP or HTTPS protocol.
func isValidHTTPorHTTPSURL(u string) bool {
parsedURL, err := url.Parse(u)
return err == nil && (parsedURL.Scheme == "http" || parsedURL.Scheme == "https")
}
// Init initializes the application by setting up necessary directories, creating a default configuration file if it doesn't exist, and loading the configuration.
func Init() error {
if _, err := os.Stat(BaseDirectory); os.IsNotExist(err) {
GlobalConfig.Logger.Info(fmt.Sprintf("The \"%s\" folder does not exist, creation in progress...\n", BaseDirectory))
err := os.MkdirAll(BaseDirectory, os.ModePerm)
if err != nil {
return fmt.Errorf("error folder creation: %s", err)
}
GlobalConfig.Logger.Info(fmt.Sprintf("\"%s\" folder created successfully\n\n", BaseDirectory))
}
confFilePath := BaseDirectory + "/default.conf"
if _, err := os.Stat(confFilePath); os.IsNotExist(err) {
file, err := os.Create(confFilePath)
if err != nil {
return fmt.Errorf("error creating file: %v", err)
}
defer file.Close()
configContent := `Discord = False
Update = False`
writer := bufio.NewWriter(file)
_, err = writer.WriteString(configContent)
if err != nil {
return fmt.Errorf("error when writing to file: %v", err)
}
err = writer.Flush()
if err != nil {
return fmt.Errorf("error clearing buffer: %v", err)
}
GlobalConfig.Logger.Info("Configuration file created successfully.")
}
GlobalConfig.Logger.Info("Loading configuration file...")
config, err := LoadConfig(BaseDirectory + "/default.conf")
if err != nil {
return fmt.Errorf("error loading configuration file: %v", err)
}
GlobalConfig.Logger.Info("Configuration successfully loaded")
GlobalConfig.Logger.Debug(fmt.Sprintf("%v", config))
ConfigFile = config
return nil
}