package internal import ( "fmt" "image/png" "net/http" "os" "path/filepath" "strings" "time" "git.mills.io/prologic/useragent" securejoin "github.com/cyphar/filepath-securejoin" "github.com/julienschmidt/httprouter" log "github.com/sirupsen/logrus" ) func (s *Server) NotFoundHandler(w http.ResponseWriter, r *http.Request) { if r.Header.Get("Accept") == "application/json" { w.Header().Set("Content-Type", "application/json") http.Error(w, "Endpoint Not Found", http.StatusNotFound) return } w.WriteHeader(http.StatusNotFound) w.Write([]byte("404 Not Found")) } // ConfigHandler ... func (s *Server) ConfigHandler() httprouter.Handle { configDir := filepath.Join(s.config.Data, wellknownPath) return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { w.Header().Set("Accept-Encoding", "br, gzip, deflate") w.Header().Set("X-Salty-Accept-Encoding", "br, gzip, deflate") http.ServeFile(w, r, filepath.Join(configDir, p.ByName("config"))) } } // IndexHandler ... func (s *Server) IndexHandler() httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { ua := useragent.Parse(r.UserAgent()) if ua != nil && ua.Type == useragent.Browser { http.Redirect(w, r, "/app/", http.StatusFound) } } } // AvatarHandler ... func (s *Server) AvatarHandler() httprouter.Handle { avatarsDir := filepath.Join(s.config.Data, avatarsPath) return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { w.Header().Set("Cache-Control", "public, no-cache, must-revalidate") hash := p.ByName("hash") if hash == "" { http.Error(w, "Bad Request", http.StatusBadRequest) return } fn, err := securejoin.SecureJoin(avatarsDir, fmt.Sprintf("%s.png", hash)) if err != nil { http.Error(w, "Bad Request", http.StatusBadRequest) return } if fileInfo, err := os.Stat(fn); err == nil { w.Header().Set("Etag", fmt.Sprintf("W/\"%s-%s\"", r.RequestURI, fileInfo.ModTime().Format(time.RFC3339))) w.Header().Set("Last-Modified", fileInfo.ModTime().Format(http.TimeFormat)) http.ServeFile(w, r, fn) return } etag := fmt.Sprintf("W/\"%s\"", r.RequestURI) if match := r.Header.Get("If-None-Match"); match != "" { if strings.Contains(match, etag) { w.WriteHeader(http.StatusNotModified) return } } w.Header().Set("Etag", etag) if r.Method == http.MethodHead { return } img, err := GenerateAvatar(s.config, hash) if err != nil { log.WithError(err).Errorf("error generating avatar for %s", hash) http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } if r.Method == http.MethodHead { return } w.Header().Set("Content-Type", "image/png") if err := png.Encode(w, img); err != nil { log.WithError(err).Error("error encoding auto generated avatar") http.Error(w, "Internal Server Error", http.StatusInternalServerError) return } } }