From 6b251ec7a815fdba3de8c56de707023b8772d60a Mon Sep 17 00:00:00 2001 From: Remco Date: Thu, 13 Nov 2014 21:41:43 +0100 Subject: [PATCH] docker, previews, tor, bugfixes * implemented docker * added previews (markdown, html, text, video, audio) * added tor support * several bugfixes --- .dockerignore | 16 + .ebextensions/01config_nginx.config | 6 + .gitignore | 1 + transfersh-server/Dockerfile => Dockerfile | 2 +- Gruntfile.js | 36 +- README.md | 10 + package.json | 2 + transfersh-server/handlers.go | 148 +- transfersh-server/main.go | 38 +- transfersh-server/static/404.html | 2 +- transfersh-server/static/download.audio.html | 132 ++ transfersh-server/static/download.code.html | 134 ++ transfersh-server/static/download.html | 116 ++ transfersh-server/static/download.image.html | 126 ++ .../static/download.markdown.html | 124 ++ transfersh-server/static/download.video.html | 129 ++ transfersh-server/static/images/bitcoin.png | Bin 0 -> 6157 bytes .../static/images/terminal-top.svg | 10 +- transfersh-server/static/images/tor.svg | 6 + .../static/includes/download-bottom.html | 5 + .../static/includes/download-btn.html | 10 + .../static/includes/download-top.html | 6 + transfersh-server/static/includes/footer.html | 36 + transfersh-server/static/includes/ga.html | 15 + transfersh-server/static/includes/head.html | 12 + transfersh-server/static/includes/js.html | 2 + .../static/includes/navigation.html | 15 + transfersh-server/static/index.html | 226 +-- transfersh-server/static/scripts/main.js | 6 +- transfersh-server/static/styles/main.css | 2 +- transfersh-server/storage.go | 48 +- transfersh-server/utils.go | 172 +++ transfersh-web/download.audio.html | 47 + transfersh-web/download.code.html | 143 ++ transfersh-web/download.html | 31 + transfersh-web/download.image.html | 41 + transfersh-web/download.markdown.html | 39 + transfersh-web/download.video.html | 44 + transfersh-web/images/bitcoin.png | Bin 0 -> 8772 bytes transfersh-web/images/terminal-top.svg | 10 +- transfersh-web/images/tor.svg | 6 + transfersh-web/includes/download-bottom.html | 5 + transfersh-web/includes/download-btn.html | 10 + transfersh-web/includes/download-top.html | 6 + transfersh-web/includes/footer.html | 36 + transfersh-web/includes/ga.html | 15 + transfersh-web/includes/head.html | 14 + transfersh-web/includes/js.html | 9 + transfersh-web/includes/navigation.html | 15 + transfersh-web/index.html | 142 +- transfersh-web/scripts/clipboard.js | 61 + transfersh-web/scripts/main.js | 94 +- transfersh-web/scripts/showdown.js | 1296 +++++++++++++++++ .../scripts/typewriter-bundle.min.js | 1 - transfersh-web/styles/bootstrap.less | 6 +- transfersh-web/styles/includes/global.less | 14 +- transfersh-web/styles/includes/home.less | 12 +- transfersh-web/styles/includes/pages.less | 22 +- transfersh-web/styles/includes/preview.less | 200 +++ transfersh-web/styles/includes/reviews.less | 30 +- transfersh-web/styles/main.css | 763 +++++++++- transfersh-web/styles/main.css.map | 2 +- transfersh-web/styles/main.less | 1 + 63 files changed, 4401 insertions(+), 307 deletions(-) create mode 100644 .dockerignore create mode 100644 .ebextensions/01config_nginx.config rename transfersh-server/Dockerfile => Dockerfile (89%) create mode 100644 transfersh-server/static/download.audio.html create mode 100644 transfersh-server/static/download.code.html create mode 100644 transfersh-server/static/download.html create mode 100644 transfersh-server/static/download.image.html create mode 100644 transfersh-server/static/download.markdown.html create mode 100644 transfersh-server/static/download.video.html create mode 100644 transfersh-server/static/images/bitcoin.png create mode 100644 transfersh-server/static/images/tor.svg create mode 100644 transfersh-server/static/includes/download-bottom.html create mode 100644 transfersh-server/static/includes/download-btn.html create mode 100644 transfersh-server/static/includes/download-top.html create mode 100644 transfersh-server/static/includes/footer.html create mode 100644 transfersh-server/static/includes/ga.html create mode 100644 transfersh-server/static/includes/head.html create mode 100644 transfersh-server/static/includes/js.html create mode 100644 transfersh-server/static/includes/navigation.html create mode 100644 transfersh-web/download.audio.html create mode 100644 transfersh-web/download.code.html create mode 100644 transfersh-web/download.html create mode 100644 transfersh-web/download.image.html create mode 100644 transfersh-web/download.markdown.html create mode 100644 transfersh-web/download.video.html create mode 100644 transfersh-web/images/bitcoin.png create mode 100644 transfersh-web/images/tor.svg create mode 100644 transfersh-web/includes/download-bottom.html create mode 100644 transfersh-web/includes/download-btn.html create mode 100644 transfersh-web/includes/download-top.html create mode 100644 transfersh-web/includes/footer.html create mode 100644 transfersh-web/includes/ga.html create mode 100644 transfersh-web/includes/head.html create mode 100644 transfersh-web/includes/js.html create mode 100644 transfersh-web/includes/navigation.html create mode 100644 transfersh-web/scripts/clipboard.js create mode 100644 transfersh-web/scripts/showdown.js delete mode 100644 transfersh-web/scripts/typewriter-bundle.min.js create mode 100644 transfersh-web/styles/includes/preview.less diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..30ea494 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,16 @@ +build +pkg +dist +src +bin +*.pyc +*.egg-info +.vagrant +.git +.tmp +bower_components +node_modules +extras +build +transfersh-server/run.sh +.elasticbeanstalk diff --git a/.ebextensions/01config_nginx.config b/.ebextensions/01config_nginx.config new file mode 100644 index 0000000..5b2b9cf --- /dev/null +++ b/.ebextensions/01config_nginx.config @@ -0,0 +1,6 @@ +files: + "/etc/nginx/conf.d/client_max_body_size.conf": + mode: "000644" + owner: root + group: root + content: "client_max_body_size 0;" diff --git a/.gitignore b/.gitignore index 15ce9b5..f8201fb 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ bower_components/ node_modules/ transfersh-server/run.sh +.elasticbeanstalk/ diff --git a/transfersh-server/Dockerfile b/Dockerfile similarity index 89% rename from transfersh-server/Dockerfile rename to Dockerfile index cb6bab1..01da0cc 100644 --- a/transfersh-server/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ RUN mkdir -p /go/src/app WORKDIR /go/src/app # Copy the local package files to the container's workspace. -ADD . /go/src/app +ADD ./transfersh-server /go/src/app # install dependencies RUN go get ./ diff --git a/Gruntfile.js b/Gruntfile.js index 944237e..bc3854c 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -28,6 +28,10 @@ module.exports = function (grunt) { gruntfile: { files: ['Gruntfile.js'] }, + includes: { + files: ['<%= yeoman.app %>/*.html', '.tmp/*.html'], + tasks: ['includes:server'] + }, livereload: { options: { livereload: '<%= connect.options.livereload %>' @@ -37,7 +41,8 @@ module.exports = function (grunt) { '{.tmp,<%= yeoman.app %>}/styles/{,*/}*.css', '{.tmp,<%= yeoman.app %>}/scripts/{,*/}*.js', '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}' - ] + ], + tasks: ['includes:server'] } }, connect: { @@ -112,6 +117,27 @@ module.exports = function (grunt) { } } }, + + includes: { + build: { + cwd: '<%= yeoman.app %>', + src: ['*.html', 'includes/*.html'], + dest: '<%= yeoman.dist %>', + options: { + flatten: true, + banner: '' + } + }, + server: { + cwd: '<%= yeoman.app %>', + src: ['*.html', 'includes/*.html'], + dest: '.tmp/', + options: { + flatten: true, + banner: '' + } + } + }, // not used since Uglify task does concat, // but still available if needed /*concat: { @@ -240,6 +266,7 @@ module.exports = function (grunt) { grunt.task.run([ 'clean:server', 'less', + 'includes:server', 'copy:server', 'connect:livereload', 'watch' @@ -260,14 +287,17 @@ module.exports = function (grunt) { grunt.registerTask('build', [ 'clean:dist', + 'copy:server', 'useminPrepare', 'concurrent', 'cssmin', 'concat', + 'includes:build', 'uglify', 'copy', - 'usemin' + 'usemin', + ]); grunt.registerTask('default', [ @@ -275,4 +305,4 @@ module.exports = function (grunt) { 'test', 'build' ]); -}; +}; \ No newline at end of file diff --git a/README.md b/README.md index c1ce53a..b2518e2 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,16 @@ go run transfersh-server/*.go -provider=local --port 8080 --temp=/tmp/ --basedir go build -o transfersh-server *.go ``` +## Docker + +For easy deployment we've enabled Docker deployment. + +``` +cd ./transfer-server/ +docker build -t transfersh . +docker run --publish 8080:8080 --rm transfersh --provider local --basedir /tmp/ +``` + ## Contributions Contributions are welcome. diff --git a/package.json b/package.json index ea7bf74..860d013 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,8 @@ "grunt-contrib-less": "~0.11.4", "grunt-contrib-uglify": "~0.6.0", "grunt-contrib-watch": "~0.6.1", + "grunt-include-replace": "^2.0.0", + "grunt-includes": "^0.4.5", "grunt-rev": "~0.1.0", "grunt-svgmin": "1.0.0", "grunt-usemin": "~2.4.0", diff --git a/transfersh-server/handlers.go b/transfersh-server/handlers.go index a4fd93f..1e19c47 100644 --- a/transfersh-server/handlers.go +++ b/transfersh-server/handlers.go @@ -35,9 +35,9 @@ import ( "errors" "fmt" "github.com/dutchcoders/go-clamd" - "github.com/golang/gddo/httputil/header" "github.com/gorilla/mux" "github.com/kennygrant/sanitize" + "github.com/russross/blackfriday" html_template "html/template" "io" "io/ioutil" @@ -57,23 +57,94 @@ func healthHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Approaching Neutral Zone, all systems normal and functioning.") } +/* The preview handler will show a preview of the content for browsers (accept type text/html), and referer is not transfer.sh */ +func previewHandler(w http.ResponseWriter, r *http.Request) { + + vars := mux.Vars(r) + + token := vars["token"] + filename := vars["filename"] + + contentType, contentLength, err := storage.Head(token, filename) + if err != nil { + http.Error(w, http.StatusText(404), 404) + return + } + + var templatePath string + var content html_template.HTML + + switch { + case strings.HasPrefix(contentType, "image/"): + templatePath = "download.image.html" + case strings.HasPrefix(contentType, "video/"): + templatePath = "download.video.html" + case strings.HasPrefix(contentType, "audio/"): + templatePath = "download.audio.html" + case strings.HasPrefix(contentType, "text/"): + templatePath = "download.markdown.html" + + var reader io.ReadCloser + if reader, _, _, err = storage.Get(token, filename); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + var data []byte + if data, err = ioutil.ReadAll(reader); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + if strings.HasPrefix(contentType, "text/x-markdown") || strings.HasPrefix(contentType, "text/markdown") { + output := blackfriday.MarkdownCommon(data) + content = html_template.HTML(output) + } else if strings.HasPrefix(contentType, "text/plain") { + content = html_template.HTML(fmt.Sprintf("
%s
", data)) + } else { + content = html_template.HTML(data) + } + + templatePath = "download.markdown.html" + default: + templatePath = "download.html" + } + + tmpl, err := html_template.New(templatePath).Funcs(html_template.FuncMap{"format": formatNumber}).ParseFiles("static/" + templatePath) + + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + data := struct { + ContentType string + Content html_template.HTML + Filename string + Url string + ContentLength uint64 + }{ + contentType, + content, + filename, + r.URL.String(), + contentLength, + } + + if err := tmpl.ExecuteTemplate(w, templatePath, data); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + +} + // this handler will output html or text, depending on the // support of the client (Accept header). func viewHandler(w http.ResponseWriter, r *http.Request) { // vars := mux.Vars(r) - actual := header.ParseAccept(r.Header, "Accept") - - html := false - - for _, s := range actual { - if s.Value == "text/html" { - html = true - } - } - - if html { + if acceptsHtml(r.Header) { tmpl, err := html_template.ParseFiles("static/index.html") if err != nil { @@ -106,7 +177,7 @@ func notFoundHandler(w http.ResponseWriter, r *http.Request) { func postHandler(w http.ResponseWriter, r *http.Request) { if err := r.ParseMultipartForm(_24K); nil != err { - log.Println(err) + log.Printf("%s", err.Error()) http.Error(w, "Error occured copying to output stream", 500) return } @@ -128,7 +199,7 @@ func postHandler(w http.ResponseWriter, r *http.Request) { var err error if f, err = fheader.Open(); err != nil { - log.Print(err) + log.Printf("%s", err.Error()) http.Error(w, err.Error(), 500) return } @@ -137,7 +208,7 @@ func postHandler(w http.ResponseWriter, r *http.Request) { n, err := io.CopyN(&b, f, _24K+1) if err != nil && err != io.EOF { - log.Print(err) + log.Printf("%s", err.Error()) http.Error(w, err.Error(), 500) return } @@ -155,7 +226,7 @@ func postHandler(w http.ResponseWriter, r *http.Request) { if err != nil { os.Remove(file.Name()) - log.Print(err) + log.Printf("%s", err.Error()) http.Error(w, err.Error(), 500) return } @@ -170,7 +241,7 @@ func postHandler(w http.ResponseWriter, r *http.Request) { log.Printf("Uploading %s %s %d %s", token, filename, contentLength, contentType) if err = storage.Put(token, filename, reader, contentType, uint64(contentLength)); err != nil { - log.Print(err) + log.Printf("%s", err.Error()) http.Error(w, err.Error(), 500) return @@ -199,7 +270,9 @@ func scanHandler(w http.ResponseWriter, r *http.Request) { response, err := c.ScanStream(reader) if err != nil { + log.Printf("%s", err.Error()) http.Error(w, err.Error(), 500) + return } var b string @@ -237,7 +310,7 @@ func putHandler(w http.ResponseWriter, r *http.Request) { n, err := io.CopyN(&b, f, _24K+1) if err != nil && err != io.EOF { - log.Print(err) + log.Printf("%s", err.Error()) http.Error(w, err.Error(), 500) return } @@ -245,7 +318,7 @@ func putHandler(w http.ResponseWriter, r *http.Request) { if n > _24K { file, err := ioutil.TempFile(config.Temp, "transfer-") if err != nil { - log.Print(err) + log.Printf("%s", err.Error()) http.Error(w, err.Error(), 500) return } @@ -255,8 +328,7 @@ func putHandler(w http.ResponseWriter, r *http.Request) { n, err = io.Copy(file, io.MultiReader(&b, f)) if err != nil { os.Remove(file.Name()) - - log.Print(err) + log.Printf("%s", err.Error()) http.Error(w, err.Error(), 500) return } @@ -282,6 +354,7 @@ func putHandler(w http.ResponseWriter, r *http.Request) { var err error if err = storage.Put(token, filename, reader, contentType, uint64(contentLength)); err != nil { + log.Printf("%s", err.Error()) http.Error(w, errors.New("Could not save file").Error(), 500) return } @@ -307,10 +380,17 @@ func zipHandler(w http.ResponseWriter, r *http.Request) { zw := zip.NewWriter(w) for _, key := range strings.Split(files, ",") { - token := sanitize.Path(strings.Split(key, "/")[0]) + if strings.HasPrefix(key, "/") { + key = key[1:] + } + + key = strings.Replace(key, "\\", "/", -1) + + token := strings.Split(key, "/")[0] filename := sanitize.Path(strings.Split(key, "/")[1]) reader, _, _, err := storage.Get(token, filename) + if err != nil { if err.Error() == "The specified key does not exist." { http.Error(w, "File not found", 404) @@ -371,8 +451,14 @@ func tarGzHandler(w http.ResponseWriter, r *http.Request) { defer zw.Close() for _, key := range strings.Split(files, ",") { + if strings.HasPrefix(key, "/") { + key = key[1:] + } + + key = strings.Replace(key, "\\", "/", -1) + token := strings.Split(key, "/")[0] - filename := strings.Split(key, "/")[1] + filename := sanitize.Path(strings.Split(key, "/")[1]) reader, _, contentLength, err := storage.Get(token, filename) if err != nil { @@ -482,23 +568,11 @@ func getHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", contentType) w.Header().Set("Content-Length", strconv.FormatUint(contentLength, 10)) - - mediaType, _, _ := mime.ParseMediaType(contentType) - - switch { - case mediaType == "text/html": - w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename)) - break - case strings.HasPrefix(mediaType, "text"): - case mediaType == "": - break - default: - w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename)) - } - + w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename)) w.Header().Set("Connection", "close") if _, err = io.Copy(w, reader); err != nil { + log.Printf("%s", err.Error()) http.Error(w, "Error occured copying to output stream", 500) return } diff --git a/transfersh-server/main.go b/transfersh-server/main.go index 1f4a997..6369705 100644 --- a/transfersh-server/main.go +++ b/transfersh-server/main.go @@ -33,7 +33,9 @@ import ( "github.com/gorilla/mux" "log" "math/rand" + "mime" "net/http" + "net/url" "os" "time" ) @@ -86,23 +88,27 @@ func main() { r.HandleFunc("/({files:.*}).tar.gz", tarGzHandler).Methods("GET") r.HandleFunc("/download/{token}/{filename}", getHandler).Methods("GET") - /*r.HandleFunc("/{token}/{filename}", viewHandler).MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) bool { - u, err := url.Parse(r.Referer()) - if err != nil { - log.Fatal(err) - return true - } + r.HandleFunc("/{token}/{filename}", previewHandler).MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) (match bool) { + match = false - if u.Host == "transfer.sh" { - return false - } + // The file will show a preview page when opening the link in browser directly or + // from external link. If the referer url path and current path are the same it will be + // downloaded. + if !acceptsHtml(r.Header) { + return false + } - if u.Host == "" { - return false - } + match = (r.Referer() == "") - return true - }).Methods("GET")*/ + u, err := url.Parse(r.Referer()) + if err != nil { + log.Fatal(err) + return + } + + match = match || (u.Path != r.URL.Path) + return + }).Methods("GET") r.HandleFunc("/{token}/{filename}", getHandler).Methods("GET") r.HandleFunc("/get/{token}/{filename}", getHandler).Methods("GET") @@ -156,7 +162,9 @@ func main() { log.Panic("Error while creating storage.") } - log.Printf("Transfer.sh server started. :%v using temp folder: %s", *port, config.Temp) + mime.AddExtensionType(".md", "text/x-markdown") + + log.Printf("Transfer.sh server started. :\nlistening on port: %v\nusing temp folder: %s\nusing storage provider: %s", *port, config.Temp, *provider) log.Printf("---------------------------") s := &http.Server{ diff --git a/transfersh-server/static/404.html b/transfersh-server/static/404.html index 73397ed..0446544 100644 --- a/transfersh-server/static/404.html +++ b/transfersh-server/static/404.html @@ -154,4 +154,4 @@ - \ No newline at end of file + diff --git a/transfersh-server/static/download.audio.html b/transfersh-server/static/download.audio.html new file mode 100644 index 0000000..16643cd --- /dev/null +++ b/transfersh-server/static/download.audio.html @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + transfer.sh - Easy and fast file sharing from the command-line. + + + + + + + + + + + + + + + + + +
+
+ +
+

{{.Filename}}

+

type: {{.ContentType}}

+

size: {{.ContentLength | format "#,###."}} bytes

+ + download

+ + +
+
+
+ +
+
+ +
+
+
+
+
+ +
+ + + + + Fork me on GitHub + + + + + + + + + + + + + + + diff --git a/transfersh-server/static/download.code.html b/transfersh-server/static/download.code.html new file mode 100644 index 0000000..2905cc6 --- /dev/null +++ b/transfersh-server/static/download.code.html @@ -0,0 +1,134 @@ + + + + + + + + + + + + {{.Filename}} - transfer.sh + + + + + + + + + + + + + + + + +
+
+

+ {{.Filename}}

+ +
+
+
+ +
+
+
+
+ + + +
+ +
+ +
+ copy link    + download + +
+
+ + +
+ + + + + + + + + + + + + + + + diff --git a/transfersh-server/static/download.html b/transfersh-server/static/download.html new file mode 100644 index 0000000..8a27deb --- /dev/null +++ b/transfersh-server/static/download.html @@ -0,0 +1,116 @@ + + + + + + + + + + + + transfer.sh - Easy and fast file sharing from the command-line. + + + + + + + + + + + + + + + + + +
+
+ +
+

{{.Filename}}

+

type: {{.ContentType}}

+

size: {{.ContentLength | format "#,###."}} bytes

+ + download

+ +
+
+ + + + + Fork me on GitHub + + + + + + + + + + + + + + + + + diff --git a/transfersh-server/static/download.image.html b/transfersh-server/static/download.image.html new file mode 100644 index 0000000..a8ea14c --- /dev/null +++ b/transfersh-server/static/download.image.html @@ -0,0 +1,126 @@ + + + + + + + + + + + + transfer.sh - Easy and fast file sharing from the command-line. + + + + + + + + + + + + + + + + +
+
+ +
+

{{.Filename}}

+

type: {{.ContentType}}

+

size: {{.ContentLength | format "#,###."}} bytes

+ + download

+ + +
+
+
+ +
+
+ +
+
+
+
+
+
+
+ + + + + Fork me on GitHub + + + + + + + + + + + + + + + diff --git a/transfersh-server/static/download.markdown.html b/transfersh-server/static/download.markdown.html new file mode 100644 index 0000000..8896414 --- /dev/null +++ b/transfersh-server/static/download.markdown.html @@ -0,0 +1,124 @@ + + + + + + + + + + + + transfer.sh - Easy and fast file sharing from the command-line. + + + + + + + + + + + + + + + + +
+
+ +
+

{{.Filename}}

+

type: {{.ContentType}}

+

size: {{.ContentLength | format "#,###."}} bytes

+ + download

+ + +
+
+
+
+
+
{{.Content}}
+
+
+
+
+ +
+ + + + + + Fork me on GitHub + + + + + + + + + + + + + + diff --git a/transfersh-server/static/download.video.html b/transfersh-server/static/download.video.html new file mode 100644 index 0000000..8124e36 --- /dev/null +++ b/transfersh-server/static/download.video.html @@ -0,0 +1,129 @@ + + + + + + + + + + + + transfer.sh - Easy and fast file sharing from the command-line. + + + + + + + + + + + + + + + + + +
+
+ +
+

{{.Filename}}

+

type: {{.ContentType}}

+

size: {{.ContentLength | format "#,###."}} bytes

+ + download

+ + +
+
+
+ +
+
+ +
+
+
+
+
+ +
+ + + + + Fork me on GitHub + + + + + + + + + + + + + + + diff --git a/transfersh-server/static/images/bitcoin.png b/transfersh-server/static/images/bitcoin.png new file mode 100644 index 0000000000000000000000000000000000000000..67bb94d2307fe0862162339fbf2da29ea52a56b4 GIT binary patch literal 6157 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 + + +image/svg+xml + + \ No newline at end of file diff --git a/transfersh-server/static/includes/download-bottom.html b/transfersh-server/static/includes/download-bottom.html new file mode 100644 index 0000000..ffdd2ef --- /dev/null +++ b/transfersh-server/static/includes/download-bottom.html @@ -0,0 +1,5 @@ + + + +
+ diff --git a/transfersh-server/static/includes/download-btn.html b/transfersh-server/static/includes/download-btn.html new file mode 100644 index 0000000..515b585 --- /dev/null +++ b/transfersh-server/static/includes/download-btn.html @@ -0,0 +1,10 @@ +
+ copy link    + download + +
+
+ \ No newline at end of file diff --git a/transfersh-server/static/includes/download-top.html b/transfersh-server/static/includes/download-top.html new file mode 100644 index 0000000..fc113a1 --- /dev/null +++ b/transfersh-server/static/includes/download-top.html @@ -0,0 +1,6 @@ +
+

{{.Filename}}

+

type: {{.ContentType}}

+

size: {{.ContentLength | format "#,###."}} bytes

+ + download

diff --git a/transfersh-server/static/includes/footer.html b/transfersh-server/static/includes/footer.html new file mode 100644 index 0000000..8ac82c4 --- /dev/null +++ b/transfersh-server/static/includes/footer.html @@ -0,0 +1,36 @@ + + + +Fork me on GitHub + + + + + + + diff --git a/transfersh-server/static/includes/ga.html b/transfersh-server/static/includes/ga.html new file mode 100644 index 0000000..c6d5bfd --- /dev/null +++ b/transfersh-server/static/includes/ga.html @@ -0,0 +1,15 @@ + diff --git a/transfersh-server/static/includes/head.html b/transfersh-server/static/includes/head.html new file mode 100644 index 0000000..ca98fe2 --- /dev/null +++ b/transfersh-server/static/includes/head.html @@ -0,0 +1,12 @@ + + + + transfer.sh - Easy and fast file sharing from the command-line. + + + + + + + + diff --git a/transfersh-server/static/includes/js.html b/transfersh-server/static/includes/js.html new file mode 100644 index 0000000..63aabd7 --- /dev/null +++ b/transfersh-server/static/includes/js.html @@ -0,0 +1,2 @@ + + diff --git a/transfersh-server/static/includes/navigation.html b/transfersh-server/static/includes/navigation.html new file mode 100644 index 0000000..12db9a7 --- /dev/null +++ b/transfersh-server/static/includes/navigation.html @@ -0,0 +1,15 @@ + \ No newline at end of file diff --git a/transfersh-server/static/index.html b/transfersh-server/static/index.html index 15014de..223f42c 100644 --- a/transfersh-server/static/index.html +++ b/transfersh-server/static/index.html @@ -11,16 +11,16 @@ transfer.sh - Easy and fast file sharing from the command-line. - + - - - - - - + + + + + + -