Browse Source

Keep original file names

pull/123/head
xtrafrancyz 6 years ago
parent
commit
a31648586a
  1. 6
      backends/localfs/localfs.go
  2. 1
      backends/meta.go
  3. 6
      backends/s3/s3.go
  4. 2
      backends/storage.go
  5. 2
      delete.go
  6. 6
      display.go
  7. 3
      fileserve.go
  8. 9
      static/css/linx.css
  9. 4
      templates/base.html
  10. 4
      templates/display/base.html
  11. 2
      templates/display/file.html
  12. 2
      templates/index.html
  13. 53
      upload.go

6
backends/localfs/localfs.go

@ -18,6 +18,7 @@ type LocalfsBackend struct {
} }
type MetadataJSON struct { type MetadataJSON struct {
OriginalName string `json:"original_name"`
DeleteKey string `json:"delete_key"` DeleteKey string `json:"delete_key"`
Sha256sum string `json:"sha256sum"` Sha256sum string `json:"sha256sum"`
Mimetype string `json:"mimetype"` Mimetype string `json:"mimetype"`
@ -56,6 +57,7 @@ func (b LocalfsBackend) Head(key string) (metadata backends.Metadata, err error)
return metadata, backends.BadMetadata return metadata, backends.BadMetadata
} }
metadata.OriginalName = mjson.OriginalName
metadata.DeleteKey = mjson.DeleteKey metadata.DeleteKey = mjson.DeleteKey
metadata.Mimetype = mjson.Mimetype metadata.Mimetype = mjson.Mimetype
metadata.ArchiveFiles = mjson.ArchiveFiles metadata.ArchiveFiles = mjson.ArchiveFiles
@ -84,6 +86,7 @@ func (b LocalfsBackend) writeMetadata(key string, metadata backends.Metadata) er
metaPath := path.Join(b.metaPath, key) metaPath := path.Join(b.metaPath, key)
mjson := MetadataJSON{ mjson := MetadataJSON{
OriginalName: metadata.OriginalName,
DeleteKey: metadata.DeleteKey, DeleteKey: metadata.DeleteKey,
Mimetype: metadata.Mimetype, Mimetype: metadata.Mimetype,
ArchiveFiles: metadata.ArchiveFiles, ArchiveFiles: metadata.ArchiveFiles,
@ -108,7 +111,7 @@ func (b LocalfsBackend) writeMetadata(key string, metadata backends.Metadata) er
return nil return nil
} }
func (b LocalfsBackend) Put(key string, r io.Reader, expiry time.Time, deleteKey string) (m backends.Metadata, err error) {
func (b LocalfsBackend) Put(key string, originalName string, r io.Reader, expiry time.Time, deleteKey string) (m backends.Metadata, err error) {
filePath := path.Join(b.filesPath, key) filePath := path.Join(b.filesPath, key)
dst, err := os.Create(filePath) dst, err := os.Create(filePath)
@ -126,6 +129,7 @@ func (b LocalfsBackend) Put(key string, r io.Reader, expiry time.Time, deleteKey
return m, err return m, err
} }
m.OriginalName = originalName
m.Expiry = expiry m.Expiry = expiry
m.DeleteKey = deleteKey m.DeleteKey = deleteKey
m.Size = bytes m.Size = bytes

1
backends/meta.go

@ -6,6 +6,7 @@ import (
) )
type Metadata struct { type Metadata struct {
OriginalName string
DeleteKey string DeleteKey string
Sha256sum string Sha256sum string
Mimetype string Mimetype string

6
backends/s3/s3.go

@ -81,6 +81,7 @@ func (b S3Backend) Get(key string) (metadata backends.Metadata, r io.ReadCloser,
func mapMetadata(m backends.Metadata) map[string]*string { func mapMetadata(m backends.Metadata) map[string]*string {
return map[string]*string{ return map[string]*string{
"Original_name": aws.String(m.OriginalName),
"Expiry": aws.String(strconv.FormatInt(m.Expiry.Unix(), 10)), "Expiry": aws.String(strconv.FormatInt(m.Expiry.Unix(), 10)),
"Delete_key": aws.String(m.DeleteKey), "Delete_key": aws.String(m.DeleteKey),
"Size": aws.String(strconv.FormatInt(m.Size, 10)), "Size": aws.String(strconv.FormatInt(m.Size, 10)),
@ -101,13 +102,14 @@ func unmapMetadata(input map[string]*string) (m backends.Metadata, err error) {
return return
} }
m.OriginalName = aws.StringValue(input["Original_name"])
m.DeleteKey = aws.StringValue(input["Delete_key"]) m.DeleteKey = aws.StringValue(input["Delete_key"])
m.Mimetype = aws.StringValue(input["Mimetype"]) m.Mimetype = aws.StringValue(input["Mimetype"])
m.Sha256sum = aws.StringValue(input["Sha256sum"]) m.Sha256sum = aws.StringValue(input["Sha256sum"])
return return
} }
func (b S3Backend) Put(key string, r io.Reader, expiry time.Time, deleteKey string) (m backends.Metadata, err error) {
func (b S3Backend) Put(key string, originalName string, r io.Reader, expiry time.Time, deleteKey string) (m backends.Metadata, err error) {
tmpDst, err := ioutil.TempFile("", "linx-server-upload") tmpDst, err := ioutil.TempFile("", "linx-server-upload")
if err != nil { if err != nil {
return m, err return m, err
@ -122,6 +124,7 @@ func (b S3Backend) Put(key string, r io.Reader, expiry time.Time, deleteKey stri
return m, err return m, err
} }
m.OriginalName = originalName
m.Expiry = expiry m.Expiry = expiry
m.DeleteKey = deleteKey m.DeleteKey = deleteKey
m.Size = bytes m.Size = bytes
@ -169,7 +172,6 @@ func (b S3Backend) List() ([]string, error) {
return nil, err return nil, err
} }
for _, object := range results.Contents { for _, object := range results.Contents {
output = append(output, *object.Key) output = append(output, *object.Key)
} }

2
backends/storage.go

@ -11,7 +11,7 @@ type StorageBackend interface {
Exists(key string) (bool, error) Exists(key string) (bool, error)
Head(key string) (Metadata, error) Head(key string) (Metadata, error)
Get(key string) (Metadata, io.ReadCloser, error) Get(key string) (Metadata, io.ReadCloser, error)
Put(key string, r io.Reader, expiry time.Time, deleteKey string) (Metadata, error)
Put(key string, originalName string, r io.Reader, expiry time.Time, deleteKey string) (Metadata, error)
Size(key string) (int64, error) Size(key string) (int64, error)
} }

2
delete.go

@ -30,7 +30,7 @@ func deleteHandler(c web.C, w http.ResponseWriter, r *http.Request) {
return return
} }
fmt.Fprintf(w, "DELETED")
_, _ = fmt.Fprintf(w, "DELETED")
return return
} else { } else {

6
display.go

@ -51,6 +51,7 @@ func fileDisplayHandler(c web.C, w http.ResponseWriter, r *http.Request) {
if strings.EqualFold("application/json", r.Header.Get("Accept")) { if strings.EqualFold("application/json", r.Header.Get("Accept")) {
js, _ := json.Marshal(map[string]string{ js, _ := json.Marshal(map[string]string{
"original_name": metadata.OriginalName,
"filename": fileName, "filename": fileName,
"direct_url": getSiteURL(r) + Config.selifPath + fileName, "direct_url": getSiteURL(r) + Config.selifPath + fileName,
"expiry": strconv.FormatInt(metadata.Expiry.Unix(), 10), "expiry": strconv.FormatInt(metadata.Expiry.Unix(), 10),
@ -130,8 +131,13 @@ func fileDisplayHandler(c web.C, w http.ResponseWriter, r *http.Request) {
tpl = Templates["display/file.html"] tpl = Templates["display/file.html"]
} }
if metadata.OriginalName == "" {
metadata.OriginalName = fileName
}
err = renderTemplate(tpl, pongo2.Context{ err = renderTemplate(tpl, pongo2.Context{
"mime": metadata.Mimetype, "mime": metadata.Mimetype,
"original_name": metadata.OriginalName,
"filename": fileName, "filename": fileName,
"size": sizeHuman, "size": sizeHuman,
"expiry": expiryHuman, "expiry": expiryHuman,

3
fileserve.go

@ -40,6 +40,9 @@ func fileServeHandler(c web.C, w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Security-Policy", Config.fileContentSecurityPolicy) w.Header().Set("Content-Security-Policy", Config.fileContentSecurityPolicy)
w.Header().Set("Referrer-Policy", Config.fileReferrerPolicy) w.Header().Set("Referrer-Policy", Config.fileReferrerPolicy)
if metadata.OriginalName != "" {
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", metadata.OriginalName))
}
w.Header().Set("Content-Type", metadata.Mimetype) w.Header().Set("Content-Type", metadata.Mimetype)
w.Header().Set("Content-Length", strconv.FormatInt(metadata.Size, 10)) w.Header().Set("Content-Length", strconv.FormatInt(metadata.Size, 10))
w.Header().Set("Etag", fmt.Sprintf("\"%s\"", metadata.Sha256sum)) w.Header().Set("Etag", fmt.Sprintf("\"%s\"", metadata.Sha256sum))

9
static/css/linx.css

@ -74,6 +74,13 @@ body {
padding: 5px; padding: 5px;
} }
#filename {
max-width: 500px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.info-flex { .info-flex {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
@ -326,6 +333,8 @@ body {
.display-audio, .display-audio,
.display-file { .display-file {
width: 100%; width: 100%;
max-width: 1000px;
word-break: break-word;
} }
.display-image { .display-image {

4
templates/base.html

@ -4,7 +4,7 @@
<title>{% block title %}{{ sitename }}{% endblock %}</title> <title>{% block title %}{{ sitename }}{% endblock %}</title>
<meta charset='utf-8' content='text/html' http-equiv='content-type'> <meta charset='utf-8' content='text/html' http-equiv='content-type'>
<meta name='viewport' content='width=device-width, initial-scale=1.0'> <meta name='viewport' content='width=device-width, initial-scale=1.0'>
<link href='{{ sitepath }}static/css/linx.css?v=1' media='screen, projection' rel='stylesheet' type='text/css'>
<link href='{{ sitepath }}static/css/linx.css?v=2' media='screen, projection' rel='stylesheet' type='text/css'>
<link href='{{ sitepath }}static/css/hint.css' rel='stylesheet' type='text/css'> <link href='{{ sitepath }}static/css/hint.css' rel='stylesheet' type='text/css'>
<link href='{{ sitepath }}static/images/favicon.gif' rel='icon' type='image/gif'> <link href='{{ sitepath }}static/images/favicon.gif' rel='icon' type='image/gif'>
{% block head %}{% endblock %} {% block head %}{% endblock %}
@ -27,7 +27,7 @@
{% block content %}{% endblock %} {% block content %}{% endblock %}
<div id="footer"> <div id="footer">
<a href="https://github.com/andreimarcu/linx-server">linx</a>
<a href="https://github.com/xtrafrancyz/linx-server">linx</a>
</div> </div>
</div> </div>

4
templates/display/base.html

@ -1,6 +1,6 @@
{% extends "../base.html" %} {% extends "../base.html" %}
{% block title %}{{ filename }}{% endblock %}
{% block title %}{{ original_name }}{% endblock %}
{% block bodymore %}{% endblock %} {% block bodymore %}{% endblock %}
@ -8,7 +8,7 @@
<div id="info" class="dinfo info-flex"> <div id="info" class="dinfo info-flex">
<div id="filename"> <div id="filename">
{{ filename }}
{{ original_name }}
</div> </div>
<div class="info-actions"> <div class="info-actions">

2
templates/display/file.html

@ -2,7 +2,7 @@
{% block main %} {% block main %}
<div class="normal display-file"> <div class="normal display-file">
<p class="center">You are requesting <a href="{{ sitepath }}{{ selifpath }}{{ filename }}">{{ filename }}</a>, click below to download.</p>
<p class="center">You are requesting <a href="{{ sitepath }}{{ selifpath }}{{ filename }}">{{ original_name }}</a>, click below to download.</p>
<a href="{{ sitepath }}{{ selifpath }}{{ filename }}" class="download-btn">Download</a> <a href="{{ sitepath }}{{ selifpath }}{{ filename }}" class="download-btn">Download</a>
{% if files|length > 0 %} {% if files|length > 0 %}

2
templates/index.html

@ -17,7 +17,7 @@
</div> </div>
<div id="choices"> <div id="choices">
<label>{% if not forcerandom %}<input name="randomize" id="randomize" type="checkbox" checked /> Randomize filename{% endif %}</label>
<label>{% if not forcerandom %}<input name="randomize" id="randomize" type="checkbox" /> Randomize filename{% endif %}</label>
<div id="expiry"> <div id="expiry">
<label>File expiry: <label>File expiry:
<select name="expires" id="expires"> <select name="expires" id="expires">

53
upload.go

@ -39,7 +39,7 @@ type UploadRequest struct {
filename string filename string
expiry time.Duration // Seconds until expiry, 0 = never expiry time.Duration // Seconds until expiry, 0 = never
deleteKey string // Empty string if not defined deleteKey string // Empty string if not defined
randomBarename bool
randomize bool
} }
// Metadata associated with a file as it would actually be stored // Metadata associated with a file as it would actually be stored
@ -90,7 +90,7 @@ func uploadPostHandler(c web.C, w http.ResponseWriter, r *http.Request) {
upReq.expiry = parseExpiry(r.PostFormValue("expires")) upReq.expiry = parseExpiry(r.PostFormValue("expires"))
if r.PostFormValue("randomize") == "true" { if r.PostFormValue("randomize") == "true" {
upReq.randomBarename = true
upReq.randomize = true
} }
upload, err := processUpload(upReq) upload, err := processUpload(upReq)
@ -181,7 +181,7 @@ func uploadRemote(c web.C, w http.ResponseWriter, r *http.Request) {
upReq.filename = filepath.Base(grabUrl.Path) upReq.filename = filepath.Base(grabUrl.Path)
upReq.src = http.MaxBytesReader(w, resp.Body, Config.maxSize) upReq.src = http.MaxBytesReader(w, resp.Body, Config.maxSize)
upReq.deleteKey = r.FormValue("deletekey") upReq.deleteKey = r.FormValue("deletekey")
upReq.randomBarename = r.FormValue("randomize") == "yes"
upReq.randomize = r.FormValue("randomize") == "yes"
upReq.expiry = parseExpiry(r.FormValue("expiry")) upReq.expiry = parseExpiry(r.FormValue("expiry"))
upload, err := processUpload(upReq) upload, err := processUpload(upReq)
@ -207,7 +207,7 @@ func uploadRemote(c web.C, w http.ResponseWriter, r *http.Request) {
func uploadHeaderProcess(r *http.Request, upReq *UploadRequest) { func uploadHeaderProcess(r *http.Request, upReq *UploadRequest) {
if r.Header.Get("Linx-Randomize") == "yes" { if r.Header.Get("Linx-Randomize") == "yes" {
upReq.randomBarename = true
upReq.randomize = true
} }
upReq.deleteKey = r.Header.Get("Linx-Delete-Key") upReq.deleteKey = r.Header.Get("Linx-Delete-Key")
@ -223,14 +223,8 @@ func processUpload(upReq UploadRequest) (upload Upload, err error) {
} }
// Determine the appropriate filename // Determine the appropriate filename
barename, extension := barePlusExt(upReq.filename)
randomize := false
// Randomize the "barename" (filename without extension) if needed
if upReq.randomBarename || len(barename) == 0 {
barename = generateBarename()
randomize = true
}
_, extension := barePlusExt(upReq.filename)
slug := generateBarename()
var header []byte var header []byte
if len(extension) == 0 { if len(extension) == 0 {
@ -251,7 +245,7 @@ func processUpload(upReq UploadRequest) (upload Upload, err error) {
} }
} }
upload.Filename = strings.Join([]string{barename, extension}, ".")
upload.Filename = strings.Join([]string{slug, extension}, ".")
upload.Filename = strings.Replace(upload.Filename, " ", "", -1) upload.Filename = strings.Replace(upload.Filename, " ", "", -1)
fileexists, _ := storageBackend.Exists(upload.Filename) fileexists, _ := storageBackend.Exists(upload.Filename)
@ -262,35 +256,13 @@ func processUpload(upReq UploadRequest) (upload Upload, err error) {
if merr == nil { if merr == nil {
if upReq.deleteKey == metad.DeleteKey { if upReq.deleteKey == metad.DeleteKey {
fileexists = false fileexists = false
} else if Config.forceRandomFilename == true {
// the file exists
// the delete key doesn't match
// force random filenames is enabled
randomize = true
} }
} }
} else if Config.forceRandomFilename == true {
// the file doesn't exist
// force random filenames is enabled
randomize = true
// set fileexists to true to generate a new barename
fileexists = true
} }
for fileexists { for fileexists {
if randomize {
barename = generateBarename()
} else {
counter, err := strconv.Atoi(string(barename[len(barename)-1]))
if err != nil {
barename = barename + "1"
} else {
barename = barename[:len(barename)-1] + strconv.Itoa(counter+1)
}
}
upload.Filename = strings.Join([]string{barename, extension}, ".")
slug = generateBarename()
upload.Filename = strings.Join([]string{slug, extension}, ".")
fileexists, err = storageBackend.Exists(upload.Filename) fileexists, err = storageBackend.Exists(upload.Filename)
} }
@ -310,7 +282,11 @@ func processUpload(upReq UploadRequest) (upload Upload, err error) {
upReq.deleteKey = uniuri.NewLen(30) upReq.deleteKey = uniuri.NewLen(30)
} }
upload.Metadata, err = storageBackend.Put(upload.Filename, io.MultiReader(bytes.NewReader(header), upReq.src), fileExpiry, upReq.deleteKey)
if Config.forceRandomFilename || upReq.randomize || len(slug) == 0 {
upReq.filename = upload.Filename
}
upload.Metadata, err = storageBackend.Put(upload.Filename, upReq.filename, io.MultiReader(bytes.NewReader(header), upReq.src), fileExpiry, upReq.deleteKey)
if err != nil { if err != nil {
return upload, err return upload, err
} }
@ -327,6 +303,7 @@ func generateJSONresponse(upload Upload, r *http.Request) []byte {
"url": getSiteURL(r) + upload.Filename, "url": getSiteURL(r) + upload.Filename,
"direct_url": getSiteURL(r) + Config.selifPath + upload.Filename, "direct_url": getSiteURL(r) + Config.selifPath + upload.Filename,
"filename": upload.Filename, "filename": upload.Filename,
"original_name": upload.Metadata.OriginalName,
"delete_key": upload.Metadata.DeleteKey, "delete_key": upload.Metadata.DeleteKey,
"expiry": strconv.FormatInt(upload.Metadata.Expiry.Unix(), 10), "expiry": strconv.FormatInt(upload.Metadata.Expiry.Unix(), 10),
"size": strconv.FormatInt(upload.Metadata.Size, 10), "size": strconv.FormatInt(upload.Metadata.Size, 10),

Loading…
Cancel
Save