diff --git a/README.md b/README.md index 6cb85ab..cf05858 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ allowhotlink = true - ```-xframeoptions "..." ``` -- X-Frame-Options header (default is "SAMEORIGIN") - ```-remoteuploads``` -- (optionally) enable remote uploads (/upload?url=https://...) - ```-nologs``` -- (optionally) disable request logs in stdout +- ```-force-random-filename``` -- (optionally) force the use of random filenames #### Storage backends The following storage backends are available: diff --git a/pages.go b/pages.go index bb38f37..6fcc934 100644 --- a/pages.go +++ b/pages.go @@ -21,8 +21,9 @@ const ( func indexHandler(c web.C, w http.ResponseWriter, r *http.Request) { err := renderTemplate(Templates["index.html"], pongo2.Context{ - "maxsize": Config.maxSize, - "expirylist": listExpirationTimes(), + "maxsize": Config.maxSize, + "expirylist": listExpirationTimes(), + "forcerandom": Config.forceRandomFilename, }, r, w) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) @@ -31,7 +32,8 @@ func indexHandler(c web.C, w http.ResponseWriter, r *http.Request) { func pasteHandler(c web.C, w http.ResponseWriter, r *http.Request) { err := renderTemplate(Templates["paste.html"], pongo2.Context{ - "expirylist": listExpirationTimes(), + "expirylist": listExpirationTimes(), + "forcerandom": Config.forceRandomFilename, }, r, w) if err != nil { oopsHandler(c, w, r, RespHTML, "") @@ -40,7 +42,8 @@ func pasteHandler(c web.C, w http.ResponseWriter, r *http.Request) { func apiDocHandler(c web.C, w http.ResponseWriter, r *http.Request) { err := renderTemplate(Templates["API.html"], pongo2.Context{ - "siteurl": getSiteURL(r), + "siteurl": getSiteURL(r), + "forcerandom": Config.forceRandomFilename, }, r, w) if err != nil { oopsHandler(c, w, r, RespHTML, "") diff --git a/server.go b/server.go index 7883a07..e4e1661 100644 --- a/server.go +++ b/server.go @@ -65,6 +65,7 @@ var Config struct { s3Region string s3Bucket string s3ForcePathStyle bool + forceRandomFilename bool } var Templates = make(map[string]*pongo2.Template) @@ -268,6 +269,8 @@ func main() { "S3 bucket to use for files and metadata") flag.BoolVar(&Config.s3ForcePathStyle, "s3-force-path-style", false, "Force path-style addressing for S3 (e.g. https://s3.amazonaws.com/linx/example.txt)") + flag.BoolVar(&Config.forceRandomFilename, "force-random-filename", false, + "Force all uploads to use a random filename") iniflags.Parse() diff --git a/server_test.go b/server_test.go index a1ec853..fc225ce 100644 --- a/server_test.go +++ b/server_test.go @@ -763,6 +763,32 @@ func TestPutRandomizedUpload(t *testing.T) { } } +func TestPutForceRandomUpload(t *testing.T) { + mux := setup() + w := httptest.NewRecorder() + + oldFRF := Config.forceRandomFilename + Config.forceRandomFilename = true + filename := "randomizeme.file" + + req, err := http.NewRequest("PUT", "/upload/"+filename, strings.NewReader("File content")) + if err != nil { + t.Fatal(err) + } + + // while this should also work without this header, let's try to force + // the randomized filename off to be sure + req.Header.Set("Linx-Randomize", "no") + + mux.ServeHTTP(w, req) + + if w.Body.String() == Config.siteURL+filename { + t.Fatal("Filename was not random") + } + + Config.forceRandomFilename = oldFRF +} + func TestPutNoExtensionUpload(t *testing.T) { mux := setup() w := httptest.NewRecorder() @@ -1013,6 +1039,55 @@ func TestPutAndOverwrite(t *testing.T) { } } +func TestPutAndOverwriteForceRandom(t *testing.T) { + var myjson RespOkJSON + + mux := setup() + w := httptest.NewRecorder() + + oldFRF := Config.forceRandomFilename + Config.forceRandomFilename = true + + req, err := http.NewRequest("PUT", "/upload", strings.NewReader("File content")) + if err != nil { + t.Fatal(err) + } + + req.Header.Set("Accept", "application/json") + + mux.ServeHTTP(w, req) + + err = json.Unmarshal([]byte(w.Body.String()), &myjson) + if err != nil { + t.Fatal(err) + } + + // Overwrite it + w = httptest.NewRecorder() + req, err = http.NewRequest("PUT", "/upload/"+myjson.Filename, strings.NewReader("New file content")) + req.Header.Set("Linx-Delete-Key", myjson.Delete_Key) + mux.ServeHTTP(w, req) + + if w.Code != 200 { + t.Fatal("Status code was not 200, but " + strconv.Itoa(w.Code)) + } + + // Make sure it's the new file + w = httptest.NewRecorder() + req, err = http.NewRequest("GET", "/"+Config.selifPath+myjson.Filename, nil) + mux.ServeHTTP(w, req) + + if w.Code == 404 { + t.Fatal("Status code was 404") + } + + if w.Body.String() != "New file content" { + t.Fatal("File did not contain 'New file content") + } + + Config.forceRandomFilename = oldFRF +} + func TestPutAndSpecificDelete(t *testing.T) { var myjson RespOkJSON diff --git a/templates/API.html b/templates/API.html index 64404b6..251cbaf 100644 --- a/templates/API.html +++ b/templates/API.html @@ -25,8 +25,10 @@
Optional headers with the request
+{% if not forcerandom %}Randomize the filename
Linx-Randomize: yes
Specify a custom deletion key
Linx-Delete-Key: mysecret
$ curl -H "Linx-Api-Key: mysecretkey" -T myphoto.jpg {{ siteurl }}upload/
-{{ siteurl }}myphoto.jpg
+{{ siteurl }}{% if not forcerandom %}myphoto.jpg{% else %}7z4h4ut.jpg{% endif %}
{% else %}
$ curl -T myphoto.jpg {{ siteurl }}upload/
-{{ siteurl }}myphoto.jpg
+{{ siteurl }}{% if not forcerandom %}myphoto.jpg{% else %}wtq7pan.jpg{% endif %}
{% endif %}
Uploading myphoto.jpg with an expiry of 20 minutes
{% if using_auth %}$ curl -H "Linx-Api-Key: mysecretkey" -H "Linx-Expiry: 1200" -T myphoto.jpg {{ siteurl }}upload/
-{{ siteurl }}myphoto.jpg
+{{ siteurl }}{% if not forcerandom %}myphoto.jpg{% else %}jm295snf.jpg{% endif %}
{% else %}
$ curl -H "Linx-Expiry: 1200" -T myphoto.jpg {{ siteurl }}upload/
-{{ siteurl }}myphoto.jpg
+{{ siteurl }}{% if not forcerandom %}myphoto.jpg{% else %}1doym9u2.jpg{% endif %}
{% endif %}
Uploading myphoto.jpg with a random filename and getting a json response:
{% if using_auth %} -$ curl -H "Linx-Api-Key: mysecretkey" -H "Accept: application/json" -H "Linx-Randomize: yes" -T myphoto.jpg {{ siteurl }}upload/
+ $ curl -H "Linx-Api-Key: mysecretkey" -H "Accept: application/json"{% if not forcerandom %} -H "Linx-Randomize: yes"{% endif %} -T myphoto.jpg {{ siteurl }}upload/
{"delete_key":"...","expiry":"0","filename":"f34h4iu.jpg","mimetype":"image/jpeg",
"sha256sum":"...","size":"...","url":"{{ siteurl }}f34h4iu.jpg"}
{% else %}
- $ curl -H "Accept: application/json" -H "Linx-Randomize: yes" -T myphoto.jpg {{ siteurl }}upload/
+ $ curl -H "Accept: application/json"{% if not forcerandom %} -H "Linx-Randomize: yes"{% endif %} -T myphoto.jpg {{ siteurl }}upload/
{"delete_key":"...","expiry":"0","filename":"f34h4iu.jpg","mimetype":"image/jpeg",
"sha256sum":"...","size":"...","url":"{{ siteurl }}f34h4iu.jpg"}
{% endif %}
diff --git a/templates/index.html b/templates/index.html
index d423879..2843109 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -17,7 +17,7 @@
-
+