diff --git a/.gitignore b/.gitignore index 4c49bd7..183b6bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .env +bitninja-manager diff --git a/env.example b/env.example new file mode 100644 index 0000000..fac700a --- /dev/null +++ b/env.example @@ -0,0 +1,3 @@ +MONGO_URI="mongodb://localhost:27017" #or MONGO_URI="mongodb://username:password@localhost:27017/bitninja" for authenticated selfhosted or MONGO_URI="mongodb+srv://username:password@cluster.mongodb.net/" for cloud based +MONGO_DATABASE="bitninja" +MONGO_COLLECTION="ban_records" diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..23dcd9d --- /dev/null +++ b/go.mod @@ -0,0 +1,18 @@ +module bitninjainteract + +go 1.22.2 + +require ( + github.com/golang/snappy v0.0.4 // indirect + github.com/joho/godotenv v1.5.1 // indirect + github.com/klauspost/compress v1.16.7 // indirect + github.com/montanaflynn/stats v0.7.1 // indirect + github.com/xdg-go/pbkdf2 v1.0.0 // indirect + github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect + github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect + go.mongodb.org/mongo-driver v1.17.4 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/text v0.17.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..43f8145 --- /dev/null +++ b/go.sum @@ -0,0 +1,48 @@ +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= +github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= +github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= +github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw= +go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/main.go b/main.go new file mode 100644 index 0000000..2e94bde --- /dev/null +++ b/main.go @@ -0,0 +1,472 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "log" + "os" + "os/exec" + "strconv" + "strings" + "time" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + + "github.com/joho/godotenv" +) + +type BanRecord struct { + ID primitive.ObjectID `bson:"_id,omitempty" json:"id,omitempty"` + IP string `bson:"ip" json:"ip"` + Reason string `bson:"reason" json:"reason"` + BannedAt time.Time `bson:"banned_at" json:"banned_at"` + ExpiresAt *time.Time `bson:"expires_at,omitempty" json:"expires_at,omitempty"` + Duration string `bson:"duration" json:"duration"` + JsonData map[string]interface{} `bson:"json_data" json:"json_data"` + Status string `bson:"status" json:"status"` + Hostname string `bson:"hostname" json:"hostname"` +} + +type MongoConfig struct { + URI string + Database string + Collection string +} + +func getMongoConfig() MongoConfig { + // Load environment variables from .env file + err := godotenv.Load() + + if err != nil { + log.Fatal("Error loading .env file") + } + + return MongoConfig{ + URI: getEnvOrDefault("MONGO_URI", "mongodb://localhost:27017"), + Database: getEnvOrDefault("MONGO_DATABASE", "bitninja"), + Collection: getEnvOrDefault("MONGO_COLLECTION", "ban_records"), + } +} + +func getEnvOrDefault(key, defaultValue string) string { + if value := os.Getenv(key); value != "" { + return value + } + return defaultValue +} + +func connectMongoDB(config MongoConfig) (*mongo.Client, *mongo.Collection, error) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + client, err := mongo.Connect(ctx, options.Client().ApplyURI(config.URI)) + if err != nil { + return nil, nil, err + } + + // Test connection + err = client.Ping(ctx, nil) + if err != nil { + return nil, nil, err + } + + collection := client.Database(config.Database).Collection(config.Collection) + + // Create indexes for better performance + indexes := []mongo.IndexModel{ + { + Keys: bson.D{{Key: "ip", Value: 1}}, + }, + { + Keys: bson.D{{Key: "expires_at", Value: 1}}, + }, + { + Keys: bson.D{{Key: "status", Value: 1}}, + }, + { + Keys: bson.D{ + {Key: "status", Value: 1}, + {Key: "expires_at", Value: 1}, + }, + }, + } + + ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + _, err = collection.Indexes().CreateMany(ctx, indexes) + if err != nil { + log.Printf("Warning: Could not create indexes: %v", err) + } + + return client, collection, nil +} + +func parseDuration(duration string) (time.Duration, error) { + if duration == "permanent" || duration == "0" { + return 0, nil // 0 means permanent + } + + if strings.HasSuffix(duration, "d") { + days, err := strconv.Atoi(strings.TrimSuffix(duration, "d")) + if err != nil { + return 0, err + } + return time.Duration(days) * 24 * time.Hour, nil + } + return time.ParseDuration(duration) +} + +func getHostname() string { + hostname, err := os.Hostname() + if err != nil { + return "unknown" + } + return hostname +} + +func addBanRecord(collection *mongo.Collection, ip, reason, duration string, jsonData map[string]interface{}) error { + d, err := parseDuration(duration) + if err != nil { + return err + } + + now := time.Now() + var expiresAt *time.Time + + if d > 0 { // Not permanent + expiry := now.Add(d) + expiresAt = &expiry + } + + record := BanRecord{ + IP: ip, + Reason: reason, + BannedAt: now, + ExpiresAt: expiresAt, + Duration: duration, + JsonData: jsonData, + Status: "active", + Hostname: getHostname(), + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + _, err = collection.InsertOne(ctx, record) + return err +} + +func removeBanRecord(collection *mongo.Collection, ip string) error { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + filter := bson.M{ + "ip": ip, + "status": "active", + } + + update := bson.M{ + "$set": bson.M{ + "status": "removed", + }, + } + + _, err := collection.UpdateMany(ctx, filter, update) + return err +} + +func cleanupExpiredBans(collection *mongo.Collection) error { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + + // Find expired bans + filter := bson.M{ + "expires_at": bson.M{"$lte": time.Now()}, + "status": "active", + } + + cursor, err := collection.Find(ctx, filter) + if err != nil { + return err + } + defer cursor.Close(ctx) + + var expiredBans []BanRecord + if err = cursor.All(ctx, &expiredBans); err != nil { + return err + } + + // Remove expired IPs from BitNinja and mark as expired in MongoDB + for _, ban := range expiredBans { + fmt.Printf("Removing expired ban for IP: %s (banned at: %s)\n", + ban.IP, ban.BannedAt.Format("2006-01-02 15:04:05")) + + // Remove from BitNinja + cmd := exec.Command("bitninjacli", "--blacklist", fmt.Sprintf("--del=%s", ban.IP)) + if err := cmd.Run(); err != nil { + fmt.Printf("Error removing IP %s from BitNinja: %v\n", ban.IP, err) + continue + } + + // Mark as expired in MongoDB + updateFilter := bson.M{"_id": ban.ID} + update := bson.M{ + "$set": bson.M{ + "status": "expired", + }, + } + + _, err = collection.UpdateOne(ctx, updateFilter, update) + if err != nil { + fmt.Printf("Error updating MongoDB for IP %s: %v\n", ban.IP, err) + } + } + + fmt.Printf("Processed %d expired bans\n", len(expiredBans)) + return nil +} + +func handleAdd(collection *mongo.Collection, ip string, duration string, reason string, jsonObject map[string]interface{}) { + // Add to BitNinja blacklist + enhancedReason := fmt.Sprintf("%s (Duration: %s, Host: %s)", reason, duration, getHostname()) + cmd := exec.Command("bitninjacli", "--blacklist", fmt.Sprintf("--add=%s", ip), fmt.Sprintf("--comment=%s", enhancedReason)) + out, err := cmd.Output() + if err != nil { + fmt.Println("Error adding IP to BitNinja:", err) + return + } + fmt.Println(string(out)) + + // Add to MongoDB + err = addBanRecord(collection, ip, reason, duration, jsonObject) + if err != nil { + fmt.Printf("Error adding to MongoDB: %v\n", err) + return + } + + if duration != "permanent" && duration != "0" { + d, _ := parseDuration(duration) + fmt.Printf("IP %s added to blacklist, will expire at: %s\n", ip, time.Now().Add(d).Format("2006-01-02 15:04:05")) + } else { + fmt.Printf("IP %s added to blacklist permanently\n", ip) + } +} + +func handleDel(collection *mongo.Collection, ip string, duration string, reason string, jsonObject map[string]interface{}) { + // Remove from BitNinja + cmd := exec.Command("bitninjacli", "--blacklist", fmt.Sprintf("--del=%s", ip)) + out, err := cmd.Output() + if err != nil { + fmt.Println("Error deleting IP from BitNinja:", err) + return + } + fmt.Println(string(out)) + + // Update MongoDB + err = removeBanRecord(collection, ip) + if err != nil { + fmt.Printf("Error updating MongoDB: %v\n", err) + } else { + fmt.Printf("IP %s removed from tracking database\n", ip) + } +} + +func handleCleanup(collection *mongo.Collection) { + fmt.Println("Cleaning up expired bans...") + err := cleanupExpiredBans(collection) + if err != nil { + fmt.Printf("Error during cleanup: %v\n", err) + } else { + fmt.Println("Cleanup completed") + } +} + +func handleList(collection *mongo.Collection) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + // Find active bans, sorted by banned_at descending + filter := bson.M{"status": "active"} + opts := options.Find().SetSort(bson.D{{Key: "banned_at", Value: -1}}) + + cursor, err := collection.Find(ctx, filter, opts) + if err != nil { + fmt.Printf("Error querying MongoDB: %v\n", err) + return + } + defer cursor.Close(ctx) + + var bans []BanRecord + if err = cursor.All(ctx, &bans); err != nil { + fmt.Printf("Error decoding results: %v\n", err) + return + } + + fmt.Println("\nActive Bans:") + fmt.Printf("%-15s %-20s %-19s %-19s %-10s %-12s\n", "IP", "Reason", "Banned At", "Expires At", "Duration", "Hostname") + fmt.Println(strings.Repeat("-", 100)) + + for _, ban := range bans { + expiryStr := "Permanent" + if ban.ExpiresAt != nil { + expiryStr = ban.ExpiresAt.Format("2006-01-02 15:04") + } + + reasonTrunc := ban.Reason + if len(reasonTrunc) > 20 { + reasonTrunc = reasonTrunc[:17] + "..." + } + + fmt.Printf("%-15s %-20s %-19s %-19s %-10s %-12s\n", + ban.IP, + reasonTrunc, + ban.BannedAt.Format("2006-01-02 15:04"), + expiryStr, + ban.Duration, + ban.Hostname) + } + + fmt.Printf("\nTotal active bans: %d\n", len(bans)) +} + +func handleStats(collection *mongo.Collection) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + // Count by status + pipeline := []bson.M{ + {"$group": bson.M{ + "_id": "$status", + "count": bson.M{"$sum": 1}, + }}, + } + + cursor, err := collection.Aggregate(ctx, pipeline) + if err != nil { + fmt.Printf("Error getting stats: %v\n", err) + return + } + defer cursor.Close(ctx) + + fmt.Println("\nBan Statistics:") + for cursor.Next(ctx) { + var result bson.M + if err := cursor.Decode(&result); err != nil { + continue + } + fmt.Printf(" %s: %v\n", result["_id"], result["count"]) + } + + // Count expiring soon (next 24 hours) + tomorrow := time.Now().Add(24 * time.Hour) + expiringSoonFilter := bson.M{ + "status": "active", + "expires_at": bson.M{ + "$gte": time.Now(), + "$lte": tomorrow, + }, + } + + count, err := collection.CountDocuments(ctx, expiringSoonFilter) + if err == nil { + fmt.Printf(" Expiring in next 24h: %d\n", count) + } +} + +func processCommand(collection *mongo.Collection, command string, ip string, duration string, reason string, jsonObject map[string]interface{}) { + switch command { + case "add": + handleAdd(collection, ip, duration, reason, jsonObject) + case "del": + handleDel(collection, ip, duration, reason, jsonObject) + case "cleanup": + handleCleanup(collection) + case "list": + handleList(collection) + case "stats": + handleStats(collection) + default: + fmt.Println("Invalid command. Available: add, del, cleanup, list, stats") + } +} + +func main() { + config := getMongoConfig() + + // Connect to MongoDB + client, collection, err := connectMongoDB(config) + if err != nil { + log.Fatal("Failed to connect to MongoDB:", err) + } + defer func() { + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + client.Disconnect(ctx) + }() + + if len(os.Args) < 2 { + fmt.Println("BitNinja MongoDB Duration Manager") + fmt.Println("\nUsage:") + fmt.Println(" go run main.go add [json_object]") + fmt.Println(" go run main.go del [duration] [reason] [json_object]") + fmt.Println(" go run main.go cleanup") + fmt.Println(" go run main.go list") + fmt.Println(" go run main.go stats") + fmt.Println("\nDuration examples: 24h, 30m, 2d, permanent") + fmt.Println("\nEnvironment variables:") + fmt.Printf(" MONGO_URI=%s\n", config.URI) + fmt.Printf(" MONGO_DATABASE=%s\n", config.Database) + fmt.Printf(" MONGO_COLLECTION=%s\n", config.Collection) + fmt.Println("\nNote: Run 'cleanup' command regularly (e.g., via cron) to remove expired bans") + os.Exit(1) + } + + command := os.Args[1] + + // Handle special commands that don't need all parameters + if command == "cleanup" { + handleCleanup(collection) + return + } + if command == "list" { + handleList(collection) + return + } + if command == "stats" { + handleStats(collection) + return + } + + // Regular commands need at least IP + if len(os.Args) < 3 { + fmt.Println("Error: IP address required") + os.Exit(1) + } + + ip := os.Args[2] + duration := "" + reason := "" + var jsonObject map[string]interface{} + + if len(os.Args) > 3 { + duration = os.Args[3] + } + if len(os.Args) > 4 { + reason = os.Args[4] + } + if len(os.Args) > 5 { + jsonStr := os.Args[5] + err := json.Unmarshal([]byte(jsonStr), &jsonObject) + if err != nil { + fmt.Println("Invalid JSON object:", err) + os.Exit(1) + } + } + + processCommand(collection, command, ip, duration, reason, jsonObject) +} diff --git a/main.go-old b/main.go-old new file mode 100644 index 0000000..ea2fcb3 --- /dev/null +++ b/main.go-old @@ -0,0 +1,177 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + "os/exec" + //"time" + //"net/http" + //"bytes" +) + +func handleAdd(ip string, duration string, reason string, jsonObject map[string]interface{}) { + cmd := exec.Command("bitninjacli", "--blacklist", fmt.Sprintf("--add=%s", ip), fmt.Sprintf("--comment=%s", reason)) + out, err := cmd.Output() + if err != nil { + fmt.Println("Error adding IP:", err) + return + } + fmt.Println(string(out)) + //webhookURL := "https://discord.com/api/webhooks/1215603532451946566/JsMb7nSHAHOIZ4FJZf8xu0I495dsh1_5LV5x7x52KQBfYM5BoamNCDPAiRbk7yv6q-cX" + // embedColor := 0xff0000 + //hostname, err := os.Hostname() + //if err != nil { + // fmt.Println("Error:", err) + //} + + //currentDate := time.Now().Format("2006-01-02 15:04") + + // Create the embed + // embed := map[string]interface{} { + // "Banned IP": ip, + // "Comment": reason, + // "Duration": duration, + // "JSON_DATA": jsonObject, + //} + + //payload := map[string]interface{} { + //"content": fmt.Sprintf("Banned IP: %s\nComment: %s\nDuration: %s\nJSON_DATA: %s", ip, reason, duration, jsonObject), + // "embeds": []map[string]interface{}{embed}, + //} + //payload := map[string]string { + // "content": fmt.Sprintf("Hostname: %s\nCurrent date: %s\nBanned IP: %s\nComment: %s\nDuration: %s\nJSON_DATA: %s", hostname, currentDate, ip, reason, duration, jsonObject), + //} + //jsonData, err := json.Marshal(payload) + //if err != nil { + // fmt.Println("Error marshaling JSON:", err) + // return + //} + // Create the HTTP request + //req, err := http.NewRequest("POST", webhookURL, bytes.NewBuffer(jsonData)) + //if err != nil { + // fmt.Println("Error creating request:", err) + // return + //} + //req.Header.Set("Content-Type", "application/json") + + // Send the HTTP request + //client := &http.Client{} + //resp, err := client.Do(req) + //if err != nil { + // fmt.Println("Error sending request:", err) + // return + //} + //defer resp.Body.Close() + + // Check the response + //if resp.StatusCode == http.StatusOK { + // fmt.Println("Message sent successfully!") + //} else if resp.StatusCode == http.StatusNoContent { + // fmt.Println("Message send, but there was a response with no content (HTTP 204)") + //} else { + // fmt.Println("Failed to send message. Status code:", resp.StatusCode) + //} + + // fmt.Printf("Currently unused data: duration: %s json data: %s\n", duration, jsonObject) +} + +func handleDel(ip string, duration string, reason string, jsonObject map[string]interface{}) { + cmd := exec.Command("bitninjacli", "--blacklist", fmt.Sprintf("--del=%s", ip)) + out, err := cmd.Output() + if err != nil { + fmt.Println("Error deleting IP:", err) + return + } + fmt.Println(string(out)) + + //hostname, err := os.Hostname() + //if err != nil { + // fmt.Println("Error:", err) + //} + + //currentDate := time.Now().Format("2006-01-02 15:04") + + //webhookURL := "https://discord.com/api/webhooks/1215603532451946566/JsMb7nSHAHOIZ4FJZf8xu0I495dsh1_5LV5x7x52KQBfYM5BoamNCDPAiRbk7yv6q-cX" + // embedColor := 0x1fff00 + + // Create the embed + // embed := map[string]interface{} { + // "Banned IP": ip, + // "Comment": reason, + // "Was banned for": duration, + // "JSON_DATA": jsonObject, + //} + + //payload := map[string]interface{} { + //"content": fmt.Sprintf("Unbanned IP: %s\nComment: %s\nWas banned for: %s\nJSON_DATA: %s", ip, reason, duration, jsonObject), + // "embeds": []map[string]interface{}{embed}, + //} + //payload := map[string]string { + // "content": fmt.Sprintf("Hostname: %s\nCurrent date: %s\nUnbanned IP: %s\nComment: %s\nJSON_DATA: %s", hostname, currentDate, ip, reason, jsonObject), + //} + //jsonData, err := json.Marshal(payload) + //if err != nil { + // fmt.Println("Error marshaling JSON:", err) + // return + //} + // Create the HTTP request + //req, err := http.NewRequest("POST", webhookURL, bytes.NewBuffer(jsonData)) + //if err != nil { + // fmt.Println("Error creating request:", err) + // return + //} + //req.Header.Set("Content-Type", "application/json") + + // Send the HTTP request + //client := &http.Client{} + //resp, err := client.Do(req) + //if err != nil { + // fmt.Println("Error sending request:", err) + // return + //} + //defer resp.Body.Close() + + // Check the response + //if resp.StatusCode == http.StatusOK { + // fmt.Println("Message sent successfully!") + //} else if resp.StatusCode == http.StatusNoContent { + // fmt.Println("Message send, but there was a response with no content (HTTP 204)") + //} else { + // fmt.Println("Failed to send message. Status code:", resp.StatusCode) + //} + // fmt.Printf("Currently unused data: reason: %s duration: %s json data: %s\n", reason, duration, jsonObject) +} + +func processCommand(command string, ip string, duration string, reason string, jsonObject map[string]interface{}) { + switch command { + case "add": + handleAdd(ip, duration, reason, jsonObject) + case "del": + handleDel(ip, duration, reason, jsonObject) + default: + fmt.Println("Invalid command") + } +} + +func main() { + if len(os.Args) != 6 { + fmt.Println("Usage: go run main.go ") + os.Exit(1) + } + + command := os.Args[1] + ip := os.Args[2] + duration := os.Args[3] + reason := os.Args[4] + jsonStr := os.Args[5] + + var jsonObject map[string]interface{} + err := json.Unmarshal([]byte(jsonStr), &jsonObject) + if err != nil { + fmt.Println("Invalid JSON object:", err) + os.Exit(1) + } + + processCommand(command, ip, duration, reason, jsonObject) +}