diff --git a/README.md b/README.md
index a9c63d3..9a9023c 100644
--- a/README.md
+++ b/README.md
@@ -11,9 +11,10 @@ Simple standalone file upload server with api and cli
that is: do remove the file when it expires but not the associated
db entry.
- also serve a html upload page
-- add api version in path
- add auth options (access key, users, roles, oauth2)
- add metrics
- add upctl command to remove a file
- upd: add short uuid to files, in case multiple files with the same
name are being uploaded
+- use global map of api endpoints like /file/get/ etc
+- use separate group for /file/
diff --git a/upctl/lib/client.go b/upctl/lib/client.go
index c05bb9e..b0bf3df 100644
--- a/upctl/lib/client.go
+++ b/upctl/lib/client.go
@@ -34,6 +34,8 @@ type Response struct {
Message string `json:"message"`
}
+const ApiVersion string = "/v1"
+
func Runclient(c *cfg.Config, args []string) error {
client := req.C()
if c.Debug {
@@ -42,7 +44,7 @@ func Runclient(c *cfg.Config, args []string) error {
client.SetUserAgent("upctl-" + cfg.VERSION)
- url := c.Endpoint + "/putfile"
+ url := c.Endpoint + ApiVersion + "/file/put"
rq := client.R()
for _, file := range args {
diff --git a/upd/api/api.go b/upd/api/api.go
new file mode 100644
index 0000000..029907e
--- /dev/null
+++ b/upd/api/api.go
@@ -0,0 +1,63 @@
+/*
+Copyright © 2023 Thomas von Dein
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+package api
+
+import (
+ "fmt"
+ "regexp"
+ "time"
+)
+
+const ApiVersion string = "/v1"
+
+// used to return to the api client
+type Result struct {
+ Success bool
+ Message string
+ Code int
+}
+
+// Binding from JSON, data coming from user, not tainted
+type Meta struct {
+ Expire string `json:"expire" form:"expire"`
+}
+
+// stores 1 upload object, gets into db
+type Upload struct {
+ Id string `json:"id"`
+ Expire string `json:"expire"`
+ File string `json:"file"` // final filename (visible to the downloader)
+ Members []string `json:"members"` // contains multiple files, so File is an archive
+ Uploaded time.Time `json:"uploaded"`
+}
+
+// vaious helbers
+func Log(format string, values ...any) {
+ fmt.Printf("[DEBUG] "+format+"\n", values...)
+}
+
+func Ts() string {
+ t := time.Now()
+ return t.Format("2006-01-02-15-04-")
+}
+
+func NormalizeFilename(file string) string {
+ r := regexp.MustCompile(`[^\w\d\-_\\.]`)
+
+ return Ts() + r.ReplaceAllString(file, "")
+}
diff --git a/upd/api/fileio.go b/upd/api/fileio.go
new file mode 100644
index 0000000..b3eb1a5
--- /dev/null
+++ b/upd/api/fileio.go
@@ -0,0 +1,114 @@
+/*
+Copyright © 2023 Thomas von Dein
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+package api
+
+import (
+ "archive/zip"
+ "io"
+ "os"
+ "path/filepath"
+ "sync"
+)
+
+// cleanup an upload directory, either because we got an error in the
+// middle of an upload or something else went wrong. we fork off a go
+// routine because this may block.
+func cleanup(dir string) {
+ go func() {
+ err := os.RemoveAll(dir)
+ if err != nil {
+ Log("Failed to remove dir %s: %s", dir, err.Error())
+ }
+ }()
+}
+
+func ZipSource(source, target string) error {
+ // 1. Create a ZIP file and zip.Writer
+ // source must be an absolute path, target a zip file
+ f, err := os.Create(target)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ writer := zip.NewWriter(f)
+ defer writer.Close()
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+
+ // don't chdir the server itself
+ go func() {
+ defer wg.Done()
+
+ os.Chdir(source)
+ newDir, err := os.Getwd()
+ if err != nil {
+ }
+ //Log("Current Working Direcotry: %s\n, source: %s", newDir, source)
+
+ err = filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
+ // 2. Go through all the files of the source
+ if err != nil {
+ return err
+ }
+
+ // 3. Create a local file header
+ header, err := zip.FileInfoHeader(info)
+ if err != nil {
+ return err
+ }
+
+ // set compression
+ header.Method = zip.Deflate
+
+ // 4. Set relative path of a file as the header name
+ header.Name = path
+ //Log("a: <%s>, b: <%s>, rel: <%s>", filepath.Dir(source), path, header.Name)
+ if err != nil {
+ return err
+ }
+ if info.IsDir() {
+ header.Name += "/"
+ }
+
+ // 5. Create writer for the file header and save content of the file
+ headerWriter, err := writer.CreateHeader(header)
+ if err != nil {
+ return err
+ }
+
+ if info.IsDir() {
+ return nil
+ }
+
+ f, err := os.Open(path)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ _, err = io.Copy(headerWriter, f)
+ return err
+ })
+ }()
+
+ wg.Wait()
+
+ return err
+}
diff --git a/upd/lib/handlers.go b/upd/api/handlers.go
similarity index 86%
rename from upd/lib/handlers.go
rename to upd/api/handlers.go
index 951e8b6..ebbf08e 100644
--- a/upd/lib/handlers.go
+++ b/upd/api/handlers.go
@@ -15,14 +15,15 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
-package lib
+package api
import (
//"archive/zip"
"fmt"
- "github.com/gin-gonic/gin"
+ //"github.com/gin-gonic/gin"
//"github.com/gin-gonic/gin/binding"
"encoding/json"
+ "github.com/gofiber/fiber/v2"
"github.com/google/uuid"
"github.com/tlinden/up/upd/cfg"
bolt "go.etcd.io/bbolt"
@@ -35,7 +36,7 @@ import (
"time"
)
-func Putfile(c *gin.Context, cfg *cfg.Config, db *bolt.DB) (string, error) {
+func Putfile(c *fiber.Ctx, cfg *cfg.Config, db *bolt.DB) (string, error) {
// supports upload of multiple files with:
//
// curl -X POST localhost:8080/putfile \
@@ -57,7 +58,11 @@ func Putfile(c *gin.Context, cfg *cfg.Config, db *bolt.DB) (string, error) {
os.MkdirAll(filepath.Join(cfg.StorageDir, id), os.ModePerm)
// fetch auxiliary form data
- form, _ := c.MultipartForm()
+ form, err := c.MultipartForm()
+ if err != nil {
+ Log("multipart error %s", err.Error())
+ return "", err
+ }
entry := &Upload{Id: id, Uploaded: time.Now()}
@@ -71,15 +76,17 @@ func Putfile(c *gin.Context, cfg *cfg.Config, db *bolt.DB) (string, error) {
entry.Members = append(entry.Members, filename)
Log("Received: %s => %s/%s", file.Filename, id, filename)
- if err := c.SaveUploadedFile(file, path); err != nil {
+ if err := c.SaveFile(file, path); err != nil {
cleanup(filepath.Join(cfg.StorageDir, id))
return "", err
}
}
- if err := c.ShouldBind(&formdata); err != nil {
+ if err := c.BodyParser(&formdata); err != nil {
+ Log("bodyparser error %s", err.Error())
return "", err
}
+
if len(formdata.Expire) == 0 {
entry.Expire = "asap"
} else {
@@ -95,8 +102,9 @@ func Putfile(c *gin.Context, cfg *cfg.Config, db *bolt.DB) (string, error) {
finalzip := filepath.Join(cfg.StorageDir, id, zipfile)
iddir := filepath.Join(cfg.StorageDir, id)
- if err := zipSource(iddir, tmpzip); err != nil {
+ if err := ZipSource(iddir, tmpzip); err != nil {
cleanup(iddir)
+ Log("zip error")
return "", err
}
@@ -105,7 +113,7 @@ func Putfile(c *gin.Context, cfg *cfg.Config, db *bolt.DB) (string, error) {
return "", err
}
- returnUrl = strings.Join([]string{cfg.Url + cfg.ApiPrefix, "getfile", id, zipfile}, "/")
+ returnUrl = strings.Join([]string{cfg.Url + cfg.ApiPrefix + ApiVersion, "file/get", id, zipfile}, "/")
entry.File = zipfile
// clean up after us
diff --git a/upd/api/server.go b/upd/api/server.go
new file mode 100644
index 0000000..c0d4799
--- /dev/null
+++ b/upd/api/server.go
@@ -0,0 +1,93 @@
+/*
+Copyright © 2023 Thomas von Dein
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see .
+*/
+
+package api
+
+import (
+ "github.com/gofiber/fiber/v2"
+ "github.com/gofiber/fiber/v2/middleware/logger"
+ "github.com/gofiber/fiber/v2/middleware/requestid"
+ "github.com/tlinden/up/upd/cfg"
+ bolt "go.etcd.io/bbolt"
+ "os"
+ "path/filepath"
+ "time"
+)
+
+func Runserver(cfg *cfg.Config, args []string) error {
+ dst := cfg.StorageDir
+ router := fiber.New()
+ router.Use(requestid.New())
+ router.Use(logger.New(logger.Config{
+ // For more options, see the Config section
+ Format: "${pid} ${locals:requestid} ${status} - ${method} ${path}\n",
+ }))
+ api := router.Group(cfg.ApiPrefix + ApiVersion)
+
+ db, err := bolt.Open(cfg.DbFile, 0600, nil)
+ if err != nil {
+ return err
+ }
+ defer db.Close()
+
+ {
+ api.Post("/file/put", func(c *fiber.Ctx) error {
+ uri, err := Putfile(c, cfg, db)
+
+ if err != nil {
+ return c.Status(fiber.StatusBadRequest).JSON(Result{
+ Code: fiber.StatusBadRequest,
+ Message: err.Error(),
+ Success: false,
+ })
+ } else {
+ return c.Status(fiber.StatusOK).JSON(Result{
+ Code: fiber.StatusOK,
+ Message: uri,
+ Success: true,
+ })
+ }
+ })
+
+ api.Get("/file/get/:id/:file", func(c *fiber.Ctx) error {
+ // deliver a file and delete it after a delay (FIXME: check
+ // when gin has done delivering it?). Redirect to the static
+ // handler for actual delivery.
+ id := c.Params("id")
+ file := c.Params("file")
+
+ filename := filepath.Join(dst, id, file)
+
+ if _, err := os.Stat(filename); err == nil {
+ go func() {
+ time.Sleep(500 * time.Millisecond)
+ cleanup(filepath.Join(dst, id))
+ }()
+ }
+
+ return c.Download(filename, file)
+ })
+ }
+
+ router.Get("/", func(c *fiber.Ctx) error {
+ return c.Send([]byte("welcome to upload api, use /api enpoint!"))
+ })
+
+ router.Listen(cfg.Listen)
+
+ return nil
+}
diff --git a/upd/cmd/root.go b/upd/cmd/root.go
index 033a13a..2913e88 100644
--- a/upd/cmd/root.go
+++ b/upd/cmd/root.go
@@ -22,8 +22,8 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/spf13/viper"
+ "github.com/tlinden/up/upd/api"
"github.com/tlinden/up/upd/cfg"
- "github.com/tlinden/up/upd/lib"
"os"
"strings"
)
@@ -71,7 +71,7 @@ func Execute() {
conf.ApplyDefaults()
// actual execution starts here
- return lib.Runserver(&conf, args)
+ return api.Runserver(&conf, args)
},
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
return initConfig(cmd)
diff --git a/upd/go.mod b/upd/go.mod
index 5b05b91..69170e0 100644
--- a/upd/go.mod
+++ b/upd/go.mod
@@ -11,27 +11,40 @@ require (
)
require (
+ github.com/andybalholm/brotli v1.0.4 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.0 // indirect
github.com/go-playground/universal-translator v0.18.0 // indirect
github.com/go-playground/validator/v10 v10.11.1 // indirect
github.com/goccy/go-json v0.9.11 // indirect
+ github.com/gofiber/fiber/v2 v2.42.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/json-iterator/go v1.1.12 // indirect
+ github.com/klauspost/compress v1.15.9 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
github.com/magiconair/properties v1.8.7 // indirect
- github.com/mattn/go-isatty v0.0.16 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.17 // indirect
+ github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
+ github.com/philhofer/fwd v1.1.1 // indirect
+ github.com/rivo/uniseg v0.2.0 // indirect
+ github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect
+ github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d // indirect
github.com/spf13/afero v1.9.3 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
+ github.com/tinylib/msgp v1.1.6 // indirect
github.com/ugorji/go/codec v1.2.7 // indirect
+ github.com/valyala/bytebufferpool v1.0.0 // indirect
+ github.com/valyala/fasthttp v1.44.0 // indirect
+ github.com/valyala/tcplisten v1.0.0 // indirect
go.etcd.io/bbolt v1.3.7 // indirect
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
golang.org/x/net v0.4.0 // indirect
diff --git a/upd/go.sum b/upd/go.sum
index 8af145c..9252124 100644
--- a/upd/go.sum
+++ b/upd/go.sum
@@ -38,6 +38,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY=
+github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
@@ -77,6 +79,8 @@ github.com/go-playground/validator/v10 v10.11.1 h1:prmOlTVv+YjZjmRmNSF3VmspqJIxJ
github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk=
github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
+github.com/gofiber/fiber/v2 v2.42.0 h1:Fnp7ybWvS+sjNQsFvkhf4G8OhXswvB6Vee8hM/LyS+8=
+github.com/gofiber/fiber/v2 v2.42.0/go.mod h1:3+SGNjqMh5VQH5Vz2Wdi43zTIV16ktlFd3x3R6O1Zlc=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -150,6 +154,8 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.15.9 h1:wKRjX6JRtDdrE9qwa4b/Cip7ACOshUI4smpCQanqjSY=
+github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@@ -163,8 +169,14 @@ github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
+github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
+github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -174,17 +186,25 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
+github.com/philhofer/fwd v1.1.1 h1:GdGcTjf5RNAxwS4QLsiMzJYj5KEvPJD3Abr261yRQXQ=
+github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4=
+github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8=
+github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d h1:Q+gqLBOPkFGHyCJxXMRqtUgUbTjI8/Ze8vu8GGyNFwo=
+github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4=
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
@@ -212,9 +232,17 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
+github.com/tinylib/msgp v1.1.6 h1:i+SbKraHhnrf9M5MYmvQhFnbLhAXSDWF8WWsuyRdocw=
+github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
+github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
+github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/valyala/fasthttp v1.44.0 h1:R+gLUhldIsfg1HokMuQjdQ5bh9nuXHPIfvkYUu9eR5Q=
+github.com/valyala/fasthttp v1.44.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seBFc2uWtgiY=
+github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
+github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -235,6 +263,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -302,6 +331,7 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -359,6 +389,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ=
@@ -366,6 +397,7 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -420,6 +452,7 @@ golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
+golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
diff --git a/upd/lib/server.go b/upd/lib/server.go
deleted file mode 100644
index 44945b8..0000000
--- a/upd/lib/server.go
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
-Copyright © 2023 Thomas von Dein
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program. If not, see .
-*/
-
-package lib
-
-import (
- "archive/zip"
- "fmt"
- "github.com/gin-gonic/gin"
- //"github.com/gin-gonic/gin/binding"
- //"encoding/json"
- //"github.com/google/uuid"
- "github.com/tlinden/up/upd/cfg"
- bolt "go.etcd.io/bbolt"
- "io"
- "net/http"
- "os"
- "path/filepath"
- "regexp"
- //"strings"
- "time"
-)
-
-type Result struct {
- success bool
- url string
- error string
-}
-
-// Binding from JSON, data coming from user, not tainted
-type Meta struct {
- Expire string `form:"expire"`
-}
-
-// stores 1 upload object, gets into db
-type Upload struct {
- Id string `json:"id"`
- Expire string `json:"expire"`
- File string `json:"file"` // final filename (visible to the downloader)
- Members []string `json:"members"` // contains multiple files, so File is an archive
- Uploaded time.Time `json:"uploaded"`
-}
-
-func Log(format string, values ...any) {
- fmt.Fprintf(gin.DefaultWriter, "[GIN] "+format+"\n", values...)
-}
-
-func Ts() string {
- t := time.Now()
- return t.Format("2006-01-02-15-04-")
-}
-
-func NormalizeFilename(file string) string {
- r := regexp.MustCompile(`[^\w\d\-_\\.]`)
-
- return Ts() + r.ReplaceAllString(file, "")
-}
-
-func Runserver(cfg *cfg.Config, args []string) error {
- dst := cfg.StorageDir
- router := gin.Default()
- router.SetTrustedProxies(nil)
- api := router.Group(cfg.ApiPrefix)
-
- db, err := bolt.Open(cfg.DbFile, 0600, nil)
- if err != nil {
- return err
- }
- defer db.Close()
-
- {
- api.POST("/putfile", func(c *gin.Context) {
- uri, err := Putfile(c, cfg, db)
-
- if err != nil {
- c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
- } else {
- c.JSON(http.StatusOK, gin.H{
- "code": http.StatusOK,
- "message": uri,
- "success": true,
- })
- }
- })
-
- api.GET("/getfile/:id/:file", func(c *gin.Context) {
- // deliver a file and delete it after a delay (FIXME: check
- // when gin has done delivering it?). Redirect to the static
- // handler for actual delivery.
- id := c.Param("id")
- file := c.Param("file")
- c.Request.URL.Path = cfg.ApiPrefix + "/static/" + id + "/" + file
- filename := filepath.Join(dst, id, file)
-
- if _, err := os.Stat(filename); err == nil {
- go func() {
- time.Sleep(500 * time.Millisecond)
- cleanup(filepath.Join(dst, id))
- }()
- }
-
- router.HandleContext(c)
- })
-
- // actual delivery of static files, uri's must be known to the
- // user, mostly being redirected here internally from /f
- api.Static("/static", dst)
- }
-
- router.GET("/", func(c *gin.Context) {
- c.String(http.StatusOK, "welcome to upload api, use /api enpoint!")
- })
-
- router.Run(cfg.Listen)
-
- return nil
-}
-
-// cleanup an upload directory, either because we got an error in the
-// middle of an upload or something else went wrong. we fork off a go
-// routine because this may block.
-func cleanup(dir string) {
- go func() {
- err := os.RemoveAll(dir)
- if err != nil {
- Log("Failed to remove dir %s: %s", dir, err.Error())
- }
- }()
-}
-
-func zipSource(source, target string) error {
- // 1. Create a ZIP file and zip.Writer
- f, err := os.Create(target)
- if err != nil {
- return err
- }
- defer f.Close()
-
- writer := zip.NewWriter(f)
- defer writer.Close()
-
- // 2. Go through all the files of the source
- return filepath.Walk(source, func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
-
- // 3. Create a local file header
- header, err := zip.FileInfoHeader(info)
- if err != nil {
- return err
- }
-
- // set compression
- header.Method = zip.Deflate
-
- // 4. Set relative path of a file as the header name
- header.Name, err = filepath.Rel(filepath.Dir(source), path)
- if err != nil {
- return err
- }
- if info.IsDir() {
- header.Name += "/"
- }
-
- // 5. Create writer for the file header and save content of the file
- headerWriter, err := writer.CreateHeader(header)
- if err != nil {
- return err
- }
-
- if info.IsDir() {
- return nil
- }
-
- f, err := os.Open(path)
- if err != nil {
- return err
- }
- defer f.Close()
-
- _, err = io.Copy(headerWriter, f)
- return err
- })
-}
diff --git a/upd/testzip.go b/upd/testzip.go
new file mode 100644
index 0000000..d7c61d4
--- /dev/null
+++ b/upd/testzip.go
@@ -0,0 +1,18 @@
+package main
+
+import (
+ "github.com/tlinden/up/upd/api"
+ "log"
+ "os"
+)
+
+func main() {
+ if len(os.Args) > 2 {
+ dir, err := os.Getwd()
+ if err != nil {
+ }
+ if err := api.ZipSource(dir+"/"+os.Args[1], os.Args[2]); err != nil {
+ log.Fatal(err)
+ }
+ }
+}