Skip to content
Merged
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
17 changes: 6 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@ It's **fast** :rocket:, **secured** :lock: and pretty **lite** :mouse2:
What do you really need ?

### ngrok token

**https tunneling** (port-forwarding) is provided by [ngrok](https://ngrok.com/) go implementation. So, you **need a ngrok token** :key:

... if don't have a ngrok account, don't worry, **it's free** :grimacing:

### docker

If you're familiar with golang, you can build your own server but we recommand to **use our docker image** :whale:

You can download [docker desktop](https://www.docker.com/products/docker-desktop/) and use default settings.
Expand All @@ -30,13 +32,12 @@ You can download [docker desktop](https://www.docker.com/products/docker-desktop

Ok, so now, you may have a **ngrok token** and **run docker** on your machine.

### :one: Let's start the server.
### :one: Let's start the server

Run the following docker command in order to share the content of your local path.

`docker run -it --rm -e NGROK_AUTHTOKEN="YOUR_TOKEN" -v $(pwd):/shared ghcr.io/trendev/ngrok-file-server`
> this example is based on Linux/MacOS usage. If you run `ngrok-file-server` on Windows, you may change local path command `$(pwd)` by something like `%cd%` or direcly set the path...

> do not forget to replace "YOUR_TOKEN" by your ngrok token...

It will pull our docker image and then, build and start a new container :thumbsup:
Expand All @@ -47,12 +48,6 @@ You may see an output like this :

Copy the URL :memo:

#### ... or start the server with a static domain !

At first, you may claim a `static domain` (cf [ngrok static domain](https://ngrok.com/blog-post/free-static-domains-ngrok-users?utm_campaign=Monthly%20Newsletter&utm_medium=email&_hsmi=273371496&_hsenc=p2ANqtz--jWYbTK8jp0_nOfOtdv6J-xx3yPPThs-yue05TvNqnWnV4cddDpbDVOBgfdT9o-xuo6-7UUEBImW1PlHTFoh3ZCmJCtw&utm_content=273371496&utm_source=hs_email))

`docker run -it --rm -e NGROK_AUTHTOKEN="YOUR_TOKEN" -v $(pwd):/shared ghcr.io/trendev/ngrok-file-server --static_domain={your_static_domain}.ngrok-free.app`

This URL is easier to remember, isn't it ?

### :two: Visit the file server from anywhere
Expand All @@ -68,16 +63,16 @@ You can browse your content and share the URL with anyone and access to your fil

You can also control access using an oauth2 provider (like Google, Facebook, Github, Linkedin, etc) and setting an authorized oauth2_domain (for eg, only `trendev.fr` users).

> you can find the supported list [here](https://ngrok.com/docs/cloud-edge/modules/oauth/#oauth-providers-supported-by-ngrok)
> you can find the [supported list](https://ngrok.com/docs/cloud-edge/modules/oauth/#oauth-providers-supported-by-ngrok)

### Enable oauth2 authentication

`docker run -it --rm -e NGROK_AUTHTOKEN=$NGROK_AUTHTOKEN -v $(pwd):/shared ghcr.io/trendev/ngrok-file-server --provider=google`

### Enable oauth2 authentication + oauth2_domain control

`docker run -it --rm -e NGROK_AUTHTOKEN=$NGROK_AUTHTOKEN -v $(pwd):/shared ghcr.io/trendev/ngrok-file-server --provider=google --oauth2_domain=trendev.fr`

## :hand: Something else ?

If you need more, you can open an issue and describe your requirement... and BTW, you can also star the repo :wink:


86 changes: 67 additions & 19 deletions api/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,47 +7,95 @@ import (
"log"
"net/http"

"github.com/Jeffail/gabs/v2"
"github.com/trendev/ngrok-file-server/pkg/colorlog"
"golang.ngrok.com/ngrok"
"golang.ngrok.com/ngrok/config"
"golang.ngrok.com/ngrok/v2"
)

func setConfigHTTPEndpoint() config.Tunnel {
sd := flag.String("static_domain", "", "ngrok static domain")
p := flag.String("provider", "", "oauth2 provider")
const config = `
{
"on_http_response": [
{
"actions": [
{
"type": "add-headers",
"config": {
"headers": {
"x-ngrok-file-server": "trendev.fr",
"x-endpoint-id": "${endpoint.id}",
"x-client-ip": "${conn.client_ip}",
"x-client-conn-start": "${conn.ts.start}",
"x-client-loc": "${conn.geo.country}",
"x-client-path": "${req.url.path}"
}
}
}
]
}
]
}`

func setConfigHTTPEndpoint() []ngrok.EndpointOption {
var opts []ngrok.EndpointOption
p := flag.String("provider", "", "oauth2 provider (google, github, etc.)")
o2d := flag.String("oauth2_domain", "", "oauth2 authorized oauth2_domain")
flag.Parse()

var opts []config.HTTPEndpointOption

if *sd != "" {
opts = append(opts, config.WithDomain(*sd))
c, err := gabs.ParseJSON([]byte(config))
if err != nil {
log.Fatal(err)
}

if *p != "" {
// Create OAuth action structure
a1 := gabs.New()
a1.Set("oauth", "type")
a1.Set(*p, "config", "provider")

// Create request entry
r := gabs.New()
r.ArrayAppend(a1.Data(), "actions")
// Append to on_http_request array
c.ArrayAppend(r.Data(), "on_http_request")

if *o2d != "" {
opts = append(opts, config.WithOAuth(*p, config.WithAllowOAuthDomain(*o2d)),
config.WithRequestHeader("email", "${.oauth.user.email}"))
} else {
opts = append(opts, config.WithOAuth(*p), config.WithRequestHeader("email", "${.oauth.user.email}"))
dr := gabs.New() // domain rule

da := gabs.New() // deny action
da.Set("deny", "type")
da.Set(401, "config", "status_code")

expression := fmt.Sprintf(
"!actions.ngrok.oauth.identity.email.endsWith('%s')",
*o2d,
)

dr.ArrayAppend(expression, "expressions")
dr.ArrayAppend(da.Data(), "actions")

// Ajouter la deuxième règle
c.ArrayAppend(dr.Data(), "on_http_request")
}

log.Println(c.StringIndent("", " "))
}
return config.HTTPEndpoint(opts...)

opts = append(opts, ngrok.WithTrafficPolicy(c.String()))
return opts
}

func main() {
fs := http.FileServer(http.Dir("./shared"))

l, err := ngrok.Listen(context.Background(),
setConfigHTTPEndpoint(),
ngrok.WithAuthtokenFromEnv(),
)
l, err := ngrok.Listen(context.Background(), setConfigHTTPEndpoint()...)

if err != nil {
log.Fatal(err)
}
fmt.Println("ngrok ingress url: ", l.URL())
http.Serve(l, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
colorlog.LogRequest(*r)
w.Header().Add("x-ngrok-file-server", "trendev.fr")
// w.Header().Add("x-ngrok-file-server", "trendev.fr")
ww := colorlog.NewResponseWriterWrapper(w)
fs.ServeHTTP(ww, r)
colorlog.LogResponse(*ww, r)
Expand Down
7 changes: 3 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ module github.com/trendev/ngrok-file-server

go 1.24

require golang.ngrok.com/ngrok v1.13.0
require golang.ngrok.com/ngrok/v2 v2.0.0

require github.com/Jeffail/gabs/v2 v2.7.0

require (
github.com/go-stack/stack v1.8.1 // indirect
Expand All @@ -14,10 +16,7 @@ require (
go.uber.org/multierr v1.11.0 // indirect
golang.ngrok.com/muxado/v2 v2.0.1 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/sync v0.15.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/term v0.32.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
31 changes: 5 additions & 26 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/Jeffail/gabs/v2 v2.7.0 h1:Y2edYaTcE8ZpRsR2AtmPu5xQdFDIthFG0jYhu5PY8kg=
github.com/Jeffail/gabs/v2 v2.7.0/go.mod h1:dp5ocw1FvBBQYssgHsG7I1WYsiLRtkUaB1FEtSwvNUw=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
Expand All @@ -12,11 +14,8 @@ github.com/inconshreveable/log15/v3 v3.0.0-testing.5 h1:h4e0f3kjgg+RJBlKOabrohjH
github.com/inconshreveable/log15/v3 v3.0.0-testing.5/go.mod h1:3GQg1SVrLoWGfRv/kAZMsdyU5cp8eFc1P3cw+Wwku94=
github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand All @@ -27,40 +26,20 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
golang.ngrok.com/muxado/v2 v2.0.1 h1:jM9i6Pom6GGmnPrHKNR6OJRrUoHFkSZlJ3/S0zqdVpY=
golang.ngrok.com/muxado/v2 v2.0.1/go.mod h1:wzxJYX4xiAtmwumzL+QsukVwFRXmPNv86vB8RPpOxyM=
golang.ngrok.com/ngrok v1.11.0 h1:lvbBcoOvH+Ek15wgrjvxpCB+PBM7vinU6jQPsrCdOLw=
golang.ngrok.com/ngrok v1.11.0/go.mod h1:1/gLOyOJm7ygHJlcEbtldFLQwQnQ42z+rucpLE2YsvA=
golang.ngrok.com/ngrok v1.13.0 h1:6SeOS+DAeIaHlkDmNH5waFHv0xjlavOV3wml0Z59/8k=
golang.ngrok.com/ngrok v1.13.0/go.mod h1:BKOMdoZXfD4w6o3EtE7Cu9TVbaUWBqptrZRWnVcAuI4=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.ngrok.com/ngrok/v2 v2.0.0 h1:eUEF7ULph6hUdOVR9r7oue2UhT2vvDoLAo0q//N6vJo=
golang.ngrok.com/ngrok/v2 v2.0.0/go.mod h1:nppMCtZ44/KeGrDHOV0c4bRyMGdHCEBo2Rvjdv/1Uio=
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=