Skip to content

Commit c56f56a

Browse files
committed
fix: Ensure .env file always overrides environment variables
- Fixed envloader to always override existing env vars from .env file - Updated all entry points (StartBot, StartAPI, StartBoth, Main) to load .env dynamically - Fixed InteractionCreate to read guild restrictions from .env dynamically - Updated env.example to clarify .env file behavior - Bumped version to 3.3.1 This ensures that DISCORD_ALLOWED_GUILD and other .env values are properly loaded for all commands (js scan, subdomains, etc.) instead of using package-level initialization values.
1 parent 1443d70 commit c56f56a

10 files changed

Lines changed: 95 additions & 47 deletions

File tree

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -393,8 +393,8 @@ Once the bot is running, use these slash commands in Discord:
393393
- `/github-wordlist org:microsoft` - Generate wordlists from organization files
394394

395395
#### Workflows
396-
- `/lite_scan domain:example.com [skip_js:false] [verbose:false] [phase_timeout:3600]` - Comprehensive automated scan workflow with real-time progress and file sending
397-
- `/fastlook domain:example.com` - Quick scan
396+
- `/lite_scan domain:example.com [skip_js:false] [verbose:false] [phase_timeout:3600]` - Comprehensive automated scan: livehosts → reflection → JS → CNAME → backup → DNS → misconfig → nuclei (with real-time progress and file sending)
397+
- `/fast_look domain:example.com` - Quick reconnaissance: subdomain enumeration → live host filtering → URL/JS collection
398398
- `/domain domain:example.com` - Full domain analysis
399399

400400
#### Monitoring Commands
@@ -450,8 +450,8 @@ autoar gf scan -d example.com
450450
autoar wpDepConf scan -d example.com
451451

452452
# Workflows
453-
autoar fastlook run -d example.com
454-
autoar lite run -d example.com --skip-js
453+
autoar fastlook run -d example.com # Quick reconnaissance: subdomains → live hosts → URLs/JS
454+
autoar lite run -d example.com --skip-js # Comprehensive scan: livehosts → reflection → JS → CNAME → backup → DNS → misconfig → nuclei
455455
autoar domain run -d example.com
456456

457457
# Database operations
@@ -931,7 +931,7 @@ curl -X POST "http://localhost:8000/scan/github_org" \
931931
-H "Content-Type: application/json" \
932932
-d '{"org": "organization", "max_repos": 50}'
933933

934-
# Lite Scan Workflow (comprehensive automated scan)
934+
# Lite Scan Workflow (comprehensive automated scan: livehosts → reflection → JS → CNAME → backup → DNS → misconfig → nuclei)
935935
curl -X POST "http://localhost:8000/scan/lite" \
936936
-H "Content-Type: application/json" \
937937
-d '{"domain": "example.com", "skip_js": false, "phase_timeout": 3600}'

bughunt.db-shm

32 KB
Binary file not shown.

bughunt.db-wal

Whitespace-only changes.

env.example

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ DISCORD_WEBHOOK=your_discord_webhook_url_here
2929
DISCORD_ALLOWED_GUILD_ID=
3030

3131
# Option 2: Use Guild Name (legacy, deprecated - use GUID instead)
32-
# Leave empty to allow bot in all servers, or set to server name (e.g., "Zhunterz")
32+
# Leave empty to allow bot in all servers, or set to your server name
3333
# The bot will reject commands from other servers
34+
# Note: .env file values always override system environment variables
3435
DISCORD_ALLOWED_GUILD=
3536

3637
# ============================================================================

internal/modules/envloader/envloader.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,9 @@ func LoadEnv() error {
5353
}
5454
}
5555

56-
// Only set if not already set in environment
57-
if os.Getenv(key) == "" {
58-
os.Setenv(key, value)
59-
}
56+
// Always set from .env file (override any existing environment variables)
57+
// This ensures .env file is the source of truth
58+
os.Setenv(key, value)
6059
}
6160

