From 283c31564a9d5dab4b8b71d7498886b0cd20a999 Mon Sep 17 00:00:00 2001 From: Jan Wolff Date: Fri, 12 Sep 2025 09:34:01 +0200 Subject: initial commit --- controller/app.go | 39 +++++++++++++++++++ controller/controller.go | 8 ++++ controller/file.go | 79 +++++++++++++++++++++++++++++++++++++++ controller/index.go | 13 +++++++ controller/template/404.html | 7 ++++ controller/template/base.html | 49 ++++++++++++++++++++++++ controller/template/index.html | 28 ++++++++++++++ controller/template/uploaded.html | 10 +++++ 8 files changed, 233 insertions(+) create mode 100644 controller/app.go create mode 100644 controller/controller.go create mode 100644 controller/file.go create mode 100644 controller/index.go create mode 100644 controller/template/404.html create mode 100644 controller/template/base.html create mode 100644 controller/template/index.html create mode 100644 controller/template/uploaded.html (limited to 'controller') diff --git a/controller/app.go b/controller/app.go new file mode 100644 index 0000000..f145ce2 --- /dev/null +++ b/controller/app.go @@ -0,0 +1,39 @@ +package controller + +import ( + "embed" + "html/template" + "net/http" + + "drop.janw.name/config" + "drop.janw.name/storage" +) + +//go:embed template/* +var templateFs embed.FS + +type App struct { + storage *storage.Storage + tmpl *template.Template + config config.Configuration +} + +func NewApp(configFilename string) *App { + return &App{ + storage: storage.NewStorage(), + tmpl: template.Must(template.ParseFS(templateFs, "template/*.html")), + config: config.Must(config.Open(configFilename)), + } +} + +func (app App) requireAuth(res http.ResponseWriter, req *http.Request) bool { + username, password, ok := req.BasicAuth() + if ok && username == app.config.Authentication.Username && password == app.config.Authentication.Password { + return true + } + + res.Header().Add("WWW-Authenticate", "Basic realm=\"Authentication Required\", charset=\"UTF-8\"") + res.WriteHeader(http.StatusUnauthorized) + + return false +} diff --git a/controller/controller.go b/controller/controller.go new file mode 100644 index 0000000..1f28562 --- /dev/null +++ b/controller/controller.go @@ -0,0 +1,8 @@ +package controller + +import "net/http" + +type Controller struct { + GET http.HandlerFunc + POST http.HandlerFunc +} diff --git a/controller/file.go b/controller/file.go new file mode 100644 index 0000000..53121d5 --- /dev/null +++ b/controller/file.go @@ -0,0 +1,79 @@ +package controller + +import ( + "fmt" + "io" + "net/http" + "time" + + "drop.janw.name/storage" +) + +const MAX_FILESIZE = (1 << 19) * 100 + +func (app App) FilePost(res http.ResponseWriter, req *http.Request) { + if !app.requireAuth(res, req) { + return + } + + if err := req.ParseMultipartForm(MAX_FILESIZE); err != nil { + panic(err) + } + + formFile, formFileHeader, err := req.FormFile("file") + if err != nil { + panic(err) + } + + protected := req.FormValue("protect") == "on" + + fileData, err := io.ReadAll(formFile) + if err != nil { + panic(err) + } + + file := storage.File{ + Protected: protected, + Filename: formFileHeader.Filename, + Data: fileData, + AvailableUntil: time.Now().Add(time.Hour * 2), + } + + key, err := app.storage.Put(file) + if err != nil { + panic(err) + } + + app.tmpl.ExecuteTemplate(res, "uploaded", struct { + DownloadURL string + }{ + DownloadURL: fmt.Sprintf("%s/%s", app.config.Http.BaseAddress, key), + }) +} + +func (app App) FileGet(res http.ResponseWriter, req *http.Request) { + fileId := req.PathValue("file") + + file, _ := app.storage.Get(fileId) + + if file == nil || !file.IsAvailable() { + if !app.requireAuth(res, req) { + return + } + + res.WriteHeader(http.StatusNotFound) + app.tmpl.ExecuteTemplate(res, "404", nil) + return + } + + if file.Protected && !app.requireAuth(res, req) { + return + } + + res.Header().Add("Content-Type", "application/octet-stream") + res.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", file.Filename)) + + if _, err := res.Write(file.Data); err != nil { + panic(err) + } +} diff --git a/controller/index.go b/controller/index.go new file mode 100644 index 0000000..6f927ed --- /dev/null +++ b/controller/index.go @@ -0,0 +1,13 @@ +package controller + +import ( + "net/http" +) + +func (app App) Index(res http.ResponseWriter, req *http.Request) { + if !app.requireAuth(res, req) { + return + } + + app.tmpl.ExecuteTemplate(res, "index", nil) +} diff --git a/controller/template/404.html b/controller/template/404.html new file mode 100644 index 0000000..fa19547 --- /dev/null +++ b/controller/template/404.html @@ -0,0 +1,7 @@ +{{define "404"}} +{{template "header" .}} +
+

no such file

+
+{{template "footer" .}} +{{end}} diff --git a/controller/template/base.html b/controller/template/base.html new file mode 100644 index 0000000..c91245d --- /dev/null +++ b/controller/template/base.html @@ -0,0 +1,49 @@ +{{define "header"}} + + + + drop.janw.name + + + + + + + +{{end}} + +{{define "footer"}} + + +{{end}} diff --git a/controller/template/index.html b/controller/template/index.html new file mode 100644 index 0000000..f50be97 --- /dev/null +++ b/controller/template/index.html @@ -0,0 +1,28 @@ +{{define "index"}} +{{template "header" .}} +
+

drop.janw.name

+
+
+ + +
+
+ + +
+
+ + +
+ +
+
+{{template "footer" .}} +{{end}} diff --git a/controller/template/uploaded.html b/controller/template/uploaded.html new file mode 100644 index 0000000..1324082 --- /dev/null +++ b/controller/template/uploaded.html @@ -0,0 +1,10 @@ +{{define "uploaded"}} +{{template "header" .}} +
+

File uploaded successfully

+

+ {{.DownloadURL}} +

+
+{{template "footer" .}} +{{end}} -- cgit v1.2.3