local-ip.sh/cmd/root.go
2024-07-26 12:16:53 +02:00

112 lines
3.1 KiB
Go

package cmd
import (
"fmt"
"net/mail"
"net/url"
"strings"
"time"
"github.com/asaskevich/govalidator"
"github.com/go-acme/lego/v4/lego"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"local-ip.sh/certs"
"local-ip.sh/http"
"local-ip.sh/utils"
"local-ip.sh/xip"
)
var command = &cobra.Command{
Use: "local-ip.sh",
PreRun: func(cmd *cobra.Command, args []string) {
viper.SetEnvKeyReplacer(strings.NewReplacer("-", "_"))
viper.SetEnvPrefix("XIP")
viper.AutomaticEnv()
email := viper.GetString("Email")
_, err := mail.ParseAddress(email)
if err != nil {
utils.Logger.Fatal().Err(err).Msg("Invalid email address")
}
domain := viper.GetString("Domain")
if !govalidator.IsDNSName(domain) {
utils.Logger.Fatal().Err(err).Msg("Invalid domain")
}
nameservers := strings.Split(viper.GetString("nameservers"), ",")
for _, ns := range nameservers {
if !govalidator.IsIPv4(ns) {
utils.Logger.Fatal().Err(err).Str("ns", ns).Msg("Invalid name server")
}
}
viper.Set("NameServers", nameservers)
staging := viper.GetBool("staging")
var caDir string
if staging {
caDir = lego.LEDirectoryStaging
} else {
caDir = lego.LEDirectoryProduction
}
viper.Set("CADirURL", caDir)
parsedCaDirUrl, _ := url.Parse(caDir)
caDirHostname := parsedCaDirUrl.Hostname()
viper.Set("AccountFilePath", fmt.Sprintf("./.lego/accounts/%s/%s/account.json", caDirHostname, email))
viper.Set("KeyFilePath", fmt.Sprintf("./.lego/accounts/%s/%s/keys/%s.key", caDirHostname, email, email))
utils.InitConfig()
},
Run: func(cmd *cobra.Command, args []string) {
n := xip.NewXip()
go func() {
// try to obtain certificates once the DNS server is accepting requests
account := certs.LoadAccount()
certsClient := certs.NewCertsClient(n, account)
time.Sleep(5 * time.Second)
certsClient.RequestCertificates()
for {
// afterwards, try to renew certificates once a day
time.Sleep(24 * time.Hour)
certsClient.RequestCertificates()
}
}()
go http.ServeHttp()
n.StartServer()
},
}
func Execute() {
command.Flags().Uint("dns-port", 53, "Port for the DNS server")
viper.BindPFlag("dns-port", command.Flags().Lookup("dns-port"))
command.Flags().Uint("http-port", 80, "Port for the HTTP server")
viper.BindPFlag("http-port", command.Flags().Lookup("http-port"))
command.Flags().Uint("https-port", 443, "Port for the HTTPS server")
viper.BindPFlag("https-port", command.Flags().Lookup("https-port"))
command.Flags().Bool("staging", false, "Enable to use the Let's Encrypt staging environment to obtain certificates")
viper.BindPFlag("staging", command.Flags().Lookup("staging"))
command.Flags().String("domain", "", "Root domain (required)")
viper.BindPFlag("domain", command.Flags().Lookup("domain"))
command.Flags().String("email", "", "ACME account email address (required)")
viper.BindPFlag("email", command.Flags().Lookup("email"))
command.Flags().String("nameservers", "", "List of nameservers separated by commas (required)")
viper.BindPFlag("nameservers", command.Flags().Lookup("nameservers"))
if err := command.Execute(); err != nil {
utils.Logger.Fatal().Err(err).Msg("Failed to run local-ip.sh")
}
}