forked from tcp.direct/tcp.ac
implement termbin functionality
This commit is contained in:
parent
d79575721a
commit
022073c9a7
65
config.go
65
config.go
@ -2,12 +2,42 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/prologic/bitcask"
|
||||||
"github.com/rs/zerolog"
|
"github.com/rs/zerolog"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
////////////// global declarations
|
||||||
|
var (
|
||||||
|
// datastores
|
||||||
|
imgDB *bitcask.Bitcask
|
||||||
|
hashDB *bitcask.Bitcask
|
||||||
|
keyDB *bitcask.Bitcask
|
||||||
|
urlDB *bitcask.Bitcask
|
||||||
|
txtDB *bitcask.Bitcask
|
||||||
|
|
||||||
|
// config directives
|
||||||
|
debugBool bool
|
||||||
|
baseUrl string
|
||||||
|
webPort string
|
||||||
|
webIP string
|
||||||
|
dbDir string
|
||||||
|
logDir string
|
||||||
|
uidSize int
|
||||||
|
keySize int
|
||||||
|
txtPort string
|
||||||
|
|
||||||
|
// utilitarian globals
|
||||||
|
err error
|
||||||
|
fn string
|
||||||
|
s string
|
||||||
|
i int
|
||||||
|
f *os.File
|
||||||
|
)
|
||||||
|
|
||||||
func configRead() {
|
func configRead() {
|
||||||
// name of the file
|
// name of the file
|
||||||
// and the extension
|
// and the extension
|
||||||
@ -34,34 +64,17 @@ func configRead() {
|
|||||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// base URL of site
|
baseUrl = viper.GetString("http.baseurl")
|
||||||
s = "http.baseurl"
|
|
||||||
baseUrl = viper.GetString(s)
|
|
||||||
|
|
||||||
// bind port
|
i := viper.GetInt("http.port")
|
||||||
s = "http.port"
|
webPort = strconv.Itoa(i)
|
||||||
i := viper.GetInt(s)
|
|
||||||
webPort = strconv.Itoa(i) // int looks cleaner in config
|
|
||||||
|
|
||||||
// bind IP
|
webIP = viper.GetString("http.bindip")
|
||||||
s = "http.bindip"
|
dbDir = viper.GetString("files.data")
|
||||||
webIP = viper.GetString(s)
|
logDir = viper.GetString("files.logs")
|
||||||
|
uidSize = viper.GetInt("global.uidsize")
|
||||||
// database location (main storage)
|
keySize = viper.GetInt("global.delkeysize")
|
||||||
s = "files.data"
|
txtPort = viper.GetString("txt.port")
|
||||||
dbDir = viper.GetString(s)
|
|
||||||
|
|
||||||
// logfile location
|
|
||||||
s = "files.logs"
|
|
||||||
logDir = viper.GetString(s)
|
|
||||||
|
|
||||||
// character count of unique IDs for posts
|
|
||||||
s = "img.uidsize"
|
|
||||||
uidSize = viper.GetInt(s)
|
|
||||||
|
|
||||||
// size of generated unique delete keys
|
|
||||||
s = "img.delkeysize"
|
|
||||||
keySize = viper.GetInt(s)
|
|
||||||
|
|
||||||
log.Debug().Str("baseUrl", baseUrl).Str("webIP", webIP).Str("webPort", webPort).Msg("Web")
|
log.Debug().Str("baseUrl", baseUrl).Str("webIP", webIP).Str("webPort", webPort).Msg("Web")
|
||||||
log.Debug().Str("logDir", logDir).Str("dbDir", dbDir).Msg("Filesystem")
|
log.Debug().Str("logDir", logDir).Str("dbDir", dbDir).Msg("Filesystem")
|
||||||
|
17
config.toml
17
config.toml
@ -1,16 +1,19 @@
|
|||||||
title = "tcp.ac config"
|
title = "tcp.ac config"
|
||||||
|
|
||||||
[global]
|
[global]
|
||||||
debug = false
|
debug = true
|
||||||
|
uidsize = 5
|
||||||
|
delkeysize = 12
|
||||||
|
|
||||||
[http]
|
[http]
|
||||||
baseurl = "http://192.168.69.1/"
|
baseurl = "http://127.0.0.1:8080/"
|
||||||
bindip = "192.168.69.1"
|
basehost = "127.0.0.1"
|
||||||
port = 80
|
bindip = "127.0.0.1"
|
||||||
|
port = 8080
|
||||||
|
|
||||||
[img]
|
[txt]
|
||||||
uidsize = 4
|
# string: port to listen on for termbin clone
|
||||||
delkeysize = 12
|
port = "9999"
|
||||||
|
|
||||||
[files]
|
[files]
|
||||||
data = "/etc/tcpac/data/"
|
data = "/etc/tcpac/data/"
|
||||||
|
29
globals.go
29
globals.go
@ -1,29 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import "github.com/prologic/bitcask"
|
|
||||||
import "os"
|
|
||||||
|
|
||||||
////////////// global declarations
|
|
||||||
// datastores
|
|
||||||
var imgDB *bitcask.Bitcask
|
|
||||||
var hashDB *bitcask.Bitcask
|
|
||||||
var keyDB *bitcask.Bitcask
|
|
||||||
var urlDB *bitcask.Bitcask
|
|
||||||
var txtDB *bitcask.Bitcask
|
|
||||||
|
|
||||||
// config directives
|
|
||||||
var debugBool bool
|
|
||||||
var baseUrl string
|
|
||||||
var webPort string
|
|
||||||
var webIP string
|
|
||||||
var dbDir string
|
|
||||||
var logDir string
|
|
||||||
var uidSize int
|
|
||||||
var keySize int
|
|
||||||
|
|
||||||
// utilitarian globals
|
|
||||||
var err error
|
|
||||||
var fn string
|
|
||||||
var s string
|
|
||||||
var i int
|
|
||||||
var f *os.File
|
|
112
img.go
112
img.go
@ -18,46 +18,21 @@ import (
|
|||||||
|
|
||||||
var fExt string
|
var fExt string
|
||||||
|
|
||||||
type Post struct {
|
|
||||||
Type string
|
|
||||||
Uid string
|
|
||||||
Key string
|
|
||||||
Priv bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Post) Serve(c *gin.Context) {
|
|
||||||
url := baseUrl + p.Type + "/" + string(p.Uid)
|
|
||||||
priv := "no"
|
|
||||||
keyurl := ""
|
|
||||||
if p.Key != "" {
|
|
||||||
keyurl = baseUrl + "d/" + p.Type + "/" + p.Key
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.Priv == true {
|
|
||||||
priv = "yes"
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info().Str("type", p.Type).Str("uid", p.Uid).Str("key", p.Key).Str("private", priv).Msg("success")
|
|
||||||
c.JSON(201, gin.H{"Imgurl": url, "ToDelete": keyurl})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func imgDel(c *gin.Context) {
|
func imgDel(c *gin.Context) {
|
||||||
fn = "imgDel"
|
slog := log.With().Str("caller", "imgView").Logger()
|
||||||
|
|
||||||
log.Debug().Str("func", fn).Msg("Request received!") // received request
|
slog.Debug().Msg("Request received!") // received request
|
||||||
rKey := c.Param("key")
|
rKey := c.Param("key")
|
||||||
|
|
||||||
// if it doesn't match the key size or it isn't alphanumeric - throw it out
|
if !validateKey(rKey) {
|
||||||
if len(rKey) != keySize || !valid.IsAlphanumeric(rKey) {
|
slog.Error().Msg("delete request failed sanity check!")
|
||||||
log.Error().Str("func", fn).Msg("delete request failed sanity check!")
|
|
||||||
errThrow(c, 400, "400", "400")
|
errThrow(c, 400, "400", "400")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
targetImg, _ := keyDB.Get([]byte(rKey))
|
targetImg, _ := keyDB.Get([]byte(rKey))
|
||||||
if targetImg == nil || !strings.Contains(string(targetImg), "i.") {
|
if targetImg == nil || !strings.Contains(string(targetImg), "i.") {
|
||||||
log.Error().Str("func", fn).Str("rkey", rKey).Msg("no img delete entry found with provided key")
|
slog.Error().Str("rkey", rKey).Msg("no img delete entry found with provided key")
|
||||||
errThrow(c, 400, "400", "400")
|
errThrow(c, 400, "400", "400")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -65,28 +40,28 @@ func imgDel(c *gin.Context) {
|
|||||||
finalTarget := strings.Split(string(targetImg), ".")
|
finalTarget := strings.Split(string(targetImg), ".")
|
||||||
|
|
||||||
if !imgDB.Has([]byte(finalTarget[1])) {
|
if !imgDB.Has([]byte(finalTarget[1])) {
|
||||||
log.Error().Str("func", fn).Str("rkey", rKey).Msg("corresponding image not found in database!")
|
slog.Error().Str("rkey", rKey).Msg("corresponding image not found in database!")
|
||||||
errThrow(c, 500, "500", "500") // this shouldn't happen...?
|
errThrow(c, 500, "500", "500") // this shouldn't happen...?
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err := imgDB.Delete([]byte(finalTarget[1]))
|
err := imgDB.Delete([]byte(finalTarget[1]))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Str("func", fn).Str("rkey", finalTarget[1]).Msg("delete failed!")
|
slog.Error().Str("rkey", finalTarget[1]).Msg("delete failed!")
|
||||||
errThrow(c, 500, "500", "500")
|
errThrow(c, 500, "500", "500")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if imgDB.Has([]byte(finalTarget[1])) {
|
if imgDB.Has([]byte(finalTarget[1])) {
|
||||||
log.Error().Str("func", fn).Str("rkey", finalTarget[1]).Msg("delete failed!?")
|
slog.Error().Str("rkey", finalTarget[1]).Msg("delete failed!?")
|
||||||
errThrow(c, 500, "500", "500")
|
errThrow(c, 500, "500", "500")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().Str("func", fn).Str("rkey", finalTarget[1]).Msg("Image file deleted successfully")
|
slog.Info().Str("rkey", finalTarget[1]).Msg("Image file deleted successfully")
|
||||||
log.Debug().Str("func", fn).Str("rkey", finalTarget[1]).Msg("Removing delete key entry")
|
slog.Debug().Str("rkey", finalTarget[1]).Msg("Removing delete key entry")
|
||||||
err = keyDB.Delete([]byte(rKey))
|
err = keyDB.Delete([]byte(rKey))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Str("func", fn).Str("rkey", finalTarget[1]).Msg("Couldn't delete key")
|
slog.Error().Str("rkey", finalTarget[1]).Msg("Couldn't delete key")
|
||||||
// it would be insane to try and delete the hash here
|
// it would be insane to try and delete the hash here
|
||||||
} // if someone is uploading this image again after del
|
} // if someone is uploading this image again after del
|
||||||
c.JSON(200, "DELETE_SUCCESS") // and the file corresponding to the hash no longer exists
|
c.JSON(200, "DELETE_SUCCESS") // and the file corresponding to the hash no longer exists
|
||||||
@ -94,18 +69,18 @@ func imgDel(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func imgView(c *gin.Context) {
|
func imgView(c *gin.Context) {
|
||||||
fn = "imgView"
|
slog := log.With().Str("caller", "imgView").Logger()
|
||||||
|
|
||||||
// the user can access their image with or without a file extension in URI
|
// the user can access their image with or without a file extension in URI
|
||||||
log.Debug().Str("func", fn).Msg("request received") // however it must be a valid extension (more checks further down)
|
slog.Debug().Msg("request received") // however it must be a valid extension (more checks further down)
|
||||||
sUid := strings.Split(c.Param("uid"), ".")
|
sUid := strings.Split(c.Param("uid"), ".")
|
||||||
rUid := sUid[0]
|
rUid := sUid[0]
|
||||||
|
|
||||||
if len(sUid) > 1 {
|
if len(sUid) > 1 {
|
||||||
fExt = strings.ToLower(sUid[1])
|
fExt = strings.ToLower(sUid[1])
|
||||||
log.Debug().Str("func", fn).Str("ext", fExt).Msg("detected file extension")
|
slog.Debug().Str("ext", fExt).Msg("detected file extension")
|
||||||
if fExt != "png" && fExt != "jpg" && fExt != "jpeg" && fExt != "gif" {
|
if fExt != "png" && fExt != "jpg" && fExt != "jpeg" && fExt != "gif" {
|
||||||
log.Error().Str("func", fn).Msg("Bad file extension!")
|
slog.Error().Msg("Bad file extension!")
|
||||||
errThrow(c, 400, "400", "400")
|
errThrow(c, 400, "400", "400")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -115,18 +90,18 @@ func imgView(c *gin.Context) {
|
|||||||
|
|
||||||
// if it doesn't match the key size or it isn't alphanumeric - throw it out
|
// if it doesn't match the key size or it isn't alphanumeric - throw it out
|
||||||
if !valid.IsAlphanumeric(rUid) || len(rUid) != uidSize {
|
if !valid.IsAlphanumeric(rUid) || len(rUid) != uidSize {
|
||||||
log.Error().Str("func", fn).Msg("request discarded as invalid") // these limits should be variables eventually
|
slog.Error().Msg("request discarded as invalid") // these limits should be variables eventually
|
||||||
errThrow(c, 400, "400", "400")
|
errThrow(c, 400, "400", "400")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// now that we think its a valid request we will query
|
// now that we think its a valid request we will query
|
||||||
log.Debug().Str("func", fn).Str("rUid", rUid).Msg("request validated")
|
slog.Debug().Str("rUid", rUid).Msg("request validated")
|
||||||
|
|
||||||
// query bitcask for the id
|
// query bitcask for the id
|
||||||
fBytes, _ := imgDB.Get([]byte(rUid))
|
fBytes, _ := imgDB.Get([]byte(rUid))
|
||||||
if fBytes == nil {
|
if fBytes == nil {
|
||||||
log.Error().Str("func", fn).Str("rUid", rUid).Msg("no corresponding file for this id")
|
slog.Error().Str("rUid", rUid).Msg("no corresponding file for this id")
|
||||||
errThrow(c, 404, "404", "File not found")
|
errThrow(c, 404, "404", "File not found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -137,16 +112,16 @@ func imgView(c *gin.Context) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
// extra sanity check to make sure we don't serve non-image data that somehow got into the database
|
// extra sanity check to make sure we don't serve non-image data that somehow got into the database
|
||||||
errThrow(c, http.StatusBadRequest, "400", "400")
|
errThrow(c, http.StatusBadRequest, "400", "400")
|
||||||
log.Error().Str("func", fn).Str("rUid", rUid).Msg("the file we grabbed is not an image!?")
|
slog.Error().Str("rUid", rUid).Msg("the file we grabbed is not an image!?")
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
// seems like its an image, we will proceed
|
// seems like its an image, we will proceed
|
||||||
log.Debug().Str("func", fn).Str("rUid", rUid).Str("imageFormat", imageFormat).Msg("Image format detected")
|
slog.Debug().Str("rUid", rUid).Str("imageFormat", imageFormat).Msg("Image format detected")
|
||||||
}
|
}
|
||||||
|
|
||||||
// additional extension sanity check - if they're gonna use an extension it needs to be the right one
|
// additional extension sanity check - if they're gonna use an extension it needs to be the right one
|
||||||
if fExt != "nil" && fExt != imageFormat {
|
if fExt != "nil" && fExt != imageFormat {
|
||||||
log.Error().Str("func", fn).Str("rUid", rUid).Msg("requested file extension does not match filetype")
|
slog.Error().Str("rUid", rUid).Msg("requested file extension does not match filetype")
|
||||||
errThrow(c, 400, "400", "400")
|
errThrow(c, 400, "400", "400")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -156,14 +131,16 @@ func imgView(c *gin.Context) {
|
|||||||
contentType := "image/" + imageFormat
|
contentType := "image/" + imageFormat
|
||||||
c.Data(200, contentType, fBytes)
|
c.Data(200, contentType, fBytes)
|
||||||
|
|
||||||
log.Info().Str("func", fn).Str("rUid", rUid).Msg("Successful upload")
|
slog.Info().Str("rUid", rUid).Msg("Successful upload")
|
||||||
}
|
}
|
||||||
|
|
||||||
func imgPost(c *gin.Context) {
|
func imgPost(c *gin.Context) {
|
||||||
fn = "imgPost"
|
slog := log.With().Str("caller", "imgPost").Logger()
|
||||||
var Scrubbed []byte
|
var (
|
||||||
var priv bool = false
|
Scrubbed []byte
|
||||||
var key string = ""
|
priv bool = false
|
||||||
|
key string = ""
|
||||||
|
)
|
||||||
|
|
||||||
// check if incoming POST data is invalid
|
// check if incoming POST data is invalid
|
||||||
f, err := c.FormFile("upload")
|
f, err := c.FormFile("upload")
|
||||||
@ -171,7 +148,7 @@ func imgPost(c *gin.Context) {
|
|||||||
errThrow(c, http.StatusBadRequest, err.Error(), "400")
|
errThrow(c, http.StatusBadRequest, err.Error(), "400")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug().Str("func", fn).Str("filename", f.Filename).Msg("[+] New upload")
|
slog.Debug().Str("filename", f.Filename).Msg("[+] New upload")
|
||||||
|
|
||||||
// read the incoming file into an io file reader
|
// read the incoming file into an io file reader
|
||||||
file, err := f.Open()
|
file, err := f.Open()
|
||||||
@ -180,38 +157,38 @@ func imgPost(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// verify the incoming file is an image
|
// verify the incoming file is an image
|
||||||
log.Debug().Str("func", fn).Msg("verifying file is an image")
|
slog.Debug().Msg("verifying file is an image")
|
||||||
imageFormat, ok := checkImage(file)
|
imageFormat, ok := checkImage(file)
|
||||||
if !ok {
|
if !ok {
|
||||||
errThrow(c, http.StatusBadRequest, "400", "input does not appear to be an image")
|
errThrow(c, http.StatusBadRequest, "400", "input does not appear to be an image")
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
log.Debug().Str("func", fn).Msg("image file type detected")
|
slog.Debug().Msg("image file type detected")
|
||||||
}
|
}
|
||||||
|
|
||||||
// dump this into a byte object and scrub it
|
// dump this into a byte object and scrub it
|
||||||
// TO-DO: Write our own function for scrubbing exif
|
// TO-DO: Write our own function for scrubbing exif
|
||||||
log.Debug().Str("func", fn).Msg("dumping byte form of file")
|
slog.Debug().Msg("dumping byte form of file")
|
||||||
fbytes, err := ioutil.ReadAll(file)
|
fbytes, err := ioutil.ReadAll(file)
|
||||||
if imageFormat != "gif" {
|
if imageFormat != "gif" {
|
||||||
log.Debug().Str("func", fn).Err(err).Msg("error scrubbing exif")
|
slog.Debug().Err(err).Msg("error scrubbing exif")
|
||||||
Scrubbed, err = exifremove.Remove(fbytes)
|
Scrubbed, err = exifremove.Remove(fbytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errThrow(c, http.StatusInternalServerError, err.Error(), "error scrubbing exif")
|
errThrow(c, http.StatusInternalServerError, err.Error(), "error scrubbing exif")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Debug().Str("func", fn).Msg("skipping exif scrub for gif image")
|
slog.Debug().Msg("skipping exif scrub for gif image")
|
||||||
Scrubbed = fbytes
|
Scrubbed = fbytes
|
||||||
}
|
}
|
||||||
|
|
||||||
// time to start checking for duplicates
|
// time to start checking for duplicates
|
||||||
log.Debug().Str("func", fn).Msg("calculating blake2b checksum")
|
slog.Debug().Msg("calculating blake2b checksum")
|
||||||
Hashr, _ := blake2b.New(64, nil)
|
Hashr, _ := blake2b.New(64, nil)
|
||||||
Hashr.Write(Scrubbed)
|
Hashr.Write(Scrubbed)
|
||||||
hash := Hashr.Sum(nil)
|
hash := Hashr.Sum(nil)
|
||||||
|
|
||||||
log.Debug().Str("func", fn).Msg("checking for duplicate files")
|
slog.Debug().Msg("checking for duplicate files")
|
||||||
|
|
||||||
// the keys (stored in memory) for hashDb are hashes
|
// the keys (stored in memory) for hashDb are hashes
|
||||||
// making it quick to find duplicates. the value is the uid
|
// making it quick to find duplicates. the value is the uid
|
||||||
@ -220,9 +197,9 @@ func imgPost(c *gin.Context) {
|
|||||||
|
|
||||||
// if we get a hit we redirect them to the original image file with no delete key
|
// if we get a hit we redirect them to the original image file with no delete key
|
||||||
if imgRef != nil {
|
if imgRef != nil {
|
||||||
log.Debug().Str("func", fn).Str("ogUid", ogUid).Msg("duplicate checksum in hash database, checking if file still exists...")
|
slog.Debug().Str("ogUid", ogUid).Msg("duplicate checksum in hash database, checking if file still exists...")
|
||||||
if imgDB.Has(imgRef) {
|
if imgDB.Has(imgRef) {
|
||||||
log.Debug().Str("func", fn).Str("ogUid", ogUid).Msg("duplicate file found! returning original URL")
|
slog.Debug().Str("ogUid", ogUid).Msg("duplicate file found! returning original URL")
|
||||||
|
|
||||||
post := &Post{
|
post := &Post{
|
||||||
Type: "i",
|
Type: "i",
|
||||||
@ -235,12 +212,12 @@ func imgPost(c *gin.Context) {
|
|||||||
|
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
log.Debug().Str("func", fn).Str("ogUid", ogUid).Msg("stale hash found, deleting entry...")
|
slog.Debug().Str("ogUid", ogUid).Msg("stale hash found, deleting entry...")
|
||||||
hashDB.Delete(hash)
|
hashDB.Delete(hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().Str("func", fn).Msg("no duplicate images found, generating uid and delete key")
|
slog.Info().Msg("no duplicate images found, generating uid and delete key")
|
||||||
|
|
||||||
// generate new uid and delete key
|
// generate new uid and delete key
|
||||||
uid := gouid.String(uidSize, gouid.MixedCaseAlphaNum)
|
uid := gouid.String(uidSize, gouid.MixedCaseAlphaNum)
|
||||||
@ -248,11 +225,11 @@ func imgPost(c *gin.Context) {
|
|||||||
|
|
||||||
// lets make sure that we don't clash even though its highly unlikely
|
// lets make sure that we don't clash even though its highly unlikely
|
||||||
for uidRef, _ := imgDB.Get([]byte(uid)); uidRef != nil; {
|
for uidRef, _ := imgDB.Get([]byte(uid)); uidRef != nil; {
|
||||||
log.Info().Str("func", fn).Msg(" uid already exists! generating new...")
|
slog.Info().Msg(" uid already exists! generating new...")
|
||||||
uid = gouid.String(uidSize, gouid.MixedCaseAlphaNum)
|
uid = gouid.String(uidSize, gouid.MixedCaseAlphaNum)
|
||||||
}
|
}
|
||||||
for keyRef, _ := keyDB.Get([]byte(key)); keyRef != nil; {
|
for keyRef, _ := keyDB.Get([]byte(key)); keyRef != nil; {
|
||||||
log.Info().Str("func", fn).Msg(" delete key already exists! generating new...")
|
slog.Info().Msg(" delete key already exists! generating new...")
|
||||||
key = gouid.String(keySize, gouid.MixedCaseAlphaNum)
|
key = gouid.String(keySize, gouid.MixedCaseAlphaNum)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +237,7 @@ func imgPost(c *gin.Context) {
|
|||||||
hashDB.Put([]byte(hash), []byte(uid))
|
hashDB.Put([]byte(hash), []byte(uid))
|
||||||
|
|
||||||
// insert actual file to database
|
// insert actual file to database
|
||||||
log.Debug().Str("func", fn).Str("uid", uid).Msg("saving file to database")
|
slog.Debug().Str("uid", uid).Msg("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, 500, err.Error(), "upload failed")
|
errThrow(c, 500, err.Error(), "upload failed")
|
||||||
@ -276,7 +253,7 @@ func imgPost(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// good to go, send them to the finisher function
|
// good to go, send them to the finisher function
|
||||||
log.Debug().Str("func", fn).Str("uid", uid).Msg("saved to database successfully, sending to Serve")
|
slog.Debug().Str("uid", uid).Msg("saved to database successfully, sending to Serve")
|
||||||
|
|
||||||
post := &Post{
|
post := &Post{
|
||||||
Type: "i",
|
Type: "i",
|
||||||
@ -285,6 +262,7 @@ func imgPost(c *gin.Context) {
|
|||||||
Priv: priv,
|
Priv: priv,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
post.Serve(c)
|
post.Serve(c)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
1
main.go
1
main.go
@ -62,6 +62,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
go serveTermbin()
|
||||||
// see router.go
|
// see router.go
|
||||||
httpRouter()
|
httpRouter()
|
||||||
}
|
}
|
||||||
|
29
router.go
29
router.go
@ -3,7 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"github.com/gin-contrib/gzip"
|
"github.com/gin-contrib/gzip"
|
||||||
"github.com/gin-contrib/logger"
|
// "github.com/gin-contrib/logger"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
@ -41,7 +41,7 @@ func httpRouter() {
|
|||||||
|
|
||||||
router := gin.New()
|
router := gin.New()
|
||||||
|
|
||||||
router.Use(logger.SetLogger())
|
//router.Use(logger.SetLogger())
|
||||||
|
|
||||||
router.MaxMultipartMemory = 16 << 20 // crude POST limit (fix this)
|
router.MaxMultipartMemory = 16 << 20 // crude POST limit (fix this)
|
||||||
|
|
||||||
@ -57,26 +57,33 @@ func httpRouter() {
|
|||||||
|
|
||||||
imgR := router.Group("/i")
|
imgR := router.Group("/i")
|
||||||
{
|
{
|
||||||
imgR.GET("/", func(c *gin.Context) { c.String(200, "") })
|
imgR.GET("/", placeHolder)
|
||||||
// put looks nicer even though its actually POST
|
// put looks nicer even though its actually POST
|
||||||
imgR.POST("/put", imgPost)
|
imgR.POST("/put", imgPost)
|
||||||
imgR.GET("/:uid", imgView)
|
imgR.GET("/:uid", imgView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
txtR := router.Group("/t")
|
||||||
|
{
|
||||||
|
txtR.GET("/", placeHolder)
|
||||||
|
txtR.GET("/:uid", txtView)
|
||||||
|
}
|
||||||
|
|
||||||
delR := router.Group("/d")
|
delR := router.Group("/d")
|
||||||
{
|
{
|
||||||
delR.GET("/i/:key", imgDel)
|
delR.GET("/i/:key", imgDel)
|
||||||
|
delR.GET("/t/:key", txtDel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// txtR := router.Group("/t")
|
// txtR := router.Group("/t")
|
||||||
// {
|
// {
|
||||||
// txtR.POST("/put", txtPost)
|
// txtR.POST("/put", txtPost)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// urlR := router.Group("/u")
|
// urlR := router.Group("/u")
|
||||||
// {
|
// {
|
||||||
// urlR.POST("/put", urlPost)
|
// urlR.POST("/put", urlPost)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
log.Info().Str("webIP", webIP).Str("webPort", webPort).Msg("done; tcp.ac is live.")
|
log.Info().Str("webIP", webIP).Str("webPort", webPort).Msg("done; tcp.ac is live.")
|
||||||
router.Run(webIP + ":" + webPort)
|
router.Run(webIP + ":" + webPort)
|
||||||
|
@ -10,6 +10,8 @@ import (
|
|||||||
var (
|
var (
|
||||||
// Msg is a channel for status information during concurrent server operations
|
// Msg is a channel for status information during concurrent server operations
|
||||||
Msg chan Message
|
Msg chan Message
|
||||||
|
// Reply is a channel to receive messages to send our client upon completion
|
||||||
|
Reply chan Message
|
||||||
// Timeout is the read timeout for incoming data in seconds
|
// Timeout is the read timeout for incoming data in seconds
|
||||||
Timeout int = 4
|
Timeout int = 4
|
||||||
// Max size for incoming data (default: 3 << 30 or 3 MiB)
|
// Max size for incoming data (default: 3 << 30 or 3 MiB)
|
||||||
@ -31,6 +33,7 @@ type Message struct {
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Msg = make(chan Message)
|
Msg = make(chan Message)
|
||||||
|
Reply = make(chan Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
func termStatus(m Message) {
|
func termStatus(m Message) {
|
||||||
@ -113,6 +116,13 @@ func serve(c net.Conn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
termStatus(Message{Type: "FINAL", RAddr: c.RemoteAddr().String(), Size: len(final), Bytes: final, Content: "SUCCESS"})
|
termStatus(Message{Type: "FINAL", RAddr: c.RemoteAddr().String(), Size: len(final), Bytes: final, Content: "SUCCESS"})
|
||||||
|
url := <- Reply
|
||||||
|
switch url.Type {
|
||||||
|
case "URL":
|
||||||
|
c.Write([]byte(url.Content))
|
||||||
|
case "ERROR":
|
||||||
|
c.Write([]byte("ERROR: " + url.Content))
|
||||||
|
}
|
||||||
c.Close()
|
c.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,11 +10,11 @@ var (
|
|||||||
// Users contains all remote addresses currently being ratelimited
|
// Users contains all remote addresses currently being ratelimited
|
||||||
Users *cache.Cache
|
Users *cache.Cache
|
||||||
// Rate is the amount of seconds between each post from an IP address
|
// Rate is the amount of seconds between each post from an IP address
|
||||||
Rate time.Duration = 30
|
Rate time.Duration = 8
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Users = cache.New(Rate*time.Second, 30*time.Second)
|
Users = cache.New(Rate*time.Second, 10*time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
func isThrottled(addr string) bool {
|
func isThrottled(addr string) bool {
|
||||||
|
346
txt.go
346
txt.go
@ -3,226 +3,252 @@ package main
|
|||||||
import (
|
import (
|
||||||
valid "github.com/asaskevich/govalidator"
|
valid "github.com/asaskevich/govalidator"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
cache "github.com/patrickmn/go-cache"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/twharmon/gouid"
|
"github.com/twharmon/gouid"
|
||||||
"golang.org/x/crypto/blake2b"
|
"golang.org/x/crypto/blake2b"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
"tcp.ac/termbin"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var hash []byte
|
var (
|
||||||
var uid string
|
Users *cache.Cache
|
||||||
var key string
|
)
|
||||||
|
|
||||||
func txtFin(c *gin.Context, id string, key string) {
|
func init() {
|
||||||
txturl := baseUrl + "t/" + string(id)
|
termbin.UseChannel = true
|
||||||
keyurl := "duplicate"
|
Users = cache.New(termbin.Rate*time.Second, 30*time.Second)
|
||||||
if key != "nil" {
|
|
||||||
keyurl = baseUrl + "d/t/" + string(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info().Str("func", "txtPost").Str("id", id).Str("status", "201").Str("txturl", txturl).Str("keyurl", keyurl).Msg("success")
|
|
||||||
c.JSON(201, gin.H{"delkey": keyurl, "txturl": txturl})
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func txtDel(c *gin.Context) {
|
func txtThrottled(addr string) bool {
|
||||||
fn = "txtDel"
|
if _, ok := Users.Get(addr); !ok {
|
||||||
|
Users.Set(addr, 1, 0)
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// make sure its the proper amount of characters and is alphanumeric
|
func incoming() {
|
||||||
log.Info().Str("func", fn).Msg("delete request received")
|
var msg termbin.Message
|
||||||
rKey := c.Param("key")
|
|
||||||
|
|
||||||
if len(rKey) != keySize || !valid.IsAlphanumeric(rKey) {
|
select {
|
||||||
log.Error().Err(err).Str("func", fn).Msg("delete request failed sanity check!")
|
case msg = <-termbin.Msg:
|
||||||
errThrow(c, 400, "400", "400")
|
switch msg.Type {
|
||||||
return
|
case "ERROR":
|
||||||
|
log.Error().
|
||||||
|
Str("RemoteAddr", msg.RAddr).
|
||||||
|
Int("Size", msg.Size).
|
||||||
|
Msg(msg.Content)
|
||||||
|
case "INCOMING_DATA":
|
||||||
|
log.Debug().
|
||||||
|
Str("RemoteAddr", msg.RAddr).
|
||||||
|
Int("Size", msg.Size).
|
||||||
|
Msg("termbin_data")
|
||||||
|
case "FINISH":
|
||||||
|
log.Debug().
|
||||||
|
Str("RemoteAddr", msg.RAddr).
|
||||||
|
Int("Size", msg.Size).
|
||||||
|
Msg(msg.Content)
|
||||||
|
|
||||||
|
case "DEBUG":
|
||||||
|
log.Debug().
|
||||||
|
Str("RemoteAddr", msg.RAddr).
|
||||||
|
Int("Size", msg.Size).
|
||||||
|
Msg(msg.Content)
|
||||||
|
|
||||||
|
case "FINAL":
|
||||||
|
log.Info().
|
||||||
|
Str("RemoteAddr", msg.RAddr).
|
||||||
|
Int("Size", msg.Size).
|
||||||
|
Msg(msg.Content)
|
||||||
|
|
||||||
|
termPost(msg.Bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func termPost(b []byte) {
|
||||||
|
slog := log.With().Str("caller", "termPost").Logger()
|
||||||
|
Hashr, _ := blake2b.New(64, nil)
|
||||||
|
Hashr.Write(b)
|
||||||
|
hash := Hashr.Sum(nil)
|
||||||
|
if ogTxt, _ := hashDB.Get(hash); ogTxt != nil {
|
||||||
|
if txtDB.Has(ogTxt) {
|
||||||
|
slog.Debug().Str("ogUid", string(ogTxt)).Msg("duplicate file found! returning original URL")
|
||||||
|
post := &Post{
|
||||||
|
Type: "t",
|
||||||
|
Uid: string(ogTxt),
|
||||||
|
Key: "",
|
||||||
|
Priv: false,
|
||||||
|
}
|
||||||
|
termbin.Reply <- termbin.Message{Type: "URL", Content: post.URLString()}
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// first we see if the key even exists, and if it does, is it a txt key (vs txt or url)
|
// generate new uid and delete key
|
||||||
targettxt, _ := keyDB.Get([]byte(rKey))
|
uid := gouid.String(uidSize, gouid.MixedCaseAlphaNum)
|
||||||
if targettxt == nil || !strings.Contains(string(targettxt), "t.") {
|
key := gouid.String(keySize, gouid.MixedCaseAlphaNum)
|
||||||
log.Error().Err(err).Str("func", fn).Str("rkey", rKey).Msg("no txt delete entry found with provided key")
|
|
||||||
errThrow(c, 400, "400", "400")
|
// lets make sure that we don't clash even though its highly unlikely
|
||||||
return
|
for uidRef, _ := txtDB.Get([]byte(uid)); uidRef != nil; {
|
||||||
|
slog.Info().Msg(" uid already exists! generating new...")
|
||||||
|
uid = gouid.String(uidSize, gouid.MixedCaseAlphaNum)
|
||||||
|
}
|
||||||
|
for keyRef, _ := keyDB.Get([]byte(key)); keyRef != nil; {
|
||||||
|
slog.Info().Msg(" delete key already exists! generating new...")
|
||||||
|
key = gouid.String(keySize, gouid.MixedCaseAlphaNum)
|
||||||
}
|
}
|
||||||
|
|
||||||
// seperate the key from the indicator to get the actual txt delete key
|
hashDB.Put([]byte(hash), []byte(uid))
|
||||||
finalTarget := strings.Split(string(targettxt), ".")
|
|
||||||
|
|
||||||
// somehow we have a key that doesn't correspond with with an actual entry
|
uid = gouid.String(uidSize, gouid.MixedCaseAlphaNum)
|
||||||
if !txtDB.Has([]byte(finalTarget[1])) {
|
key = gouid.String(keySize, gouid.MixedCaseAlphaNum)
|
||||||
log.Error().Err(err).Str("func", fn).Str("rkey", rKey).Msg("corresponding text entry not found in database!")
|
|
||||||
errThrow(c, 500, "500", "500")
|
for uidRef, _ := txtDB.Get([]byte(uid)); uidRef != nil; {
|
||||||
return
|
slog.Info().Msg(" uid already exists! generating new...")
|
||||||
|
uid = gouid.String(uidSize, gouid.MixedCaseAlphaNum)
|
||||||
|
}
|
||||||
|
for keyRef, _ := keyDB.Get([]byte(key)); keyRef != nil; {
|
||||||
|
slog.Info().Msg(" delete key already exists! generating new...")
|
||||||
|
key = gouid.String(keySize, gouid.MixedCaseAlphaNum)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we passed all those checks, delete the txt entry from the database
|
hashDB.Put([]byte(hash), []byte(uid))
|
||||||
err := txtDB.Delete([]byte(finalTarget[1]))
|
|
||||||
|
|
||||||
// failed to delete it? shouldn't happen
|
err = txtDB.Put([]byte(uid), b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Str("func", fn).Str("rkey", finalTarget[1]).Msg("delete failed!")
|
slog.Error().Msg("failed to save text!")
|
||||||
errThrow(c, 500, "500", "500")
|
termbin.Reply <- termbin.Message{Type: "ERROR", Content: "internal server error"}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
err = keyDB.Put([]byte(key), []byte("t."+uid))
|
||||||
// make sure its actually gone
|
|
||||||
if txtDB.Has([]byte(finalTarget[1])) {
|
|
||||||
log.Error().Err(err).Str("func", fn).Str("rkey", finalTarget[1]).Msg("delete failed!?")
|
|
||||||
errThrow(c, 500, "500", "500")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove the delete key entry but not the hash (see below)
|
|
||||||
log.Info().Str("func", fn).Str("rkey", finalTarget[1]).Msg("text deleted successfully")
|
|
||||||
log.Debug().Str("func", fn).Str("rkey", finalTarget[1]).Msg("Removing delete key entry")
|
|
||||||
err = keyDB.Delete([]byte(rKey))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Str("func", fn).Str("rkey", finalTarget[1]).Msg("Couldn't delete key")
|
slog.Error().Msg("failed to save delete key!")
|
||||||
|
termbin.Reply <- termbin.Message{Type: "ERROR", Content: "internal server error"}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
c.JSON(200, "DELETE_SUCCESS")
|
|
||||||
|
|
||||||
// it would be insane to try and delete the hash here
|
slog.Debug().Str("uid", uid).Msg("saved to database successfully, sending to Serve")
|
||||||
// if someone is uploading this text again after del
|
|
||||||
// and the file corresponding to the hash no longer exists
|
post := &Post{
|
||||||
// we will delete the hash entry then and re-add then
|
Type: "t",
|
||||||
|
Uid: uid,
|
||||||
|
Key: key,
|
||||||
|
Priv: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
termbin.Reply <- termbin.Message{Type: "URL", Content: post.URLString()}
|
||||||
}
|
}
|
||||||
|
|
||||||
func txtView(c *gin.Context) {
|
func txtView(c *gin.Context) {
|
||||||
fn = "txtView"
|
slog := log.With().Str("caller", "txtView").Logger()
|
||||||
// the user can access their text with or without a file extension in URI
|
|
||||||
// however it must be a valid extension (more checks further down)
|
raddr, _ := c.RemoteIP()
|
||||||
log.Info().Str("func", fn).Msg("request received")
|
if txtThrottled(raddr.String()) {
|
||||||
|
errThrow(c, 429, "ratelimited", "too many requests")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// the user can access their image with or without a file extension in URI
|
||||||
|
slog.Debug().Msg("request received") // however it must be a valid extension (more checks further down)
|
||||||
|
|
||||||
sUid := strings.Split(c.Param("uid"), ".")
|
sUid := strings.Split(c.Param("uid"), ".")
|
||||||
rUid := sUid[0]
|
rUid := sUid[0]
|
||||||
|
fExt = ""
|
||||||
|
|
||||||
if len(sUid) > 1 {
|
if len(sUid) > 1 {
|
||||||
fExt = strings.ToLower(sUid[1])
|
fExt = strings.ToLower(sUid[1])
|
||||||
log.Debug().Str("func", fn).Str("ext", fExt).Msg("detected file extension")
|
|
||||||
if fExt != "txt" {
|
if fExt != "txt" {
|
||||||
log.Error().Err(err).Str("func", fn).Msg("Bad file extension!")
|
slog.Error().Msg("bad file extension")
|
||||||
errThrow(c, 400, "400", "400")
|
errThrow(c, 400, "400", "400")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
fExt = "nil"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if it doesn't match the key size or it isn't alphanumeric - throw it out
|
||||||
if !valid.IsAlphanumeric(rUid) || len(rUid) != uidSize {
|
if !valid.IsAlphanumeric(rUid) || len(rUid) != uidSize {
|
||||||
log.Error().Err(err).Str("func", fn).Msg("request discarded as invalid")
|
slog.Error().Msg("request discarded as invalid") // these limits should be variables eventually
|
||||||
errThrow(c, 400, "400", "400")
|
errThrow(c, 400, "400", "400")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// now that we think its a valid request we will query
|
// query bitcask for the id
|
||||||
log.Debug().Str("func", fn).Str("rUid", rUid).Msg("request validated")
|
|
||||||
fBytes, _ := txtDB.Get([]byte(rUid))
|
fBytes, _ := txtDB.Get([]byte(rUid))
|
||||||
if fBytes == nil {
|
if fBytes == nil {
|
||||||
log.Error().Err(err).Str("func", fn).Str("rUid", rUid).Msg("no corresponding file for this id")
|
slog.Error().Str("rUid", rUid).Msg("no corresponding file for this id")
|
||||||
errThrow(c, 404, "404", "File not found")
|
errThrow(c, 404, "404", "file not found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Data(200, "text/plain", fBytes)
|
file, _ := termbin.Deflate(fBytes)
|
||||||
|
c.Data(200, "text/plain", file)
|
||||||
|
|
||||||
log.Info().Str("func", fn).Str("rUid", rUid).Msg("Success")
|
slog.Info().Str("rUid", rUid).Msg("success")
|
||||||
}
|
}
|
||||||
|
|
||||||
func txtPost(c *gin.Context) {
|
func txtDel(c *gin.Context) {
|
||||||
fn = "txtPost"
|
slog := log.With().
|
||||||
|
Str("caller", "txtDel").Logger()
|
||||||
|
|
||||||
t := c.PostForm("txt")
|
slog.Debug().Msg("new_request") // received request
|
||||||
priv := c.PostForm("priv")
|
|
||||||
|
|
||||||
tbyte := []byte(t)
|
if !validateKey(c.Param("key")) {
|
||||||
|
errThrow(c, 400, "400", "400")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
rKey := c.Param("key")
|
||||||
log.Error().Err(err).Str("fn", fn).Msg("Oh?")
|
|
||||||
|
targetTxt, _ := keyDB.Get([]byte(rKey))
|
||||||
|
if targetTxt == nil || !strings.Contains(string(targetTxt), "t.") {
|
||||||
|
slog.Warn().Str("rkey", rKey).Msg("no txt delete entry found with provided key")
|
||||||
|
errThrow(c, 400, "400", "400")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t := strings.Split(string(targetTxt), ".")[1]
|
||||||
|
|
||||||
|
if !txtDB.Has([]byte(t)) {
|
||||||
|
slog.Warn().Str("rkey", rKey).Msg("corresponding image not found in database!")
|
||||||
|
errThrow(c, 500, "500", "500") // this shouldn't happen...?
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := txtDB.Delete([]byte(t)); err != nil {
|
||||||
|
slog.Error().Str("rkey", t).Msg("delete failed!")
|
||||||
errThrow(c, 500, "500", "500")
|
errThrow(c, 500, "500", "500")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(t) == 0 {
|
if txtDB.Has([]byte(t)) {
|
||||||
log.Warn().Str("fn", fn).Msg("received an empty request")
|
slog.Error().Str("rkey", t).Msg("delete failed!?")
|
||||||
errThrow(c, 400, "400", "400")
|
errThrow(c, 500, "500", "500")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.ContentType() != "text/plain" {
|
slog.Info().Str("rkey", t).Msg("Image file deleted successfully")
|
||||||
log.Warn().Str("fn", fn).Str("ContentType", c.ContentType()).Msg("received a non-text content-type")
|
slog.Debug().Str("rkey", t).Msg("Removing delete key entry")
|
||||||
errThrow(c, 400, "400", "400")
|
err = keyDB.Delete([]byte(rKey))
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// an optional switch for a privnote style burn after read
|
|
||||||
// priv := c.GetBool("private")
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// incoming POST data is invalid
|
slog.Error().Str("rkey", t).Msg("Couldn't delete key")
|
||||||
errThrow(c, http.StatusBadRequest, err.Error(), "400") // 400 bad request
|
// it would be insane to try and delete the hash here
|
||||||
}
|
} // if someone is uploading this image again after del
|
||||||
|
c.JSON(200, "DELETE_SUCCESS") // and the file corresponding to the hash no longer exists
|
||||||
log.Debug().Str("func", fn).Msg("New paste")
|
// we will delete the hash entry then and re-add then
|
||||||
|
}
|
||||||
if priv == "on" {
|
|
||||||
// check for dupes
|
//func serveTermbin() {
|
||||||
log.Debug().Str("func", fn).Msg("calculating blake2b checksum")
|
func serveTermbin() {
|
||||||
Hashr, _ := blake2b.New(64, nil)
|
go func() {
|
||||||
Hashr.Write(tbyte)
|
for {
|
||||||
hash := Hashr.Sum(nil)
|
incoming()
|
||||||
log.Debug().Str("func", fn).Msg("Checking for duplicate's in database")
|
}
|
||||||
txtRef, _ := txtDB.Get(hash)
|
}()
|
||||||
ogUid := string(txtRef)
|
err := termbin.Listen("", txtPort)
|
||||||
|
if err != nil {
|
||||||
if txtRef != nil {
|
println(err.Error())
|
||||||
log.Debug().Str("func", fn).Str("ogUid", ogUid).Msg("duplicate checksum in hash database, checking if file still exists...")
|
return
|
||||||
if txtDB.Has(txtRef) {
|
}
|
||||||
log.Debug().Str("func", fn).Str("ogUid", ogUid).Msg("duplicate file found! returning original URL")
|
|
||||||
// they weren't the original uploader so they don't get a delete key
|
|
||||||
txtFin(c, ogUid, "nil")
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
log.Debug().Str("func", fn).Str("ogUid", ogUid).Msg("stale hash found, deleting entry...")
|
|
||||||
hashDB.Delete(hash)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Info().Str("func", fn).Msg("no duplicate txts found, generating uid and delete key")
|
|
||||||
|
|
||||||
// generate identifier and delete key based on configured sizes
|
|
||||||
uid := gouid.String(uidSize, gouid.MixedCaseAlphaNum)
|
|
||||||
key := gouid.String(keySize, gouid.MixedCaseAlphaNum)
|
|
||||||
|
|
||||||
// lets make sure that we don't clash even though its highly unlikely
|
|
||||||
for uidRef, _ := txtDB.Get([]byte(uid)); uidRef != nil; {
|
|
||||||
log.Info().Str("func", fn).Msg("uid already exists! generating another...")
|
|
||||||
uid = gouid.String(uidSize, gouid.MixedCaseAlphaNum)
|
|
||||||
}
|
|
||||||
for keyRef, _ := keyDB.Get([]byte(key)); keyRef != nil; {
|
|
||||||
log.Info().Str("func", fn).Msg(" delete key already exists! generating another...")
|
|
||||||
key = gouid.String(keySize, gouid.MixedCaseAlphaNum)
|
|
||||||
}
|
|
||||||
|
|
||||||
// save checksum to db to prevent dupes in the future
|
|
||||||
hashDB.Put([]byte(hash), []byte(uid))
|
|
||||||
|
|
||||||
log.Debug().Str("func", fn).Str("uid", uid).Msg("saving file to database")
|
|
||||||
|
|
||||||
err = txtDB.Put([]byte(uid), []byte(tbyte))
|
|
||||||
if err != nil {
|
|
||||||
errThrow(c, 500, err.Error(), "upload failed")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// add delete key to database with txt prefix
|
|
||||||
err = keyDB.Put([]byte(key), []byte("t."+uid))
|
|
||||||
if err != nil {
|
|
||||||
errThrow(c, http.StatusInternalServerError, err.Error(), "internal error")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Debug().Str("func", fn).Str("uid", uid).Msg("saved to database successfully, sending to txtFin")
|
|
||||||
|
|
||||||
txtFin(c, uid, key)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user