Quellcode durchsuchen

Merge remote-tracking branch 'dutchcoders/master'

# Conflicts:
#	README.md
#	go.sum
tags/v1.2.0
Stefan Benten vor 3 Jahren
Ursprung
Commit
b372dc97b5
8 geänderte Dateien mit 247 neuen und 64 gelöschten Zeilen
  1. +89
    -0
      .github/workflows/build-docker-images.yml
  2. +1
    -1
      Dockerfile
  3. +36
    -32
      README.md
  4. +48
    -3
      cmd/cmd.go
  5. +1
    -0
      go.mod
  6. +2
    -0
      go.sum
  7. +33
    -26
      server/handlers.go
  8. +37
    -2
      server/server.go

+ 89
- 0
.github/workflows/build-docker-images.yml Datei anzeigen

@@ -0,0 +1,89 @@
name: Deploy multi-architecture Docker images for transfer.sh with buildx

on:
schedule:
- cron: '0 0 * * *' # everyday at midnight UTC
pull_request:
branches: master
push:
branches: master
tags:
- v*

jobs:
buildx:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Prepare
id: prepare
run: |
DOCKER_IMAGE=dutchcoders/transfer.sh
DOCKER_PLATFORMS=linux/amd64,linux/arm/v7,linux/arm64,linux/386
VERSION=edge

