working on preview templates
This commit is contained in:
10
README.md
10
README.md
@ -62,6 +62,16 @@ go run transfersh-server/*.go -provider=local --port 8080 --temp=/tmp/ --basedir
|
|||||||
go build -o transfersh-server *.go
|
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
|
||||||
|
|
||||||
Contributions are welcome.
|
Contributions are welcome.
|
||||||
|
6
transfersh-server/.ebextensions/01config_nginx.config
Normal file
6
transfersh-server/.ebextensions/01config_nginx.config
Normal file
@ -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;"
|
@ -76,9 +76,9 @@ func previewHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
switch {
|
switch {
|
||||||
case strings.HasPrefix(contentType, "image/"):
|
case strings.HasPrefix(contentType, "image/"):
|
||||||
templatePath = "static/download.image.html"
|
templatePath = "download.image.html"
|
||||||
case strings.HasPrefix(contentType, "text/"):
|
case strings.HasPrefix(contentType, "text/"):
|
||||||
templatePath = "static/download.md.html"
|
templatePath = "download.md.html"
|
||||||
|
|
||||||
var reader io.ReadCloser
|
var reader io.ReadCloser
|
||||||
if reader, _, _, err = storage.Get(token, filename); err != nil {
|
if reader, _, _, err = storage.Get(token, filename); err != nil {
|
||||||
@ -100,12 +100,12 @@ func previewHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
content = html_template.HTML(data)
|
content = html_template.HTML(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
templatePath = "static/download.md.html"
|
templatePath = "download.md.html"
|
||||||
default:
|
default:
|
||||||
templatePath = "static/download.html"
|
templatePath = "download.html"
|
||||||
}
|
}
|
||||||
|
|
||||||
tmpl, err := html_template.ParseFiles(templatePath)
|
tmpl, err := html_template.New(templatePath).Funcs(html_template.FuncMap{"format": formatNumber}).ParseFiles("static/" + templatePath)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
@ -126,7 +126,7 @@ func previewHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
contentLength,
|
contentLength,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tmpl.Execute(w, data); err != nil {
|
if err := tmpl.ExecuteTemplate(w, templatePath, data); err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -88,27 +88,26 @@ func main() {
|
|||||||
r.HandleFunc("/({files:.*}).tar.gz", tarGzHandler).Methods("GET")
|
r.HandleFunc("/({files:.*}).tar.gz", tarGzHandler).Methods("GET")
|
||||||
r.HandleFunc("/download/{token}/{filename}", getHandler).Methods("GET")
|
r.HandleFunc("/download/{token}/{filename}", getHandler).Methods("GET")
|
||||||
|
|
||||||
r.HandleFunc("/{token}/{filename}", previewHandler).MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) bool {
|
r.HandleFunc("/{token}/{filename}", previewHandler).MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) (match bool) {
|
||||||
|
match = false
|
||||||
|
|
||||||
// The file will show a preview page when opening the link in browser directly or
|
// The file will show a preview page when opening the link in browser directly or
|
||||||
// from external link. Otherwise it will download the file immediatly.
|
// from external link. If the referer url path and current path are the same it will be
|
||||||
|
// downloaded.
|
||||||
if !acceptsHtml(r.Header) {
|
if !acceptsHtml(r.Header) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
match := (r.Referer() == "")
|
match = (r.Referer() == "")
|
||||||
|
|
||||||
u, err := url.Parse(r.Referer())
|
u, err := url.Parse(r.Referer())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
return match
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
match = match || (u.Host == "transfersh.elasticbeanstalk.com")
|
match = match || (u.Path != r.URL.Path)
|
||||||
match = match || (u.Host == "jxm5d6emw5rknovg.onion")
|
return
|
||||||
match = match || (u.Host == "transfer.sh")
|
|
||||||
match = match || (u.Host == "127.0.0.1")
|
|
||||||
|
|
||||||
return match
|
|
||||||
}).Methods("GET")
|
}).Methods("GET")
|
||||||
|
|
||||||
r.HandleFunc("/{token}/{filename}", getHandler).Methods("GET")
|
r.HandleFunc("/{token}/{filename}", getHandler).Methods("GET")
|
||||||
|
@ -57,12 +57,9 @@
|
|||||||
<section id="home">
|
<section id="home">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<br/>
|
<br/>
|
||||||
<h2>
|
<h2>{{.Filename}}</h2>
|
||||||
{{.Filename}}</h2>
|
<h4>type: <b>{{.ContentType}}</b></h4>
|
||||||
<h4>
|
<h4>size: <b>{{.ContentLength | format "#,###."}}</b> bytes</h4>
|
||||||
Type: <b>{{.ContentType}}</b></h4>
|
|
||||||
<h4>
|
|
||||||
Length: <b>{{.ContentLength}}</b> bytes</h4>
|
|
||||||
<div>
|
<div>
|
||||||
<a href="#" id="copy-link-btn" class="btn-cta btn">copy link</a>
|
<a href="#" id="copy-link-btn" class="btn-cta btn">copy link</a>
|
||||||
<a href="{{.Url}}" class="btn-cta btn"> download</i> </a>
|
<a href="{{.Url}}" class="btn-cta btn"> download</i> </a>
|
||||||
|
@ -56,10 +56,9 @@
|
|||||||
<section id="home">
|
<section id="home">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<br/>
|
<br/>
|
||||||
<h2>
|
<h2> {{.Filename}}</h2>
|
||||||
{{.Filename}}</h2>
|
<h4>type: <b>{{.ContentType}}</b></h4>
|
||||||
<a href="{{.Url}}"></a>
|
<h4>size: <b>{{.ContentLength | format "#,###."}}</b> bytes</h4>
|
||||||
|
|
||||||
<div class="row animated fadeInDown">
|
<div class="row animated fadeInDown">
|
||||||
<div id="from-terminal" class=" box col-md-8 col-md-offset-2 col-xs-12">
|
<div id="from-terminal" class=" box col-md-8 col-md-offset-2 col-xs-12">
|
||||||
<div class="terminal-top">
|
<div class="terminal-top">
|
||||||
|
@ -55,9 +55,10 @@
|
|||||||
|
|
||||||
<section id="home">
|
<section id="home">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
|
<br/>
|
||||||
<h2>{{.Filename}}</h2>
|
<h2>{{.Filename}}</h2>
|
||||||
<h4>Type: <b>{{.ContentType}}</b></h4>
|
<h4>type: <b>{{.ContentType}}</b></h4>
|
||||||
<h4>Length: <b>{{.ContentLength}}</b> bytes</h4>
|
<h4>size: <b>{{.ContentLength | format "#,###."}}</b> bytes</h4>
|
||||||
<div class="row animated fadeInDown">
|
<div class="row animated fadeInDown">
|
||||||
<div id="from-terminal" class=" box col-md-8 col-md-offset-2 col-xs-12">
|
<div id="from-terminal" class=" box col-md-8 col-md-offset-2 col-xs-12">
|
||||||
<div class="terminal-top">
|
<div class="terminal-top">
|
||||||
|
@ -28,8 +28,10 @@ import (
|
|||||||
"github.com/goamz/goamz/aws"
|
"github.com/goamz/goamz/aws"
|
||||||
"github.com/goamz/goamz/s3"
|
"github.com/goamz/goamz/s3"
|
||||||
"github.com/golang/gddo/httputil/header"
|
"github.com/golang/gddo/httputil/header"
|
||||||
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
@ -45,6 +47,163 @@ func getBucket() (*s3.Bucket, error) {
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func formatNumber(format string, s uint64) string {
|
||||||
|
|
||||||
|
return RenderFloat(format, float64(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
var renderFloatPrecisionMultipliers = [10]float64{
|
||||||
|
1,
|
||||||
|
10,
|
||||||
|
100,
|
||||||
|
1000,
|
||||||
|
10000,
|
||||||
|
100000,
|
||||||
|
1000000,
|
||||||
|
10000000,
|
||||||
|
100000000,
|
||||||
|
1000000000,
|
||||||
|
}
|
||||||
|
|
||||||
|
var renderFloatPrecisionRounders = [10]float64{
|
||||||
|
0.5,
|
||||||
|
0.05,
|
||||||
|
0.005,
|
||||||
|
0.0005,
|
||||||
|
0.00005,
|
||||||
|
0.000005,
|
||||||
|
0.0000005,
|
||||||
|
0.00000005,
|
||||||
|
0.000000005,
|
||||||
|
0.0000000005,
|
||||||
|
}
|
||||||
|
|
||||||
|
func RenderFloat(format string, n float64) string {
|
||||||
|
// Special cases:
|
||||||
|
// NaN = "NaN"
|
||||||
|
// +Inf = "+Infinity"
|
||||||
|
// -Inf = "-Infinity"
|
||||||
|
if math.IsNaN(n) {
|
||||||
|
return "NaN"
|
||||||
|
}
|
||||||
|
if n > math.MaxFloat64 {
|
||||||
|
return "Infinity"
|
||||||
|
}
|
||||||
|
if n < -math.MaxFloat64 {
|
||||||
|
return "-Infinity"
|
||||||
|
}
|
||||||
|
|
||||||
|
// default format
|
||||||
|
precision := 2
|
||||||
|
decimalStr := "."
|
||||||
|
thousandStr := ","
|
||||||
|
positiveStr := ""
|
||||||
|
negativeStr := "-"
|
||||||
|
|
||||||
|
if len(format) > 0 {
|
||||||
|
// If there is an explicit format directive,
|
||||||
|
// then default values are these:
|
||||||
|
precision = 9
|
||||||
|
thousandStr = ""
|
||||||
|
|
||||||
|
// collect indices of meaningful formatting directives
|
||||||
|
formatDirectiveChars := []rune(format)
|
||||||
|
formatDirectiveIndices := make([]int, 0)
|
||||||
|
for i, char := range formatDirectiveChars {
|
||||||
|
if char != '#' && char != '0' {
|
||||||
|
formatDirectiveIndices = append(formatDirectiveIndices, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(formatDirectiveIndices) > 0 {
|
||||||
|
// Directive at index 0:
|
||||||
|
// Must be a '+'
|
||||||
|
// Raise an error if not the case
|
||||||
|
// index: 0123456789
|
||||||
|
// +0.000,000
|
||||||
|
// +000,000.0
|
||||||
|
// +0000.00
|
||||||
|
// +0000
|
||||||
|
if formatDirectiveIndices[0] == 0 {
|
||||||
|
if formatDirectiveChars[formatDirectiveIndices[0]] != '+' {
|
||||||
|
panic("RenderFloat(): invalid positive sign directive")
|
||||||
|
}
|
||||||
|
positiveStr = "+"
|
||||||
|
formatDirectiveIndices = formatDirectiveIndices[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Two directives:
|
||||||
|
// First is thousands separator
|
||||||
|
// Raise an error if not followed by 3-digit
|
||||||
|
// 0123456789
|
||||||
|
// 0.000,000
|
||||||
|
// 000,000.00
|
||||||
|
if len(formatDirectiveIndices) == 2 {
|
||||||
|
if (formatDirectiveIndices[1] - formatDirectiveIndices[0]) != 4 {
|
||||||
|
panic("RenderFloat(): thousands separator directive must be followed by 3 digit-specifiers")
|
||||||
|
}
|
||||||
|
thousandStr = string(formatDirectiveChars[formatDirectiveIndices[0]])
|
||||||
|
formatDirectiveIndices = formatDirectiveIndices[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// One directive:
|
||||||
|
// Directive is decimal separator
|
||||||
|
// The number of digit-specifier following the separator indicates wanted precision
|
||||||
|
// 0123456789
|
||||||
|
// 0.00
|
||||||
|
// 000,0000
|
||||||
|
if len(formatDirectiveIndices) == 1 {
|
||||||
|
decimalStr = string(formatDirectiveChars[formatDirectiveIndices[0]])
|
||||||
|
precision = len(formatDirectiveChars) - formatDirectiveIndices[0] - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate sign part
|
||||||
|
var signStr string
|
||||||
|
if n >= 0.000000001 {
|
||||||
|
signStr = positiveStr
|
||||||
|
} else if n <= -0.000000001 {
|
||||||
|
signStr = negativeStr
|
||||||
|
n = -n
|
||||||
|
} else {
|
||||||
|
signStr = ""
|
||||||
|
n = 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
// split number into integer and fractional parts
|
||||||
|
intf, fracf := math.Modf(n + renderFloatPrecisionRounders[precision])
|
||||||
|
|
||||||
|
// generate integer part string
|
||||||
|
intStr := strconv.Itoa(int(intf))
|
||||||
|
|
||||||
|
// add thousand separator if required
|
||||||
|
if len(thousandStr) > 0 {
|
||||||
|
for i := len(intStr); i > 3; {
|
||||||
|
i -= 3
|
||||||
|
intStr = intStr[:i] + thousandStr + intStr[i:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// no fractional part, we can leave now
|
||||||
|
if precision == 0 {
|
||||||
|
return signStr + intStr
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate fractional part
|
||||||
|
fracStr := strconv.Itoa(int(fracf * renderFloatPrecisionMultipliers[precision]))
|
||||||
|
// may need padding
|
||||||
|
if len(fracStr) < precision {
|
||||||
|
fracStr = "000000000000000"[:precision-len(fracStr)] + fracStr
|
||||||
|
}
|
||||||
|
|
||||||
|
return signStr + intStr + decimalStr + fracStr
|
||||||
|
}
|
||||||
|
|
||||||
|
func RenderInteger(format string, n int) string {
|
||||||
|
return RenderFloat(format, float64(n))
|
||||||
|
}
|
||||||
|
|
||||||
// Request.RemoteAddress contains port, which we want to remove i.e.:
|
// Request.RemoteAddress contains port, which we want to remove i.e.:
|
||||||
// "[::1]:58292" => "[::1]"
|
// "[::1]:58292" => "[::1]"
|
||||||
func ipAddrFromRemoteAddr(s string) string {
|
func ipAddrFromRemoteAddr(s string) string {
|
||||||
|
@ -31,12 +31,9 @@ include "includes/head.html"
|
|||||||
<section id="home">
|
<section id="home">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<br/>
|
<br/>
|
||||||
<h2>
|
<h2>{{.Filename}}</h2>
|
||||||
{{.Filename}}</h2>
|
<h4>type: <b>{{.ContentType}}</b></h4>
|
||||||
<h4>
|
<h4>size: <b>{{.ContentLength | format "#,###."}}</b> bytes</h4>
|
||||||
Type: <b>{{.ContentType}}</b></h4>
|
|
||||||
<h4>
|
|
||||||
Length: <b>{{.ContentLength}}</b> bytes</h4>
|
|
||||||
<div>
|
<div>
|
||||||
<a href="#" id="copy-link-btn" class="btn-cta btn">copy link</a>
|
<a href="#" id="copy-link-btn" class="btn-cta btn">copy link</a>
|
||||||
<a href="{{.Url}}" class="btn-cta btn"> download</i> </a>
|
<a href="{{.Url}}" class="btn-cta btn"> download</i> </a>
|
||||||
|
@ -30,10 +30,9 @@ include "includes/head.html"
|
|||||||
<section id="home">
|
<section id="home">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<br/>
|
<br/>
|
||||||
<h2>
|
<h2> {{.Filename}}</h2>
|
||||||
{{.Filename}}</h2>
|
<h4>type: <b>{{.ContentType}}</b></h4>
|
||||||
<a href="{{.Url}}"></a>
|
<h4>size: <b>{{.ContentLength | format "#,###."}}</b> bytes</h4>
|
||||||
|
|
||||||
<div class="row animated fadeInDown">
|
<div class="row animated fadeInDown">
|
||||||
<div id="from-terminal" class=" box col-md-8 col-md-offset-2 col-xs-12">
|
<div id="from-terminal" class=" box col-md-8 col-md-offset-2 col-xs-12">
|
||||||
<div class="terminal-top">
|
<div class="terminal-top">
|
||||||
|
@ -29,9 +29,10 @@ include "includes/head.html"
|
|||||||
|
|
||||||
<section id="home">
|
<section id="home">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
|
<br/>
|
||||||
<h2>{{.Filename}}</h2>
|
<h2>{{.Filename}}</h2>
|
||||||
<h4>Type: <b>{{.ContentType}}</b></h4>
|
<h4>type: <b>{{.ContentType}}</b></h4>
|
||||||
<h4>Length: <b>{{.ContentLength}}</b> bytes</h4>
|
<h4>size: <b>{{.ContentLength | format "#,###."}}</b> bytes</h4>
|
||||||
<div class="row animated fadeInDown">
|
<div class="row animated fadeInDown">
|
||||||
<div id="from-terminal" class=" box col-md-8 col-md-offset-2 col-xs-12">
|
<div id="from-terminal" class=" box col-md-8 col-md-offset-2 col-xs-12">
|
||||||
<div class="terminal-top">
|
<div class="terminal-top">
|
||||||
|
Reference in New Issue
Block a user