// Subscribe the given UID to the notification list. func subscribe(u config.User) bool { if isSubscribed(u) { log.Debugf("[Posts] %[1]s attempted to subscribe to the notification list, but was already subscribed", u.Name) return false } log.Debugf("[Posts] %[1]s successfully subscribed to the notifcation list", u.Name) u.SetSetting(subSetting, "true") config.ASave() return true }
// Unsubscribe the given UID from the notification list. func unsubscribe(u config.User) bool { if !isSubscribed(u) { log.Debugf("[Posts] %[1]s attempted to unsubscribe from the notification list, but was not subscribed", u.Name) return false } log.Debugf("[Posts] %[1]s successfully unsubscribed from the notifcation list", u.Name) u.RemoveSetting(subSetting) config.ASave() return true }
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}) } }
func listen(bot *telebot.Bot) { reader := bufio.NewReader(os.Stdin) for { text, _ := reader.ReadString('\n') text = text[:len(text)-1] log.Debugf("[Syscmds] Received %s", text) args := strings.Split(text, " ") onCommand(bot, strings.ToLower(args[0]), args[1:]) } }
// 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) }
// Insert handles insert requests func Insert(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 ifr InsertForm // Decode the payload. err := decoder.Decode(&ifr) // Check if there was an error decoding. if err != nil || len(ifr.Image) == 0 { log.Debugf("%[1]s sent an invalid insert request.", ip) w.WriteHeader(http.StatusBadRequest) return } // Fill out all non-necessary unfilled values. if len(ifr.ImageName) == 0 { ifr.ImageName = ImageName(5) } if len(ifr.ImageFormat) == 0 { ifr.ImageFormat = "png" } if len(ifr.Client) == 0 { ifr.Client = "Unknown Client" } if len(ifr.Username) == 0 || len(ifr.AuthToken) == 0 { // Username or authentication token not supplied. if config.RequireAuth { // The user is not logged in, but the config is set to require authentication, send error. log.Debugf("%[1]s tried to upload an image without authentication, even though authentication is required.", ip) output(w, GenericResponse{ Success: false, Status: "not-logged-in", StatusReadable: "This MIS server requires authentication. Please log in or register.", }, http.StatusUnauthorized) return } // The user is not logged in, but login is not required, set username to "anonymous" ifr.Username = "******" } else { // Username and authentication token supplied, check them. err = auth.CheckAuthToken(ifr.Username, []byte(ifr.AuthToken)) if err != nil { log.Debugf("%[1]s tried to authenticate as %[2]s with the wrong token.", ip, ifr.Username) output(w, GenericResponse{ Success: false, Status: "invalid-authtoken", StatusReadable: "Your authentication token was incorrect. Please try logging in again.", }, http.StatusUnauthorized) return } } // If the image already exists, make sure that the uploader is the owner of the image. var replace = false owner := database.GetOwner(ifr.ImageName) if len(owner) > 0 { if owner != ifr.Username || ifr.Username == "anonymous" { output(w, GenericResponse{ Success: false, Status: "already-exists", StatusReadable: "The requested image name is already in use by another user", }, http.StatusForbidden) log.Debugf("%[1]s@%[2]s attempted to override an image uploaded by %[3]s.", ifr.Username, ip, owner) return } replace = true } // Decode the base64 image from the JSON request. image, err := base64.StdEncoding.DecodeString(ifr.Image) if err != nil { output(w, GenericResponse{Success: false, Status: "invalid-image-encoding", StatusReadable: "The given image is not properly encoded in base64."}, http.StatusUnsupportedMediaType) log.Errorf("Error while decoding image from %[1]s@%[2]s: %[3]s", ifr.Username, ip, err) return } mimeType := http.DetectContentType(image) if !strings.HasPrefix(mimeType, "image/") { log.Debugf("%[1]s@%[2]s attempted to upload an image with an incorrect MIME type.", ifr.Username, ip, owner) output(w, GenericResponse{ Success: false, Status: "invalid-mime", StatusReadable: "The uploaded data is of an incorrect MIME type.", }, http.StatusUnsupportedMediaType) return } mimeType = mimeType[len("image/"):] // Write the image to disk. err = ioutil.WriteFile(config.ImageLocation+"/"+ifr.ImageName+"."+ifr.ImageFormat, image, 0644) if err != nil { log.Errorf("Error while saving image from %[1]s@%[2]s: %[3]s", ifr.Username, ip, err) w.WriteHeader(http.StatusInternalServerError) return } if !replace { // The image name has not been used. Insert it into the database. err = database.Insert(ifr.ImageName, ifr.ImageFormat, mimeType, ifr.Username, ip, ifr.Client, ifr.Hidden) if err != nil { log.Errorf("Error while inserting image from %[1]s@%[2]s into the database: %[3]s", ifr.Username, ip, err) output(w, GenericResponse{ Success: false, Status: "database-error", StatusReadable: "An internal server error occurred while attempting to save image information to the database.", }, http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError) return } log.Debugf("%[1]s@%[2]s successfully uploaded an image with the name %[3]s (new).", ifr.Username, ip, ifr.ImageName) output(w, GenericResponse{ Success: true, Status: "created", StatusReadable: "The image was successfully saved with the name " + ifr.ImageName, ImageName: ifr.ImageName, }, http.StatusCreated) } else { // The image name was in use. Update the data in the database. err = database.Update(ifr.ImageName, ifr.ImageFormat, mimeType, ip, ifr.Client, ifr.Hidden) if err != nil { log.Errorf("Error while updating data of image from %[1]s@%[2]s into the database: %[3]s", ifr.Username, ip, err) output(w, GenericResponse{ Success: false, Status: "database-error", StatusReadable: "An internal server error occurred while attempting to save image information to the database.", }, http.StatusInternalServerError) return } log.Debugf("%[1]s@%[2]s successfully uploaded an image with the name %[3]s (replaced).", ifr.Username, ip, ifr.ImageName) output(w, GenericResponse{ Success: true, Status: "replaced", StatusReadable: "The image was successfully saved with the name " + ifr.ImageName + ", replacing your previous image with the same name", ImageName: ifr.ImageName, }, 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) }