if [[ $GITHUB_REF == refs/tags/* ]]; then
VERSION=${GITHUB_REF#refs/tags/v}
fi

if [ "${{ github.event_name }}" = "schedule" ]; then
VERSION=nightly
fi

TAGS="--tag ${DOCKER_IMAGE}:${VERSION}"

if [ $VERSION = edge -o $VERSION = nightly ]; then
TAGS="$TAGS --tag ${DOCKER_IMAGE}:latest"
fi

echo ::set-output name=docker_image::${DOCKER_IMAGE}
echo ::set-output name=version::${VERSION}
echo ::set-output name=buildx_args::--platform ${DOCKER_PLATFORMS} \
--build-arg VERSION=${VERSION} \
--build-arg BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ') \
--build-arg VCS_REF=${GITHUB_SHA::8} \
${TAGS} .
-
name: Set up QEMU
uses: docker/setup-qemu-action@v1
with:
platforms: all
-
name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v1
with:
version: latest
-
name: Available platforms
run: echo ${{ steps.buildx.outputs.platforms }}
-
name: Docker Buildx (build)
run: |
docker buildx build --no-cache --pull --output "type=image,push=false" ${{ steps.prepare.outputs.buildx_args }}
-
name: Docker Login
if: success() && github.event_name != 'pull_request'
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
run: |
echo "${DOCKER_PASSWORD}" | docker login --username "${DOCKER_USERNAME}" --password-stdin
-
name: Docker Buildx (push)
if: success() && github.event_name != 'pull_request'
run: |
docker buildx build --output "type=image,push=true" ${{ steps.prepare.outputs.buildx_args }}
-
name: Docker Check Manifest
if: always() && github.event_name != 'pull_request'
run: |
docker run --rm mplatform/mquery ${{ steps.prepare.outputs.docker_image }}:${{ steps.prepare.outputs.version }}
-
name: Clear
if: always() && github.event_name != 'pull_request'
run: |
rm -f ${HOME}/.docker/config.json

+ 1
- 1
Dockerfile Datei anzeigen

@@ -12,7 +12,7 @@ WORKDIR /go/src/github.com/dutchcoders/transfer.sh
ENV GO111MODULE=on ENV GO111MODULE=on


# build & install server # build & install server
RUN go get -u ./... && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags -a -tags netgo -ldflags '-w -extldflags "-static"' -o /go/bin/transfersh github.com/dutchcoders/transfer.sh
RUN go get -u ./... && CGO_ENABLED=0 go build -ldflags -a -tags netgo -ldflags '-w -extldflags "-static"' -o /go/bin/transfersh github.com/dutchcoders/transfer.sh


FROM scratch AS final FROM scratch AS final
LABEL maintainer="Andrea Spacca <andrea.spacca@gmail.com>" LABEL maintainer="Andrea Spacca <andrea.spacca@gmail.com>"


+ 36
- 32
README.md Datei anzeigen

@@ -76,42 +76,46 @@ https://transfer.sh/1lDau/test.txt --> https://transfer.sh/inline/1lDau/test.txt


Parameter | Description | Value | Env Parameter | Description | Value | Env
--- | --- | --- | --- --- | --- | --- | ---
listener | port to use for http (:80) | |
profile-listener | port to use for profiler (:6060)| |
force-https | redirect to https | false |
tls-listener | port to use for https (:443) | |
tls-listener-only | flag to enable tls listener only | |
tls-cert-file | path to tls certificate | |
tls-private-key | path to tls private key | |
http-auth-user | user for basic http auth on upload | |
http-auth-pass | pass for basic http auth on upload | |
ip-whitelist | comma separated list of ips allowed to connect to the service | |
ip-blacklist | comma separated list of ips not allowed to connect to the service | |
temp-path | path to temp folder | system temp |
web-path | path to static web files (for development or custom front end) | |
proxy-path | path prefix when service is run behind a proxy | |
ga-key | google analytics key for the front end | |
uservoice-key | user voice key for the front end | |
listener | port to use for http (:80) | | LISTENER |
profile-listener | port to use for profiler (:6060) | | PROFILE_LISTENER |
force-https | redirect to https | false | FORCE_HTTPS
tls-listener | port to use for https (:443) | | TLS_LISTENER |
tls-listener-only | flag to enable tls listener only | | TLS_LISTENER_ONLY |
tls-cert-file | path to tls certificate | | TLS_CERT_FILE |
tls-private-key | path to tls private key | | TLS_PRIVATE_KEY |
http-auth-user | user for basic http auth on upload | | HTTP_AUTH_USER |
http-auth-pass | pass for basic http auth on upload | | HTTP_AUTH_PASS |
ip-whitelist | comma separated list of ips allowed to connect to the service | | IP_WHITELIST |
ip-blacklist | comma separated list of ips not allowed to connect to the service | | IP_BLACKLIST |
temp-path | path to temp folder | system temp | TEMP_PATH |
web-path | path to static web files (for development or custom front end) | | WEB_PATH |
proxy-path | path prefix when service is run behind a proxy | | PROXY_PATH |
proxy-port | port of the proxy when the service is run behind a proxy | | PROXY_PORT |
ga-key | google analytics key for the front end | | GA_KEY |
provider | which storage provider to use | (s3, storj, gdrive or local) | provider | which storage provider to use | (s3, storj, gdrive or local) |
aws-access-key | aws access key | | AWS_ACCESS_KEY
aws-secret-key | aws access key | | AWS_SECRET_KEY
bucket | aws bucket | | BUCKET
s3-endpoint | Custom S3 endpoint. | |
s3-region | region of the s3 bucket | eu-west-1 | S3_REGION
s3-no-multipart | disables s3 multipart upload | false | |
s3-path-style | Forces path style URLs, required for Minio. | false | |
storj-access | Access for the project | | STORJ_ACCESS
storj-bucket | Bucket to use within the project | | STORJ_BUCKET
basedir | path storage for local/gdrive provider| |
gdrive-client-json-filepath | path to oauth client json config for gdrive provider| |
gdrive-local-config-path | path to store local transfer.sh config cache for gdrive provider| |
gdrive-chunk-size | chunk size for gdrive upload in megabytes, must be lower than available memory (8 MB) | |
lets-encrypt-hosts | hosts to use for lets encrypt certificates (comma seperated) | |
log | path to log file| |
uservoice-key | user voice key for the front end | | USERVOICE_KEY |
aws-access-key | aws access key | | AWS_ACCESS_KEY |
aws-secret-key | aws access key | | AWS_SECRET_KEY |
bucket | aws bucket | | BUCKET |
s3-endpoint | Custom S3 endpoint. | | S3_ENDPOINT |
s3-region | region of the s3 bucket | eu-west-1 | S3_REGION |
s3-no-multipart | disables s3 multipart upload | false | S3_NO_MULTIPART |
s3-path-style | Forces path style URLs, required for Minio. | false | S3_PATH_STYLE |
storj-access | Access for the project | | STORJ_ACCESS |
storj-bucket | Bucket to use within the project | | STORJ_BUCKET |
basedir | path storage for local/gdrive provider | | BASEDIR |
gdrive-client-json-filepath | path to oauth client json config for gdrive provider | | GDRIVE_CLIENT_JSON_FILEPATH |
gdrive-local-config-path | path to store local transfer.sh config cache for gdrive provider| | GDRIVE_LOCAL_CONFIG_PATH |
gdrive-chunk-size | chunk size for gdrive upload in megabytes, must be lower than available memory (8 MB) | | GDRIVE_CHUNK_SIZE |
lets-encrypt-hosts | hosts to use for lets encrypt certificates (comma seperated) | | HOSTS |
log | path to log file| | LOG |
cors-domains | comma separated list of domains for CORS, setting it enable CORS | | CORS_DOMAINS |
clamav-host | host for clamav feature | | CLAMAV_HOST |
rate-limit | request per minute | | RATE_LIMIT |


If you want to use TLS using lets encrypt certificates, set lets-encrypt-hosts to your domain, set tls-listener to :443 and enable force-https. If you want to use TLS using lets encrypt certificates, set lets-encrypt-hosts to your domain, set tls-listener to :443 and enable force-https.


If you want to use TLS using your own certificates, set tls-listener to :443, force-https, tls-cert=file and tls-private-key.
If you want to use TLS using your own certificates, set tls-listener to :443, force-https, tls-cert-file and tls-private-key.


## Development ## Development




+ 48
- 3
cmd/cmd.go Datei anzeigen

@@ -12,7 +12,7 @@ import (
"google.golang.org/api/googleapi" "google.golang.org/api/googleapi"
) )


var Version = "1.1.4"
var Version = "1.1.7"
var helpTemplate = `NAME: var helpTemplate = `NAME:
{{.Name}} - {{.Usage}} {{.Name}} - {{.Usage}}


@@ -37,6 +37,7 @@ var globalFlags = []cli.Flag{
Name: "listener", Name: "listener",
Usage: "127.0.0.1:8080", Usage: "127.0.0.1:8080",
Value: "127.0.0.1:8080", Value: "127.0.0.1:8080",
EnvVar: "LISTENER",
}, },
// redirect to https? // redirect to https?
// hostnames // hostnames
@@ -44,57 +45,75 @@ var globalFlags = []cli.Flag{
Name: "profile-listener", Name: "profile-listener",
Usage: "127.0.0.1:6060", Usage: "127.0.0.1:6060",
Value: "", Value: "",
EnvVar: "PROFILE_LISTENER",
}, },
cli.BoolFlag{ cli.BoolFlag{
Name: "force-https", Name: "force-https",
Usage: "", Usage: "",
EnvVar: "FORCE_HTTPS",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "tls-listener", Name: "tls-listener",
Usage: "127.0.0.1:8443", Usage: "127.0.0.1:8443",
Value: "", Value: "",
EnvVar: "TLS_LISTENER",
}, },
cli.BoolFlag{ cli.BoolFlag{
Name: "tls-listener-only", Name: "tls-listener-only",
Usage: "", Usage: "",
EnvVar: "TLS_LISTENER_ONLY",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "tls-cert-file", Name: "tls-cert-file",
Value: "", Value: "",
EnvVar: "TLS_CERT_FILE",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "tls-private-key", Name: "tls-private-key",
Value: "", Value: "",
EnvVar: "TLS_PRIVATE_KEY",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "temp-path", Name: "temp-path",
Usage: "path to temp files", Usage: "path to temp files",
Value: os.TempDir(), Value: os.TempDir(),
EnvVar: "TEMP_PATH",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "web-path", Name: "web-path",
Usage: "path to static web files", Usage: "path to static web files",
Value: "", Value: "",
EnvVar: "WEB_PATH",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "proxy-path", Name: "proxy-path",
Usage: "path prefix when service is run behind a proxy", Usage: "path prefix when service is run behind a proxy",
Value: "", Value: "",
EnvVar: "PROXY_PATH",
},
cli.StringFlag{
Name: "proxy-port",
Usage: "port of the proxy when the service is run behind a proxy",
Value: "",
EnvVar: "PROXY_PORT",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "ga-key", Name: "ga-key",
Usage: "key for google analytics (front end)", Usage: "key for google analytics (front end)",
Value: "", Value: "",
EnvVar: "GA_KEY",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "uservoice-key", Name: "uservoice-key",
Usage: "key for user voice (front end)", Usage: "key for user voice (front end)",
Value: "", Value: "",
EnvVar: "USERVOICE_KEY",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "provider", Name: "provider",
Usage: "s3|gdrive|local", Usage: "s3|gdrive|local",
Value: "", Value: "",
EnvVar: "PROVIDER",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "s3-endpoint", Name: "s3-endpoint",
@@ -129,25 +148,30 @@ var globalFlags = []cli.Flag{
cli.BoolFlag{ cli.BoolFlag{
Name: "s3-no-multipart", Name: "s3-no-multipart",
Usage: "Disables S3 Multipart Puts", Usage: "Disables S3 Multipart Puts",
EnvVar: "S3_NO_MULTIPART",
}, },
cli.BoolFlag{ cli.BoolFlag{
Name: "s3-path-style", Name: "s3-path-style",
Usage: "Forces path style URLs, required for Minio.", Usage: "Forces path style URLs, required for Minio.",
EnvVar: "S3_PATH_STYLE",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "gdrive-client-json-filepath", Name: "gdrive-client-json-filepath",
Usage: "", Usage: "",
Value: "", Value: "",
EnvVar: "GDRIVE_CLIENT_JSON_FILEPATH",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "gdrive-local-config-path", Name: "gdrive-local-config-path",
Usage: "", Usage: "",
Value: "", Value: "",
EnvVar: "GDRIVE_LOCAL_CONFIG_PATH",
}, },
cli.IntFlag{ cli.IntFlag{
Name: "gdrive-chunk-size", Name: "gdrive-chunk-size",
Usage: "", Usage: "",
Value: googleapi.DefaultUploadChunkSize / 1024 / 1024, Value: googleapi.DefaultUploadChunkSize / 1024 / 1024,
EnvVar: "GDRIVE_CHUNK_SIZE",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "storj-access", Name: "storj-access",
@@ -165,7 +189,7 @@ var globalFlags = []cli.Flag{
Name: "rate-limit", Name: "rate-limit",
Usage: "requests per minute", Usage: "requests per minute",
Value: 0, Value: 0,
EnvVar: "",
EnvVar: "RATE_LIMIT",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "lets-encrypt-hosts", Name: "lets-encrypt-hosts",
@@ -177,11 +201,13 @@ var globalFlags = []cli.Flag{
Name: "log", Name: "log",
Usage: "/var/log/transfersh.log", Usage: "/var/log/transfersh.log",
Value: "", Value: "",
EnvVar: "LOG",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "basedir", Name: "basedir",
Usage: "path to storage", Usage: "path to storage",
Value: "", Value: "",
EnvVar: "BASEDIR",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "clamav-host", Name: "clamav-host",
@@ -198,26 +224,37 @@ var globalFlags = []cli.Flag{
cli.BoolFlag{ cli.BoolFlag{
Name: "profiler", Name: "profiler",
Usage: "enable profiling", Usage: "enable profiling",
EnvVar: "PROFILER",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "http-auth-user", Name: "http-auth-user",
Usage: "user for http basic auth", Usage: "user for http basic auth",
Value: "", Value: "",
EnvVar: "HTTP_AUTH_USER",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "http-auth-pass", Name: "http-auth-pass",
Usage: "pass for http basic auth", Usage: "pass for http basic auth",
Value: "", Value: "",
EnvVar: "HTTP_AUTH_PASS",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "ip-whitelist", Name: "ip-whitelist",
Usage: "comma separated list of ips allowed to connect to the service", Usage: "comma separated list of ips allowed to connect to the service",
Value: "", Value: "",
EnvVar: "IP_WHITELIST",
}, },
cli.StringFlag{ cli.StringFlag{
Name: "ip-blacklist", Name: "ip-blacklist",
Usage: "comma separated list of ips not allowed to connect to the service", Usage: "comma separated list of ips not allowed to connect to the service",
Value: "", Value: "",
EnvVar: "IP_BLACKLIST",
},
cli.StringFlag{
Name: "cors-domains",
Usage: "comma separated list of domains allowed for CORS requests",
Value: "",
EnvVar: "CORS_DOMAINS",
}, },
} }


@@ -226,7 +263,7 @@ type Cmd struct {
} }


func VersionAction(c *cli.Context) { func VersionAction(c *cli.Context) {
fmt.Println(color.YellowString(fmt.Sprintf("transfer.sh: Easy file sharing from the command line")))
fmt.Println(color.YellowString(fmt.Sprintf("transfer.sh %s: Easy file sharing from the command line", Version)))
} }


func New() *Cmd { func New() *Cmd {
@@ -257,6 +294,10 @@ func New() *Cmd {
options = append(options, server.Listener(v)) options = append(options, server.Listener(v))
} }


if v := c.String("cors-domains"); v != "" {
options = append(options, server.CorsDomains(v))
}

if v := c.String("tls-listener"); v == "" { if v := c.String("tls-listener"); v == "" {
} else if c.Bool("tls-listener-only") { } else if c.Bool("tls-listener-only") {
options = append(options, server.TLSListener(v, true)) options = append(options, server.TLSListener(v, true))
@@ -276,6 +317,10 @@ func New() *Cmd {
options = append(options, server.ProxyPath(v)) options = append(options, server.ProxyPath(v))
} }


if v := c.String("proxy-port"); v != "" {
options = append(options, server.ProxyPort(v))
}

if v := c.String("ga-key"); v != "" { if v := c.String("ga-key"); v != "" {
options = append(options, server.GoogleAnalytics(v)) options = append(options, server.GoogleAnalytics(v))
} }


+ 1
- 0
go.mod Datei anzeigen

@@ -16,6 +16,7 @@ require (
github.com/garyburd/redigo v1.6.0 // indirect github.com/garyburd/redigo v1.6.0 // indirect
github.com/golang/gddo v0.0.0-20200310004957-95ce5a452273 github.com/golang/gddo v0.0.0-20200310004957-95ce5a452273
github.com/golang/protobuf v1.3.5 // indirect github.com/golang/protobuf v1.3.5 // indirect
github.com/gorilla/handlers v1.4.2
github.com/gorilla/mux v1.7.4 github.com/gorilla/mux v1.7.4
github.com/gorilla/securecookie v1.1.1 // indirect github.com/gorilla/securecookie v1.1.1 // indirect
github.com/jmespath/go-jmespath v0.3.0 // indirect github.com/jmespath/go-jmespath v0.3.0 // indirect


+ 2
- 0
go.sum Datei anzeigen

@@ -136,6 +136,8 @@ github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=


+ 33
- 26
server/handlers.go Datei anzeigen

@@ -158,9 +158,9 @@ func (s *Server) previewHandler(w http.ResponseWriter, r *http.Request) {
} }


relativeURL, _ := url.Parse(path.Join(s.proxyPath, token, filename)) relativeURL, _ := url.Parse(path.Join(s.proxyPath, token, filename))
resolvedURL := resolveURL(r, relativeURL)
resolvedURL := resolveURL(r, relativeURL, s.proxyPort)
relativeURLGet, _ := url.Parse(path.Join(s.proxyPath, getPathPart, token, filename)) relativeURLGet, _ := url.Parse(path.Join(s.proxyPath, getPathPart, token, filename))
resolvedURLGet := resolveURL(r, relativeURLGet)
resolvedURLGet := resolveURL(r, relativeURLGet, s.proxyPort)
var png []byte var png []byte
png, err = qrcode.Encode(resolvedURL, qrcode.High, 150) png, err = qrcode.Encode(resolvedURL, qrcode.High, 150)
if err != nil { if err != nil {
@@ -170,8 +170,8 @@ func (s *Server) previewHandler(w http.ResponseWriter, r *http.Request) {


qrCode := base64.StdEncoding.EncodeToString(png) qrCode := base64.StdEncoding.EncodeToString(png)


hostname := getURL(r).Host
webAddress := resolveWebAddress(r, s.proxyPath)
hostname := getURL(r, s.proxyPort).Host
webAddress := resolveWebAddress(r, s.proxyPath, s.proxyPort)


data := struct { data := struct {
ContentType string ContentType string
@@ -212,8 +212,8 @@ func (s *Server) previewHandler(w http.ResponseWriter, r *http.Request) {
func (s *Server) viewHandler(w http.ResponseWriter, r *http.Request) { func (s *Server) viewHandler(w http.ResponseWriter, r *http.Request) {
// vars := mux.Vars(r) // vars := mux.Vars(r)


hostname := getURL(r).Host
webAddress := resolveWebAddress(r, s.proxyPath)
hostname := getURL(r, s.proxyPort).Host
webAddress := resolveWebAddress(r, s.proxyPath, s.proxyPort)


data := struct { data := struct {
Hostname string Hostname string
@@ -339,7 +339,7 @@ func (s *Server) postHandler(w http.ResponseWriter, r *http.Request) {


filename = url.PathEscape(filename) filename = url.PathEscape(filename)
relativeURL, _ := url.Parse(path.Join(s.proxyPath, token, filename)) relativeURL, _ := url.Parse(path.Join(s.proxyPath, token, filename))
fmt.Fprintln(w, getURL(r).ResolveReference(relativeURL).String())
fmt.Fprintln(w, getURL(r, s.proxyPort).ResolveReference(relativeURL).String())


cleanTmpFile(file) cleanTmpFile(file)
} }
@@ -500,15 +500,15 @@ func (s *Server) putHandler(w http.ResponseWriter, r *http.Request) {
relativeURL, _ := url.Parse(path.Join(s.proxyPath, token, filename)) relativeURL, _ := url.Parse(path.Join(s.proxyPath, token, filename))
deleteURL, _ := url.Parse(path.Join(s.proxyPath, token, filename, metadata.DeletionToken)) deleteURL, _ := url.Parse(path.Join(s.proxyPath, token, filename, metadata.DeletionToken))


w.Header().Set("X-Url-Delete", resolveURL(r, deleteURL))
w.Header().Set("X-Url-Delete", resolveURL(r, deleteURL, s.proxyPort))


fmt.Fprint(w, resolveURL(r, relativeURL))
fmt.Fprint(w, resolveURL(r, relativeURL, s.proxyPort))
} }


func resolveURL(r *http.Request, u *url.URL) string {
func resolveURL(r *http.Request, u *url.URL, proxyPort string) string {
r.URL.Path = "" r.URL.Path = ""


return getURL(r).ResolveReference(u).String()
return getURL(r, proxyPort).ResolveReference(u).String()
} }


func resolveKey(key, proxyPath string) string { func resolveKey(key, proxyPath string) string {
@@ -525,8 +525,8 @@ func resolveKey(key, proxyPath string) string {
return key return key
} }


func resolveWebAddress(r *http.Request, proxyPath string) string {
url := getURL(r)
func resolveWebAddress(r *http.Request, proxyPath string, proxyPort string) string {
url := getURL(r, proxyPort)


var webAddress string var webAddress string


@@ -544,7 +544,7 @@ func resolveWebAddress(r *http.Request, proxyPath string) string {
return webAddress return webAddress
} }


func getURL(r *http.Request) *url.URL {
func getURL(r *http.Request, proxyPort string) *url.URL {
u, _ := url.Parse(r.URL.String()) u, _ := url.Parse(r.URL.String())


if r.TLS != nil { if r.TLS != nil {
@@ -555,16 +555,25 @@ func getURL(r *http.Request) *url.URL {
u.Scheme = "http" u.Scheme = "http"
} }


if u.Host != "" {
} else if host, port, err := net.SplitHostPort(r.Host); err != nil {
u.Host = r.Host
} else {
if port == "80" && u.Scheme == "http" {
u.Host = host
} else if port == "443" && u.Scheme == "https" {
if u.Host == "" {
host, port, err := net.SplitHostPort(r.Host)
if err != nil {
host = r.Host
port = ""
}
if len(proxyPort) != 0 {
port = proxyPort
}
if len(port) == 0 {
u.Host = host u.Host = host
} else { } else {
u.Host = net.JoinHostPort(host, port)
if port == "80" && u.Scheme == "http" {
u.Host = host
} else if port == "443" && u.Scheme == "https" {
u.Host = host
} else {
u.Host = net.JoinHostPort(host, port)
}
} }
} }


@@ -614,9 +623,7 @@ func (s *Server) CheckMetadata(token, filename string, increaseDownload bool) (M
var metadata Metadata var metadata Metadata


r, _, err := s.storage.Get(token, fmt.Sprintf("%s.metadata", filename)) r, _, err := s.storage.Get(token, fmt.Sprintf("%s.metadata", filename))
if s.storage.IsNotExist(err) {
return metadata, nil
} else if err != nil {
if err != nil {
return metadata, err return metadata, err
} }


@@ -1011,7 +1018,7 @@ func (s *Server) RedirectHandler(h http.Handler) http.HandlerFunc {
} else if r.Header.Get("X-Forwarded-Proto") == "https" { } else if r.Header.Get("X-Forwarded-Proto") == "https" {
} else if r.URL.Scheme == "https" { } else if r.URL.Scheme == "https" {
} else { } else {
u := getURL(r)
u := getURL(r, s.proxyPort)
u.Scheme = "https" u.Scheme = "https"


http.Redirect(w, r, u.String(), http.StatusPermanentRedirect) http.Redirect(w, r, u.String(), http.StatusPermanentRedirect)


+ 37
- 2
server/server.go Datei anzeigen

@@ -26,7 +26,10 @@ package server


import ( import (
"errors" "errors"
gorillaHandlers "github.com/gorilla/handlers"
"log" "log"
crypto_rand "crypto/rand"
"encoding/binary"
"math/rand" "math/rand"
"mime" "mime"
"net/http" "net/http"
@@ -85,6 +88,13 @@ func Listener(s string) OptionFn {


} }


func CorsDomains(s string) OptionFn {
return func(srvr *Server) {
srvr.CorsDomains = s
}

}

func GoogleAnalytics(gaKey string) OptionFn { func GoogleAnalytics(gaKey string) OptionFn {
return func(srvr *Server) { return func(srvr *Server) {
srvr.gaKey = gaKey srvr.gaKey = gaKey
@@ -131,6 +141,12 @@ func ProxyPath(s string) OptionFn {
} }
} }


func ProxyPort(s string) OptionFn {
return func(srvr *Server) {
srvr.proxyPort = s
}
}

func TempPath(s string) OptionFn { func TempPath(s string) OptionFn {
return func(srvr *Server) { return func(srvr *Server) {
if s[len(s)-1:] != "/" { if s[len(s)-1:] != "/" {
@@ -270,11 +286,13 @@ type Server struct {


webPath string webPath string
proxyPath string proxyPath string
proxyPort string
gaKey string gaKey string
userVoiceKey string userVoiceKey string


TLSListenerOnly bool TLSListenerOnly bool


CorsDomains string
ListenerString string ListenerString string
TLSListenerString string TLSListenerString string
ProfileListenerString string ProfileListenerString string
@@ -297,7 +315,11 @@ func New(options ...OptionFn) (*Server, error) {
} }


func init() { func init() {
rand.Seed(time.Now().UTC().UnixNano())
var seedBytes [8]byte
if _, err := crypto_rand.Read(seedBytes[:]); err != nil {
panic("cannot obtain cryptographically secure seed")
}
rand.Seed(int64(binary.LittleEndian.Uint64(seedBytes[:])))
} }


func (s *Server) Run() { func (s *Server) Run() {
@@ -413,11 +435,24 @@ func (s *Server) Run() {


s.logger.Printf("Transfer.sh server started.\nusing temp folder: %s\nusing storage provider: %s", s.tempPath, s.storage.Type()) s.logger.Printf("Transfer.sh server started.\nusing temp folder: %s\nusing storage provider: %s", s.tempPath, s.storage.Type())


var cors func(http.Handler) http.Handler
if len(s.CorsDomains) > 0 {
cors = gorillaHandlers.CORS(
gorillaHandlers.AllowedHeaders([]string{"*"}),
gorillaHandlers.AllowedOrigins(strings.Split(s.CorsDomains, ",")),
gorillaHandlers.AllowedMethods([]string{"GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"}),
)
} else {
cors = func(h http.Handler) http.Handler {
return h
}
}

h := handlers.PanicHandler( h := handlers.PanicHandler(
IPFilterHandler( IPFilterHandler(
handlers.LogHandler( handlers.LogHandler(
LoveHandler( LoveHandler(
s.RedirectHandler(r)),
s.RedirectHandler(cors(r))),
handlers.NewLogOptions(s.logger.Printf, "_default_"), handlers.NewLogOptions(s.logger.Printf, "_default_"),
), ),
s.ipFilterOptions, s.ipFilterOptions,


Laden…
Abbrechen
Speichern