add expiry mechanism

This commit is contained in:
hgc 2022-09-30 19:58:29 +09:30
parent d66cf13471
commit de29fceba2
4 changed files with 130 additions and 24 deletions

1
go.mod
View File

@ -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
View File

@ -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=

View File

@ -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
View File

@ -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()
}