Compare commits
10 Commits
5578822c3f
...
master
Author | SHA1 | Date | |
---|---|---|---|
571ffca339 | |||
9b0d448698 | |||
35958f2ade | |||
71fed69dd7 | |||
339d8ed9a7 | |||
0f317edb28 | |||
d4906360e1 | |||
df6d009ce7 | |||
cd29f363fa | |||
110a7387b5 |
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -1,3 +1,3 @@
|
||||
[submodule "gebs"]
|
||||
path = gebs
|
||||
url = http://git.kamkow1lair/kamkow1/gebs.git
|
||||
url = http://git.kamkow1lair.pl/kamkow1/gebs.git
|
||||
|
5
Makefile
5
Makefile
@ -3,7 +3,7 @@ BUILD_MODE ?= DEBUG
|
||||
ifeq ($(BUILD_MODE),DEBUG)
|
||||
LISTEN_ADDR = "localhost:9090"
|
||||
else ifeq ($(BUILD_MODE),RELEASE)
|
||||
LISTEN_ADDR = "0.0.0.0:80"
|
||||
LISTEN_ADDR = "0.0.0.0:4000"
|
||||
else
|
||||
$(error Unknown build mode)
|
||||
endif
|
||||
@ -21,7 +21,8 @@ watcher: watcher.c
|
||||
|
||||
clean:
|
||||
go clean
|
||||
rm watcher
|
||||
rm -f watcher
|
||||
rm -f ltscleanerd
|
||||
|
||||
watch: all
|
||||
./watcher . sh -c "make BUILD_MODE=$(BUILD_MODE) && ./lts"
|
||||
|
5
go.mod
5
go.mod
@ -1,8 +1,3 @@
|
||||
module lts
|
||||
|
||||
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=
|
||||
|
100
lts.go
100
lts.go
@ -16,8 +16,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
var LISTEN_ADDR string
|
||||
@ -30,22 +30,23 @@ var tmpls embed.FS
|
||||
//go:embed etc/*
|
||||
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) {
|
||||
os.Mkdir(storePath, 0755)
|
||||
}
|
||||
|
||||
uuidBytes, err := NewV4()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, "", err
|
||||
}
|
||||
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 {
|
||||
return nil, err
|
||||
return nil, bare_name, err
|
||||
}
|
||||
return dst, nil
|
||||
return dst, bare_name, nil
|
||||
}
|
||||
|
||||
type AllowedUser struct {
|
||||
@ -107,6 +108,20 @@ func byteCountSI(b int64) string {
|
||||
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) {
|
||||
limit := int64(10737418240) // 10GiB
|
||||
r.ParseMultipartForm(limit)
|
||||
@ -147,7 +162,7 @@ func handleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
dst, err := createFile(storePath, handler.Filename)
|
||||
dst, bare_name, err := createFile(storePath, handler.Filename)
|
||||
if err != nil {
|
||||
http.Error(w, "Could not save file", http.StatusInternalServerError)
|
||||
return
|
||||
@ -161,18 +176,23 @@ func handleUpload(w http.ResponseWriter, r *http.Request) {
|
||||
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/%s", listener.Addr().String(), dst.Name()))
|
||||
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)
|
||||
}
|
||||
err = cmd.Process.Release()
|
||||
if err != nil {
|
||||
log.Fatal("Could not detach from 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) {
|
||||
@ -188,6 +208,7 @@ type BrowseRecord struct {
|
||||
ReadableName string
|
||||
Perm string
|
||||
Modtime string
|
||||
TimeLeft string
|
||||
}
|
||||
|
||||
func handleBrowse(w http.ResponseWriter, r *http.Request) {
|
||||
@ -211,12 +232,22 @@ func handleBrowse(w http.ResponseWriter, r *http.Request) {
|
||||
info.ModTime().Day(), info.ModTime().Month().String(), info.ModTime().Year(),
|
||||
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{
|
||||
FileName: filename,
|
||||
ReadableName: readable_name,
|
||||
Perm: info.Mode().Perm().String(),
|
||||
Modtime: modtime,
|
||||
TimeLeft: timeleft,
|
||||
})
|
||||
}
|
||||
|
||||
@ -225,7 +256,7 @@ func handleBrowse(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func reloadAllowedUsers() {
|
||||
func loadAllowedUsers() {
|
||||
log.Println("loading ALLOWED_USERS.txt")
|
||||
allowedUsersTxt, err := ioutil.ReadFile("./ALLOWED_USERS.txt")
|
||||
if err != nil {
|
||||
@ -242,47 +273,8 @@ func reloadAllowedUsers() {
|
||||
allowedUsersMutex.Unlock()
|
||||
}
|
||||
|
||||
func watchAllowedUsers() chan bool {
|
||||
watcher, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
log.Fatal("Error creating new watcher: ", 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("Watcher error: ", err)
|
||||
case <-done:
|
||||
break
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
err = watcher.Add("./ALLOWED_USERS.txt")
|
||||
if err != nil {
|
||||
log.Fatal("Error adding ALLOWED_USERS.txt to watcher: ", err)
|
||||
}
|
||||
|
||||
return done
|
||||
}
|
||||
|
||||
func main() {
|
||||
reloadAllowedUsers()
|
||||
doneWatching := watchAllowedUsers()
|
||||
loadAllowedUsers()
|
||||
|
||||
http.HandleFunc("/", handleHome)
|
||||
http.HandleFunc("/browse", handleBrowse)
|
||||
@ -302,6 +294,4 @@ func main() {
|
||||
if err != nil {
|
||||
log.Fatal("Error in serving: ", err)
|
||||
}
|
||||
|
||||
doneWatching<-true
|
||||
}
|
||||
|
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><span>{{.Perm}}</span></td>
|
||||
<td><span>{{.Modtime}}</span></td>
|
||||
<td><span>{{.TimeLeft}}</span></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
|
@ -11,19 +11,24 @@
|
||||
<p>
|
||||
Welcome to The Lair's temporary storage service. Use this service to transport files via
|
||||
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 30PLN / 12MON.
|
||||
ONLY WHITELISTED USERS can upload! For access, reach out to <a href="mailto:kamkow256@gmail.com">me</a>.
|
||||
</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Upload</h2>
|
||||
<p>
|
||||
<form id="upload-form" method="POST" enctype="multipart/form-data">
|
||||
<label for="myfile">File:</label>
|
||||
<input type="file" name="myfile" id="myfile" required />
|
||||
<label for="user">User:</label>
|
||||
<input type="text" name="user" id="user" required />
|
||||
<label for="pass">Password:</label>
|
||||
<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" />
|
||||
</form>
|
||||
|
Reference in New Issue
Block a user