forked from tcp.direct/tcp.ac
wow. it works. delete keys now implemented, image functionalit appears to be ready for testing
This commit is contained in:
parent
3e54b47a98
commit
6bfc79cc6f
129
img.go
129
img.go
@ -3,19 +3,22 @@ package main
|
|||||||
import(
|
import(
|
||||||
valid "github.com/asaskevich/govalidator"
|
valid "github.com/asaskevich/govalidator"
|
||||||
exifremove "github.com/scottleedavis/go-exif-remove"
|
exifremove "github.com/scottleedavis/go-exif-remove"
|
||||||
|
"golang.org/x/crypto/blake2b"
|
||||||
"github.com/twharmon/gouid"
|
"github.com/twharmon/gouid"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
_ "image/gif"
|
_ "image/gif"
|
||||||
"crypto/md5"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"image"
|
"image"
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var fExt string
|
||||||
|
|
||||||
type Post struct {
|
type Post struct {
|
||||||
Imgurl string `json:"Imgurl"`
|
Imgurl string `json:"Imgurl"`
|
||||||
Delkey string `json:"Delkey"`
|
Delkey string `json:"Delkey"`
|
||||||
@ -23,13 +26,15 @@ type Post struct {
|
|||||||
|
|
||||||
func postUpload(c *gin.Context, id string, key string) {
|
func postUpload(c *gin.Context, id string, key string) {
|
||||||
imgurl := baseUrl + "i/" + string(id)
|
imgurl := baseUrl + "i/" + string(id)
|
||||||
keyurl := baseUrl + "i/d/" + string(key)
|
keyurl := "image_is_duplicate"
|
||||||
|
if key != "nil" { keyurl = baseUrl + "d/i/" + string(key) }
|
||||||
|
|
||||||
d := Post{
|
d := Post{
|
||||||
Imgurl: imgurl,
|
Imgurl: imgurl,
|
||||||
Delkey: keyurl,
|
Delkey: keyurl,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var p []byte
|
var p []byte
|
||||||
p, err := json.Marshal(d)
|
p, err := json.Marshal(d)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -37,15 +42,81 @@ func postUpload(c *gin.Context, id string, key string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(200, string(p)) // they weren't the original uploader so they don't get a delete key
|
fmt.Println("[imgPost]["+id+"] Success: " + imgurl + " " + keyurl)
|
||||||
|
c.JSON(200, string(p))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func imgView(c *gin.Context) {
|
func imgDel(c *gin.Context) {
|
||||||
rUid := c.Param("uid")
|
fmt.Println("[imgDel] Received request")
|
||||||
fmt.Println("[imgView] Received request")
|
rKey := c.Param("key")
|
||||||
if (valid.IsAlphanumeric(rUid)) {
|
if (len(rKey) != 16 || !valid.IsAlphanumeric(rKey)) {
|
||||||
fmt.Println("[imgView][" + rUid + "] Request validated")
|
fmt.Println("[imgDel] delete request failed sanity check")
|
||||||
|
errThrow(c, 400, "400", "Bad request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
targetImg, _ := keyDB.Get([]byte(rKey))
|
||||||
|
if (targetImg == nil || !strings.Contains(string(targetImg), "i.")) {
|
||||||
|
fmt.Println("[imgDel] no img delete entry found with key: " + rKey)
|
||||||
|
errThrow(c, 400, "400", "Bad request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
finalTarget := strings.Split(string(targetImg), ".")
|
||||||
|
|
||||||
|
if !imgDB.Has([]byte(finalTarget[1])) {
|
||||||
|
fmt.Println("[imgDel]["+finalTarget[1]+"] corresponding image not found in database??")
|
||||||
|
errThrow(c, 500, "500", "Internal error") // this shouldn't happen...?
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err := imgDB.Delete([]byte(finalTarget[1]))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("[imgDel]["+finalTarget[1]+"] Delete failed!!")
|
||||||
|
errThrow(c, 500, err.Error(), "Internal error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if imgDB.Has([]byte(finalTarget[1])) {
|
||||||
|
fmt.Println("[imgDel]["+finalTarget[1]+"] Delete failed!?")
|
||||||
|
errThrow(c, 500, err.Error(), "Internal error")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("[imgDel]["+finalTarget[1]+"] Image file deleted successfully")
|
||||||
|
fmt.Println("[imgDel]["+finalTarget[1]+"] Removing delete key entry")
|
||||||
|
err = keyDB.Delete([]byte(rKey))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("[imgDel]["+finalTarget[1]+"] Couldn't delete key") // it would be insane to try and delete the hash here
|
||||||
|
} // if someone is uploading this image again after del
|
||||||
|
c.JSON(200, "OK") // and the file corresponding to the hash no longer exists
|
||||||
|
// we will delete the hash entry then and re-add then
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func imgView(c *gin.Context) { // the user can access their image with or without a file extension in URI
|
||||||
|
fmt.Println("[imgView] Received request") // however it must be a valid extension (more checks further down)
|
||||||
|
sUid := strings.Split(c.Param("uid"), ".")
|
||||||
|
rUid := sUid[0]
|
||||||
|
if len(sUid) > 1 {
|
||||||
|
fExt = strings.ToLower(sUid[1])
|
||||||
|
fmt.Println("[imgView] Detected file extension: " + fExt)
|
||||||
|
if (fExt != "png" && fExt != "jpg" && fExt != "jpeg" && fExt != "gif") {
|
||||||
|
fmt.Println("[imgView] Bad file extension!")
|
||||||
|
errThrow(c, 400, "400", "Bad request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else { fExt = "nil" }
|
||||||
|
|
||||||
|
|
||||||
|
if (!valid.IsAlphanumeric(rUid) || len(rUid) < 3 || len(rUid) > 16) {
|
||||||
|
fmt.Println("[imgView] request discarded as invalid") // these limits should be variables eventually
|
||||||
|
errThrow(c,400,"400", "Bad request")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("[imgView][" + rUid + "] Request validated") // now that we think its a valid request we will query
|
||||||
|
|
||||||
fBytes, _ := imgDB.Get([]byte(rUid))
|
fBytes, _ := imgDB.Get([]byte(rUid))
|
||||||
if fBytes == nil {
|
if fBytes == nil {
|
||||||
fmt.Println("[imgView] No data found for: " + rUid)
|
fmt.Println("[imgView] No data found for: " + rUid)
|
||||||
@ -53,18 +124,24 @@ func imgView(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("[imgView][" + rUid + "] Detecting image type")
|
fmt.Println("[imgView][" + rUid + "] Detecting image type") // not sure how a non image would get uploaded
|
||||||
file := bytes.NewReader(fBytes)
|
file := bytes.NewReader(fBytes) // however, better safe than sorry
|
||||||
imageFormat, ok := checkImage(file)
|
imageFormat, ok := checkImage(file)
|
||||||
if !ok {
|
if !ok {
|
||||||
errThrow(c, http.StatusBadRequest, "bad request", "content does not appear to be an image")
|
errThrow(c, http.StatusBadRequest, "bad request", "content does not appear to be an image")
|
||||||
return
|
return
|
||||||
} else { fmt.Println("[imgView][" + rUid + "] " + imageFormat + " detected") }
|
} else { fmt.Println("[imgView][" + rUid + "] " + imageFormat + " detected") }
|
||||||
|
|
||||||
contentType := "image/" + imageFormat
|
if (fExt != "nil" && fExt != imageFormat) { // additional extension sanity check
|
||||||
|
fmt.Println("[imgView][" + rUid + "] given file extension does not match filetype " + imageFormat)
|
||||||
c.Data(200, contentType, fBytes)
|
errThrow(c,400,"400", "Bad request")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
contentType := "image/" + imageFormat // extension or not
|
||||||
|
// we give them the proper content type
|
||||||
|
c.Data(200, contentType, fBytes)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -104,25 +181,31 @@ func imgPost(c *gin.Context) {
|
|||||||
Scrubbed = fbytes
|
Scrubbed = fbytes
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("[imgPost] calculating MD5 hash")
|
fmt.Println("[imgPost] calculating blake2b checksum")
|
||||||
|
|
||||||
Hashr := md5.New()
|
Hashr, _ := blake2b.New(64,nil)
|
||||||
Hashr.Write(Scrubbed)
|
Hashr.Write(Scrubbed)
|
||||||
hash := Hashr.Sum(nil)
|
hash := Hashr.Sum(nil)
|
||||||
|
|
||||||
fmt.Println("[imgPost] Checking for duplicate's in database")
|
fmt.Println("[imgPost] Checking for duplicate's in database")
|
||||||
|
|
||||||
imgRef, _ := md5DB.Get(hash)
|
imgRef, _ := hashDB.Get(hash)
|
||||||
|
|
||||||
if imgRef != nil {
|
if imgRef != nil {
|
||||||
fmt.Println("[imgPost][" + string(imgRef) + "] duplicate file found in md5 database, returning URL for uid: " + string(imgRef))
|
fmt.Println("[imgPost][" + string(imgRef) + "] duplicate checksum in hash database, checking if file still exists...")
|
||||||
|
if imgDB.Has(imgRef) {
|
||||||
|
fmt.Println("[imgPost][" + string(imgRef) + "] duplicate file found! returning URL for uid: " + string(imgRef))
|
||||||
postUpload(c,string(imgRef),"nil") // they weren't the original uploader so they don't get a delete key
|
postUpload(c,string(imgRef),"nil") // they weren't the original uploader so they don't get a delete key
|
||||||
return
|
return
|
||||||
|
} else {
|
||||||
|
fmt.Println("[imgPost][" + string(imgRef) + "] stale hash found, deleting entry...")
|
||||||
|
hashDB.Delete(hash)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("[imgPost] no duplicate md5s found, generating uid and delete key")
|
fmt.Println("[imgPost] no duplicate images found, generating uid and delete key")
|
||||||
|
|
||||||
uid := gouid.String(5)
|
uid := gouid.String(5) // these should both be config directives eventually
|
||||||
key := gouid.String(16) // generate delete key
|
key := gouid.String(16) // generate delete key
|
||||||
|
|
||||||
|
|
||||||
@ -131,23 +214,23 @@ func imgPost(c *gin.Context) {
|
|||||||
fmt.Println("[imgPost] uid already exists! generating new...")
|
fmt.Println("[imgPost] uid already exists! generating new...")
|
||||||
uid = gouid.String(5)
|
uid = gouid.String(5)
|
||||||
}
|
}
|
||||||
for keyRef, _ := keyDB.Get([]byte(uid)); keyRef != nil; {
|
for keyRef, _ := keyDB.Get([]byte(key)); keyRef != nil; {
|
||||||
fmt.Println("[imgPost] delete key already exists! generating new...")
|
fmt.Println("[imgPost] delete key already exists! generating new...")
|
||||||
key = gouid.String(16)
|
key = gouid.String(16)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
md5DB.Put([]byte(hash),[]byte(uid)) // save md5 to db to prevent dupes in the future
|
hashDB.Put([]byte(hash),[]byte(uid)) // save checksum to db to prevent dupes in the future
|
||||||
|
|
||||||
fmt.Println("[imgPost][" + uid + "] saving file to database")
|
fmt.Println("[imgPost][" + uid + "] saving file to database")
|
||||||
|
|
||||||
err = imgDB.Put([]byte(uid), []byte(Scrubbed))
|
err = imgDB.Put([]byte(uid), []byte(Scrubbed))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errThrow(c, http.StatusInternalServerError, err.Error(), "upload failed")
|
errThrow(c, 500, err.Error(), "upload failed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = keyDB.Put([]byte("i." + uid), []byte(key)) // add delete key to database with image prefix
|
err = keyDB.Put([]byte(key), []byte("i." + uid)) // add delete key to database with image prefix
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errThrow(c, http.StatusInternalServerError, err.Error(), "internal error")
|
errThrow(c, http.StatusInternalServerError, err.Error(), "internal error")
|
||||||
return
|
return
|
||||||
|
@ -9,7 +9,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var imgDB *bitcask.Bitcask
|
var imgDB *bitcask.Bitcask
|
||||||
var md5DB *bitcask.Bitcask
|
var hashDB *bitcask.Bitcask
|
||||||
var keyDB *bitcask.Bitcask
|
var keyDB *bitcask.Bitcask
|
||||||
var urlDB *bitcask.Bitcask
|
var urlDB *bitcask.Bitcask
|
||||||
var txtDB *bitcask.Bitcask
|
var txtDB *bitcask.Bitcask
|
||||||
@ -65,7 +65,7 @@ func init() {
|
|||||||
imgDB, _ = bitcask.Open("./data/img", opts...)
|
imgDB, _ = bitcask.Open("./data/img", opts...)
|
||||||
fmt.Println("Initializing img database")
|
fmt.Println("Initializing img database")
|
||||||
|
|
||||||
md5DB, _ = bitcask.Open("./data/md5", opts...) // this will probably only be for images
|
hashDB, _ = bitcask.Open("./data/hsh", opts...) // this will probably only be for images
|
||||||
fmt.Println("Initializing md5 database")
|
fmt.Println("Initializing md5 database")
|
||||||
|
|
||||||
txtDB, _ = bitcask.Open("./data/txt")
|
txtDB, _ = bitcask.Open("./data/txt")
|
||||||
@ -89,6 +89,11 @@ func main() {
|
|||||||
imgR.GET("/:uid", imgView)
|
imgR.GET("/:uid", imgView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delR := router.Group("/d")
|
||||||
|
{
|
||||||
|
delR.GET("/i/:key", imgDel)
|
||||||
|
}
|
||||||
|
|
||||||
txtR := router.Group("/t")
|
txtR := router.Group("/t")
|
||||||
{
|
{
|
||||||
txtR.POST("/put", txtPost)
|
txtR.POST("/put", txtPost)
|
Loading…
Reference in New Issue
Block a user