refactor cmds for goreleaser

This commit is contained in:
AJ ONeal 2020-11-13 02:43:17 -07:00
parent 750f339f58
commit ade7f0ba80
23 changed files with 474 additions and 312 deletions

48
.goreleaser.yml Normal file
View File

@ -0,0 +1,48 @@
# This is an example goreleaser.yaml file with some sane defaults.
# Make sure to check the documentation at http://goreleaser.com
before:
hooks:
# You may remove this if you don't use go modules.
- go mod download
# you may remove this if you don't need go generate
- go generate ./...
builds:
- id: telebit-client
main: ./cmd/telebit/telebit.go
env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
goarch:
- amd64
- arm64
- arm
- id: telebit-mgmt
main: ./cmd/mgmt/mgmt.go
env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
goarch:
- amd64
- arm64
- arm
archives:
- replacements:
386: i386
amd64: x86_64
arm64: aarch64
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ .Tag }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'

352
README.md
View File

@ -1,9 +1,45 @@
# Telebit
| **Telebit Client** | [Telebit Relay](/tree/master/cmd/telebit) | [Telebit Mgmt](/tree/master/cmd/mgmt) |
A secure, end-to-end Encrypted tunnel.
Because friends don't let friends localhost.
# Usage
```bash
telebit --env ./.env --verbose
```
Command-line flags or `.env` may be used.
```bash
# --acme-agree
export ACME_AGREE=true
# --acme-email
export ACME_EMAIL=johndoe@example.com
# --vendor-id
export VENDOR_ID=example.com
# --secret
export SECRET=QQgPyfzVdxJTcUc1ceot3pgJFKtWSHMQ
# --tunnel-relay
export TUNNEL_RELAY_URL=https://tunnel.example.com/
# --tls-locals
export TLS_LOCALS=https:*:3000
```
See `./telebit --help` for all options. \
See [`examples/client.env`][client-env] for detail explanations.
[client-env]: /tree/master/examples/client.env
# Build
```bash
goreleaser --rm-dist --skip-publish
```
## Install Go
Installs Go to `~/.local/opt/go` for MacOS and Linux:
@ -37,239 +73,6 @@ The binary can be built with `VENDOR_ID` and `CLIENT_SECRET` built into the bina
You can also change the `serviceName` and `serviceDescription` at build time.
See `examples/run-as-client.sh`.
### Configure
Command-line flags or `.env` may be used.
See `./telebit --help` for all options, and `examples/relay.env` for their corresponding ENVs.
### Example
Copy `examples/relay.env` as `.env` in the working directory.
```bash
# For Tunnel Relay Server
API_HOSTNAME=devices.example.com
LISTEN=:443
LOCALS=https:mgmt.devices.example.com:3010
VERBOSE=false
# For Device Management & Authentication
AUTH_URL=http://localhost:3010/api
# For Let's Encrypt / ACME registration
ACME_AGREE=true
ACME_EMAIL=letsencrypt@example.com
# For Let's Encrypt / ACME challenges
ACME_HTTP_01_RELAY_URL=http://localhost:3010/api/http
ACME_RELAY_URL=http://localhost:3010/api/dns
SECRET=xxxxxxxxxxxxxxxx
GODADDY_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
GODADDY_API_SECRET=xxxxxxxxxxxxxxxxxxxxxx
```
Note: It is not necessary to specify the `--flags` when using the ENVs.
```bash
./telebit \
--api-hostname $API_HOSTNAME \
--auth-url "$AUTH_URL" \
--acme-agree "$ACME_AGREE" \
--acme-email "$ACME_EMAIL" \
--secret "$SECRET" \
--listen "$LISTEN"
```
### API
List all connected devices
```bash
bash examples/admin-list-devices.sh
```
```bash
curl -L https://devices.example.com/api/subscribers -H "Authorization: Bearer ${TOKEN}"
```
```json
{
"success": true,
"subscribers": [{ "since": "2020-07-22T08:20:40Z", "sub": "ruby", "sockets": ["73.228.72.97:50737"], "clients": 0 }]
}
```
Show connectivity, of a single device, if any
```bash
curl -L https://devices.example.com/api/subscribers -H "Authorization: Bearer ${TOKEN}"
```
```json
{
"success": true,
"subscribers": [{ "since": "2020-07-22T08:20:40Z", "sub": "ruby", "sockets": ["73.228.72.97:50737"], "clients": 0 }]
}
```
Force a device to disconnect:
```bash
bash examples/admin-disconnect-device.sh
```
```bash
my_subdomain="ruby"
curl -X DELETE http://mgmt.example.com:3010/api/subscribers/ruby" -H "Authorization: Bearer ${TOKEN}"
```
```json
{ "success": true }
```
## Management Server
```bash
go generate ./...
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -mod vendor -o mgmt-server-linux ./cmd/mgmt/*.go
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -mod vendor -o mgmt-server-macos ./cmd/mgmt/*.go
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -mod vendor -o mgmt-server-windows-debug.exe ./cmd/mgmt/*.go
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -mod vendor -ldflags "-H windowsgui" -o mgmt-server-windows.exe ./cmd/mgmt/*.go
```
### Example
```bash
./telebit-mgmt --domain devices.example.com --port 3010
```
Copy `examples/mgmt.env` as `.env` in the working directory.
### Device Management API
Create a token with the same `SECRET` used with the `mgmt` server,
and add a device by its `subdomain`.
To build `signjwt`:
```bash
go build -mod=vendor -ldflags "-s -w" -o signjwt cmd/signjwt/*.go
```
To generate an `admin` token:
```bash
VENDOR_ID="test-id"
SECRET="xxxxxxxxxxx"
TOKEN=$(./signjwt \
--expires-in 15m \
--vendor-id $VENDOR_ID \
--secret $SECRET \
--machine-ppid $SECRET
)
```
Authorize a device:
```bash
my_subdomain="xxxx"
my_mgmt_host=http://mgmt.example.com:3010
curl -X POST $my_mgmt_host/api/devices \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{ "slug": "'$my_subdomain'" }'
```
```json
{ "shared_key": "ZZZZZZZZ" }
```
Show data of a single device
```bash
my_subdomain="xxxx"
curl -L http://mgmt.example.com:3010/api/devices/${my_subdomain} -H "Authorization: Bearer ${TOKEN}"
```
```json
{ "subdomain": "sub1", "updated_at": "2020-05-20T12:00:01Z" }
```
Get a list of connected devices:
```bash
curl -L http://mgmt.example.com:3010/api/devices -H "Authorization: Bearer ${TOKEN}"
```
```json
[{ "subdomain": "sub1", "updated_at": "2020-05-20T12:00:01Z" }]
```
Get a list of disconnected devices:
```bash
curl -L http://mgmt.example.com:3010/api/devices?inactive=true -H "Authorization: Bearer ${TOKEN}"
```
Deauthorize a device:
```bash
my_subdomain="xxxx"
curl -L -X DELETE http://mgmt.example.com:3010/api/devices/${my_subdomain} -H "Authorization: Bearer ${TOKEN}"
```
## Tunnel Client
The tunnel relay binary is also the client binary.
You do not need to build a separate client binary.
### Configure
Command-line flags or `.env` may be used.
See `./telebit --help` for all options, and `examples/client.env` for their corresponding ENVs.
### Example
Copy `examples/client.env` as `.env` in the working directory.
```bash
# For Client
VENDOR_ID=test-id
CLIENT_SUBJECT=newieb
CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxx
AUTH_URL="https://mgmt.devices.example.com/api"
TUNNEL_RELAY_URL=https://devices.example.com/
LOCALS=https:newbie.devices.example.com:3000,http:newbie.devices.example.com:3000
#PORT_FORWARDS=3443:3001,8443:3002
# For Debugging
VERBOSE=true
#VERBOSE_BYTES=true
#VERBOSE_RAW=true
# For Let's Encrypt / ACME registration
ACME_AGREE=true
ACME_EMAIL=letsencrypt@example.com
# For Let's Encrypt / ACME challenges
ACME_RELAY_URL="https://mgmt.devices.example.com/api/dns"
```
```bash
./telebit \
--vendor-id "$VENDOR_ID" \
--secret "$CLIENT_SECRET" \
--tunnel-relay-url $TUNNEL_RELAY_URL \
--locals "$LOCALS" \
--acme-agree="$ACME_AGREE" \
--acme-email "$ACME_EMAIL" \
--verbose=$VERBOSE
```
## Local Web Application
Currently only raw TCP is tunneled.
@ -288,20 +91,75 @@ EOF
python3 -m http.server 3000
```
## Glossary
## Help
```
--vendor-id $VENDOR_ID an arbitrary id used as part of authentication
--secret $SECRET the secret for creating JWTs
--tunnel-relay-url $TUNNEL_RELAY_URL the url of the tunnel server
--auth-url $AUTH_URL use to override the server-provided auth url
--acme-relay-url $ACME_RELAY_URL use to override the server-provided acme dns 01 proxy
--locals $LOCALS a list of `scheme:domainname:port`
for forwarding incoming `domainname` to local `port`
--port-forwards $PORT_FORWARDS a list of `remote:local` tcp port-forwarding
--verbose $VERBOSE logs everything, including abbreviated data (as hex)
$VERBOSE_BYTES logs full data (as hex)
$VERBOSE_RAW logs full data (as string)
--acme-agree $ACME_AGREE agree to the ACME service agreement
--acme-email $ACME_EMAIL the webmaster email for ACME notices
Usage of telebit:
ACME_AGREE
--acme-agree
agree to the terms of the ACME service provider (required)
--acme-directory string
ACME Directory URL
ACME_EMAIL
--acme-email string
email to use for Let's Encrypt / ACME registration
--acme-http-01
enable HTTP-01 ACME challenges
ACME_HTTP_01_RELAY_URL
--acme-http-01-relay-url string
the base url of the ACME HTTP-01 relay, if not the same as the DNS-01 relay
--acme-relay-url string
the base url of the ACME DNS-01 relay, if not the same as the tunnel relay
--acme-staging
get fake certificates for testing
--acme-storage string
path to ACME storage directory (default "./acme.d/")
--acme-tls-alpn-01
enable TLS-ALPN-01 ACME challenges
API_HOSTNAME
--api-hostname string
the hostname used to manage clients
--auth-url string
the base url for authentication, if not the same as the tunnel relay
DEBUG
--debug
show debug output (default true)
--dns-01-delay duration
add an extra delay after dns self-check to allow DNS-01 challenges to propagate
--dns-resolvers string
a list of resolvers in the format 8.8.8.8:53,8.8.4.4:53
--env string
path to .env file
--leeway duration
allow for time drift / skew (hard-coded to 15 minutes) (default 15m0s)
LISTEN
--listen string
list of bind addresses on which to listen, such as localhost:80, or :443
LOCALS
--locals string
a list of <from-domain>:<to-port>
PORT_FORWARD
--port-forward string
a list of <from-port>:<to-port> for raw port-forwarding
SECRET
--secret string
the same secret used by telebit-relay (used for JWT authentication)
--spf-domain string
domain with SPF-like list of IP addresses which are allowed to connect to clients
TLS_LOCALS
--tls-locals string
like --locals, but TLS will be used to connect to the local port
--token string
an auth token for the server (instead of generating --secret); use --token=false to ignore any $TOKEN in env
TUNNEL_RELAY_URL
--tunnel-relay-url string
the websocket url at which to connect to the tunnel relay
VENDOR_ID
--vendor-id string
a unique identifier for a deploy target environment
VERBOSE
VERBOSE_BYTES
VERBOSE_RAW
--verbose
log excessively
```

View File

@ -1,4 +1,4 @@
# MGMT Server
# Telebit Mgmt
# Config
@ -18,6 +18,17 @@ NAMECOM_USERNAME=johndoe
NAMECOM_API_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```
## API
```bash
my_subdomain="ruby"
curl -X DELETE http://mgmt.example.com:3010/api/subscribers/ruby" -H "Authorization: Bearer ${TOKEN}"
```
```json
{ "success": true }
```
# Build
```bash
@ -27,3 +38,95 @@ pushd cmd/mgmt
go build -mod vendor -o telebit-mgmt
popd
```
## Management Server
```bash
go generate ./...
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -mod vendor -o mgmt-server-linux ./cmd/mgmt/*.go
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -mod vendor -o mgmt-server-macos ./cmd/mgmt/*.go
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -mod vendor -o mgmt-server-windows-debug.exe ./cmd/mgmt/*.go
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -mod vendor -ldflags "-H windowsgui" -o mgmt-server-windows.exe ./cmd/mgmt/*.go
```
### Example
```bash
./telebit-mgmt --domain devices.example.com --port 3010
```
Copy `examples/mgmt.env` as `.env` in the working directory.
### Device Management API
Create a token with the same `SECRET` used with the `mgmt` server,
and add a device by its `subdomain`.
To build `signjwt`:
```bash
go build -mod=vendor -ldflags "-s -w" -o signjwt cmd/signjwt/*.go
```
To generate an `admin` token:
```bash
VENDOR_ID="test-id"
SECRET="xxxxxxxxxxx"
TOKEN=$(./signjwt \
--expires-in 15m \
--vendor-id $VENDOR_ID \
--secret $SECRET \
--machine-ppid $SECRET
)
```
Authorize a device:
```bash
my_subdomain="xxxx"
my_mgmt_host=http://mgmt.example.com:3010
curl -X POST $my_mgmt_host/api/devices \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{ "slug": "'$my_subdomain'" }'
```
```json
{ "shared_key": "ZZZZZZZZ" }
```
Show data of a single device
```bash
my_subdomain="xxxx"
curl -L http://mgmt.example.com:3010/api/devices/${my_subdomain} -H "Authorization: Bearer ${TOKEN}"
```
```json
{ "subdomain": "sub1", "updated_at": "2020-05-20T12:00:01Z" }
```
Get a list of connected devices:
```bash
curl -L http://mgmt.example.com:3010/api/devices -H "Authorization: Bearer ${TOKEN}"
```
```json
[{ "subdomain": "sub1", "updated_at": "2020-05-20T12:00:01Z" }]
```
Get a list of disconnected devices:
```bash
curl -L http://mgmt.example.com:3010/api/devices?inactive=true -H "Authorization: Bearer ${TOKEN}"
```
Deauthorize a device:
```bash
my_subdomain="xxxx"
curl -L -X DELETE http://mgmt.example.com:3010/api/devices/${my_subdomain} -H "Authorization: Bearer ${TOKEN}"
```

