Files
acme-dns/pkg/api/api.go

136 lines
3.8 KiB
Go

package api
import (
"context"
"crypto/tls"
"net/http"
"time"
"github.com/joohoi/acme-dns/pkg/acmedns"
"github.com/caddyserver/certmagic"
"github.com/julienschmidt/httprouter"
"github.com/rs/cors"
"go.uber.org/zap"
)
type AcmednsAPI struct {
Config *acmedns.AcmeDnsConfig
DB acmedns.AcmednsDB
Logger *zap.SugaredLogger
errChan chan error
}
func Init(config *acmedns.AcmeDnsConfig, db acmedns.AcmednsDB, logger *zap.SugaredLogger, errChan chan error) AcmednsAPI {
a := AcmednsAPI{Config: config, DB: db, Logger: logger, errChan: errChan}
return a
}
func (a *AcmednsAPI) Start(dnsservers []acmedns.AcmednsNS) {
var err error
//TODO: do we want to debug log the HTTP server?
stderrorlog, err := zap.NewStdLogAt(a.Logger.Desugar(), zap.ErrorLevel)
if err != nil {
a.errChan <- err
return
}
api := httprouter.New()
c := cors.New(cors.Options{
AllowedOrigins: a.Config.API.CorsOrigins,
AllowedMethods: []string{"GET", "POST"},
OptionsPassthrough: false,
Debug: a.Config.General.Debug,
})
if a.Config.General.Debug {
// Logwriter for saner log output
c.Log = stderrorlog
}
if !a.Config.API.DisableRegistration {
api.POST("/register", a.webRegisterPost)
}
api.POST("/update", a.Auth(a.webUpdatePost))
api.GET("/health", a.healthCheck)
host := a.Config.API.IP + ":" + a.Config.API.Port
// TLS specific general settings
cfg := &tls.Config{
MinVersion: tls.VersionTLS12,
}
switch a.Config.API.TLS {
case acmedns.ApiTlsProviderLetsEncrypt, acmedns.ApiTlsProviderLetsEncryptStaging:
magic := a.setupTLS(dnsservers)
err = magic.ManageAsync(context.Background(), []string{a.Config.General.Domain})
if err != nil {
a.errChan <- err
return
}
cfg.GetCertificate = magic.GetCertificate
srv := &http.Server{
Addr: host,
Handler: c.Handler(api),
TLSConfig: cfg,
ErrorLog: stderrorlog,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}
a.Logger.Infow("Listening HTTPS",
"host", host,
"domain", a.Config.General.Domain)
err = srv.ListenAndServeTLS("", "")
case acmedns.ApiTlsProviderCert:
srv := &http.Server{
Addr: host,
Handler: c.Handler(api),
TLSConfig: cfg,
ErrorLog: stderrorlog,
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}
a.Logger.Infow("Listening HTTPS",
"host", host,
"domain", a.Config.General.Domain)
err = srv.ListenAndServeTLS(a.Config.API.TLSCertFullchain, a.Config.API.TLSCertPrivkey)
default:
a.Logger.Infow("Listening HTTP",
"host", host)
err = http.ListenAndServe(host, c.Handler(api))
}
if err != nil {
a.errChan <- err
}
}
func (a *AcmednsAPI) setupTLS(dnsservers []acmedns.AcmednsNS) *certmagic.Config {
provider := NewChallengeProvider(dnsservers)
certmagic.Default.Logger = a.Logger.Desugar()
storage := certmagic.FileStorage{Path: a.Config.API.ACMECacheDir}
// Set up certmagic for getting certificate for acme-dns api
certmagic.DefaultACME.DNS01Solver = &provider
certmagic.DefaultACME.Agreed = true
certmagic.DefaultACME.Logger = a.Logger.Desugar()
if a.Config.API.TLS == acmedns.ApiTlsProviderLetsEncrypt {
certmagic.DefaultACME.CA = certmagic.LetsEncryptProductionCA
} else {
certmagic.DefaultACME.CA = certmagic.LetsEncryptStagingCA
}
certmagic.DefaultACME.Email = a.Config.API.NotificationEmail
magicConf := certmagic.Default
magicConf.Logger = a.Logger.Desugar()
magicConf.Storage = &storage
magicConf.DefaultServerName = a.Config.General.Domain
magicCache := certmagic.NewCache(certmagic.CacheOptions{
GetConfigForCert: func(cert certmagic.Certificate) (*certmagic.Config, error) {
return &magicConf, nil
},
Logger: a.Logger.Desugar(),
})
magic := certmagic.New(magicCache, magicConf)
return magic
}