start of management api
This commit is contained in:
parent
2a76b7679d
commit
96f4d34ce1
|
@ -4,6 +4,7 @@ certs
|
||||||
acme.d
|
acme.d
|
||||||
xversion.go
|
xversion.go
|
||||||
|
|
||||||
|
/mplexer/cmd/mgmt/mgmt
|
||||||
/mplexer/cmd/telebit/telebit
|
/mplexer/cmd/telebit/telebit
|
||||||
/telebit
|
/telebit
|
||||||
/cmd/telebit/telebit
|
/cmd/telebit/telebit
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -7,6 +7,7 @@ require (
|
||||||
github.com/caddyserver/certmagic v0.10.12
|
github.com/caddyserver/certmagic v0.10.12
|
||||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||||
github.com/go-acme/lego/v3 v3.7.0
|
github.com/go-acme/lego/v3 v3.7.0
|
||||||
|
github.com/go-chi/chi v4.1.1+incompatible
|
||||||
github.com/gorilla/mux v1.7.4
|
github.com/gorilla/mux v1.7.4
|
||||||
github.com/gorilla/websocket v1.4.2
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/joho/godotenv v1.3.0
|
github.com/joho/godotenv v1.3.0
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -93,6 +93,8 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME
|
||||||
github.com/go-acme/lego/v3 v3.4.0/go.mod h1:xYbLDuxq3Hy4bMUT1t9JIuz6GWIWb3m5X+TeTHYaT7M=
|
github.com/go-acme/lego/v3 v3.4.0/go.mod h1:xYbLDuxq3Hy4bMUT1t9JIuz6GWIWb3m5X+TeTHYaT7M=
|
||||||
github.com/go-acme/lego/v3 v3.7.0 h1:qC5/8/CbltyAE8fGLE6bGlqucj7pXc/vBxiLwLOsmAQ=
|
github.com/go-acme/lego/v3 v3.7.0 h1:qC5/8/CbltyAE8fGLE6bGlqucj7pXc/vBxiLwLOsmAQ=
|
||||||
github.com/go-acme/lego/v3 v3.7.0/go.mod h1:4eDjjYkAsDXyNcwN8IhhZAwxz9Ltiks1Zmpv0q20J7A=
|
github.com/go-acme/lego/v3 v3.7.0/go.mod h1:4eDjjYkAsDXyNcwN8IhhZAwxz9Ltiks1Zmpv0q20J7A=
|
||||||
|
github.com/go-chi/chi v4.1.1+incompatible h1:MmTgB0R8Bt/jccxp+t6S/1VGIKdJw5J74CK/c9tTfA4=
|
||||||
|
github.com/go-chi/chi v4.1.1+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
|
||||||
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
|
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
|
||||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
|
|
|
@ -0,0 +1,179 @@
|
||||||
|
//go:generate go run -mod=vendor git.rootprojects.org/root/go-gitver
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"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-chi/chi"
|
||||||
|
"github.com/go-chi/chi/middleware"
|
||||||
|
_ "github.com/joho/godotenv/autoload"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// GitRev refers to the abbreviated commit hash
|
||||||
|
GitRev = "0000000"
|
||||||
|
// GitVersion refers to the most recent tag, plus any commits made since then
|
||||||
|
GitVersion = "v0.0.0-pre0+0000000"
|
||||||
|
// GitTimestamp refers to the timestamp of the most recent commit
|
||||||
|
GitTimestamp = "0000-00-00T00:00:00+0000"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var err error
|
||||||
|
var provider challenge.Provider = nil // TODO is this concurrency-safe?
|
||||||
|
var presenters = make(chan *Challenge)
|
||||||
|
var cleanups = make(chan *Challenge)
|
||||||
|
|
||||||
|
addr := flag.String("address", "", "IPv4 or IPv6 bind address")
|
||||||
|
port := flag.String("port", "3000", "port to listen to")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if "" != os.Getenv("GODADDY_API_KEY") {
|
||||||
|
id := os.Getenv("GODADDY_API_KEY")
|
||||||
|
secret := os.Getenv("GODADDY_API_SECRET")
|
||||||
|
if provider, err = newGoDaddyDNSProvider(id, secret); nil != err {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
} else if "" != os.Getenv("DUCKDNS_TOKEN") {
|
||||||
|
if provider, err = newDuckDNSProvider(os.Getenv("DUCKDNS_TOKEN")); nil != err {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic("Must provide either DUCKDNS or GODADDY credentials")
|
||||||
|
}
|
||||||
|
|
||||||
|
r := chi.NewRouter()
|
||||||
|
r.Use(middleware.Logger)
|
||||||
|
r.Use(middleware.Timeout(15 * time.Second))
|
||||||
|
r.Use(middleware.Recoverer)
|
||||||
|
|
||||||
|
// TODO add authorization header and validation
|
||||||
|
//r.Post("/api/dns/{domain:[a-z0-9\\.-]+}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
//r.Post("/api/dns/*", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
r.Post("/api/dns/{domain}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
ch := Challenge{}
|
||||||
|
|
||||||
|
// TODO prevent slow loris
|
||||||
|
decoder := json.NewDecoder(r.Body)
|
||||||
|
err := decoder.Decode(&ch)
|
||||||
|
if nil != err || "" == ch.Token || "" == ch.KeyAuth {
|
||||||
|
msg := `{"error":"expected json in the format {\"token\":\"xxx\",\"key_authorization\":\"yyy\"}"}`
|
||||||
|
http.Error(w, msg, http.StatusUnprocessableEntity)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
domain := chi.URLParam(r, "domain")
|
||||||
|
//domain := chi.URLParam(r, "*")
|
||||||
|
ch.Domain = domain
|
||||||
|
|
||||||
|
// TODO some additional error checking before the handoff
|
||||||
|
//ch.error = make(chan error, 1)
|
||||||
|
ch.error = make(chan error)
|
||||||
|
presenters <- &ch
|
||||||
|
err = <-ch.error
|
||||||
|
if nil != err || "" == ch.Token || "" == ch.KeyAuth {
|
||||||
|
msg := `{"error":"expected json in the format {\"token\":\"xxx\",\"key_authorization\":\"yyy\"}"}`
|
||||||
|
http.Error(w, msg, http.StatusUnprocessableEntity)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write([]byte("{\"success\":true}\n"))
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO ugly Delete, but wahtever
|
||||||
|
r.Delete("/api/dns/{domain}/{token}/{keyAuth}", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
ch := Challenge{
|
||||||
|
Domain: chi.URLParam(r, "domain"),
|
||||||
|
Token: chi.URLParam(r, "token"),
|
||||||
|
KeyAuth: chi.URLParam(r, "keyAuth"),
|
||||||
|
error: make(chan error),
|
||||||
|
//error: make(chan error, 1),
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanups <- &ch
|
||||||
|
err = <-ch.error
|
||||||
|
if nil != err || "" == ch.Token || "" == ch.KeyAuth {
|
||||||
|
msg := `{"error":"expected json in the format {\"token\":\"xxx\",\"key_authorization\":\"yyy\"}"}`
|
||||||
|
http.Error(w, msg, http.StatusUnprocessableEntity)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write([]byte("{\"success\":true}\n"))
|
||||||
|
})
|
||||||
|
|
||||||
|
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.Write([]byte("welcome\n"))
|
||||||
|
})
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
// TODO make parallel?
|
||||||
|
// TODO make cancellable?
|
||||||
|
ch := <-presenters
|
||||||
|
err := provider.Present(ch.Domain, ch.Token, ch.KeyAuth)
|
||||||
|
ch.error <- err
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
// TODO make parallel?
|
||||||
|
// TODO make cancellable?
|
||||||
|
ch := <-cleanups
|
||||||
|
ch.error <- provider.CleanUp(ch.Domain, ch.Token, ch.KeyAuth)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
bind := *addr + ":" + *port
|
||||||
|
fmt.Println("Listening on", bind)
|
||||||
|
fmt.Fprintf(os.Stderr, "failed:", http.ListenAndServe(bind, r))
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Challenge has the data necessary to create an ACME DNS-01 Key Authorization Digest.
|
||||||
|
type Challenge struct {
|
||||||
|
Domain string `json:"domain"`
|
||||||
|
Token string `json:"token"`
|
||||||
|
KeyAuth string `json:"key_authorization"`
|
||||||
|
error chan error
|
||||||
|
}
|
||||||
|
|
||||||
|
type acmeProvider struct {
|
||||||
|
BaseURL string
|
||||||
|
provider challenge.Provider
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *acmeProvider) Present(domain, token, keyAuth string) error {
|
||||||
|
return p.provider.Present(domain, token, keyAuth)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *acmeProvider) CleanUp(domain, token, keyAuth string) error {
|
||||||
|
return p.provider.CleanUp(domain, token, keyAuth)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newDuckDNSProvider is for the sake of demoing the tunnel
|
||||||
|
func newDuckDNSProvider(token string) (*duckdns.DNSProvider, error) {
|
||||||
|
config := duckdns.NewDefaultConfig()
|
||||||
|
config.Token = token
|
||||||
|
return duckdns.NewDNSProviderConfig(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newGoDaddyDNSProvider is for the sake of demoing the tunnel
|
||||||
|
func newGoDaddyDNSProvider(id, secret string) (*godaddy.DNSProvider, error) {
|
||||||
|
config := godaddy.NewDefaultConfig()
|
||||||
|
config.APIKey = id
|
||||||
|
config.APISecret = secret
|
||||||
|
return godaddy.NewDNSProviderConfig(config)
|
||||||
|
}
|
|
@ -31,6 +31,10 @@ github.com/go-acme/lego/v3/platform/wait
|
||||||
github.com/go-acme/lego/v3/providers/dns/duckdns
|
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/godaddy
|
||||||
github.com/go-acme/lego/v3/registration
|
github.com/go-acme/lego/v3/registration
|
||||||
|
# github.com/go-chi/chi v4.1.1+incompatible
|
||||||
|
## explicit
|
||||||
|
github.com/go-chi/chi
|
||||||
|
github.com/go-chi/chi/middleware
|
||||||
# github.com/gorilla/mux v1.7.4
|
# github.com/gorilla/mux v1.7.4
|
||||||
## explicit
|
## explicit
|
||||||
github.com/gorilla/mux
|
github.com/gorilla/mux
|
||||||
|
|
Loading…
Reference in New Issue