// main.go package main import ( "html/template" "log" "net/http" "os" "path/filepath" "time" "siteproxy/auth" "siteproxy/cache" "siteproxy/config" "siteproxy/proxy" "siteproxy/security" ) func main() { cfg := config.LoadFromEnv() log.Printf("Starting Secure Site Proxy...") log.Printf("Session timeout: %v", cfg.SessionTimeout) log.Printf("Rate limit: %d requests per %v", cfg.RateLimit, cfg.RateLimitWindow) log.Printf("Cache enabled: %v (max: %d MB)", cfg.CacheEnabled, cfg.CacheMaxSize/1024/1024) templates, err := loadTemplates() if err != nil { log.Fatalf("Failed to load templates: %v", err) } authSessionMgr := auth.NewSessionManager(cfg.SessionTimeout) authMw := auth.NewAuthMiddleware(cfg.Username, cfg.Password, authSessionMgr, templates) blockedDomainsMap := make(map[string]bool) for _, domain := range cfg.BlockedDomains { blockedDomainsMap[domain] = true } validator := security.NewRequestValidator( blockedDomainsMap, cfg.BlockedCIDRs, cfg.AllowedSchemes, ) rateLimiter := security.NewRateLimiter(cfg.RateLimit, cfg.RateLimitWindow) var memCache *cache.MemoryCache if cfg.CacheEnabled { memCache = cache.NewMemoryCache(cfg.CacheMaxSize, cfg.CacheTTL) } else { memCache = cache.NewMemoryCache(0, 0) } proxySessionMgr := proxy.NewProxySessionManager(30 * time.Minute) proxyHandler := proxy.NewHandler( validator, rateLimiter, memCache, proxySessionMgr, cfg.UserAgent, cfg.MaxResponseSize, ) indexHandler := proxy.NewIndexHandler(templates) statsHandler := proxy.NewStatsHandler(memCache) mux := http.NewServeMux() mux.HandleFunc("/login", authMw.Login) mux.HandleFunc("/health", healthCheck) mux.Handle("/", authMw.Require(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.URL.Path != "/" { http.NotFound(w, r) return } if r.Method == "POST" { targetURL := r.FormValue("url") if targetURL == "" { http.Error(w, "URL required", http.StatusBadRequest) return } token := proxySessionMgr.Create(targetURL) http.Redirect(w, r, "/p/"+token, http.StatusSeeOther) return } indexHandler.ServeHTTP(w, r) }))) mux.Handle("/p/", authMw.Require(proxyHandler)) mux.Handle("/stats", authMw.Require(statsHandler)) mux.HandleFunc("/logout", authMw.Logout) addr := ":" + cfg.Port log.Printf("Server listening on %s", addr) log.Printf("Login with username: %s", cfg.Username) log.Printf("Access at: http://localhost:%s", cfg.Port) if err := http.ListenAndServe(addr, mux); err != nil { log.Fatal(err) } } func loadTemplates() (*template.Template, error) { templateDirs := []string{"templates", "./templates", "/app/templates"} var templateDir string for _, dir := range templateDirs { if _, err := os.Stat(dir); err == nil { templateDir = dir break } } if templateDir == "" { return nil, os.ErrNotExist } log.Printf("Loading templates from: %s", templateDir) pattern := filepath.Join(templateDir, "*.html") tmpl, err := template.ParseGlob(pattern) if err != nil { return nil, err } log.Printf("Loaded templates: %v", tmpl.DefinedTemplates()) return tmpl, nil } func healthCheck(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(`{"status":"ok","version":"1.0.0"}`)) }