add expiry mechanism
This commit is contained in:
parent
d66cf13471
commit
de29fceba2
1
go.mod
1
go.mod
|
@ -3,6 +3,7 @@ module git.tcp.direct/hgc/filehole
|
|||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/boltdb/bolt v1.3.1
|
||||
github.com/gabriel-vasile/mimetype v1.4.1
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/rs/zerolog v1.28.0
|
||||
|
|
2
go.sum
2
go.sum
|
@ -1,3 +1,5 @@
|
|||
github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
|
||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/gabriel-vasile/mimetype v1.4.1 h1:TRWk7se+TOjCYgRth7+1/OYLNiRNIotknkFtf/dnN7Q=
|
||||
github.com/gabriel-vasile/mimetype v1.4.1/go.mod h1:05Vi0w3Y9c/lNvJOdmIwvrrAhX3rYhfQQCaf9VJcv7M=
|
||||
|
|
73
index.html
73
index.html
|
@ -1,29 +1,74 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Filehole</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background: black;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
.container {
|
||||
padding-right: 15px;
|
||||
padding-left: 15px;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.container {
|
||||
width: 750px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
.container {
|
||||
width: 970px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1200px) {
|
||||
.container {
|
||||
width: 1170px;
|
||||
}
|
||||
}
|
||||
input,select {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Filehole</h1>
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
<label for="url_len">URL Length (5-69)</label>
|
||||
<input type="number" name="url_len" id="url_len" min=5 max=69 value=24></input><br>
|
||||
<label for="expiry">Expiry (slider is 1d-5d)</label>
|
||||
<input type="range" name="expiry" id="expiry" min=86400 max=432000 step=86400 value=86400></input><br>
|
||||
<br>
|
||||
<input type="file" name="file"></input>
|
||||
<input type="submit"></input>
|
||||
<label for="url_len">URL Length (5-169)</label>
|
||||
<input type="number" name="url_len" id="url_len" min=5 max=169 value=24 /><br>
|
||||
<label for="expiry">Expiry</label>
|
||||
<select name="expiry" id="expiry">
|
||||
<option value="3600">1 hour</option>
|
||||
<option value="18000">5 hours</option>
|
||||
<option value="86400" selected>1 day</option>
|
||||
<option value="140400">39 hours</option>
|
||||
<option value="172800">2 days</option>
|
||||
<option value="248400">69 hours</option>
|
||||
<option value="432000">5 days</option>
|
||||
</select><br>
|
||||
<input type="file" name="file" />
|
||||
<input type="submit" />
|
||||
</form>
|
||||
<br>
|
||||
<hr>
|
||||
<h1>How to put your files in the hole</h1>
|
||||
<h2>curl</h2>
|
||||
<p>
|
||||
<pre>curl -X POST -F 'file=@filehole.png' https://filehole.org</pre>
|
||||
</p>
|
||||
<p>
|
||||
<pre>curl -X POST -F 'file=@filehole.png' -F "url_len=5" -F "expiry=86400" https://filehole.org</pre>
|
||||
</p>
|
||||
<p><pre>curl -X POST -F 'file=@filehole.png' https://filehole.org</pre></p>
|
||||
<p><pre>curl -X POST -F 'file=@filehole.png' -F "url_len=5" -F "expiry=86400" https://filehole.org</pre></p>
|
||||
<h2>Firefox</h2>
|
||||
<a href="https://addons.mozilla.org/en-US/firefox/addon/post-image/">POST Image by rj1</a>
|
||||
<h2>Mac OS</h2>
|
||||
<a href="https://github.com/AndroidKitKat/Filehole.org-Mac">Filehole.org-Mac by AndroidKitKat</a>*
|
||||
<p><small>*not actually tested or endorsed because I will never own a Mac</small></p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
64
main.go
64
main.go
|
@ -6,16 +6,19 @@ import (
|
|||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gabriel-vasile/mimetype"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
func shortID(length int64) string {
|
||||
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
|
||||
const chars = "abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ123456789"
|
||||
ll := len(chars)
|
||||
b := make([]byte, length)
|
||||
rand.Read(b) // generates len(b) random bytes
|
||||
|
@ -25,6 +28,8 @@ func shortID(length int64) string {
|
|||
return string(b)
|
||||
}
|
||||
|
||||
var db *bolt.DB
|
||||
|
||||
func UploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// url_len sanitize
|
||||
inpUrlLen := r.FormValue("url_len")
|
||||
|
@ -32,8 +37,8 @@ func UploadHandler(w http.ResponseWriter, r *http.Request) {
|
|||
if err != nil {
|
||||
sanUrlLen = 24
|
||||
}
|
||||
if sanUrlLen < 5 || sanUrlLen > 64 {
|
||||
w.Write([]byte("url_len needs to be between 5 and 64\n"))
|
||||
if sanUrlLen < 5 || sanUrlLen > 169 {
|
||||
w.Write([]byte("url_len needs to be between 5 and 169\n"))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -66,6 +71,15 @@ func UploadHandler(w http.ResponseWriter, r *http.Request) {
|
|||
// ready for upload
|
||||
name := shortID(sanUrlLen) + mtype.Extension()
|
||||
|
||||
err = db.Update(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte("expiry"))
|
||||
err := b.Put([]byte(name), []byte(strconv.FormatInt(time.Now().Unix()+sanExpiry, 10)))
|
||||
return err
|
||||
})
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to put expiry")
|
||||
}
|
||||
|
||||
log.Info().Str("mtype", mtype.String()).Str("ext", mtype.Extension()).Int64("expiry", sanExpiry).Int64("url_len", sanUrlLen).Msg("Writing new file")
|
||||
|
||||
f, err := os.OpenFile("data/"+name, os.O_WRONLY|os.O_CREATE, 0644)
|
||||
|
@ -81,9 +95,50 @@ func UploadHandler(w http.ResponseWriter, r *http.Request) {
|
|||
w.Write([]byte("https://u.filehole.org/" + name + "\n"))
|
||||
}
|
||||
|
||||
func ExpiryDoer() {
|
||||
for {
|
||||
removed := 0
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
b := tx.Bucket([]byte("expiry"))
|
||||
c := b.Cursor()
|
||||
for k, v := c.First(); k != nil; k, v = c.Next() {
|
||||
expiryTime, err := strconv.ParseInt(string(v), 10, 64)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Bytes("k", k).Bytes("v", v).Msg("Expiry time could not be parsed")
|
||||
continue
|
||||
}
|
||||
if time.Now().After(time.Unix(expiryTime, 0)) {
|
||||
os.Remove("data/" + string(k))
|
||||
removed += 1
|
||||
c.Delete()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if removed >= 1 {
|
||||
log.Info().Int("amt", removed).Msg("Purged based on expiry")
|
||||
}
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||
|
||||
var err error
|
||||
db, err = bolt.Open("filehole.db", 0600, nil)
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("dangerous database activity")
|
||||
}
|
||||
db.Update(func(tx *bolt.Tx) error {
|
||||
_, err := tx.CreateBucketIfNotExists([]byte("expiry"))
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Error creating expiry bucket")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
r := mux.NewRouter()
|
||||
r.HandleFunc("/", UploadHandler).Methods("POST")
|
||||
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
|
@ -91,5 +146,8 @@ func main() {
|
|||
}).Methods("GET")
|
||||
http.Handle("/", r)
|
||||
|
||||
go ExpiryDoer()
|
||||
http.ListenAndServe("127.0.0.1:8000", r)
|
||||
|
||||
db.Close()
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue