func get(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { w.Header().Add("Allow", "GET") w.WriteHeader(http.StatusMethodNotAllowed) return } // Cut out the prefix slash path := r.URL.Path[1:] log.Debugf("%[1]s requested long url of %[2]s", getIP(r), path) url, redirect, err := data.Query(path) if err != nil { // No short url found log.Warnf("Failed to find redirect from short url %[2]s: %[1]s", err, path) writeError(w, http.StatusNotFound, "notfound", "404: %[1]s is not a valid short url", path) return } if redirect == "http" { // Short URL with HTTP redirect found. w.Header().Add("Location", url) w.WriteHeader(http.StatusFound) } else if redirect == "html" { // Short URL with HTML redirect found. w.WriteHeader(http.StatusOK) templRedirect.Execute(w, struct{ URL interface{} }{url}) } }
// Delete handles delete requests func Delete(w http.ResponseWriter, r *http.Request) { var ip = getIP(r) if r.Method != "POST" { w.Header().Add("Allow", "POST") w.WriteHeader(http.StatusMethodNotAllowed) return } // Create a json decoder for the payload. decoder := json.NewDecoder(r.Body) var dfr DeleteForm // Decode the payload. err := decoder.Decode(&dfr) // Check if there was an error decoding. if err != nil || len(dfr.ImageName) == 0 || len(dfr.Username) == 0 || len(dfr.AuthToken) == 0 { log.Debugf("%[1]s sent an invalid delete request.", ip) w.WriteHeader(http.StatusBadRequest) return } err = auth.CheckAuthToken(dfr.Username, []byte(dfr.AuthToken)) // Check if the auth token was correct if err != nil { log.Debugf("%[1]s tried to authenticate as %[2]s with the wrong token.", ip, dfr.Username) output(w, GenericResponse{ Success: false, Status: "invalid-authtoken", StatusReadable: "The authentication token was incorrect. Please try logging in again.", }, http.StatusUnauthorized) return } data, err := database.Query(dfr.ImageName) if err != nil { log.Debugf("%[1]s@%[2]s attempted to delete an image that doesn't exist.", dfr.Username, ip, data.Adder) output(w, GenericResponse{Success: false, Status: "not-found", StatusReadable: "The image you requested to be deleted does not exist."}, http.StatusNotFound) return } if data.Adder != dfr.Username { log.Debugf("%[1]s@%[2]s attempted to delete an image uploaded by %[3]s.", dfr.Username, ip, data.Adder) output(w, GenericResponse{Success: false, Status: "no-permissions", StatusReadable: "The image you requested to be deleted was not uploaded by you."}, http.StatusForbidden) return } err = database.Remove(dfr.ImageName) if err != nil { log.Warnf("Error deleting %[4]s from the database (requested by %[1]s@%[2]s): %[3]s", dfr.Username, ip, err, dfr.ImageName) w.WriteHeader(http.StatusInternalServerError) return } err = os.Remove(config.ImageLocation + "/" + dfr.ImageName + "." + data.Format) if err != nil { // If the file just didn't exist, warn about the error. If the error was something else, cancel. if strings.HasSuffix(err.Error(), "no such file or directory") { log.Warnf("Error deleting %[3]s from the filesystem (requested by %[1]s@%[2]s): File not found", dfr.Username, ip, dfr.ImageName) } else { log.Errorf("Error deleting %[4]s from the filesystem (requested by %[1]s@%[2]s): %[3]s", dfr.Username, ip, err, dfr.ImageName) w.WriteHeader(http.StatusInternalServerError) return } } log.Debugf("%[1]s@%[2]s successfully deleted the image with the name %[3]s.", dfr.Username, ip, dfr.ImageName) output(w, GenericResponse{ Success: true, Status: "deleted", StatusReadable: "The image " + dfr.ImageName + " was successfully deleted.", }, http.StatusAccepted) }
func query(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { w.Header().Add("Allow", "POST") w.WriteHeader(http.StatusMethodNotAllowed) return } ip := getIP(r) decoder := json.NewDecoder(r.Body) var req Request // Decode the payload. err := decoder.Decode(&req) if err != nil || len(req.Action) == 0 || len(req.URL) == 0 { log.Debugf("%[1]s sent an invalid insert request.", ip) w.WriteHeader(http.StatusBadRequest) return } if req.Action == "unshorten" { if !strings.HasPrefix(req.URL, config.URL) { log.Warnf("%[1]s attempted to unshorten an invalid URL.", ip) writeError(w, http.StatusBadRequest, "notshortened", "The URL you entered is not a mau\\Lu short URL.") return } shortID := req.URL[len(config.URL):] if len(shortID) > 20 { log.Warnf("%[1]s attempted to unshorten an impossibly long short URL", ip) writeError(w, http.StatusBadRequest, "toolong", "The URL you entered is too long.") return } longURL, _, err := data.Query(shortID) if err != nil { log.Warnf("%[1]s queried the target of the non-existent short URL %[2]s", ip, req.URL) writeError(w, http.StatusNotFound, "notfound", "The short url id %[1]s doesn't exist!", req.URL) return } log.Debugf("%[1]s queried the target of %[2]s.", ip, req.URL) writeSuccess(w, longURL) } else if req.Action == "shorten" || req.Action == "google" || req.Action == "duckduckgo" { if len(req.RequestShort) == 0 { req.RequestShort = randomShortURL() } if req.RedirectType == "js" { req.RedirectType = "html" } else if len(req.RedirectType) == 0 || (req.RedirectType != "http" && req.RedirectType != "html") { req.RedirectType = "http" } if !validShortURL(req.RequestShort) { log.Warnf("%[1]s attempted to use invalid characters in a short URL", ip) writeError(w, http.StatusBadRequest, "illegalchars", "The short URL contains illegal characters.") return } if strings.HasPrefix(req.URL, config.URL) { log.Warnf("%[1]s attempted to shorten the mau\\Lu url %[2]s", ip, req.URL) writeError(w, http.StatusBadRequest, "alreadyshortened", "The given URL is already a mau\\Lu URL") return } if req.Action == "google" { req.URL = "http://lmgtfy.com/?q=" + url.QueryEscape(req.URL) } else if req.Action == "duckduckgo" { req.URL = "http://lmddgtfy.net/?q=" + strings.Replace(url.QueryEscape(req.URL), "+", " ", -1) } else if !strings.HasPrefix(req.URL, "https://") && !strings.HasPrefix(req.URL, "http://") { log.Warnf("%[1]s attempted to shorten an URL with an unidentified protocol", ip) writeError(w, http.StatusBadRequest, "invalidprotocol", "Protocol couldn't be identified.") return } if len(req.URL) > 255 { log.Warnf("%[1]s attempted to shorten a very long URL", ip) writeError(w, http.StatusBadRequest, "toolong", "The URL you entered is too long.") return } str, _, err := data.Query(req.RequestShort) if (err == nil || len(str) != 0) && str != req.URL { log.Warnf("%[1]s attempted to insert %[3]s into the short url %[2]s, but it is already in use.", ip, req.RequestShort, req.URL) writeError(w, http.StatusConflict, "alreadyinuse", "The short url %[1]s is already in use.", req.RequestShort) return } resultURL := config.URL + data.Insert(req.URL, req.RequestShort, req.RedirectType) log.Debugf("%[1]s shortened %[3]s into %[2]s", ip, req.URL, resultURL) writeSuccess(w, resultURL) } else { log.Warnf("%[1]s attempted to use an unidentified action: %[2]s", ip, req.Action) writeError(w, http.StatusNotFound, "action", "Invalid action \"%[1]s\"", req.Action) } }
// Hide handles hide/unhide requests func Hide(w http.ResponseWriter, r *http.Request) { var ip = getIP(r) if r.Method != "POST" { w.Header().Add("Allow", "POST") w.WriteHeader(http.StatusMethodNotAllowed) return } // Create a json decoder for the payload. decoder := json.NewDecoder(r.Body) var hfr HideForm // Decode the payload. err := decoder.Decode(&hfr) // Check if there was an error decoding. if err != nil || len(hfr.ImageName) == 0 || len(hfr.Username) == 0 || len(hfr.AuthToken) == 0 { log.Debugf("%[1]s sent an invalid hide request.", ip) w.WriteHeader(http.StatusBadRequest) return } err = auth.CheckAuthToken(hfr.Username, []byte(hfr.AuthToken)) // Check if the auth token was correct if err != nil { log.Debugf("%[1]s tried to authenticate as %[2]s with the wrong token.", ip, hfr.Username) output(w, GenericResponse{ Success: false, Status: "invalid-authtoken", StatusReadable: "The authentication token was incorrect. Please try logging in again.", }, http.StatusUnauthorized) return } owner := database.GetOwner(hfr.ImageName) if len(owner) > 0 { if owner != hfr.Username { log.Debugf("%[1]s@%[2]s attempted to hide an image uploaded by %[3]s.", hfr.Username, ip, owner) output(w, GenericResponse{ Success: false, Status: "no-permissions", StatusReadable: "The image you requested to be deleted was not uploaded by you.", }, http.StatusForbidden) return } } else { log.Debugf("%[1]s@%[2]s attempted to hide an image that doesn't exist.", hfr.Username, ip, owner) output(w, GenericResponse{Success: false, Status: "not-found", StatusReadable: "The image you requested to be deleted does not exist."}, http.StatusNotFound) return } err = database.SetHidden(hfr.ImageName, hfr.Hidden) if err != nil { log.Warnf("Error changing hide status of %[4]s (requested by %[1]s@%[2]s): %[3]s", hfr.Username, ip, err, hfr.ImageName) w.WriteHeader(http.StatusInternalServerError) return } var hid string if hfr.Hidden { hid = "hidden" } else { hid = "unhidden" } log.Debugf("%[1]s@%[2]s successfully changed hidden status to %[4]t of the image with the name %[3]s.", hfr.Username, ip, hfr.ImageName, hfr.Hidden) output(w, GenericResponse{ Success: true, Status: hid, StatusReadable: "The image " + hfr.ImageName + " was successfully " + hid + ".", }, http.StatusAccepted) }
// Search handles search requests func Search(w http.ResponseWriter, r *http.Request) { var ip = getIP(r) if r.Method != "POST" { w.Header().Add("Allow", "POST") w.WriteHeader(http.StatusMethodNotAllowed) return } if !config.AllowSearch { log.Warnf("%[1]s attempted to execute a search, even though it's not allowed", ip) w.WriteHeader(http.StatusForbidden) return } // Create a json decoder for the payload. decoder := json.NewDecoder(r.Body) var sf SearchForm // Decode the payload. err := decoder.Decode(&sf) // Check if there was an error decoding. if err != nil || (len(sf.Format) == 0 && len(sf.Adder) == 0 && len(sf.Client) == 0 && sf.MinTime <= 0 && sf.MaxTime <= 0) { log.Debugf("%[1]s sent an invalid search request.", ip) w.WriteHeader(http.StatusBadRequest) return } if sf.MinTime <= 0 && sf.MaxTime > 0 { sf.MinTime = 1 } else if sf.MinTime > 0 && sf.MaxTime <= 0 { sf.MaxTime = time.Now().Unix() } var authenticated = false if len(sf.AuthToken) != 0 { err = auth.CheckAuthToken(sf.Adder, []byte(sf.AuthToken)) if err != nil { log.Debugf("%[1]s tried to authenticate as %[2]s with the wrong token.", ip, sf.Adder) output(w, SearchResponse{ Success: false, Status: "invalid-authtoken", StatusReadable: "The authentication token was incorrect. Please try logging in again.", }, http.StatusUnauthorized) return } authenticated = true } results, err := database.Search(sf.Format, sf.Adder, sf.Client, sf.MinTime, sf.MaxTime, authenticated) if err != nil { log.Errorf("Failed to execute search %[2]s by %[1]s: %[3]s", ip, sf.String(), err) w.WriteHeader(http.StatusInternalServerError) return } if authenticated { log.Debugf("%[3]s@%[1]s executed a search: %[2]s", ip, sf.String(), sf.Adder) } else { log.Debugf("%[1]s executed a search: %[2]s", ip, sf.String()) } output(w, SearchResponse{ Success: true, Status: "success", StatusReadable: fmt.Sprintf("Search completed with %d results", len(results)), Results: results, }, http.StatusOK) }