package servers import ( "fmt" "github.com/MrMelon54/violet/domains" "github.com/MrMelon54/violet/utils" "github.com/julienschmidt/httprouter" "log" "net/http" "net/url" "time" ) // NewHttpServer creates and runs a http server containing the public http // endpoints for the reverse proxy. // // `/.well-known/acme-challenge/{token}` is used for outputting answers for // acme challenges, this is used for Lets Encrypt HTTP verification. func NewHttpServer(listen string, httpsPort int, domainCheck *domains.Domains) *http.Server { r := httprouter.New() var secureExtend string if httpsPort != 443 { secureExtend = fmt.Sprintf(":%d", httpsPort) } // Endpoint for acme challenge outputs r.GET("/.well-known/acme-challenge/{key}", func(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { if h, ok := utils.GetDomainWithoutPort(req.Host); ok { // check if the host is valid if !domainCheck.IsValid(req.Host) { http.Error(rw, fmt.Sprintf("%d %s\n", 420, "Invalid host"), 420) return } // check if the key is valid key := params.ByName("key") if key == "" { rw.WriteHeader(http.StatusOK) return } } rw.WriteHeader(http.StatusNotFound) }) // All other paths lead here and are forwarded to HTTPS r.NotFound = http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { if h, ok := utils.GetDomainWithoutPort(req.Host); ok { u := &url.URL{ Scheme: "https", Host: h + secureExtend, Path: req.URL.Path, RawPath: req.URL.RawPath, RawQuery: req.URL.RawQuery, } utils.FastRedirect(rw, req, u.String(), http.StatusPermanentRedirect) } }) // Create and run http server s := &http.Server{ Addr: listen, Handler: r, ReadTimeout: time.Minute, ReadHeaderTimeout: time.Minute, WriteTimeout: time.Minute, IdleTimeout: time.Minute, MaxHeaderBytes: 2500, } log.Printf("[HTTP] Starting HTTP server on: '%s'\n", s.Addr) go utils.RunBackgroundHttp("HTTP", s) return s }