package main import ( "encoding/json" "fmt" "log" "net/http" "os" "text/template" ) var serverConfig = map[string]string{ "serverIP": os.Getenv("SERVER_IP"), "serverURL": os.Getenv("SERVER_URL"), } func main() { port := os.Getenv("PORT") if port == "" { port = "80" } // Set up routes mux := http.NewServeMux() mux.HandleFunc("/", handleRoot) mux.HandleFunc("/config", handleConfig) mux.HandleFunc("/popup", handlePopupInstructions) mux.HandleFunc("/search", handleSearch) mux.HandleFunc("/favicon.ico", handleFavicon) // Serve static files from 'public' directory fs := http.FileServer(http.Dir("./public")) mux.Handle("/public/", http.StripPrefix("/public/", fs)) // Wende die Sicherheitsheader-Middleware auf alle Routen an secureMux := secureHeaders(mux) // Start the server log.Printf("Server is running at http://0.0.0.0:%s\n", port) log.Fatal(http.ListenAndServe("0.0.0.0:"+port, secureMux)) } // Middleware für Sicherheitsheader func secureHeaders(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Setze die Sicherheitsheader w.Header().Set("Content-Security-Policy", "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self';") w.Header().Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload") w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Set("X-Frame-Options", "DENY") w.Header().Set("X-XSS-Protection", "1; mode=block") // Führe den nächsten Handler aus next.ServeHTTP(w, r) }) } func handleRoot(w http.ResponseWriter, r *http.Request) { tmpl := template.Must(template.ParseFiles("index.html")) if err := tmpl.Execute(w, nil); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } func handleConfig(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") fmt.Fprintf(w, `{"serverIP":"%s","serverURL":"%s"}`, serverConfig["serverIP"], serverConfig["serverURL"]) } func handleSearch(w http.ResponseWriter, r *http.Request) { query := r.URL.Query().Get("query") websites := r.URL.Query()["websites"] if query == "" || len(websites) == 0 { http.Error(w, "Missing query or websites parameter", http.StatusBadRequest) return } var searchResults []map[string]string for _, website := range websites { searchUrl := generateSearchUrl(website, query) searchResults = append(searchResults, map[string]string{ "website": website, "searchUrl": searchUrl, }) } // Respond with JSON w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(searchResults) } func handleFavicon(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) } func handlePopupInstructions(w http.ResponseWriter, r *http.Request) { tmpl := template.Must(template.ParseFiles("popup.html")) if err := tmpl.Execute(w, nil); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } func generateSearchUrl(website, query string) string { searchUrls := map[string]string{ // ----- Eletronik ---- "conrad": fmt.Sprintf("https://www.conrad.de/de/search.html?search=%s", query), "reichelt": fmt.Sprintf("https://www.reichelt.de/index.html?ACTION=446&SEARCH=%s", query), "kosatec": fmt.Sprintf("https://shop.kosatec.de/search?search=%s", query), "schreiber": fmt.Sprintf("https://www.schreiber-electronics.de/search?sSearch=%s", query), // ----- Verpackungen ------ "papstar": fmt.Sprintf("https://www.papstar-shop.de/catalogsearch/result/?q=%s", query), // ----- Baumarkt ------ "hornbach": fmt.Sprintf("https://www.hornbach.de/s/%s", query), "wuerth": fmt.Sprintf("https://eshop.wuerth.de/is-bin/INTERSHOP.enfinity/WFS/1401-B1-Site/de_DE/-/EUR/ViewAfterSearch-ExecuteAfterSearch;pgid=_SyqelfHuAE7AgenBedw0kx10000h8VXDYEd;sid=R1_nTC0hndjgTEiHOQJqR90rj3eq0kN-AXWS_C06?SearchResultType=&EffectiveSearchTerm=&VisibleSearchTerm=%s&CampaignName=SR007", query), "fkr": fmt.Sprintf("https://shop.fkr-baucentrum.de/suche/?q=%s", query), "contorion": fmt.Sprintf("https://www.contorion.de/search?q=%s", query), "esska": fmt.Sprintf("https://www.esska.de/shop/search/%s", query), "voelkner": fmt.Sprintf("https://www.voelkner.de/search/search.html?keywords=%s", query), "megabad": fmt.Sprintf("https://www.megabad.com/search/?query=sdyc/#/q/%s", query), "haefele": fmt.Sprintf("https://www.haefele.de/prod-live/web/WFS/Haefele-HDE-Site/de_DE/-/EUR/ViewParametricSearch-Browse?SearchTerm=%s", query), // ------ Küche -------- "esmeyer": fmt.Sprintf("https://www.esmeyer-shop.de/search?search=%s", query), "lusini": fmt.Sprintf("https://www.lusini.com/de-de/search/#q=%s", query), "tischwelt": fmt.Sprintf("https://www.tischwelt.de/shop/Suche/?q=%s", query), "schafferer": fmt.Sprintf("https://www.schafferer.de/gastro/Artikel-Suche/?q=%s", query), "gastrokaufhaus": fmt.Sprintf("https://www.gastronomie-kaufhaus.de/index.php?lang=0&cl=search&searchparam=%s", query), "boerner": fmt.Sprintf("https://www.boerner.de/?s=%s", query), "ggmgastro": fmt.Sprintf("https://www.ggmgastro.com/de-de-eur/search?q=%s", query), "gastroteileshop": fmt.Sprintf("https://www.gastroteileshop.de/search?query=%s", query), // ----- Hygiene ------ "hygi": fmt.Sprintf("https://www.hygi.de/s/%s", query), "proficlean": fmt.Sprintf("https://www.proficleanshop.de/suche/%s", query), "reinigungsberater": fmt.Sprintf("https://www.reinigungsberater.de/%s.html", query), "franzmensch": fmt.Sprintf("https://www.franz-mensch.de/search?search=%s", query), "rossmann": fmt.Sprintf("https://www.rossmann.de/de/search/?text=%s", query), // ----- Schilder ------ "vkfrenzel": fmt.Sprintf("https://www.vkf-renzel.de/index.php?lang=0&cl=rasearch&searchparam=%s", query), // ----- Landwirtschaft ------- "siepmann": fmt.Sprintf("https://www.siepmann.net/siepmann_shop.php?suchfeld=%s", query), "fksoehnchen": fmt.Sprintf("https://www.fk-soehnchen.de/index.php?lang=0&cl=search&searchparam=%s", query), "wahlagrar": fmt.Sprintf("https://www.agrar-fachversand.com/?etcc_med=SEA&etcc_par=Google&etcc_cmp=AFDE-Performance-Max-35EUR&etcc_grp=&etcc_bky=&etcc_mty=&etcc_plc=&etcc_ctv=&etcc_bde=c&etcc_var=CjwKCAiAqY6tBhAtEiwAHeRopYcDZDIiNKtjG2cFJsJLzcQtaQXgLGPmkD5SuRsOtEy_-QSdYTElrhoCulAQAvD_BwE&gclid=CjwKCAiAqY6tBhAtEiwAHeRopYcDZDIiNKtjG2cFJsJLzcQtaQXgLGPmkD5SuRsOtEy_-QSdYTElrhoCulAQAvD_BwE#/dfclassic/query=%s&query_name=match_and", query), "kox": "https://www.kox-direct.de/?query=${query}&sid=6d0b4366af8bb99af514529b7e61ad&act=search", // ----- Arbeitsschutz ------- "engelbert": fmt.Sprintf("https://www.engelbert-strauss.de/s/suche?query=%s", query), // ------ Med. Artikel ------- "oekonomed": fmt.Sprintf("https://shop.oekonomed.de/de/advanced_search_result.php?keywords=%s&inc_subcat=1", query), "praxisdienst": fmt.Sprintf("https://www.praxisdienst.de/index.php?stoken=268B7DE4&sid=hf02v2hm41hv6v8j3nttfgej8c&lang=0&cl=search&listorderby=reset&searchparam=%s", query), // ----- Möbel ------- "ikea": fmt.Sprintf("https://www.ikea.com/de/de/search/?q=%s", query), // ----- Deko ------ "frankflechtwaren": fmt.Sprintf("https://www.frank-flechtwaren.de/suchergebnisse/?query=%s", query), "betzold": fmt.Sprintf("https://www.betzold.de/search/?q=%s", query), "vbshobby": fmt.Sprintf("https://www.vbs-hobby.com/suche/?q=%s", query), // ----- Sport ------ "thieme": fmt.Sprintf("https://www.sport-thieme.de/cat/search=%s", query), // ------ Etiketten / Papier ------- "labelident": fmt.Sprintf("https://www.labelident.com/catalogsearch/result/?q=%s", query), // ----- Stahl/Bleche ------- "stahlshop": fmt.Sprintf("https://www.stahl-shop24.de/search?search=%s", query), "feld": fmt.Sprintf("https://www.feld-eitorf.de/catalogsearch/result/?q=%s", query), // ----- Saatgut ------ "saatgutshop": fmt.Sprintf("https://www.saatgut-shop.de/advanced_search_result.php?categories_id=0&keywords=%s&inc_subcat=1", query), "saatgutmanufaktur": fmt.Sprintf("https://shop.saatgut-manufaktur.de/advanced_search_result.php?keywords=%s&inc_subcat=1", query), // ------ Bücher ------ "buchammarkt": fmt.Sprintf("https://bam-mr.buchkatalog.de/search?q=%s", query), "thalia": fmt.Sprintf("https://www.thalia.de/suche?sq=%s", query), } if url, ok := searchUrls[website]; ok { return url } return "" }