View File

@ -10,12 +10,14 @@ import (
"os"
"strings"
"git.rootprojects.org/root/telebit/mgmt/authstore"
"git.rootprojects.org/root/telebit/internal/mgmt"
"git.rootprojects.org/root/telebit/internal/mgmt/authstore"
"github.com/go-acme/lego/v3/challenge"
"github.com/go-acme/lego/v3/providers/dns/duckdns"
"github.com/go-acme/lego/v3/providers/dns/godaddy"
"github.com/go-acme/lego/v3/providers/dns/namedotcom"
_ "github.com/joho/godotenv/autoload"
)
@ -28,14 +30,8 @@ var (
GitTimestamp = "0000-00-00T00:00:00+0000"
)
// MWKey is a type guard
type MWKey string
var store authstore.Store
var provider challenge.Provider = nil // TODO is this concurrency-safe?
var secret string
var primaryDomain string
var relayDomain string
func help() {
fmt.Fprintf(os.Stderr, "Usage: mgmt --domain <devices.example.com> --secret <128-bit secret>\n")
@ -59,22 +55,22 @@ func main() {
"database (postgres) connection url")
flag.StringVar(&secret, "secret", "",
"a >= 16-character random string for JWT key signing")
flag.StringVar(&primaryDomain, "domain", "",
flag.StringVar(&mgmt.DeviceDomain, "domain", "",
"the base domain to use for all clients")
flag.StringVar(&relayDomain, "tunnel-domain", "",
flag.StringVar(&mgmt.RelayDomain, "tunnel-domain", "",
"the domain name of the tunnel relay service, if different from base domain")
flag.Parse()
if 0 == len(primaryDomain) {
primaryDomain = os.Getenv("DOMAIN")
if 0 == len(mgmt.DeviceDomain) {
mgmt.DeviceDomain = os.Getenv("DOMAIN")
}
if 0 == len(relayDomain) {
relayDomain = os.Getenv("TUNNEL_DOMAIN")
if 0 == len(mgmt.RelayDomain) {
mgmt.RelayDomain = os.Getenv("TUNNEL_DOMAIN")
}
if 0 == len(relayDomain) {
relayDomain = primaryDomain
if 0 == len(mgmt.RelayDomain) {
mgmt.RelayDomain = mgmt.DeviceDomain
}
if 0 == len(dbURL) {
@ -99,6 +95,8 @@ func main() {
lnAddr = "localhost:" + port
}
// TODO are these concurrency-safe?
var provider challenge.Provider = nil
if len(os.Getenv("GODADDY_API_KEY")) > 0 {
id := os.Getenv("GODADDY_API_KEY")
apiSecret := os.Getenv("GODADDY_API_SECRET")
@ -120,7 +118,7 @@ func main() {
fmt.Println("DNS-01 relay disabled")
}
if 0 == len(primaryDomain) || 0 == len(secret) || 0 == len(dbURL) {
if 0 == len(mgmt.DeviceDomain) || 0 == len(secret) || 0 == len(dbURL) {
help()
os.Exit(1)
return
@ -134,7 +132,7 @@ func main() {
connStr += "?sslmode=required"
}
store, err = authstore.NewStore(connStr, initSQL)
store, err = authstore.NewStore(connStr, mgmt.InitSQL)
if nil != err {
log.Fatal("connection error", err)
return
@ -142,16 +140,18 @@ func main() {
_ = store.SetMaster(secret)
defer store.Close()
mgmt.Init(store, provider)
go func() {
fmt.Println("Listening for ACME challenges on :" + challengesPort)
if err := http.ListenAndServe(":"+challengesPort, routeStatic()); nil != err {
if err := http.ListenAndServe(":"+challengesPort, mgmt.RouteStatic()); nil != err {
log.Fatal(err)
os.Exit(1)
}
}()
fmt.Println("Listening on", lnAddr)
fmt.Fprintf(os.Stderr, "failed: %s", http.ListenAndServe(lnAddr, routeAll()))
fmt.Fprintf(os.Stderr, "failed: %s", http.ListenAndServe(lnAddr, mgmt.RouteAll()))
}
// newNameDotComDNSProvider is for the sake of demoing the tunnel

View File

@ -1,3 +0,0 @@
package main
var initSQL = "./postgres.init.sql"

View File

@ -0,0 +1,79 @@
# Telebit Relay
| [Telebit Client](../../) | **Telebit Relay** | [Telebit Mgmt](../mgmt) |
### Example
Copy `examples/relay.env` as `.env` in the working directory.
```bash
# For Tunnel Relay Server
API_HOSTNAME=devices.example.com
LISTEN=:443
LOCALS=https:mgmt.devices.example.com:3010
VERBOSE=false
# For Device Management & Authentication
AUTH_URL=http://localhost:3010/api
# For Let's Encrypt / ACME registration
ACME_AGREE=true
ACME_EMAIL=letsencrypt@example.com
# For Let's Encrypt / ACME challenges
ACME_HTTP_01_RELAY_URL=http://localhost:3010/api/http
ACME_RELAY_URL=http://localhost:3010/api/dns
SECRET=xxxxxxxxxxxxxxxx
GODADDY_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
GODADDY_API_SECRET=xxxxxxxxxxxxxxxxxxxxxx
```
Note: It is not necessary to specify the `--flags` when using the ENVs.
```bash
./telebit \
--api-hostname $API_HOSTNAME \
--auth-url "$AUTH_URL" \
--acme-agree "$ACME_AGREE" \
--acme-email "$ACME_EMAIL" \
--secret "$SECRET" \
--listen "$LISTEN"
```
### API
List all connected devices
```bash
bash examples/admin-list-devices.sh
```
```bash
curl -L https://devices.example.com/api/subscribers -H "Authorization: Bearer ${TOKEN}"
```
```json
{
"success": true,
"subscribers": [{ "since": "2020-07-22T08:20:40Z", "sub": "ruby", "sockets": ["73.228.72.97:50737"], "clients": 0 }]
}
```
Show connectivity, of a single device, if any
```bash
curl -L https://devices.example.com/api/subscribers -H "Authorization: Bearer ${TOKEN}"
```
```json
{
"success": true,
"subscribers": [{ "since": "2020-07-22T08:20:40Z", "sub": "ruby", "sockets": ["73.228.72.97:50737"], "clients": 0 }]
}
```
Force a device to disconnect:
```bash
bash examples/admin-disconnect-device.sh
```

View File

@ -11,6 +11,7 @@ import (
"fmt"
"io"
"net"
"net/http"
"net/url"
"os"
"regexp"
@ -22,21 +23,23 @@ import (
"git.rootprojects.org/root/telebit/dbg"
"git.rootprojects.org/root/telebit/internal/dns01"
"git.rootprojects.org/root/telebit/internal/http01"
"git.rootprojects.org/root/telebit/internal/mgmt"
"git.rootprojects.org/root/telebit/internal/mgmt/authstore"
"git.rootprojects.org/root/telebit/internal/service"
telebitX "git.rootprojects.org/root/telebit/internal/telebit"
"git.rootprojects.org/root/telebit/iplist"
"git.rootprojects.org/root/telebit/mgmt"
"git.rootprojects.org/root/telebit/mgmt/authstore"
"git.rootprojects.org/root/telebit/table"
"git.rootprojects.org/root/telebit/tunnel"
legoDNS01 "github.com/go-acme/lego/v3/challenge/dns01"
"github.com/coolaj86/certmagic"
"github.com/denisbrodbeck/machineid"
jwt "github.com/dgrijalva/jwt-go"
"github.com/go-acme/lego/v3/challenge"
legoDNS01 "github.com/go-acme/lego/v3/challenge/dns01"
"github.com/go-acme/lego/v3/providers/dns/duckdns"
"github.com/go-acme/lego/v3/providers/dns/godaddy"
"github.com/go-acme/lego/v3/providers/dns/namedotcom"
"github.com/go-chi/chi"
"github.com/joho/godotenv"
_ "github.com/joho/godotenv/autoload"
)
@ -80,8 +83,6 @@ type Forward struct {
localTLS bool
}
var authorizer telebit.Authorizer
var isHostname = regexp.MustCompile(`^[A-Za-z0-9_\.\-]+$`).MatchString
// VendorID may be baked in, or supplied via ENVs or --args
@ -383,7 +384,6 @@ func main() {
return
}
fmt.Println("Auth URL", *authURL)
authorizer = NewAuthorizer(*authURL)
dns01Base := directory.DNS01Proxy.URL
if 0 == len(*acmeRelay) {
@ -428,7 +428,6 @@ func main() {
fmt.Printf("[Grants]\n\t%#v\n", grants)
*relay = grants.Audience
}
authorizer = NewAuthorizer(*authURL)
fmt.Printf("Email: %q\n", *email)
@ -590,9 +589,11 @@ func muxAll(
}
if "" != *apiHostname {
// this is a generic net listener
InitAdmin(*authURL)
r := chi.NewRouter()
telebitX.RouteAdmin(*authURL, r)
apiListener := tunnel.NewListener()
go func() {
httpsrv := &http.Server{Handler: r}
httpsrv.Serve(apiListener)
}()
fmt.Printf("Will respond to Websocket and API requests to %q\n", *apiHostname)

View File

@ -1,3 +1,17 @@
# VERBOSE
# Show more output in the logs
#VERBOSE=true
# DEBUG
# Show binary output in the longs too
#DEBUG=true
# Used for Let's Encrypt registration
# ACME_AGREE
ACME_AGREE=true
# ACME_EMAIL
ACME_EMAIL=johndoe@example.com
# TUNNEL_RELAY_URL
# The URL of the Telebit Relay, of course.
# Note that many client configuration details can be preassigned at
@ -9,23 +23,53 @@ TUNNEL_RELAY_URL=https://devices.example.com/
# It's just as well to generate a random ID for your organization.
VENDOR_ID=
# Used for Let's Encrypt registration
# ACME_AGREE
ACME_AGREE=true
# ACME_EMAIL
ACME_EMAIL=johndoe@example.com
# SECRET
# This is the shared secret between the client device
# and the device management server.
SECRET=shared-secret
# CLIENT_SUBJECT (optional)
# NOT used by Telebit.
# This is for the Device Management & Authentication server.
# This is for the example scripts
# (for the Device Management & Authentication server)
CLIENT_SUBJECT=newbie
CLIENT_SECRET=xxxxxxxxxxxxxxxx
LOCALS=https:$CLIENT_SUBJECT.devices.example.com:3000,https:*.$CLIENT_SUBJECT.devices.example.com:3000
#ACME_HTTP_01_RELAY_URL=http://localhost:4200/api/http
#PORT_FORWARDS=3443:3001,8443:3002
#DUCKDNS_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
# TLS_LOCALS
# ReverseProxy any matching requests to the given local port.
# This DOES NOT terminate TLS
TLS_LOCALS=https:*:3000
# LOCALS
# ReverseProxy any matching requests to the given local port.
# This terminates TLS
# Ex: LOCALS=https:$CLIENT_SUBJECT.devices.example.com:3000,https:*.$CLIENT_SUBJECT.devices.example.com:3000
LOCALS=https:*:3000
# PORT_FORWARDS
# ReverseProxy any matching TCP streams from the given remote incoming port,
# directly to the given destination port.
PORT_FORWARDS=3443:3001,8443:3002
# AUTH_URL
# The client may receive this as `.authn.url`
# through `https://$API_DOMAIN/.well-known/telebit.app/index.json`
# Setting the ENV AUTH_URL or the flag --auth-url overrides the discovery endpoint
# ACME_HTTP_01_RELAY_URL
# Overrides `.acme_http_01_relay.url`
# from `https://$API_DOMAIN/.well-known/telebit.app/index.json`
ACME_HTTP_01_RELAY_URL=https://tunnel.example.com/api/acme-relay
# ACME_RELAY_URL (deprecated)
# Overrides `.acme_dns_01_relay.url`
# from `https://$API_DOMAIN/.well-known/telebit.app/index.json`
#ACME_RELAY_URL=https://tunnel.example.com/api/acme-relay
# ACME DNS-01 Challenge Strategies
# Rather than use the http-01 or dns-01 relay you can set one of these
#DUCKDNS_TOKEN=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
#NAMECOM_USERNAME=
#NAMECOM_API_TOKEN=
#GODADDY_API_KEY=
#GODADDY_API_SECRET=

View File

@ -11,8 +11,9 @@ CLIENT_SECRET="${CLIENT_SECRET:-}"
#go build -mod=vendor -o ./telebit \
# -ldflags="-X 'main.VendorID=$VENDOR_ID' -X 'main.ClientSecret=$CLIENT_SECRET' -X 'main.serviceName=telebit' -X 'main.serviceDesc=securely tunnel through telebit.io'" \
# cmd/telebit/*.go
go build -mod=vendor -o telebit \
cmd/telebit/*.go
pushd cmd/telebit
go build -mod=vendor -o telebit .
popd
# For Device Authorization across services
#AUTH_URL=${AUTH_URL:-"https://devices.examples.com/api"}

View File

@ -1,4 +1,4 @@
package main
package mgmt
import (
"encoding/json"

View File

@ -9,7 +9,7 @@ import (
telebit "git.rootprojects.org/root/telebit"
"git.rootprojects.org/root/telebit/dbg"
"git.rootprojects.org/root/telebit/mgmt/authstore"
"git.rootprojects.org/root/telebit/internal/mgmt/authstore"
)
type SuccessResponse struct {

View File

@ -1,4 +1,4 @@
package main
package mgmt
import (
"crypto/rand"
@ -10,7 +10,8 @@ import (
"strings"
"time"
"git.rootprojects.org/root/telebit/mgmt/authstore"
"git.rootprojects.org/root/telebit/internal/mgmt/authstore"
"github.com/go-chi/chi"
)

28
internal/mgmt/mgmt.go Normal file
View File

@ -0,0 +1,28 @@
package mgmt
import (
"git.rootprojects.org/root/telebit/internal/mgmt/authstore"
"github.com/go-acme/lego/v3/challenge"
)
var store authstore.Store
var provider challenge.Provider = nil
// DeviceDomain is the base hostname used for devices, such as devices.example.com
// which has devices as foo.devices.example.com
var DeviceDomain string
// RelayDomain is the API hostname used for the tunnel
// ( currently NOT used, but will be used for wss://RELAY_DOMAIN/ )
var RelayDomain string
// MWKey is a type guard
type MWKey string
// Init initializes some package variables
func Init(s authstore.Store, p challenge.Provider) {
store = s
provider = p
}

View File

@ -0,0 +1,4 @@
package mgmt
// InitSQL is the filepath to the SQL file used to initialize the database on each start
var InitSQL = "./postgres.init.sql"

View File

@ -1,4 +1,4 @@
package main
package mgmt
import (
"context"
@ -12,7 +12,8 @@ import (
"time"
"git.rootprojects.org/root/telebit/dbg"
"git.rootprojects.org/root/telebit/mgmt/authstore"
"git.rootprojects.org/root/telebit/internal/mgmt/authstore"
"github.com/dgrijalva/jwt-go"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
@ -27,7 +28,7 @@ type MgmtClaims struct {
var presenters = make(chan *Challenge)
var cleanups = make(chan *Challenge)
func routeStatic() chi.Router {
func RouteStatic() chi.Router {
r := chi.NewRouter()
r.Use(middleware.Logger)
@ -49,7 +50,7 @@ func routeStatic() chi.Router {
return r
}
func routeAll() chi.Router {
func RouteAll() chi.Router {
go func() {
for {
@ -125,8 +126,8 @@ func routeAll() chi.Router {
return nil, fmt.Errorf("invalid jwt payload 'sub' (mismatch)")
}
claims.Subject = claims.Slug
claims.Issuer = primaryDomain
claims.Audience = fmt.Sprintf("wss://%s/ws", relayDomain)
claims.Issuer = DeviceDomain
claims.Audience = fmt.Sprintf("wss://%s/ws", RelayDomain)
/*
// a little misdirection there
@ -181,7 +182,7 @@ func routeAll() chi.Router {
claims.Subject,
claims.Audience,
claims.Slug,
primaryDomain,
DeviceDomain,
)))
})

View File

@ -1,4 +1,4 @@
package main
package telebit
import (
"context"
@ -13,7 +13,7 @@ import (
"sync"
"time"
telebit "git.rootprojects.org/root/telebit"
"git.rootprojects.org/root/telebit"
"git.rootprojects.org/root/telebit/admin"
"git.rootprojects.org/root/telebit/dbg"
"git.rootprojects.org/root/telebit/table"
@ -23,10 +23,11 @@ import (
"github.com/gorilla/websocket"
)
var httpsrv *http.Server
var authorizer telebit.Authorizer
func InitAdmin(authURL string) {
r := chi.NewRouter()
// RouteAdmin sets up the API, including the Mgmt proxy and ACME relay
func RouteAdmin(authURL string, r chi.Router) {
authorizer = NewAuthorizer(authURL)
r.Use(middleware.Logger)
//r.Use(middleware.Timeout(120 * time.Second))
@ -113,10 +114,6 @@ func InitAdmin(authURL string) {
fmt.Println("Request Path:", r.URL.Path)
adminUI.ServeHTTP(w, r)
})
httpsrv = &http.Server{
Handler: r,
}
}
var apiPingContent = []byte("{ \"success\": true, \"error\": \"\" }\n")

View File

@ -1,11 +1,11 @@
package main
package telebit
import (
"fmt"
"net/http"
"strings"
telebit "git.rootprojects.org/root/telebit"
"git.rootprojects.org/root/telebit"
)
func NewAuthorizer(authURL string) telebit.Authorizer {