mirror of
https://github.com/Luzifer/share.git
synced 2024-12-20 10:31:16 +00:00
Enable full-path templating for uploads, use safe filenames
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
d08a7a7dac
commit
7572dcdff6
5 changed files with 81 additions and 15 deletions
3
go.mod
3
go.mod
|
@ -6,6 +6,8 @@ require (
|
||||||
github.com/Luzifer/rconfig/v2 v2.3.0
|
github.com/Luzifer/rconfig/v2 v2.3.0
|
||||||
github.com/aws/aws-sdk-go v1.40.30
|
github.com/aws/aws-sdk-go v1.40.30
|
||||||
github.com/cheggaaa/pb v1.0.29
|
github.com/cheggaaa/pb v1.0.29
|
||||||
|
github.com/gofrs/uuid v4.1.0+incompatible
|
||||||
|
github.com/gosimple/slug v1.11.0
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/rivo/uniseg v0.2.0 // indirect
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
github.com/sirupsen/logrus v1.8.1
|
github.com/sirupsen/logrus v1.8.1
|
||||||
|
@ -13,6 +15,7 @@ require (
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/Luzifer/rconfig v1.2.0 // indirect
|
github.com/Luzifer/rconfig v1.2.0 // indirect
|
||||||
|
github.com/gosimple/unidecode v1.0.0 // indirect
|
||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||||
github.com/onsi/ginkgo v1.16.4 // indirect
|
github.com/onsi/ginkgo v1.16.4 // indirect
|
||||||
|
|
6
go.sum
6
go.sum
|
@ -15,6 +15,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
|
github.com/gofrs/uuid v4.1.0+incompatible h1:sIa2eCvUTwgjbqXrPLfNwUf9S3i3mpH1O1atV+iL/Wk=
|
||||||
|
github.com/gofrs/uuid v4.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||||
|
@ -28,6 +30,10 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/gosimple/slug v1.11.0 h1:QkFeOkXIEDvvtIt++P7cUuO4G9PZVQEgLuYbYZzawMA=
|
||||||
|
github.com/gosimple/slug v1.11.0/go.mod h1:MICb3w495l9KNdZm+Xn5b6T2Hn831f9DMxiJ1r+bAjw=
|
||||||
|
github.com/gosimple/unidecode v1.0.0 h1:kPdvM+qy0tnk4/BrnkrbdJ82xe88xn7c9hcaipDz4dQ=
|
||||||
|
github.com/gosimple/unidecode v1.0.0/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
|
|
28
main.go
28
main.go
|
@ -17,12 +17,13 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
cfg = struct {
|
cfg = struct {
|
||||||
BaseURL string `flag:"base-url" env:"BASE_URL" default:"" description:"URL to prepend before filename"`
|
BaseURL string `flag:"base-url" default:"" description:"URL to prepend before filename"`
|
||||||
BasePath string `flag:"base-path" env:"BASE_PATH" default:"file/{{ printf \"%.6s\" .Hash }}" description:"Path to upload the file to"`
|
BasePath string `flag:"base-path" default:"" description:"DEPRECATED: Path to upload the file to"`
|
||||||
Bootstrap bool `flag:"bootstrap" default:"false" description:"Upload frontend files into bucket"`
|
Bootstrap bool `flag:"bootstrap" default:"false" description:"Upload frontend files into bucket"`
|
||||||
Bucket string `flag:"bucket" env:"BUCKET" default:"" description:"S3 bucket to upload files to" validate:"nonzero"`
|
Bucket string `flag:"bucket" default:"" description:"S3 bucket to upload files to" validate:"nonzero"`
|
||||||
ContentType string `flag:"content-type,c" default:"" description:"Force content-type to be set to this value"`
|
ContentType string `flag:"content-type,c" vardefault:"file_template" description:"Force content-type to be set to this value"`
|
||||||
Listen string `flag:"listen" env:"LISTEN" default:"" description:"Enable HTTP server if set to IP/Port (e.g. ':3000')"`
|
FileTemplate string `flag:"file-template" default:"" description:"Full name template of the uploaded file"`
|
||||||
|
Listen string `flag:"listen" default:"" description:"Enable HTTP server if set to IP/Port (e.g. ':3000')"`
|
||||||
Progress bool `flag:"progress" default:"false" description:"Show progress bar while uploading"`
|
Progress bool `flag:"progress" default:"false" description:"Show progress bar while uploading"`
|
||||||
VersionAndExit bool `flag:"version" default:"false" description:"Prints current version and exits"`
|
VersionAndExit bool `flag:"version" default:"false" description:"Prints current version and exits"`
|
||||||
}{}
|
}{}
|
||||||
|
@ -33,8 +34,12 @@ var (
|
||||||
version = "dev"
|
version = "dev"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func initApp() {
|
||||||
rconfig.AutoEnv(true)
|
rconfig.AutoEnv(true)
|
||||||
|
rconfig.SetVariableDefaults(map[string]string{
|
||||||
|
"file_template": `file/{{ printf "%.6s" .Hash }}/{{ .SafeFileName }}`,
|
||||||
|
})
|
||||||
|
|
||||||
if err := rconfig.ParseAndValidate(&cfg); err != nil {
|
if err := rconfig.ParseAndValidate(&cfg); err != nil {
|
||||||
log.Fatalf("Unable to parse commandline options: %s", err)
|
log.Fatalf("Unable to parse commandline options: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -43,9 +48,16 @@ func init() {
|
||||||
fmt.Printf("share %s\n", version)
|
fmt.Printf("share %s\n", version)
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cfg.BasePath != "" {
|
||||||
|
cfg.FileTemplate = strings.Join([]string{strings.TrimRight(cfg.BasePath, "/"), `{{ .SafeFileName }}`}, "/")
|
||||||
|
log.WithField("file-template", cfg.FileTemplate).Warn("Using deprecated base-path parameter! Using update file-template...")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
initApp()
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|
||||||
case cfg.Bootstrap:
|
case cfg.Bootstrap:
|
||||||
|
@ -81,10 +93,12 @@ func doCLIUpload() error {
|
||||||
inFileName := rconfig.Args()[1]
|
inFileName := rconfig.Args()[1]
|
||||||
|
|
||||||
if inFileName == "-" {
|
if inFileName == "-" {
|
||||||
inFileName = "stdin"
|
|
||||||
if cfg.ContentType == "" {
|
if cfg.ContentType == "" {
|
||||||
// If we don't have an explicitly set content-type assume stdin contains text
|
// If we don't have an explicitly set content-type assume stdin contains text
|
||||||
|
inFileName = "stdin"
|
||||||
cfg.ContentType = "text/plain"
|
cfg.ContentType = "text/plain"
|
||||||
|
} else if ext, err := mimeResolver.ExtensionsByType(cfg.ContentType); err == nil {
|
||||||
|
inFileName = strings.Join([]string{"stdin", ext}, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stdin is not seekable, so we need to buffer it
|
// Stdin is not seekable, so we need to buffer it
|
||||||
|
|
37
mime.go
Normal file
37
mime.go
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"mime"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type mimeDB map[string]string
|
||||||
|
|
||||||
|
// mimeResolver contains some well-known mime-types and falls back
|
||||||
|
// to mime package to resolve the extension if no internal override
|
||||||
|
// is known for the given mime-type
|
||||||
|
var mimeResolver = mimeDB{
|
||||||
|
"text/plain": ".txt", // Detected as .asc when using mime package
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mimeDB) ExtensionsByType(t string) (string, error) {
|
||||||
|
if v, ok := m[t]; ok {
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
exts, err := mime.ExtensionsByType(t)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ext := range exts {
|
||||||
|
if !strings.HasPrefix(ext, ".") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return ext, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", errors.New("no extension found")
|
||||||
|
}
|
22
upload.go
22
upload.go
|
@ -17,6 +17,8 @@ import (
|
||||||
"github.com/aws/aws-sdk-go/aws/session"
|
"github.com/aws/aws-sdk-go/aws/session"
|
||||||
"github.com/aws/aws-sdk-go/service/s3"
|
"github.com/aws/aws-sdk-go/service/s3"
|
||||||
"github.com/cheggaaa/pb"
|
"github.com/cheggaaa/pb"
|
||||||
|
"github.com/gofrs/uuid"
|
||||||
|
"github.com/gosimple/slug"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
@ -101,18 +103,22 @@ func executeUpload(inFileName string, inFileHandle io.ReadSeeker, useCalculatedF
|
||||||
}
|
}
|
||||||
|
|
||||||
func calculateUploadFilename(inFile string, inFileHandle io.ReadSeeker) (string, error) {
|
func calculateUploadFilename(inFile string, inFileHandle io.ReadSeeker) (string, error) {
|
||||||
upFile := path.Join(
|
|
||||||
cfg.BasePath,
|
|
||||||
strings.Replace(path.Base(inFile), " ", "_", -1),
|
|
||||||
)
|
|
||||||
|
|
||||||
fileHash, err := hashFile(inFileHandle)
|
fileHash, err := hashFile(inFileHandle)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
return executeTemplate(upFile, map[string]interface{}{
|
safeFileName := strings.Join([]string{
|
||||||
"Hash": fileHash,
|
slug.Make(strings.TrimSuffix(path.Base(inFile), path.Ext(inFile))),
|
||||||
|
path.Ext(inFile),
|
||||||
|
}, "")
|
||||||
|
|
||||||
|
return executeTemplate(cfg.FileTemplate, map[string]interface{}{
|
||||||
|
"Ext": path.Ext(inFile),
|
||||||
|
"FileName": path.Base(inFile),
|
||||||
|
"Hash": fileHash,
|
||||||
|
"SafeFileName": safeFileName,
|
||||||
|
"UUID": uuid.Must(uuid.NewV4()).String(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +136,7 @@ func hashFile(inFileHandle io.ReadSeeker) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func executeTemplate(tplStr string, vars map[string]interface{}) (string, error) {
|
func executeTemplate(tplStr string, vars map[string]interface{}) (string, error) {
|
||||||
tpl, err := template.New("basepath").Parse(tplStr)
|
tpl, err := template.New("filename").Parse(tplStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue