code revamp, missing dir/db fault tolerance, frontend changes, misc cleanup
This commit is contained in:
parent
979c7e34d4
commit
f15f9de04a
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
files/
|
files/
|
||||||
|
*.db
|
@ -4,4 +4,4 @@ vhost = "hardfiles.org"
|
|||||||
dbfile = "dbfile.db"
|
dbfile = "dbfile.db"
|
||||||
filelen = 6
|
filelen = 6
|
||||||
folder = "files"
|
folder = "files"
|
||||||
fileexpiry = 86400
|
ttl_seconds = 86400
|
94
main.go
94
main.go
@ -23,13 +23,13 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Webroot string `toml:"webroot"`
|
Webroot string `toml:"webroot"`
|
||||||
LPort string `toml:"lport"`
|
LPort string `toml:"lport"`
|
||||||
VHost string `toml:"vhost"`
|
VHost string `toml:"vhost"`
|
||||||
DBFile string `toml:"dbfile"`
|
DBFile string `toml:"dbfile"`
|
||||||
FileLen int `toml:"filelen"`
|
FileLen int `toml:"filelen"`
|
||||||
FileFolder string `toml:"folder"`
|
FileFolder string `toml:"folder"`
|
||||||
FileExpirySeconds int `toml:"fileexpiry"`
|
TTLSeconds int `toml:"ttl_seconds"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadConf() {
|
func LoadConf() {
|
||||||
@ -44,18 +44,15 @@ func Shred(path string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
size := fileinfo.Size()
|
size := fileinfo.Size()
|
||||||
err = Scramble(path, size)
|
if err = Scramble(path, size); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = Zeros(path, size)
|
if err = Zeros(path, size); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.Remove(path)
|
if err = os.Remove(path); err != nil {
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +97,7 @@ func Zeros(path string, size int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NameGen() string {
|
func NameGen() string {
|
||||||
const chars = "abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ123456789"
|
const chars = "abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ0123456789"
|
||||||
ll := len(chars)
|
ll := len(chars)
|
||||||
b := make([]byte, conf.FileLen)
|
b := make([]byte, conf.FileLen)
|
||||||
rand.Read(b) // generates len(b) random bytes
|
rand.Read(b) // generates len(b) random bytes
|
||||||
@ -110,6 +107,24 @@ func NameGen() string {
|
|||||||
return string(b)
|
return string(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CheckFolder(path string) {
|
||||||
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||||
|
err := os.Mkdir(path, 0755)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("unable to create folder")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckDB(path string) {
|
||||||
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||||
|
_, err := os.Create(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("unable to create database file")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func CheckFile(name string) bool { // false if doesn't exist, true if exists
|
func CheckFile(name string) bool { // false if doesn't exist, true if exists
|
||||||
tfd, err := os.Open(conf.FileFolder + "/" + name)
|
tfd, err := os.Open(conf.FileFolder + "/" + name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -120,8 +135,8 @@ func CheckFile(name string) bool { // false if doesn't exist, true if exists
|
|||||||
}
|
}
|
||||||
|
|
||||||
func UploadHandler(w http.ResponseWriter, r *http.Request) {
|
func UploadHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
// expiry sanitize
|
// expiry time
|
||||||
twentyfour := int64(conf.FileExpirySeconds)
|
ttl := int64(conf.TTLSeconds)
|
||||||
|
|
||||||
file, _, err := r.FormFile("file")
|
file, _, err := r.FormFile("file")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -149,31 +164,33 @@ func UploadHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
err = db.Update(func(tx *bolt.Tx) error {
|
err = db.Update(func(tx *bolt.Tx) error {
|
||||||
b := tx.Bucket([]byte("expiry"))
|
b := tx.Bucket([]byte("expiry"))
|
||||||
err := b.Put([]byte(name), []byte(strconv.FormatInt(time.Now().Unix()+twentyfour, 10)))
|
err := b.Put([]byte(name), []byte(strconv.FormatInt(time.Now().Unix()+ttl, 10)))
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Failed to put expiry")
|
log.Error().Err(err).Msg("failed to put expiry")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().Int64("expiry", twentyfour).Msg("Writing new file")
|
|
||||||
|
|
||||||
f, err := os.OpenFile(conf.FileFolder+"/"+name, os.O_WRONLY|os.O_CREATE, 0644)
|
f, err := os.OpenFile(conf.FileFolder+"/"+name, os.O_WRONLY|os.O_CREATE, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Error opening a file for write")
|
log.Error().Err(err).Msg("error opening a file for write")
|
||||||
w.WriteHeader(http.StatusInternalServerError) // change to json
|
w.WriteHeader(http.StatusInternalServerError) // change to json
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
io.Copy(f, file)
|
io.Copy(f, file)
|
||||||
|
log.Info().Str("name", name).Int64("ttl", ttl).Msg("wrote new file")
|
||||||
|
|
||||||
w.Write([]byte("https://" + conf.VHost + "/uploads/" + name))
|
hostedurl := "https://" + conf.VHost + "/uploads/" + name
|
||||||
|
|
||||||
|
w.Header().Set("Location", hostedurl)
|
||||||
|
w.WriteHeader(http.StatusSeeOther)
|
||||||
|
w.Write([]byte(hostedurl))
|
||||||
}
|
}
|
||||||
|
|
||||||
func Cull() {
|
func Cull() {
|
||||||
for {
|
for {
|
||||||
removed := 0
|
|
||||||
db.Update(func(tx *bolt.Tx) error {
|
db.Update(func(tx *bolt.Tx) error {
|
||||||
b := tx.Bucket([]byte("expiry"))
|
b := tx.Bucket([]byte("expiry"))
|
||||||
c := b.Cursor()
|
c := b.Cursor()
|
||||||
@ -187,16 +204,13 @@ func Cull() {
|
|||||||
if err := Shred(conf.FileFolder + "/" + string(k)); err != nil {
|
if err := Shred(conf.FileFolder + "/" + string(k)); err != nil {
|
||||||
log.Error().Err(err).Msg("shredding failed")
|
log.Error().Err(err).Msg("shredding failed")
|
||||||
} else {
|
} else {
|
||||||
removed += 1
|
log.Info().Str("name", string(k)).Msg("shredded file")
|
||||||
}
|
}
|
||||||
c.Delete()
|
c.Delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if removed >= 1 {
|
|
||||||
log.Info().Int("amount", removed).Msg("shredded")
|
|
||||||
}
|
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,6 +219,9 @@ func main() {
|
|||||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||||
LoadConf()
|
LoadConf()
|
||||||
|
|
||||||
|
CheckFolder(conf.FileFolder)
|
||||||
|
CheckDB(conf.DBFile)
|
||||||
|
|
||||||
err := landlock.V2.BestEffort().RestrictPaths(
|
err := landlock.V2.BestEffort().RestrictPaths(
|
||||||
landlock.RWDirs(conf.FileFolder),
|
landlock.RWDirs(conf.FileFolder),
|
||||||
landlock.RWDirs(conf.Webroot),
|
landlock.RWDirs(conf.Webroot),
|
||||||
@ -217,9 +234,9 @@ func main() {
|
|||||||
|
|
||||||
_, err = os.Open("/etc/passwd")
|
_, err = os.Open("/etc/passwd")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
log.Warn().Msg("landlock failed, could open /etc/passwd")
|
log.Warn().Msg("landlock failed, could open /etc/passwd, are you on a 5.13+ kernel?")
|
||||||
} else {
|
} else {
|
||||||
log.Info().Err(err).Msg("Landlocked")
|
log.Info().Err(err).Msg("landlocked")
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err = bolt.Open(conf.DBFile, 0600, nil)
|
db, err = bolt.Open(conf.DBFile, 0600, nil)
|
||||||
@ -241,21 +258,21 @@ func main() {
|
|||||||
vars := mux.Vars(r)
|
vars := mux.Vars(r)
|
||||||
if !CheckFile(vars["name"]) {
|
if !CheckFile(vars["name"]) {
|
||||||
w.WriteHeader(http.StatusNotFound)
|
w.WriteHeader(http.StatusNotFound)
|
||||||
|
w.Write([]byte("file not found"))
|
||||||
} else {
|
} else {
|
||||||
http.ServeFile(w, r, conf.FileFolder+"/"+vars["name"])
|
http.ServeFile(w, r, conf.FileFolder+"/"+vars["name"])
|
||||||
}
|
}
|
||||||
}).Methods("GET")
|
}).Methods("GET")
|
||||||
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
http.ServeFile(w, r, conf.Webroot+"/index.html")
|
http.ServeFile(w, r, conf.Webroot+"/index.html")
|
||||||
}).Methods("GET")
|
})
|
||||||
r.HandleFunc("/index.html", func(w http.ResponseWriter, r *http.Request) {
|
r.HandleFunc("/{file}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
http.ServeFile(w, r, conf.Webroot+"/index.html")
|
file := mux.Vars(r)["file"]
|
||||||
}).Methods("GET")
|
if _, err := os.Stat(conf.Webroot + "/" + file); os.IsNotExist(err) {
|
||||||
r.HandleFunc("/fist.ico", func(w http.ResponseWriter, r *http.Request) {
|
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||||
http.ServeFile(w, r, conf.Webroot+"/fist.ico")
|
} else {
|
||||||
}).Methods("GET")
|
http.ServeFile(w, r, conf.Webroot+"/"+file)
|
||||||
r.HandleFunc("/header.png", func(w http.ResponseWriter, r *http.Request) {
|
}
|
||||||
http.ServeFile(w, r, conf.Webroot+"/header.png")
|
|
||||||
}).Methods("GET")
|
}).Methods("GET")
|
||||||
http.Handle("/", r)
|
http.Handle("/", r)
|
||||||
|
|
||||||
@ -268,6 +285,7 @@ func main() {
|
|||||||
IdleTimeout: 20 * time.Second,
|
IdleTimeout: 20 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Warn().Msg("shredding is only effective on HDD volumes")
|
||||||
log.Info().Err(err).Msg("listening on port " + conf.LPort + "...")
|
log.Info().Err(err).Msg("listening on port " + conf.LPort + "...")
|
||||||
|
|
||||||
if err := serv.ListenAndServe(); err != nil {
|
if err := serv.ListenAndServe(); err != nil {
|
||||||
|
BIN
www/header.png
BIN
www/header.png
Binary file not shown.
Before Width: | Height: | Size: 93 KiB After Width: | Height: | Size: 63 KiB |
@ -1,12 +1,9 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html style="overflow: hidden;">
|
||||||
<head>
|
<head>
|
||||||
<script type="text/javascript" src="//code.jquery.com/jquery-1.10.2.min.js"></script>
|
<script type="text/javascript" src="//code.jquery.com/jquery-1.10.2.min.js"></script>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<link rel="icon" href="fist.ico">
|
<link rel="icon" href="fist.ico">
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Black+Ops+One&display=swap" rel="stylesheet">
|
|
||||||
<title>HARDFILES</title>
|
<title>HARDFILES</title>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
@ -16,6 +13,7 @@
|
|||||||
}
|
}
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
body {
|
body {
|
||||||
|
overflow: hidden;
|
||||||
background: black;
|
background: black;
|
||||||
background-image: url('https://media.tenor.com/fYnd0R6F-0UAAAAC/gun-revolver.gif');
|
background-image: url('https://media.tenor.com/fYnd0R6F-0UAAAAC/gun-revolver.gif');
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
@ -122,7 +120,6 @@
|
|||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<img src="header.png" width="50%" alt="supernets" style="margin-top: 10rem;">
|
<img src="header.png" width="50%" alt="supernets" style="margin-top: 10rem;">
|
||||||
<!-- <h1 class="hf" style=" color: #660000; font-weight: 800; font-family: 'Black Ops One', cursive; margin-bottom: 0 !important; margin-top: 5rem !important;">HARDFILES</h1> -->
|
|
||||||
<h2 style="font-size: 1em; color: #ffffff; font-weight: 200;">curl -F file=@example.png https://hardfiles.org/</h1>
|
<h2 style="font-size: 1em; color: #ffffff; font-weight: 200;">curl -F file=@example.png https://hardfiles.org/</h1>
|
||||||
<form method="POST" class="subform" enctype="multipart/form-data">
|
<form method="POST" class="subform" enctype="multipart/form-data">
|
||||||
<div class="file-upload" style="display: flex; justify-content: center; width: 25rem;">
|
<div class="file-upload" style="display: flex; justify-content: center; width: 25rem;">
|
||||||
@ -135,6 +132,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<p style="color: white; font-weight: 300;">⚠️ Uploads are erased after 24 hours</p>
|
<p style="color: white; font-weight: 300;">⚠️ Uploads are erased after 24 hours</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div style="position: relative;">
|
||||||
|
<a href="https://supernets.org/" target="_blank" style="position: absolute; bottom: 10px; right:10px; display: flex; align-items: center; text-decoration: none;">
|
||||||
|
<p style="font-weight:200; color:#ffffff">A SUPERNETS</p>
|
||||||
|
<img src="https://git.supernets.org/assets/img/logo.png" width="30px" style="margin: 0 5px;">
|
||||||
|
<p style="font-weight:200; color: #ffffff">SERVICE</p>
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
Loading…
Reference in New Issue
Block a user