Compare commits
14 Commits
61e218e58f
...
master
Author | SHA1 | Date | |
---|---|---|---|
571ffca339 | |||
9b0d448698 | |||
35958f2ade | |||
71fed69dd7 | |||
339d8ed9a7 | |||
0f317edb28 | |||
d4906360e1 | |||
df6d009ce7 | |||
cd29f363fa | |||
110a7387b5 | |||
5578822c3f | |||
099f4777cd | |||
8d470cbe68 | |||
8ce2789588 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -35,3 +35,4 @@ watcher
|
|||||||
lts
|
lts
|
||||||
store
|
store
|
||||||
ALLOWED_USERS.txt
|
ALLOWED_USERS.txt
|
||||||
|
ltscleanerd
|
||||||
|
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -1,3 +1,3 @@
|
|||||||
[submodule "gebs"]
|
[submodule "gebs"]
|
||||||
path = gebs
|
path = gebs
|
||||||
url = http://git.kamkow1lair/kamkow1/gebs.git
|
url = http://git.kamkow1lair.pl/kamkow1/gebs.git
|
||||||
|
@ -1 +1,2 @@
|
|||||||
./lts
|
./lts
|
||||||
|
./ltscleanerd
|
||||||
|
14
Makefile
14
Makefile
@ -1,24 +1,28 @@
|
|||||||
BUILD_MODE ?= DEBUG
|
BUILD_MODE ?= DEBUG
|
||||||
|
|
||||||
ifeq ($(BUILD_MODE),DEBUG)
|
ifeq ($(BUILD_MODE),DEBUG)
|
||||||
LISTEN_PORT = ":9090"
|
LISTEN_ADDR = "localhost:9090"
|
||||||
else ifeq ($(BUILD_MODE),RELEASE)
|
else ifeq ($(BUILD_MODE),RELEASE)
|
||||||
LISTEN_PORT = ":80"
|
LISTEN_ADDR = "0.0.0.0:4000"
|
||||||
else
|
else
|
||||||
$(error Unknown build mode)
|
$(error Unknown build mode)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: lts watcher
|
all: lts watcher
|
||||||
|
|
||||||
lts: lts.go uuid.go
|
lts: ltscleanerd lts.go uuid.go
|
||||||
go build -ldflags="-X main.LISTEN_PORT=$(LISTEN_PORT)"
|
go build -ldflags="-X main.LISTEN_ADDR=$(LISTEN_ADDR)"
|
||||||
|
|
||||||
|
ltscleanerd: ltscleanerd.c
|
||||||
|
cc -o ltscleanerd ltscleanerd.c
|
||||||
|
|
||||||
watcher: watcher.c
|
watcher: watcher.c
|
||||||
cc -o $@ $<
|
cc -o $@ $<
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
go clean
|
go clean
|
||||||
rm watcher
|
rm -f watcher
|
||||||
|
rm -f ltscleanerd
|
||||||
|
|
||||||
watch: all
|
watch: all
|
||||||
./watcher . sh -c "make BUILD_MODE=$(BUILD_MODE) && ./lts"
|
./watcher . sh -c "make BUILD_MODE=$(BUILD_MODE) && ./lts"
|
||||||
|
5
go.mod
5
go.mod
@ -1,8 +1,3 @@
|
|||||||
module lts
|
module lts
|
||||||
|
|
||||||
go 1.24.3
|
go 1.24.3
|
||||||
|
|
||||||
require (
|
|
||||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
|
||||||
golang.org/x/sys v0.13.0 // indirect
|
|
||||||
)
|
|
||||||
|
4
go.sum
4
go.sum
@ -1,4 +0,0 @@
|
|||||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
|
||||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
|
||||||
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
|
||||||
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
|
169
lts.go
169
lts.go
@ -8,16 +8,21 @@ import (
|
|||||||
"html/template"
|
"html/template"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"syscall"
|
||||||
"github.com/fsnotify/fsnotify"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var LISTEN_PORT string
|
var LISTEN_ADDR string
|
||||||
|
|
||||||
|
var listener net.Listener
|
||||||
|
|
||||||
//go:embed tmpls/*
|
//go:embed tmpls/*
|
||||||
var tmpls embed.FS
|
var tmpls embed.FS
|
||||||
@ -25,22 +30,23 @@ var tmpls embed.FS
|
|||||||
//go:embed etc/*
|
//go:embed etc/*
|
||||||
var etc embed.FS
|
var etc embed.FS
|
||||||
|
|
||||||
func createFile(storePath, name string) (*os.File, error) {
|
func createFile(storePath, name string) (*os.File, string, error) {
|
||||||
if _, err := os.Stat(storePath); os.IsNotExist(err) {
|
if _, err := os.Stat(storePath); os.IsNotExist(err) {
|
||||||
os.Mkdir(storePath, 0755)
|
os.Mkdir(storePath, 0755)
|
||||||
}
|
}
|
||||||
|
|
||||||
uuidBytes, err := NewV4()
|
uuidBytes, err := NewV4()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
uuid := uuidBytes.String()
|
uuid := uuidBytes.String()
|
||||||
|
|
||||||
dst, err := os.Create(filepath.Join(storePath, fmt.Sprintf("%s-%s", uuid, name)))
|
bare_name := fmt.Sprintf("%s-%s", uuid, name)
|
||||||
|
dst, err := os.Create(filepath.Join(storePath, bare_name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, bare_name, err
|
||||||
}
|
}
|
||||||
return dst, nil
|
return dst, bare_name, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type AllowedUser struct {
|
type AllowedUser struct {
|
||||||
@ -102,23 +108,61 @@ func byteCountSI(b int64) string {
|
|||||||
float64(b)/float64(div), "kMGTPE"[exp])
|
float64(b)/float64(div), "kMGTPE"[exp])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Timeout struct {
|
||||||
|
H int64
|
||||||
|
M int64
|
||||||
|
S int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cleaner struct {
|
||||||
|
Timeout Timeout
|
||||||
|
SpawnTime int64
|
||||||
|
}
|
||||||
|
|
||||||
|
var cleaners map[string]Cleaner = map[string]Cleaner{}
|
||||||
|
var cleanersMutex sync.Mutex
|
||||||
|
|
||||||
func handleUpload(w http.ResponseWriter, r *http.Request) {
|
func handleUpload(w http.ResponseWriter, r *http.Request) {
|
||||||
limit := int64(10737418240) // 10GiB
|
limit := int64(10737418240) // 10GiB
|
||||||
r.ParseMultipartForm(limit)
|
r.ParseMultipartForm(limit)
|
||||||
|
|
||||||
|
hours_str := r.FormValue("hours")
|
||||||
|
mins_str := r.FormValue("mins")
|
||||||
|
secs_str := r.FormValue("secs")
|
||||||
|
|
||||||
|
hours, err := strconv.ParseInt(hours_str, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Could not parse timeout hours", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mins, err := strconv.ParseInt(mins_str, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Could not parse timeout mins", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
secs, err := strconv.ParseInt(secs_str, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Could not parse timeout secs", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hours < 0 || hours > 24) || (mins < 0 || mins > 60) || (secs < 0 || secs > 60) {
|
||||||
|
http.Error(w, "Max values: 24 hours, 60 mins, 60 secs, all cannot be < 0", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
total := secs + mins*60 + hours*60*60
|
||||||
|
|
||||||
|
log.Printf("h: %d m: %d s: %d, total: %d\n", hours, mins, secs, total)
|
||||||
|
|
||||||
file, handler, err := r.FormFile("myfile")
|
file, handler, err := r.FormFile("myfile")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println("Error getting file from form: ", err)
|
||||||
http.Error(w, "Could not get the file", http.StatusBadRequest)
|
http.Error(w, "Could not get the file", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
|
|
||||||
fmt.Fprintf(w, "Uploaded file: %s\n", handler.Filename)
|
dst, bare_name, err := createFile(storePath, handler.Filename)
|
||||||
fmt.Fprintf(w, "File size: %s\n", byteCountSI(handler.Size))
|
|
||||||
fmt.Fprintf(w, "Link: ")
|
|
||||||
|
|
||||||
dst, err := createFile(storePath, handler.Filename)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Could not save file", http.StatusInternalServerError)
|
http.Error(w, "Could not save file", http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
@ -128,13 +172,34 @@ func handleUpload(w http.ResponseWriter, r *http.Request) {
|
|||||||
if _, err := dst.ReadFrom(file); err != nil {
|
if _, err := dst.ReadFrom(file); err != nil {
|
||||||
http.Error(w, "Error saving file", http.StatusInternalServerError)
|
http.Error(w, "Error saving file", http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Fprintf(w, "Uploaded file: %s\n", handler.Filename)
|
||||||
|
fmt.Fprintf(w, "File size: %s\n", byteCountSI(handler.Size))
|
||||||
|
fmt.Fprintf(w, "Lifetime: %02d:%02d:%02d total %d\n", hours, mins, secs, total);
|
||||||
|
fmt.Fprintf(w, "Link: %s", fmt.Sprintf("%s/store/%s", listener.Addr().String(), bare_name))
|
||||||
|
|
||||||
|
cmd := exec.Command("./ltscleanerd", dst.Name(), strconv.FormatInt(total, 10))
|
||||||
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||||
|
Setsid: true,
|
||||||
|
}
|
||||||
|
log.Println("Started ", cmd.String())
|
||||||
|
err = cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Could not start cleaner daemon: ", err)
|
||||||
|
}
|
||||||
|
cleanersMutex.Lock()
|
||||||
|
cleaners[bare_name] = Cleaner{
|
||||||
|
Timeout: Timeout{ H: hours, M: mins, S: secs },
|
||||||
|
SpawnTime: time.Now().Unix(),
|
||||||
|
}
|
||||||
|
cleanersMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleHome(w http.ResponseWriter, r *http.Request) {
|
func handleHome(w http.ResponseWriter, r *http.Request) {
|
||||||
home_tmpl, _ := tmpls.ReadFile("tmpls/home.html")
|
home_tmpl, _ := tmpls.ReadFile("tmpls/home.html")
|
||||||
tmpl := template.Must(template.New("home").Parse(string(home_tmpl)))
|
tmpl := template.Must(template.New("home").Parse(string(home_tmpl)))
|
||||||
if err := tmpl.Execute(w, nil); err != nil {
|
if err := tmpl.Execute(w, nil); err != nil {
|
||||||
log.Println(err)
|
log.Println("Error executing template: ", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,6 +208,7 @@ type BrowseRecord struct {
|
|||||||
ReadableName string
|
ReadableName string
|
||||||
Perm string
|
Perm string
|
||||||
Modtime string
|
Modtime string
|
||||||
|
TimeLeft string
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleBrowse(w http.ResponseWriter, r *http.Request) {
|
func handleBrowse(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -151,7 +217,7 @@ func handleBrowse(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
storeEntries, err := os.ReadDir(storePath)
|
storeEntries, err := os.ReadDir(storePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Printf("Error reading store path %s %v\n", storePath, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,25 +232,35 @@ func handleBrowse(w http.ResponseWriter, r *http.Request) {
|
|||||||
info.ModTime().Day(), info.ModTime().Month().String(), info.ModTime().Year(),
|
info.ModTime().Day(), info.ModTime().Month().String(), info.ModTime().Year(),
|
||||||
info.ModTime().Hour(), info.ModTime().Minute(), info.ModTime().Second(),
|
info.ModTime().Hour(), info.ModTime().Minute(), info.ModTime().Second(),
|
||||||
)
|
)
|
||||||
|
cleanersMutex.Lock()
|
||||||
|
cleaner, _ := cleaners[e.Name()]
|
||||||
|
total := cleaner.Timeout.S + cleaner.Timeout.M*60 + cleaner.Timeout.H*60*60
|
||||||
|
now := time.Now().Unix()
|
||||||
|
timeleft_unix := time.Unix(cleaner.SpawnTime + total - now, 0)
|
||||||
|
cleanersMutex.Unlock()
|
||||||
|
timeleft := fmt.Sprintf("time left %02d:%02d:%02d",
|
||||||
|
timeleft_unix.Hour() - 1, timeleft_unix.Minute(), timeleft_unix.Second(),
|
||||||
|
)
|
||||||
|
|
||||||
records = append(records, BrowseRecord{
|
records = append(records, BrowseRecord{
|
||||||
FileName: filename,
|
FileName: filename,
|
||||||
ReadableName: readable_name,
|
ReadableName: readable_name,
|
||||||
Perm: info.Mode().Perm().String(),
|
Perm: info.Mode().Perm().String(),
|
||||||
Modtime: modtime,
|
Modtime: modtime,
|
||||||
|
TimeLeft: timeleft,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tmpl.Execute(w, records); err != nil {
|
if err := tmpl.Execute(w, records); err != nil {
|
||||||
log.Println(err)
|
log.Println("Error executing template: ", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func reloadAllowedUsers() {
|
func loadAllowedUsers() {
|
||||||
log.Println("loading ALLOWED_USERS.txt")
|
log.Println("loading ALLOWED_USERS.txt")
|
||||||
allowedUsersTxt, err := ioutil.ReadFile("./ALLOWED_USERS.txt")
|
allowedUsersTxt, err := ioutil.ReadFile("./ALLOWED_USERS.txt")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err)
|
log.Println("Error reading ALLOWED_USERS.txt: ", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
scanner := bufio.NewScanner(strings.NewReader(string(allowedUsersTxt)))
|
scanner := bufio.NewScanner(strings.NewReader(string(allowedUsersTxt)))
|
||||||
@ -197,47 +273,8 @@ func reloadAllowedUsers() {
|
|||||||
allowedUsersMutex.Unlock()
|
allowedUsersMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func watchAllowedUsers() chan bool {
|
|
||||||
watcher, err := fsnotify.NewWatcher()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
defer watcher.Close()
|
|
||||||
|
|
||||||
done := make(chan bool)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case event, ok := <-watcher.Events:
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if event.Has(fsnotify.Chmod | fsnotify.Rename) {
|
|
||||||
reloadAllowedUsers()
|
|
||||||
}
|
|
||||||
case err, ok := <-watcher.Errors:
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Println(err)
|
|
||||||
case <-done:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
err = watcher.Add("./ALLOWED_USERS.txt")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return done
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
reloadAllowedUsers()
|
loadAllowedUsers()
|
||||||
doneWatching := watchAllowedUsers()
|
|
||||||
|
|
||||||
http.HandleFunc("/", handleHome)
|
http.HandleFunc("/", handleHome)
|
||||||
http.HandleFunc("/browse", handleBrowse)
|
http.HandleFunc("/browse", handleBrowse)
|
||||||
@ -245,8 +282,16 @@ func main() {
|
|||||||
http.Handle("/etc/", http.FileServerFS(etc))
|
http.Handle("/etc/", http.FileServerFS(etc))
|
||||||
http.Handle("/store/", http.StripPrefix("/store/", http.FileServer(http.Dir(storePath))))
|
http.Handle("/store/", http.StripPrefix("/store/", http.FileServer(http.Dir(storePath))))
|
||||||
|
|
||||||
log.Printf("Listening on %s\n", LISTEN_PORT)
|
listener_tcp, err := net.Listen("tcp", LISTEN_ADDR)
|
||||||
http.ListenAndServe(LISTEN_PORT, nil)
|
if err != nil {
|
||||||
|
log.Fatal("Error starting server: ", err)
|
||||||
|
}
|
||||||
|
listener = listener_tcp
|
||||||
|
|
||||||
doneWatching<-true
|
log.Printf("Listening on %s\n", listener.Addr().String())
|
||||||
|
|
||||||
|
err = http.Serve(listener, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Error in serving: ", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
75
ltscleanerd.c
Normal file
75
ltscleanerd.c
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
//go:build exclude
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#define GEBS_NO_PREFIX
|
||||||
|
#define GEBS_IMPLEMENTATION
|
||||||
|
#include "gebs/gebs.h"
|
||||||
|
|
||||||
|
char *prog = nil;
|
||||||
|
char *file_path = nil;
|
||||||
|
|
||||||
|
void timer_handler(int sig, siginfo_t *si, void *uc)
|
||||||
|
{
|
||||||
|
if (file_path != nil) {
|
||||||
|
remove1(file_path);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void make_timer(char *name, long seconds)
|
||||||
|
{
|
||||||
|
struct sigevent timer_event;
|
||||||
|
struct itimerspec timer_spec;
|
||||||
|
struct sigaction action;
|
||||||
|
int sig_no = SIGRTMIN;
|
||||||
|
|
||||||
|
action.sa_flags = SA_SIGINFO;
|
||||||
|
action.sa_sigaction = &timer_handler;
|
||||||
|
sigemptyset(&action.sa_mask);
|
||||||
|
|
||||||
|
if (sigaction(sig_no, &action, nil) == -1) {
|
||||||
|
LOGE("Could not create timer signal handler\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
timer_event.sigev_notify = SIGEV_SIGNAL;
|
||||||
|
timer_event.sigev_signo = sig_no;
|
||||||
|
timer_event.sigev_value.sival_ptr = name;
|
||||||
|
|
||||||
|
timer_t timer_id;
|
||||||
|
if (timer_create(CLOCK_REALTIME, &timer_event, &timer_id) == -1) {
|
||||||
|
LOGE("Could not create timer\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&timer_spec, 0, sizeof(timer_spec));
|
||||||
|
timer_spec.it_value.tv_sec = seconds;
|
||||||
|
|
||||||
|
if (timer_settime(timer_id, 0, &timer_spec, nil) == -1) {
|
||||||
|
LOGE("Could not set the timeout\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char ** argv)
|
||||||
|
{
|
||||||
|
prog = SHIFT(&argc, &argv);
|
||||||
|
file_path = SHIFT(&argc, &argv);
|
||||||
|
char *timeout_string = SHIFT(&argc, &argv);
|
||||||
|
|
||||||
|
if (!exists1(file_path)) {
|
||||||
|
LOGI("Path %s does not exist\n", file_path);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *endp;
|
||||||
|
long timeout = strtol(timeout_string, &endp, 10);
|
||||||
|
|
||||||
|
make_timer("cleaner", timeout);
|
||||||
|
|
||||||
|
pause();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
9
scripts/update-release
Executable file
9
scripts/update-release
Executable file
@ -0,0 +1,9 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
systemctl stop lts.service
|
||||||
|
make clean
|
||||||
|
make -B BUILD_MODE=RELEASE
|
||||||
|
cp ./lts /usr/local/bin/lts
|
||||||
|
cp ./ltscleanerd /var/lib/lts
|
||||||
|
systemctl start lts.service
|
||||||
|
systemctl status lts.service
|
13
systemd/lts.service
Normal file
13
systemd/lts.service
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Lair Temporary Storage server
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
Restart=always
|
||||||
|
User=root
|
||||||
|
WorkingDirectory=/var/lib/lts
|
||||||
|
ExecStart=/usr/local/bin/lts
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -11,6 +11,7 @@
|
|||||||
<td><a href="/store/{{.FileName}}">{{.ReadableName}}</a></td>
|
<td><a href="/store/{{.FileName}}">{{.ReadableName}}</a></td>
|
||||||
<td><span>{{.Perm}}</span></td>
|
<td><span>{{.Perm}}</span></td>
|
||||||
<td><span>{{.Modtime}}</span></td>
|
<td><span>{{.Modtime}}</span></td>
|
||||||
|
<td><span>{{.TimeLeft}}</span></td>
|
||||||
</tr>
|
</tr>
|
||||||
{{end}}
|
{{end}}
|
||||||
</table>
|
</table>
|
||||||
|
@ -11,17 +11,25 @@
|
|||||||
<p>
|
<p>
|
||||||
Welcome to The Lair's temporary storage service. Use this service to transport files via
|
Welcome to The Lair's temporary storage service. Use this service to transport files via
|
||||||
a temporary remote storage. <br />
|
a temporary remote storage. <br />
|
||||||
ONLY WHITELISTED USERS can upload! For access, reach out to <a href="mailto:kamkow256@gmail.com">me</a>.<br />
|
ONLY WHITELISTED USERS can upload! For access, reach out to <a href="mailto:kamkow256@gmail.com">me</a>.
|
||||||
Only 30PLN / 12MON.
|
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
<section>
|
||||||
<h2>Upload</h2>
|
<h2>Upload</h2>
|
||||||
<p>
|
<p>
|
||||||
<form id="upload-form" method="POST" enctype="multipart/form-data">
|
<form id="upload-form" method="POST" enctype="multipart/form-data">
|
||||||
|
<label for="myfile">File:</label>
|
||||||
<input type="file" name="myfile" id="myfile" required />
|
<input type="file" name="myfile" id="myfile" required />
|
||||||
|
<label for="user">User:</label>
|
||||||
<input type="text" name="user" id="user" required />
|
<input type="text" name="user" id="user" required />
|
||||||
|
<label for="pass">Password:</label>
|
||||||
<input type="password" name="pass", id="pass" required />
|
<input type="password" name="pass", id="pass" required />
|
||||||
|
<label for="hours">Hours:</label>
|
||||||
|
<input type="number" name="hours" id="hours" min="0" max="24" step="1" value="0" required />
|
||||||
|
<label for="mins">Minutes:</label>
|
||||||
|
<input type="number" name="mins" id="mins" min="0" max="60" step="1" value="0" required />
|
||||||
|
<label for="secs">Seconds:</label>
|
||||||
|
<input type="number" name="secs" id="secs" min="0" max="60" step="1" value="0" required />
|
||||||
<input type="submit" value="Upload" />
|
<input type="submit" value="Upload" />
|
||||||
</form>
|
</form>
|
||||||
</p>
|
</p>
|
||||||
@ -44,8 +52,15 @@ upload_form.addEventListener("submit", async function (event) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hours = document.getElementById("hours").value;
|
||||||
|
const mins = document.getElementById("mins").value;
|
||||||
|
const secs = document.getElementById("secs").value;
|
||||||
|
|
||||||
const form_data = new FormData();
|
const form_data = new FormData();
|
||||||
form_data.append("myfile", file);
|
form_data.append("myfile", file);
|
||||||
|
form_data.append("hours", hours);
|
||||||
|
form_data.append("mins", mins);
|
||||||
|
form_data.append("secs", secs);
|
||||||
|
|
||||||
const user = document.getElementById("user").value;
|
const user = document.getElementById("user").value;
|
||||||
const pass = document.getElementById("pass").value;
|
const pass = document.getElementById("pass").value;
|
||||||
|
Reference in New Issue
Block a user