Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 58 additions & 1 deletion cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
package cache

import (
"fmt"
"io"
"log"
"os"
Expand Down Expand Up @@ -69,6 +70,9 @@ func New(dirPath string) (*Cache, error) {
log.Println("hidden file ", name)
continue
}
if id == "dummy" {
id = strings.Join(strings.Split(name, ".")[1:], ".")
}
c.files[id] = fi
}

Expand Down Expand Up @@ -133,7 +137,7 @@ func (c *Cache) Put(content io.Reader, filename string, conf Config) (string, er
sha.Read(buf)
hash = conf.ProcessHash(buf)

if _, exist := c.files[hash]; exist {
if _, exist := c.files[hash]; exist || hash == "dummy" {
log.Printf("cache: collision detected with ID '%s' - regenerating", hash)
} else {
break
Expand Down Expand Up @@ -177,6 +181,59 @@ func (c *Cache) Put(content io.Reader, filename string, conf Config) (string, er
return hash, nil
}

// PutNoHsh copies a file to disk with the given filename, preserving the name
func (c *Cache) PutNoHash(content io.Reader, filename string, conf Config) error {
if _, exist := c.files[filename]; exist {
return fmt.Errorf("A file with the same name already exists")
}

os.MkdirAll(c.dir, 0700)
dest := filepath.Join(c.dir, fmt.Sprintf("dummy.%s", filename))
destFile, err := os.OpenFile(dest, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
if err != nil {
os.Remove(dest)
return err
}

defer destFile.Close()

w := io.MultiWriter(destFile)
_, err = io.Copy(w, content)
if err != nil {
os.Remove(dest)
return err
}

fi, err := os.Stat(dest)
if err != nil {
os.Remove(dest)
return err
}

if conf.MaxSize() > 0 {
_, err = c.CutToSize(conf.MaxSize() * 1024 * 1024)
if err != nil {
os.Remove(dest)
return err
}
}

if conf.MaxCount() > 0 {
_, err = c.CutToCount(conf.MaxCount() - 1)
if err != nil {
os.Remove(dest)
return err
}
}

c.Lock()
c.files[filename] = fi
c.size += fi.Size()
c.Unlock()

return nil
}

func (c *Cache) removeFile(id string) error {
size := c.files[id].Size()
if err := os.Remove(c.filePath(id)); err != nil {
Expand Down
26 changes: 13 additions & 13 deletions cmd/airliftd/bindata_files/static.go

Large diffs are not rendered by default.

18 changes: 9 additions & 9 deletions cmd/airliftd/bindata_files/templates.go

Large diffs are not rendered by default.

34 changes: 28 additions & 6 deletions cmd/airliftd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,6 @@ func main() {
Delete("/{id}", checkPassword, deleteFile).
Post("/-/delete/{id}", checkLogin, deleteFile).
Get("/{id}/{filename}", getFile).
Get("/{id}.{ext}", getFile).
Get("/{id}", getFile).
Get("/", getIndex).
Ignition()
Expand Down Expand Up @@ -386,7 +385,20 @@ func getFile(g *gas.Gas) (int, gas.Outputter) {
id := g.Arg("id")
file := fileCache.Get(id)
if file == "" {
return 404, out.Error(g, errors.New("ID not found"))
// let's try without the extension
if !strings.Contains(id, ".") {
return 404, out.Error(g, errors.New("ID not found"))
}
split := strings.Split(id, ".")
// will not panic since there is at least one dot
file = fileCache.Get(strings.Join(split[:len(split)-1], "."))
if file == "" {
return 404, out.Error(g, errors.New("ID not found"))
}
fi := fileCache.Stat(id)
if fi == nil || strings.SplitN(fi.Name(), ".", 2)[0] == "dummy" {
return 404, out.Error(g, errors.New("ID not found"))
}
}

form := struct {
Expand Down Expand Up @@ -557,16 +569,26 @@ func postFile(g *gas.Gas) (int, gas.Outputter) {
}
defer g.Body.Close()

host := conf.Host
if host == "" {
host = g.Request.Host
}

if g.Request.URL.Query().Get("preserveName") == "true" {
err := fileCache.PutNoHash(g.Body, filename, conf)
if err != nil {
log.Println(g.Request.Method, "postFile:", err)
return 500, out.JSON(&Resp{Err: err.Error()})
}
return 201, out.JSON(&Resp{URL: path.Join(host, filename)})
}

hash, err := fileCache.Put(g.Body, filename, conf)
if err != nil {
log.Println(g.Request.Method, "postFile:", err)
return 500, out.JSON(&Resp{Err: err.Error()})
}

host := conf.Host
if host == "" {
host = g.Request.Host
}
if conf.AppendExt {
hash += filepath.Ext(filename)
}
Expand Down
25 changes: 18 additions & 7 deletions cmd/airliftd/static/uploader.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
(function() {
'use strict';

var dropZone, dropZoneText, picker, urlList, bar;
var dropZone, dropZoneText, picker, urlList, bar, preserveName;

function paste(e) {
var item;
Expand Down Expand Up @@ -32,7 +32,7 @@
}

c.then(function(pass, fail, items) {
uploadFiles(items);
uploadFiles(items, preserveName.checked);
}).pass([]);
}

Expand Down Expand Up @@ -67,10 +67,10 @@
function dropped(e) {
e.stopPropagation();
e.preventDefault();
uploadFiles(e.dataTransfer.files);
uploadFiles(e.dataTransfer.files, preserveName.checked);
}

function uploadFiles(fileList) {
function uploadFiles(fileList, preserveName) {
if (fileList == null || fileList.length == 0) {
finish();
return;
Expand Down Expand Up @@ -130,7 +130,11 @@
for (var i = 0; i < fileList.length; i++) {
(function(file) {
c.then(function(pass, fail, result, totalLoaded) {
json('POST', '/upload/web', file, function(code, resp) {
var path = '/upload/web'
if (preserveName) {
path += '?preserveName=true'
}
json('POST', path, file, function(code, resp) {
switch (code) {
case 201:
result.push(window.location.protocol + '//' + resp.URL);
Expand Down Expand Up @@ -171,7 +175,13 @@
if (svg != null) {
svg.sacrificeChildren();
}
}).catch(errorMessage).pass([], 0);
}).catch(e => {
finish();
dropZoneText.innerText = dropZoneText.dataset.oldText;
dropZone.removeEventListener('click', cancel);
dropZone.addEventListener('click', clickPicker);
errorMessage(e);
}).pass([], 0);
}

function finish() {
Expand Down Expand Up @@ -206,9 +216,10 @@
picker = $('#picker');
urlList = $('#uploaded-urls');
bar = dropZone.querySelector('.progress-bar');
preserveName = $('#preserve-name');

picker.addEventListener('change', function(e) {
uploadFiles(this.files);
uploadFiles(this.files, preserveName.checked);
}, false);

window.addEventListener('paste', paste, false);
Expand Down
6 changes: 6 additions & 0 deletions cmd/airliftd/templates/content/index.tmpl
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
{{ define "content" }}

<section id="upload" class="floating-section">
<div class="box checkbox" >
<input type="checkbox" id="preserve-name" name="preserve-name">
<label for="preserve-name">Preserve the original file name</label>
</div>

<input type="file" id="picker" name="picker[]" multiple>
<div id="drop-zone">
<div class="progress-bar"></div>
Expand Down
34 changes: 20 additions & 14 deletions cmd/lift/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,20 @@ import (
)

var (
flag_host = flag.String("h", "", "Set host to upload to")
flag_port = flag.String("p", "", "Set port or interface of remote server to upload to")
flag_addr = flag.String("a", "", "Set whole address of server to upload to")
flag_name = flag.String("f", "", "Specify a different filename to use. If -z, it names the zip archive")
flag_stdin = flag.String("s", "", "Give stdin stream a filename")
flag_remove = flag.String("r", "", "Instruct the server to delete the file with a given ID")
flag_zip = flag.Bool("z", false, "Upload the input file(s) (and stdin) as a single zip file")
flag_inclname = flag.Bool("n", false, "Include filename in returned URL (overrides -e)")
flag_inclext = flag.Bool("e", false, "Append file extension to returned URL")
flag_nocopy = flag.Bool("C", false, "Do not copy link to clipboard")
flag_noprog = flag.Bool("P", false, "Do not show progress bar")
flag_oops = flag.Bool("oops", false, "Delete the last file uploaded")
dotfilePath string
flag_host = flag.String("h", "", "Set host to upload to")
flag_port = flag.String("p", "", "Set port or interface of remote server to upload to")
flag_addr = flag.String("a", "", "Set whole address of server to upload to")
flag_name = flag.String("f", "", "Specify a different filename to use. If -z, it names the zip archive")
flag_stdin = flag.String("s", "", "Give stdin stream a filename")
flag_remove = flag.String("r", "", "Instruct the server to delete the file with a given ID")
flag_zip = flag.Bool("z", false, "Upload the input file(s) (and stdin) as a single zip file")
flag_inclname = flag.Bool("n", false, "Include filename in returned URL (overrides -e)")
flag_inclext = flag.Bool("e", false, "Append file extension to returned URL")
flag_preservename = flag.Bool("k", false, "Preserve file name")
flag_nocopy = flag.Bool("C", false, "Do not copy link to clipboard")
flag_noprog = flag.Bool("P", false, "Do not show progress bar")
flag_oops = flag.Bool("oops", false, "Delete the last file uploaded")
dotfilePath string
)

func init() {
Expand Down Expand Up @@ -379,7 +380,12 @@ func postFile(conf *Config, upload FileUpload) string {
body = file
}

req, err := http.NewRequest("POST", conf.BaseURL("/upload/file"), body)
postURL := conf.BaseURL("/upload/file")
if *flag_preservename {
postURL += "?preserveName=true"
}

req, err := http.NewRequest("POST", postURL, body)
if err != nil {
fatal(err)
}
Expand Down
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ go 1.16
require (
github.com/alecthomas/chroma v0.8.2
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/pkg/errors v0.9.1
github.com/russross/blackfriday/v2 v2.1.0 // indirect
golang.org/x/crypto v0.0.0-20210317152858-513c2a44f670
golang.org/x/image v0.0.0-20210220032944-ac19c3e999fb
Expand Down