package main import ( "cmp" "fmt" "html/template" "io" "log" "log/slog" "math/rand" "net/http" "net/url" "os" "path/filepath" "strconv" "strings" "time" agents "github.com/monperrus/crawler-user-agents" "golang.org/x/text/cases" "golang.org/x/text/language" ) var ( stats = map[string]int{} ticker = time.NewTicker(10 * time.Minute) ) func main() { logger := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{ Level: slog.LevelDebug, })) slog.SetDefault(logger) domain := cmp.Or(os.Getenv("DOMAIN"), "0.0.0.0:8070") srv := http.NewServeMux() srv.HandleFunc("/robots.txt", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/plain") _, _ = w.Write([]byte(` `)) }) srv.HandleFunc("/favicon.ico", func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "image/x-icon") _, _ = w.Write([]byte(``)) }) srv.HandleFunc("/stats", fileHandler) srv.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { // generate links1 to 7 from the names list and populate the template // with the links slog.Debug("Request received", "host", r.Host, "user_agent", r.UserAgent(), "remote_addr", r.RemoteAddr, "x_forwarded_for", r.Header.Get("X-Forwarded-For"), ) if agents.IsCrawler(r.UserAgent()) { slog.Info("crawler detected", "user_agent", r.UserAgent()) // remove all commas from simpler CSV handling. ua := strings.ReplaceAll(r.UserAgent(), ",", "") if _, ok := stats[ua]; !ok { stats[ua] = 1 } else { stats[ua]++ } } currentName := "Ziggy" // get current name from the subdomain if strings.Contains(r.Host, ".") { currentName = strings.Split(r.Host, ".")[0] currentName = strings.ReplaceAll(currentName, "-", " ") caser := cases.Title(language.English) currentName = caser.String(currentName) } baseLink := "http://%s." + domain + "/" content := indexTemplate content = strings.ReplaceAll(content, "{{img}}", img) content = strings.ReplaceAll(content, "{{current_name}}", currentName) for i := 1; i <= 7; i++ { // pick 3 random names from the list and use them as the link // the link itself will be the name with spaces replaced with // dashes and all lowercase and the title will be the names with // spaces. name1 := names[rand.Intn(len(names))] name2 := names[rand.Intn(len(names))] name3 := names[rand.Intn(len(names))] subdomain := strings.Join([]string{name1, name2, name3}, "-") subdomain = strings.ToLower(subdomain) link := fmt.Sprintf(baseLink, subdomain) title := strings.Join([]string{name1, name2, name3}, " ") content = strings.ReplaceAll(content, fmt.Sprintf("{{link%d}}", i), link) content = strings.ReplaceAll(content, fmt.Sprintf("{{link%d_title}}", i), title) } w.Header().Set("Keep-Alive", "timeout=5, max=1000") w.Header().Set("Connection", "Keep-Alive") w.Header().Set("Cache-Control", "no-cache, no-store, must-revalidate") w.Header().Set("Server", servers[rand.Intn(len(servers))]) w.Header().Set("Content-Type", "text/html") _, _ = w.Write([]byte(content)) }) go func() { err := writeStatsToFile() if err != nil { slog.Error("writeStatsToFile: failed to write stats to file", "error", err) } }() slog.Info("Starting server", "address", "0.0.0.0:8070") err := http.ListenAndServe("0.0.0.0:8070", srv) log.Fatal(err) } func safeJoin(baseDir, targetDir string) (string, error) { // Clean and absolute paths basePath, err := filepath.Abs(filepath.Clean(baseDir)) if err != nil { return "", err } targetPath, err := filepath.Abs(filepath.Clean(filepath.Join(basePath, targetDir))) if err != nil { return "", err } // Prevent directory traversal if !strings.HasPrefix(targetPath, basePath) { return "", fmt.Errorf("invalid directory traversal attempt") } return targetPath, nil } func fileHandler(w http.ResponseWriter, r *http.Request) { fileDir := cmp.Or(os.Getenv("LOG_FILE_DIR"), "logs/gridlock") requestedDir, err := url.QueryUnescape(r.URL.Query().Get("dir")) if err != nil { http.Error(w, "Invalid path.", http.StatusBadRequest) return } path, err := safeJoin(fileDir, requestedDir) if err != nil { http.Error(w, "Invalid path.", http.StatusBadRequest) return } slog.Debug("reading path", "path", path) fileInfo, err := os.Stat(path) if err != nil { http.Error(w, "File not found.", http.StatusNotFound) return } slog.Debug("reading path", "path", path, "info", fileInfo) if fileInfo.IsDir() { files, err := os.ReadDir(path) if err != nil { http.Error(w, "Could not read directory.", http.StatusInternalServerError) return } entries := make([]string, 0, len(files)) for _, file := range files { entries = append(entries, url.QueryEscape(file.Name())) } fileTemplate.Execute(w, struct { BaseDir string Path string Entries []string }{ BaseDir: fileDir, Path: requestedDir, Entries: entries, }) } else { // Handle CSV file viewing if strings.HasSuffix(path, ".csv") { data, err := os.ReadFile(path) if err != nil { http.Error(w, "Could not read file.", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.Write(data) } else { http.Error(w, "Unsupported file type.", http.StatusUnsupportedMediaType) } } } func writeStatsToFile() error { fileDir := cmp.Or(os.Getenv("LOG_FILE_DIR"), "./logs/gridlock") slog.Info("Configured to write stats file", "destination", fileDir) for range ticker.C { if len(stats) == 0 { slog.Debug("writeStatsToFile: no stats to write") continue } currentTime := time.Now() dir := filepath.Join(fileDir, fmt.Sprint(currentTime.Year()), fmt.Sprint(currentTime.Month())) slog.Debug("writeStatsToFile: creating directory", "dir", dir) err := os.MkdirAll(dir, 0o777) if err != nil { return err } filename := filepath.Join(dir, fmt.Sprint(currentTime.Day())+".csv") file, err := os.OpenFile(filename, os.O_CREATE|os.O_RDWR, 0o700) if err != nil { slog.Error("writeStatsToFile: failed to open the stats file", "error", err) // try again next tick continue } // parse the csv file and write the stats to it b, err := io.ReadAll(file) if err != nil { slog.Error("writeStatsToFile: failed to read the stats file", "error", err) file.Close() continue } data := strings.Split(string(b), "\n") for k, v := range stats { for i, line := range data { if strings.Contains(line, k) { value := strings.Split(line, ",")[1] vInt, err := strconv.Atoi(value) if err != nil { slog.Error("writeStatsToFile: failed to convert value to int", "error", err) file.Close() continue } data[i] = fmt.Sprintf(`"%s",%d`, k, vInt+v) break } else { data[i] = fmt.Sprintf(`"%s",%d`, k, v) } } } file.Truncate(0) file.Seek(0, 0) _, err = file.Write([]byte(strings.Join(data, "\n"))) if err != nil { slog.Error("writeStatsToFile: failed to write to file", "error", err) file.Close() continue } // reset the stats stats = map[string]int{} file.Close() } return nil } var fileTemplate = template.Must(template.New("files").Parse(` Stats

Stats

`)) var indexTemplate = ` Friendly space worm site

Friendly space worm

Meet {{current_name}}, the sassy space worm from Andromeda. With their shimmering purple skin and glowing red eyes, they are a beguiling rogue, always the talk of the galaxy.

This is your one stop shop to all things internet.

Here you find out everything you need to.

{{img}}

Here are some other sites you might like from our friendly web ring

{{link1_title}} {{link2_title}} {{link3_title}} {{link4_title}} {{link5_title}} {{link6_title}} {{link7_title}}
` var servers = []string{ "Apache/2.4.41 (Unix)", "nginx/1.18.0", "Microsoft-IIS/10.0", "LiteSpeed", "Apache Tomcat/9.0.37", "Jetty(9.4.28)", "Express", "Caddy", "Cherokee/1.2.104", "Kestrel", "gunicorn/20.0.4", "CherryPy/18.6.0", "Puma 4.3.5 (ruby 2.7.1-p158)", "Unicorn 5.6.2", "TornadoServer/6.0.4", "WildFly/21", "GlassFish Server Open Source Edition 5.0", "Oracle-Application-Server-11g", "Zope/(2.13.29, python 2.7.18, linux2) ZServer/1.1", "Resin/4.0.48", } var names = []string{ "Jacob", "Mason", "William", "Jayden", "Noah", "Michael", "Ethan", "Alexander", "Aiden", "Daniel", "Anthony", "Matthew", "Elijah", "Joshua", "Liam", "Andrew", "James", "David", "Benjamin", "Christopher", "Logan", "Joseph", "Jackson", "Gabriel", "Ryan", "Samuel", "John", "Nathan", "Lucas", "Christian", "Jonathan", "Caleb", "Dylan", "Landon", "Isaac", "Brayden", "Gavin", "Tyler", "Luke", "Evan", "Carter", "Nicholas", "Isaiah", "Owen", "Jack", "Jordan", "Brandon", "Wyatt", "Julian", "Jeremiah", "Aaron", "Angel", "Cameron", "Connor", "Hunter", "Adrian", "Henry", "Eli", "Justin", "Austin", "Charles", "Robert", "Thomas", "Zachary", "Jose", "Levi", "Kevin", "Sebastian", "Chase", "Ayden", "Jason", "Ian", "Blake", "Colton", "Bentley", "Xavier", "Dominic", "Oliver", "Parker", "Josiah", "Adam", "Cooper", "Brody", "Nathaniel", "Carson", "Jaxon", "Tristan", "Luis", "Juan", "Hayden", "Carlos", "Nolan", "Jesus", "Cole", "Alex", "Max", "Bryson", "Grayson", "Diego", "Jaden", "Vincent", "Micah", "Easton", "Eric", "Kayden", "Jace", "Aidan", "Ryder", "Ashton", "Bryan", "Riley", "Hudson", "Asher", "Bryce", "Miles", "Kaleb", "Giovanni", "Antonio", "Kaden", "Kyle", "Colin", "Brian", "Timothy", "Steven", "Sean", "Miguel", "Richard", "Ivan", "Jake", "Alejandro", "Santiago", "Joel", "Maxwell", "Caden", "Brady", "Axel", "Preston", "Damian", "Elias", "Jesse", "Jaxson", "Victor", "Jonah", "Patrick", "Marcus", "Rylan", "Emmanuel", "Edward", "Leonardo", "Cayden", "Grant", "Jeremy", "Braxton", "Gage", "Jude", "Wesley", "Devin", "Roman", "Mark", "Camden", "Kaiden", "Oscar", "Malachi", "Alan", "George", "Peyton", "Leo", "Nicolas", "Maddox", "Kenneth", "Mateo", "Sawyer", "Cody", "Collin", "Conner", "Declan", "Andres", "Bradley", "Lincoln", "Trevor", "Derek", "Tanner", "Silas", "Seth", "Eduardo", "Paul", "Jaiden", "Jorge", "Cristian", "Travis", "Garrett", "Abraham", "Omar", "Javier", "Ezekiel", "Tucker", "Peter", "Damien", "Harrison", "Greyson", "Avery", "Kai", "Ezra", "Weston", "Xander", "Jaylen", "Corbin", "Calvin", "Fernando", "Jameson", "Francisco", "Maximus", "Shane", "Josue", "Chance", "Ricardo", "Trenton", "Israel", "Cesar", "Emmett", "Zane", "Drake", "Jayce", "Mario", "Landen", "Spencer", "Griffin", "Kingston", "Stephen", "Theodore", "Manuel", "Erick", "Braylon", "Raymond", "Edwin", "Charlie", "Myles", "Abel", "Johnathan", "Andre", "Bennett", "Alexis", "Edgar", "Troy", "Zion", "Jeffrey", "Shawn", "Hector", "Lukas", "Amir", "Tyson", "Keegan", "Kyler", "Donovan", "Simon", "Graham", "Clayton", "Everett", "Braden", "Luca", "Emanuel", "Martin", "Brendan", "Cash", "Zander", "Dante", "Jared", "Dominick", "Kameron", "Lane", "Ryker", "Elliot", "Paxton", "Rafael", "Andy", "Dalton", "Erik", "Gregory", "Sergio", "Marco", "Jasper", "Johnny", "Emiliano", "Dean", "Drew", "Judah", "Caiden", "Skyler", "Aden", "Maximiliano", "Fabian", "Zayden", "Brennan", "Anderson", "Roberto", "Quinn", "Reid", "Angelo", "Holden", "Cruz", "Derrick", "Emilio", "Finn", "Grady", "Elliott", "Amari", "Pedro", "Frank", "Rowan", "Felix", "Lorenzo", "Dakota", "Corey", "Colby", "Dawson", "Braylen", "Allen", "Brycen", "Ty", "Brantley", "Jax", "Malik", "Ruben", "Trey", "Brock", "Dallas", "Colt", "Joaquin", "Leland", "Beckett", "Jett", "Louis", "Gunner", "Jakob", "Adan", "Taylor", "Cohen", "Marshall", "Arthur", "Marcos", "Ronald", "Julius", "Armando", "Kellen", "Brooks", "Dillon", "Cade", "Nehemiah", "Danny", "Devon", "Jayson", "Beau", "Tristen", "Enrique", "Desmond", "Randy", "Pablo", "Milo", "Gerardo", "Raul", "Romeo", "Titus", "Kellan", "Julio", "Keaton", "Karson", "Reed", "Keith", "Dustin", "Scott", "Braydon", "Ali", "Waylon", "Trent", "Walter", "Ismael", "Donald", "Phillip", "Iker", "Darius", "Jaime", "Esteban", "Landyn", "Dexter", "Matteo", "Colten", "Emerson", "Phoenix", "King", "Izaiah", "Karter", "Albert", "Tate", "Jerry", "August", "Payton", "Jay", "Larry", "Saul", "Rocco", "Jalen", "Russell", "Enzo", "Kolton", "Quentin", "Leon", "Philip", "Mathew", "Tony", "Gael", "Gideon", "Kade", "Dennis", "Damon", "Darren", "Kason", "Walker", "Jimmy", "Mitchell", "Alberto", "Alec", "Rodrigo", "Casey", "River", "Issac", "Amare", "Maverick", "Brayan", "Mohamed", "Yahir", "Arturo", "Moises", "Knox", "Maximilian", "Davis", "Barrett", "Gustavo", "Curtis", "Hugo", "Reece", "Chandler", "Jamari", "Abram", "Mauricio", "Solomon", "Archer", "Kamden", "Uriel", "Bryant", "Porter", "Zackary", "Ryland", "Lawrence", "Adriel", "Ricky", "Noel", "Ronan", "Alijah", "Chris", "Leonel", "Khalil", "Zachariah", "Brenden", "Maurice", "Atticus", "Marvin", "Ibrahim", "Lance", "Bruce", "Dane", "Orion", "Cullen", "Pierce", "Kieran", "Nikolas", "Braeden", "Remington", "Kobe", "Prince", "Finnegan", "Muhammad", "Orlando", "Sam", "Mekhi", "Alfredo", "Jacoby", "Rhys", "Eddie", "Jonas", "Joe", "Zaiden", "Kristopher", "Ernesto", "Nico", "Gary", "Jamison", "Malcolm", "Warren", "Armani", "Franklin", "Gunnar", "Johan", "Giovani", "Ramon", "Byron", "Cason", "Kane", "Ari", "Brett", "Deandre", "Finley", "Cyrus", "Justice", "Moses", "Douglas", "Talon", "Gianni", "Camron", "Cannon", "Kendrick", "Nash", "Dorian", "Sullivan", "Arjun", "Kasen", "Dominik", "Skylar", "Korbin", "Quinton", "Royce", "Ahmed", "Raiden", "Roger", "Salvador", "Terry", "Tobias", "Brodie", "Isaias", "Morgan", "Conor", "Frederick", "Moshe", "Reese", "Madden", "Braiden", "Kelvin", "Asa", "Alvin", "Julien", "Nickolas", "Kristian", "Wade", "Rodney", "Xzavier", "Davion", "Boston", "Nelson", "Alonzo", "Ezequiel", "Nasir", "Jase", "London", "Jermaine", "Rhett", "Mohammed", "Roy", "Matias", "Keagan", "Blaine", "Chad", "Ace", "Marc", "Trace", "Aarav", "Bently", "Rohan", "Aldo", "Uriah", "Nathanael", "Demetrius", "Kamari", "Lawson", "Layne", "Carmelo", "Jamarion", "Shaun", "Terrance", "Ahmad", "Carl", "Kale", "Micheal", "Callen", "Jaydon", "Noe", "Jaxen", "Lucian", "Jaxton", "Quincy", "Rory", "Javon", "Kendall", "Wilson", "Guillermo", "Jeffery", "Kian", "Joey", "Harper", "Jensen", "Mohammad", "Billy", "Jonathon", "Dayton", "Jadiel", "Willie", "Jadon", "Francis", "Melvin", "Rex", "Clark", "Malakai", "Terrell", "Kash", "Ariel", "Cristopher", "Layton", "Sylas", "Semaj", "Gerald", "Lewis", "Aron", "Kody", "Tomas", "Triston", "Messiah", "Bentlee", "Tommy", "Harley", "Marlon", "Isiah", "Nikolai", "Sincere", "Aidyn", "Alessandro", "Luciano", "Omari", "Terrence", "Jagger", "Kylan", "Rene", "Cory", "Beckham", "Urijah", "Reginald", "Aydin", "Deacon", "Felipe", "Neil", "Santino", "Tristian", "Daxton", "Jordyn", "Ulises", "Will", "Giovanny", "Kayson", "Osvaldo", "Raphael", "Makai", "Kole", "Lee", "Case", "Channing", "Tripp", "Allan", "Jamal", "Jorden", "Stanley", "Alonso", "Soren", "Jon", "Ray", "Aydan", "Bobby", "Jasiah", "Markus", "Ben", "Camren", "Davin", "Aryan", "Darrell", "Branden", "Hank", "Adonis", "Mathias", "Darian", "Marquis", "Jessie", "Raylan", "Vicente", "Zayne", "Kenny", "Wayne", "Leonard", "Jefferson", "Kolby", "Harry", "Steve", "Zechariah", "Adrien", "Ayaan", "Dax", "Emery", "Dwayne", "Rashad", "Ronnie", "Yusuf", "Samir", "Clay", "Memphis", "Odin", "Tristin", "Bowen", "Benson", "Lamar", "Tatum", "Javion", "Maxim", "Ellis", "Alexzander", "Elisha", "Draven", "Rudy", "Branson", "Rayan", "Rylee", "Zain", "Brendon", "Deshawn", "Sterling", "Brennen", "Crosby", "Jerome", "Kareem", "Kyson", "Winston", "Jairo", "Lennon", "Luka", "Niko", "Roland", "Zavier", "Yosef", "Cedric", "Kymani", "Vance", "Chaim", "Killian", "Trevon", "Gauge", "Kaeden", "Vincenzo", "Teagan", "Abdullah", "Bo", "Hamza", "Kolten", "Valentino", "Augustus", "Edison", "Gavyn", "Jovani", "Matthias", "Darwin", "Jamir", "Jaylin", "Toby", "Davian", "Hayes", "Rogelio", "Damion", "Brent", "Brogan", "Landry", "Junior", "Emmitt", "Kamron", "Bronson", "Misael", "Van", "Casen", "Lionel", "Conrad", "Giancarlo", "Yandel", "Alfonso", "Jamie", "Deangelo", "Rolando", "Aaden", "Abdiel", "Duncan", "Ishaan", "Ronin", "Maximo", "Cael", "Craig", "Ean", "Tyrone", "Xavi", "Chace", "Dominique", "Quintin", "Mayson", "Zachery", "Bradyn", "Derick", "Izayah", "Westin", "Alvaro", "Blaze", "Johnathon", "Konner", "Lennox", "Ramiro", "Keenan", "Marcelo", "Eden", "Eugene", "Rayden", "Bruno", "Sage", "Jamar", "Cale", "Camryn", "Deegan", "Rodolfo", "Seamus", "Damarion", "Leandro", "Harold", "Marcel", "Jaeden", "Jovanni", "Konnor", "Cain", "Callum", "Ernest", "Rowen", "Jair", "Justus", "Rylen", "Heath", "Randall", "Arnav", "Fisher", "Gilberto", "Irvin", "Harvey", "Amos", "Frankie", "Lyric", "Kamryn", "Theo", "Alden", "Masen", "Todd", "Hassan", "Samson", "Gilbert", "Salvatore", "Darien", "Hezekiah", "Cassius", "Krish", "Jaidyn", "Mike", "Antoine", "Darnell", "Jedidiah", "Stefan", "Isai", "Makhi", "Remy", "Camdyn", "Dario", "Callan", "Kyron", "Leonidas", "Fletcher", "Jerimiah", "Reagan", "Sonny", "Deven", "Sidney", "Yadiel", "Efrain", "Santos", "Brenton", "Tyrell", "Nixon", "Vaughn", "Aditya", "Brysen", "Elvis", "Zaire", "Freddy", "Thaddeus", "Demarcus", "Gaige", "Gibson", "Jaylon", "Clinton", "Coleman", "Zackery", "Arlo", "Braylin", "Roderick", "Turner", "Alfred", "Bodhi", "Jabari", "Agustin", "Leighton", "Arian", "Miller", "Quinten", "Yehuda", "Jakobe", "Legend", "Mustafa", "Reuben", "Enoch", "Lathan", "Ross", "Blaise", "Otto", "Benton", "Brice", "Flynn", "Rey", "Vihaan", "Crew", "Graysen", "Houston", "Hugh", "Jaycob", "Johann", "Maxton", "Trystan", "Darryl", "Jean", "Tyree", "Devan", "Donte", "Mariano", "Ralph", "Anders", "Bridger", "Howard", "Ignacio", "Franco", "Jaydan", "Valentin", "Haiden", "Joziah", "Zeke", "Brecken", "Eliseo", "Maksim", "Maxx", "Tyrese", "Broderick", "Hendrix", "Coen", "Davon", "Elian", "Keon", "Princeton", "Cristiano", "Jaron", "Damari", "Deon", "Corban", "Kyan", "Malaki", "Dimitri", "Jaydin", "Kael", "Pierre", "Major", "Jeramiah", "Kingsley", "Kohen", "Cayson", "Cortez", "Oakley", "Camilo", "Carlo", "Dangelo", "Ethen", } var img = `friendly space worm`