package routes import ( "database/sql" "net/http" "strings" "owo.codes/whats-this/api/lib/apierrors" "owo.codes/whats-this/api/lib/db" "owo.codes/whats-this/api/lib/middleware" "owo.codes/whats-this/api/lib/ratelimiter" "github.com/go-chi/render" "github.com/pkg/errors" "github.com/rs/zerolog/log" "github.com/spf13/viper" ) // objectResponse is the response format for Object. type objectResponse struct { Success bool `json:"success"` Data db.Object `json:"data"` } // Object returns metadata about any object (even objects a user isn't // associated with). func Object(w http.ResponseWriter, r *http.Request) { // Only authorized users can use this route user := middleware.GetAuthorizedUser(r) if user.ID == "" || user.IsBlocked { panic(apierrors.Unauthorized) } // Apply ratelimits bucket := middleware.GetBucket(r) err := bucket.TakeWithHeaders(w, viper.GetInt64("ratelimiter.objectCost")) if err == ratelimiter.InsufficientTokens { panic(apierrors.InsufficientTokens) } if err != nil { panic(apierrors.InternalServerError) } // Get the key key := r.URL.Path if strings.HasPrefix(key, "/objects/") { key = key[9:] } // Get the object object, err := db.GetObject(viper.GetString("database.objectBucket"), key) switch { case errors.Cause(err) == sql.ErrNoRows: panic(apierrors.NoObjectFound) case err != nil: log.Error().Err(err).Msg("failed to get object") panic(apierrors.InternalServerError) } if object.Type == 2 { // tombstone object.MD5HashBytes = nil object.SHA256HashBytes = nil object.MD5Hash = nil object.SHA256Hash = nil object.AssociatedUser = nil } associatedWithCurrentUser := false if object.AssociatedUser != nil && *object.AssociatedUser == user.ID { associatedWithCurrentUser = true } object.AssociatedWithCurrentUser = &associatedWithCurrentUser // Return response w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) render.JSON(w, r, objectResponse{true, object}) }