6261
if err := scanner.Err(); err != nil {

internal/modules/gobot/api.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ func corsMiddleware() gin.HandlerFunc {
218218
func rootHandler(c *gin.Context) {
219219
c.JSON(http.StatusOK, gin.H{
220220
"message": "AutoAR API Server",
221-
"version": "3.3.0",
221+
"version": "3.3.1",
222222
"docs": "/docs",
223223
"status": "operational",
224224
})
@@ -327,7 +327,7 @@ func docsHandler(c *gin.Context) {
327327
<div class="container">
328328
<header>
329329
<h1>AutoAR API Documentation</h1>
330-
<div class="version">Version 3.3.0</div>
330+
<div class="version">Version 3.3.1</div>
331331
</header>
332332
333333
<div class="section">
@@ -432,7 +432,7 @@ func docsHandler(c *gin.Context) {
432432
433433
<div class="endpoint">
434434
<div class="endpoint-path"><span class="method post">POST</span> /scan/lite</div>
435-
<div class="description">Lite scan (comprehensive automated scan)</div>
435+
<div class="description">Lite scan: Comprehensive automated scan workflow. Runs livehosts → reflection → JS → CNAME → backup → DNS → misconfig → nuclei phases sequentially with real-time progress updates.</div>
436436
</div>
437437
438438
<div class="endpoint">

internal/modules/gobot/bot.go

Lines changed: 63 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,19 @@ func StartBot() error {
186186

187187
// StartAPI starts the REST API server
188188
func StartAPI() error {
189+
fmt.Println("🚀 Starting AutoAR API Server...")
190+
191+
// Load .env file if it exists
192+
if err := envloader.LoadEnv(); err != nil {
193+
log.Printf("[WARN] Failed to load .env file: %v", err)
194+
} else {
195+
fmt.Println("✅ Loaded environment variables from .env file")
196+
}
197+
198+
// Re-read API host and port after loading .env
199+
apiHostEnv := getEnv("API_HOST", "0.0.0.0")
200+
apiPortEnv := getEnv("API_PORT", "8000")
201+
189202
// Initialize database if configured
190203
if os.Getenv("DB_HOST") != "" {
191204
if err := db.Init(); err != nil {
@@ -205,7 +218,7 @@ func StartAPI() error {
205218
}()
206219

207220
router := setupAPI()
208-
addr := fmt.Sprintf("%s:%s", apiHost, apiPort)
221+
addr := fmt.Sprintf("%s:%s", apiHostEnv, apiPortEnv)
209222
fmt.Printf("AutoAR API Server starting on %s\n", addr)
210223

211224
sc := make(chan os.Signal, 1)
@@ -224,6 +237,19 @@ func StartAPI() error {
224237

225238
// StartBoth starts both Discord bot and API server
226239
func StartBoth() error {
240+
fmt.Println("🚀 Starting AutoAR (Discord Bot + API Server)...")
241+
242+
// Load .env file if it exists
243+
if err := envloader.LoadEnv(); err != nil {
244+
log.Printf("[WARN] Failed to load .env file: %v", err)
245+
} else {
246+
fmt.Println("✅ Loaded environment variables from .env file")
247+
}
248+
249+
// Re-read configuration after loading .env
250+
botTokenEnv := os.Getenv("DISCORD_BOT_TOKEN")
251+
autoarModeEnv := getEnv("AUTOAR_MODE", "both")
252+
227253
// Initialize database if configured (only once for both services)
228254
if os.Getenv("DB_HOST") != "" {
229255
if err := db.Init(); err != nil {
@@ -244,27 +270,31 @@ func StartBoth() error {
244270

245271
var wg sync.WaitGroup
246272

247-
if botToken == "" {
273+
if botTokenEnv == "" {
248274
return fmt.Errorf("DISCORD_BOT_TOKEN environment variable is required")
249275
}
250276

251-
// Start Discord bot
252-
wg.Add(1)
253-
go func() {
254-
defer wg.Done()
255-
if err := StartBot(); err != nil {
256-
log.Printf("Discord bot error: %v", err)
257-
}
258-
}()
277+
// Start Discord bot if mode allows
278+
if autoarModeEnv == "discord" || autoarModeEnv == "both" {
279+
wg.Add(1)
280+
go func() {
281+
defer wg.Done()
282+
if err := StartBot(); err != nil {
283+
log.Printf("Discord bot error: %v", err)
284+
}
285+
}()
286+
}
259287

260-
// Start API server
261-
wg.Add(1)
262-
go func() {
263-
defer wg.Done()
264-
if err := StartAPI(); err != nil {
265-
log.Printf("API server error: %v", err)
266-
}
267-
}()
288+
// Start API server if mode allows
289+
if autoarModeEnv == "api" || autoarModeEnv == "both" {
290+
wg.Add(1)
291+
go func() {
292+
defer wg.Done()
293+
if err := StartAPI(); err != nil {
294+
log.Printf("API server error: %v", err)
295+
}
296+
}()
297+
}
268298

269299
// Wait for interrupt signal
270300
sc := make(chan os.Signal, 1)
@@ -282,26 +312,31 @@ func Ready(s *discordgo.Session, event *discordgo.Ready) {
282312

283313
// InteractionCreate handles Discord slash command interactions
284314
func InteractionCreate(s *discordgo.Session, i *discordgo.InteractionCreate) {
315+
// Read guild restriction from environment variables dynamically (supports .env file)
316+
// This ensures values are read after .env is loaded, not from package-level initialization
317+
allowedGuildIDEnv := getEnv("DISCORD_ALLOWED_GUILD_ID", "")
318+
allowedGuildNameEnv := getEnv("DISCORD_ALLOWED_GUILD", "")
319+
285320
// Check guild restriction by ID (GUID) - preferred method
286-
if allowedGuildID != "" {
321+
if allowedGuildIDEnv != "" {
287322
// Reject DMs (commands must be in a server)
288323
if i.GuildID == "" {
289324
log.Printf("[INFO] Rejected command from DM (not in a server)")
290-
respond(s, i, fmt.Sprintf("❌ This bot is restricted to a specific server (Guild ID: %s). Please use commands in that server.", allowedGuildID), true)
325+
respond(s, i, fmt.Sprintf("❌ This bot is restricted to a specific server (Guild ID: %s). Please use commands in that server.", allowedGuildIDEnv), true)
291326
return
292327
}
293-
if i.GuildID != allowedGuildID {
294-
log.Printf("[INFO] Rejected command from unauthorized guild ID: %s (expected: %s)", i.GuildID, allowedGuildID)
295-
respond(s, i, fmt.Sprintf("❌ This bot is restricted to a specific server (Guild ID: %s). Your server ID: %s", allowedGuildID, i.GuildID), true)
328+
if i.GuildID != allowedGuildIDEnv {
329+
log.Printf("[INFO] Rejected command from unauthorized guild ID: %s (expected: %s)", i.GuildID, allowedGuildIDEnv)
330+
respond(s, i, fmt.Sprintf("❌ This bot is restricted to a specific server (Guild ID: %s). Your server ID: %s", allowedGuildIDEnv, i.GuildID), true)
296331
return
297332
}
298333
log.Printf("[DEBUG] Command allowed from guild ID: %s", i.GuildID)
299-
} else if allowedGuildName != "" {
334+
} else if allowedGuildNameEnv != "" {
300335
// Legacy: Check by guild name (deprecated, but kept for backward compatibility)
301336
// Reject DMs (commands must be in a server)
302337
if i.GuildID == "" {
303338
log.Printf("[INFO] Rejected command from DM (not in a server)")
304-
respond(s, i, fmt.Sprintf("❌ This bot only works in the **%s** server. Please use commands in that server.", allowedGuildName), true)
339+
respond(s, i, fmt.Sprintf("❌ This bot only works in the **%s** server. Please use commands in that server.", allowedGuildNameEnv), true)
305340
return
306341
}
307342

@@ -314,9 +349,9 @@ func InteractionCreate(s *discordgo.Session, i *discordgo.InteractionCreate) {
314349
}
315350

316351
// Check if guild name matches allowed guild
317-
if guild.Name != allowedGuildName {
318-
log.Printf("[INFO] Rejected command from unauthorized guild: %s (expected: %s)", guild.Name, allowedGuildName)
319-
respond(s, i, fmt.Sprintf("❌ This bot is restricted to the **%s** server only. Your server: **%s**", allowedGuildName, guild.Name), true)
352+
if guild.Name != allowedGuildNameEnv {
353+
log.Printf("[INFO] Rejected command from unauthorized guild: %s (expected: %s)", guild.Name, allowedGuildNameEnv)
354+
respond(s, i, fmt.Sprintf("❌ This bot is restricted to the **%s** server only. Your server: **%s**", allowedGuildNameEnv, guild.Name), true)
320355
return
321356
}
322357

internal/modules/gobot/commands3.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,7 @@ func handleHelp(s *discordgo.Session, i *discordgo.InteractionCreate) {
805805
embed.Fields = []*discordgo.MessageEmbedField{
806806
{
807807
Name: "Core Workflows",
808-
Value: "• `/scan_domain` - Full domain workflow\n• `/lite_scan` - Lite scan (livehosts → reflection → JS → nuclei)\n• `/fast_look` - Fast recon (subs + livehosts + URLs)\n• `/react2shell_scan` - React2Shell smart scan",
808+
Value: "• `/scan_domain` - Full domain workflow\n• `/lite_scan` - Comprehensive automated scan: livehosts → reflection → JS → CNAME → backup → DNS → misconfig → nuclei\n• `/fast_look` - Quick reconnaissance: subdomain enumeration → live host filtering → URL/JS collection\n• `/react2shell_scan` - React2Shell smart scan",
809809
Inline: false,
810810
},
811811
{

internal/modules/gobot/commands_registration.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func registerAllCommands(s *discordgo.Session) {
4343
},
4444
{
4545
Name: "lite_scan",
46-
Description: "Perform a lite domain scan",
46+
Description: "Comprehensive automated scan: livehosts → reflection → JS → CNAME → backup → DNS → misconfig → nuclei",
4747
Options: []*discordgo.ApplicationCommandOption{
4848
{Type: discordgo.ApplicationCommandOptionString, Name: "domain", Description: "The domain to scan", Required: true},
4949
{Type: discordgo.ApplicationCommandOptionBoolean, Name: "verbose", Description: "Enable verbose output", Required: false},
@@ -57,7 +57,7 @@ func registerAllCommands(s *discordgo.Session) {
5757
},
5858
{
5959
Name: "fast_look",
60-
Description: "Perform a fast domain lookup",
60+
Description: "Quick reconnaissance: subdomain enumeration → live host filtering → URL/JS collection",
6161
Options: []*discordgo.ApplicationCommandOption{
6262
{Type: discordgo.ApplicationCommandOptionString, Name: "domain", Description: "The domain to scan", Required: true},
6363
{Type: discordgo.ApplicationCommandOptionBoolean, Name: "verbose", Description: "Enable verbose output", Required: false},

internal/modules/gobot/main.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,29 @@ import (
77
"os/signal"
88
"sync"
99
"syscall"
10+
11+
"github.com/h0tak88r/AutoAR/v3/internal/modules/envloader"
1012
)
1113

1214
// Main function for standalone bot execution (backward compatibility)
1315
// This can be used if someone wants to run the bot standalone
1416
func Main() {
17+
// Load .env file if it exists
18+
if err := envloader.LoadEnv(); err != nil {
19+
log.Printf("[WARN] Failed to load .env file: %v", err)
20+
} else {
21+
fmt.Println("✅ Loaded environment variables from .env file")
22+
}
23+
24+
// Read configuration from environment (after .env is loaded)
25+
autoarModeEnv := getEnv("AUTOAR_MODE", "discord")
26+
botTokenEnv := os.Getenv("DISCORD_BOT_TOKEN")
27+
1528
var wg sync.WaitGroup
1629

1730
// Start Discord bot if needed
18-
if autoarMode == "discord" || autoarMode == "both" {
19-
if botToken == "" {
31+
if autoarModeEnv == "discord" || autoarModeEnv == "both" {
32+
if botTokenEnv == "" {
2033
log.Fatal("DISCORD_BOT_TOKEN environment variable is required")
2134
}
2235

@@ -30,7 +43,7 @@ func Main() {
3043
}
3144

3245
// Start API server if needed
33-
if autoarMode == "api" || autoarMode == "both" {
46+
if autoarModeEnv == "api" || autoarModeEnv == "both" {
3447
wg.Add(1)
3548
go func() {
3649
defer wg.Done()

0 commit comments

Comments
 (0)