Handlers.
This commit is contained in:
parent
473b23cbb0
commit
264e403882
191
internal/handlers/handlers.go
Normal file
191
internal/handlers/handlers.go
Normal file
@ -0,0 +1,191 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"dwelling-upload/internal/configuration"
|
||||
"dwelling-upload/pkg/server"
|
||||
"dwelling-upload/pkg/utils"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/eknkc/amber"
|
||||
)
|
||||
|
||||
var defaultAmberOptions = amber.Options{PrettyPrint: false, LineNumbers: false}
|
||||
|
||||
var compiledTemplates map[string]*template.Template
|
||||
|
||||
type IndexData struct {
|
||||
MainSite string
|
||||
FileMaxSz string
|
||||
StorageCapacity int64
|
||||
StorageUsed int64
|
||||
StorageAvailable int64
|
||||
StorageCapStr string
|
||||
StorageUsedStr string
|
||||
StorageAvailStr string
|
||||
}
|
||||
|
||||
type UploadedData struct {
|
||||
MainSite string
|
||||
DownloadURL string
|
||||
KeepForHours int
|
||||
}
|
||||
|
||||
type UploadHandlers struct {
|
||||
conf *configuration.Configuration
|
||||
}
|
||||
|
||||
func NewUploadHandlers(conf *configuration.Configuration) *UploadHandlers {
|
||||
compiledTemplates = amber.MustCompileDir(conf.WebDir+"/templates",
|
||||
amber.DefaultDirOptions, defaultAmberOptions)
|
||||
return &UploadHandlers{
|
||||
conf: conf}
|
||||
}
|
||||
|
||||
func (h *UploadHandlers) Index(w http.ResponseWriter, r *http.Request) {
|
||||
var storCapacity int64 = h.conf.Uploads.Limits.Storage << 20
|
||||
var fMaxSize int64 = h.conf.Uploads.Limits.FileSize << 20
|
||||
var storSize int64 = 0
|
||||
|
||||
filepath.Walk(h.conf.Uploads.Directory, func(_ string, info fs.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
storSize += info.Size()
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
_, _, capStr := utils.ConvertFileSize(storCapacity)
|
||||
_, _, usedStr := utils.ConvertFileSize(storSize)
|
||||
_, _, availStr := utils.ConvertFileSize(storCapacity - storSize)
|
||||
_, _, fMaxSzStr := utils.ConvertFileSize(fMaxSize)
|
||||
|
||||
if err := compiledTemplates["index"].Execute(w, &IndexData{
|
||||
MainSite: utils.MainSite(r.Host),
|
||||
FileMaxSz: fMaxSzStr,
|
||||
StorageCapacity: storCapacity,
|
||||
StorageCapStr: capStr,
|
||||
StorageAvailable: storCapacity - storSize,
|
||||
StorageAvailStr: availStr,
|
||||
StorageUsed: storSize,
|
||||
StorageUsedStr: usedStr,
|
||||
}); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
log.Fatalln("failed to execute Index template:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *UploadHandlers) Upload(w http.ResponseWriter, r *http.Request) {
|
||||
var fMaxSizeBytes int64 = h.conf.Uploads.Limits.FileSize << 20
|
||||
|
||||
r.Body = http.MaxBytesReader(w, r.Body, fMaxSizeBytes)
|
||||
|
||||
if err := r.ParseMultipartForm(fMaxSizeBytes); err != nil {
|
||||
log.Println("failed to parse form:", err)
|
||||
http.Error(w, "request too big", http.StatusExpectationFailed)
|
||||
return
|
||||
}
|
||||
|
||||
f, fHandler, err := r.FormFile("file")
|
||||
if err != nil {
|
||||
log.Println("failed to open incoming file:", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
os.Remove(fHandler.Filename)
|
||||
f.Close()
|
||||
}()
|
||||
|
||||
s256 := sha256.New()
|
||||
if _, err := io.Copy(s256, f); err != nil {
|
||||
log.Println("failed to compute SHA-256 hash:", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
fSha256 := hex.EncodeToString(s256.Sum(nil))
|
||||
s256.Write([]byte(h.conf.HashSalt))
|
||||
fSaltedHash := base64.RawURLEncoding.EncodeToString(s256.Sum(nil))
|
||||
|
||||
f.Seek(0, io.SeekStart)
|
||||
|
||||
fPath := path.Join(h.conf.Uploads.Directory, fSaltedHash)
|
||||
|
||||
_, err = os.Stat(fPath)
|
||||
if os.IsNotExist(err) {
|
||||
fDst, err := os.Create(fPath)
|
||||
if err != nil {
|
||||
log.Println("failed to open file for writing", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
n, err := io.Copy(fDst, f)
|
||||
if err != nil {
|
||||
log.Println("failed to copy uploaded file to destination:", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
fmt.Println(n, err)
|
||||
fDst.Sync()
|
||||
fDst.Close()
|
||||
|
||||
log.Printf("| %s | %s | %s | SHA256 %s | %s | %d", r.RemoteAddr, utils.NetworkType(r.Host),
|
||||
fHandler.Filename, fSha256, fSaltedHash, fHandler.Size)
|
||||
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
} else {
|
||||
os.Chtimes(fPath, time.Now(), time.Now())
|
||||
}
|
||||
|
||||
downloadURL := path.Join("/f", fSaltedHash, fHandler.Filename)
|
||||
|
||||
if err := compiledTemplates["uploaded"].Execute(w, &UploadedData{
|
||||
MainSite: utils.MainSite(r.Host),
|
||||
DownloadURL: downloadURL,
|
||||
KeepForHours: h.conf.Uploads.Limits.KeepForHours,
|
||||
}); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
log.Fatalln("failed to execute Index template:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *UploadHandlers) Download(w http.ResponseWriter, r *http.Request) {
|
||||
saltedHash := server.GetURLParam(r, "hash")
|
||||
name := server.GetURLParam(r, "name")
|
||||
|
||||
path := path.Join(h.conf.Uploads.Directory, saltedHash)
|
||||
|
||||
stat, err := os.Stat(path)
|
||||
if os.IsNotExist(err) {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Add("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", name))
|
||||
// w.Header().Add("Content-Type", "application/octet-stream")
|
||||
|
||||
fd, err := os.Open(path)
|
||||
if err != nil {
|
||||
log.Println("failed to open file to read:", err)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer fd.Close()
|
||||
|
||||
http.ServeContent(w, r, path, stat.ModTime(), fd)
|
||||
}
|
Loading…
Reference in New Issue
Block a user