diff --git a/cmd/dnshelp.go b/cmd/dnshelp.go new file mode 100644 index 00000000..4e2efeba --- /dev/null +++ b/cmd/dnshelp.go @@ -0,0 +1,77 @@ +// Copyright © 2016 NAME HERE +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "fmt" + "os" + "text/tabwriter" + + "github.com/spf13/cobra" +) + +// dnshelpCmd represents the dnshelp command +var dnshelpCmd = &cobra.Command{ + Use: "dnshelp", + Short: "Shows additional help for the --dns global option", + Long: ``, + Run: func(cmd *cobra.Command, args []string) { + fmt.Printf( + `Credentials for DNS providers must be passed through environment variables. + +Here is an example bash command using the CloudFlare DNS provider: + + $ CLOUDFLARE_EMAIL=foo@bar.com \ + CLOUDFLARE_API_KEY=b9841238feb177a84330febba8a83208921177bffe733 \ + lego --dns cloudflare --domains www.example.com --email me@bar.com run + +`) + + w := tabwriter.NewWriter(os.Stdout, 0, 8, 1, '\t', 0) + fmt.Fprintln(w, "Valid providers and their associated credential environment variables:") + fmt.Fprintln(w) + fmt.Fprintln(w, "\tcloudflare:\tCLOUDFLARE_EMAIL, CLOUDFLARE_API_KEY") + fmt.Fprintln(w, "\tdigitalocean:\tDO_AUTH_TOKEN") + fmt.Fprintln(w, "\tdnsimple:\tDNSIMPLE_EMAIL, DNSIMPLE_API_KEY") + fmt.Fprintln(w, "\tgandi:\tGANDI_API_KEY") + fmt.Fprintln(w, "\tgcloud:\tGCE_PROJECT") + fmt.Fprintln(w, "\tmanual:\tnone") + fmt.Fprintln(w, "\tnamecheap:\tNAMECHEAP_API_USER, NAMECHEAP_API_KEY") + fmt.Fprintln(w, "\trfc2136:\tRFC2136_TSIG_KEY, RFC2136_TSIG_SECRET,\n\t\tRFC2136_TSIG_ALGORITHM, RFC2136_NAMESERVER") + fmt.Fprintln(w, "\troute53:\tAWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION") + fmt.Fprintln(w, "\tdyn:\tDYN_CUSTOMER_NAME, DYN_USER_NAME, DYN_PASSWORD") + fmt.Fprintln(w, "\tvultr:\tVULTR_API_KEY") + w.Flush() + + fmt.Println(` +For a more detailed explanation of a DNS provider's credential variables, +please consult their online documentation.`) + }, +} + +func init() { + RootCmd.AddCommand(dnshelpCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // dnshelpCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // dnshelpCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + +} diff --git a/cmd/renew.go b/cmd/renew.go new file mode 100644 index 00000000..5f1c1bb7 --- /dev/null +++ b/cmd/renew.go @@ -0,0 +1,27 @@ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +// renewCmd represents the renew command +var renewCmd = &cobra.Command{ + Use: "renew", + Short: "Renew a certificate", + Long: ``, + Run: func(cmd *cobra.Command, args []string) { + // TODO: Work your own magic here + fmt.Println("renew called") + }, +} + +func init() { + RootCmd.AddCommand(renewCmd) + + renewCmd.PersistentFlags().Int("days", 0, "The number of days left on a certificate to renew it.") + renewCmd.PersistentFlags().Bool("resuse-key", false, "Used to indicate you want to reuse your current private key for the new certificate.") + renewCmd.PersistentFlags().Bool("no-bundle", false, "Do not create a certificate bundle by adding the issuers certificate to the new certificate.") + +} diff --git a/cmd/revoke.go b/cmd/revoke.go new file mode 100644 index 00000000..81538826 --- /dev/null +++ b/cmd/revoke.go @@ -0,0 +1,23 @@ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +// revokeCmd represents the revoke command +var revokeCmd = &cobra.Command{ + Use: "revoke", + Short: "Revoke a certificate", + Long: ``, + Run: func(cmd *cobra.Command, args []string) { + // TODO: Work your own magic here + fmt.Println("revoke called") + }, +} + +func init() { + RootCmd.AddCommand(revokeCmd) + +} diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 00000000..f1638761 --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,78 @@ +package cmd + +import ( + "fmt" + "log" + "os" + "path" + + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var cfgFile string +var Logger *log.Logger + +func logger() *log.Logger { + if Logger == nil { + Logger = log.New(os.Stderr, "", log.LstdFlags) + } + return Logger +} + +// This represents the base command when called without any subcommands +var RootCmd = &cobra.Command{ + Use: "lego", + Short: "Let's Encrypt client written in Go", + Long: ``, + // Uncomment the following line if your bare application + // has an action associated with it: + // Run: func(cmd *cobra.Command, args []string) { }, +} + +// Execute adds all child commands to the root command sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + if err := RootCmd.Execute(); err != nil { + fmt.Println(err) + os.Exit(-1) + } +} + +func init() { + cobra.OnInitialize(initConfig) + cwd, err := os.Getwd() + if err != nil { + logger().Fatal("Could not determine current working directory. Please pass --path.") + } + defaultPath := path.Join(cwd, ".lego") + + // Cobra also supports local flags, which will only run + // when this action is called directly. + RootCmd.PersistentFlags().StringSliceP("domains", "d", nil, "Add domains to the process") + RootCmd.PersistentFlags().StringP("server", "s", "https://acme-v01.api.letsencrypt.org/directory", "CA hostname (and optionally :port). The server certificate must be trusted in order to avoid further modifications to the client.") + RootCmd.PersistentFlags().StringP("email", "m", "", "Email used for registration and recovery contact.") + RootCmd.PersistentFlags().BoolP("accept-tos", "a", false, "By setting this flag to true you indicate that you accept the current Let's Encrypt terms of service.") + RootCmd.PersistentFlags().StringP("key-type", "k", "rsa2048", "Key type to use for private keys. Supported: rsa2048, rsa4096, rsa8192, ec256, ec384") + RootCmd.PersistentFlags().String("path", defaultPath, "Directory to use for storing the data") + RootCmd.PersistentFlags().StringSliceP("exclude", "x", nil, "Explicitly disallow solvers by name from being used. Solvers: \"http-01\", \"tls-sni-01\".") + RootCmd.PersistentFlags().String("webroot", "", "Set the webroot folder to use for HTTP based challenges to write directly in a file in .well-known/acme-challenge") + RootCmd.PersistentFlags().String("http", "", "Set the port and interface to use for HTTP based challenges to listen on. Supported: interface:port or :port") + RootCmd.PersistentFlags().String("tls", "", "Set the port and interface to use for TLS based challenges to listen on. Supported: interface:port or :port") + RootCmd.PersistentFlags().String("dns", "", "Solve a DNS challenge using the specified provider. Disables all other challenges. Run 'lego dnshelp' for help on usage.") +} + +// initConfig reads in config file and ENV variables if set. +func initConfig() { + if cfgFile != "" { // enable ability to specify config file via flag + viper.SetConfigFile(cfgFile) + } + + viper.AddConfigPath("$HOME") // adding home directory as first search path + viper.AutomaticEnv() // read in environment variables that match + + // If a config file is found, read it in. + if err := viper.ReadInConfig(); err == nil { + fmt.Println("Using config file:", viper.ConfigFileUsed()) + } +} diff --git a/cmd/run.go b/cmd/run.go new file mode 100644 index 00000000..d342b154 --- /dev/null +++ b/cmd/run.go @@ -0,0 +1,39 @@ +// Copyright © 2016 NAME HERE +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +// runCmd represents the run command +var runCmd = &cobra.Command{ + Use: "run", + Short: "Register an account, then create and install a certificate", + Long: ``, + Run: func(cmd *cobra.Command, args []string) { + // TODO: Work your own magic here + fmt.Println("run called") + }, +} + +func init() { + RootCmd.AddCommand(runCmd) + + runCmd.PersistentFlags().Bool("no-bundle", false, "Do not create a certificate bundle by adding the issuers certificate to the new certificate.") + +} diff --git a/main.go b/main.go new file mode 100644 index 00000000..abf6f2b3 --- /dev/null +++ b/main.go @@ -0,0 +1,7 @@ +package main + +import "github.com/gianluca311/lego/cmd" + +func main() { + cmd.Execute() +}