diff options
author | Andrew Cady <d@jerkface.net> | 2016-04-09 03:23:34 -0400 |
---|---|---|
committer | Andrew Cady <d@jerkface.net> | 2016-04-09 03:25:30 -0400 |
commit | 5167199204f4d502e5c3b1a54d1fb5d88a043af1 (patch) | |
tree | ea948d5acb31a203d74947152ca400e26e47cfd7 | |
parent | ddf8b7b2a5759fe80a667f5bb8f2a9bc9306a6f7 (diff) |
Separate CLI into subcommands
Viz. 'update' and 'certify'
'certify' is just the previous CLI. 'update' is unimplemented.
The binary was renamed from 'acme-certify' to 'acme' to reflect this.
-rw-r--r-- | acme-certify.cabal | 2 | ||||
-rw-r--r-- | acme-certify.hs | 126 |
2 files changed, 79 insertions, 49 deletions
diff --git a/acme-certify.cabal b/acme-certify.cabal index 42c4192..6424567 100644 --- a/acme-certify.cabal +++ b/acme-certify.cabal | |||
@@ -21,7 +21,7 @@ library | |||
21 | resourcet, file-embed | 21 | resourcet, file-embed |
22 | default-language: Haskell2010 | 22 | default-language: Haskell2010 |
23 | 23 | ||
24 | executable acme-certify | 24 | executable acme |
25 | -- hs-source-dirs: app | 25 | -- hs-source-dirs: app |
26 | main-is: acme-certify.hs | 26 | main-is: acme-certify.hs |
27 | ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall | 27 | ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall |
diff --git a/acme-certify.hs b/acme-certify.hs index 9d8d770..ae7b4cf 100644 --- a/acme-certify.hs +++ b/acme-certify.hs | |||
@@ -37,15 +37,30 @@ Just stagingDirectoryUrl = parseAbsoluteURI "https://acme-staging.api.letsencryp | |||
37 | Just defaultTerms = parseAbsoluteURI "https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf" | 37 | Just defaultTerms = parseAbsoluteURI "https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf" |
38 | 38 | ||
39 | main :: IO () | 39 | main :: IO () |
40 | main = execParser opts >>= go >>= either (error . ("Error: " ++)) return | 40 | main = execParser (info opts idm) >>= run |
41 | where | 41 | where |
42 | opts = info (helper <*> cmdopts) (fullDesc <> progDesc detailedDescription <> Opt.header "Let's Encrypt! ACME client") | 42 | opts :: Parser Options |
43 | opts = Options <$> parseCommand | ||
44 | parseCommand :: Parser Command | ||
45 | parseCommand = subparser $ | ||
46 | command "certify" (info (helper <*> certifyOpts) desc) <> | ||
47 | command "update" (info (helper <*> updateOpts) desc) | ||
48 | desc = fullDesc <> progDesc detailedDescription <> Opt.header "Let's Encrypt! ACME client" | ||
43 | detailedDescription = unwords | 49 | detailedDescription = unwords |
44 | [ "This program will generate a signed TLS certificate" | 50 | [ "This program will generate a signed TLS certificate" |
45 | , "using the ACME protocol and the free Let's Encrypt! CA." | 51 | , "using the ACME protocol and the free Let's Encrypt! CA." |
46 | ] | 52 | ] |
53 | run :: Options -> IO () | ||
54 | run (Options (Certify opts)) = runCertify opts >>= either (error . ("Error: " ++)) return | ||
55 | run (Options (Update opts)) = runUpdate opts | ||
47 | 56 | ||
48 | data CmdOpts = CmdOpts { | 57 | data Command = Certify CertifyOpts | Update UpdateOpts |
58 | |||
59 | data Options = Options { | ||
60 | optCommand :: Command | ||
61 | } | ||
62 | |||
63 | data CertifyOpts = CertifyOpts { | ||
49 | optKeyFile :: String, | 64 | optKeyFile :: String, |
50 | optDomains :: [String], | 65 | optDomains :: [String], |
51 | optChallengeDir :: String, | 66 | optChallengeDir :: String, |
@@ -57,6 +72,10 @@ data CmdOpts = CmdOpts { | |||
57 | optSkipProvisionCheck :: Bool | 72 | optSkipProvisionCheck :: Bool |
58 | } | 73 | } |
59 | 74 | ||
75 | data UpdateOpts = UpdateOpts { | ||
76 | updateConfigFile :: Maybe FilePath | ||
77 | } | ||
78 | |||
60 | data AcmeCertRequest = AcmeCertRequest { | 79 | data AcmeCertRequest = AcmeCertRequest { |
61 | acrDomains :: [(DomainName, HttpProvisioner)], | 80 | acrDomains :: [(DomainName, HttpProvisioner)], |
62 | acrSkipDH :: Bool, | 81 | acrSkipDH :: Bool, |
@@ -64,51 +83,62 @@ data AcmeCertRequest = AcmeCertRequest { | |||
64 | acrUserKeys :: Keys | 83 | acrUserKeys :: Keys |
65 | } | 84 | } |
66 | 85 | ||
67 | cmdopts :: Parser CmdOpts | 86 | updateOpts :: Parser Command |
68 | cmdopts = CmdOpts <$> strOption (long "key" <> metavar "FILE" <> | 87 | updateOpts = fmap Update $ |
69 | help "Filename of your private RSA key") | 88 | UpdateOpts <$> optional |
70 | <*> some | 89 | (strOption |
71 | (strOption | 90 | (long "config" <> |
72 | (long "domain" <> | 91 | metavar "FILENAME" <> |
73 | metavar "DOMAIN" <> | 92 | help "location of YAML configuration file")) |
74 | help | 93 | |
75 | (unwords | 94 | certifyOpts :: Parser Command |
76 | [ "The domain name(s) to certify;" | 95 | certifyOpts = fmap Certify $ |
77 | , "specify more than once for a multi-domain certificate" | 96 | CertifyOpts <$> strOption (long "key" <> metavar "FILE" <> |
78 | ]))) | 97 | help "Filename of your private RSA key") |
79 | <*> strOption (long "challenge-dir" <> metavar "DIR" <> | 98 | <*> some |
80 | help "Output directory for ACME challenges") | 99 | (strOption |
81 | <*> optional | 100 | (long "domain" <> |
82 | (strOption | 101 | metavar "DOMAIN" <> |
83 | (long "domain-dir" <> | 102 | help |
84 | metavar "DIR" <> | 103 | (unwords |
85 | help | 104 | [ "The domain name(s) to certify;" |
86 | (unwords | 105 | , "specify more than once for a multi-domain certificate" |
87 | [ "Directory in which to domain certificates and keys are stored;" | 106 | ]))) |
88 | , "the default is to use the (first) domain name as a directory name" | 107 | <*> strOption (long "challenge-dir" <> metavar "DIR" <> |
89 | ]))) | 108 | help "Output directory for ACME challenges") |
90 | <*> optional | 109 | <*> optional |
91 | (strOption (long "email" <> metavar "ADDRESS" <> | 110 | (strOption |
92 | help "An email address with which to register an account")) | 111 | (long "domain-dir" <> |
93 | <*> optional (strOption (long "terms" <> metavar "URL" <> | 112 | metavar "DIR" <> |
94 | help "The terms param of the registration request")) | 113 | help |
95 | <*> switch | 114 | (unwords |
96 | (long "skip-dhparams" <> help "Don't generate DH params for combined cert") | 115 | [ "Directory in which to domain certificates and keys are stored;" |
97 | <*> switch | 116 | , "the default is to use the (first) domain name as a directory name" |
98 | (long "staging" <> help | 117 | ]))) |
99 | (unwords | 118 | <*> optional (strOption (long "email" <> metavar "ADDRESS" <> |
100 | [ "Use staging servers instead of live servers" | 119 | help "An email address with which to register an account")) |
101 | , "(generated certificates will not be trusted!)" | 120 | <*> optional (strOption (long "terms" <> metavar "URL" <> |
102 | ])) | 121 | help "The terms param of the registration request")) |
103 | <*> switch | 122 | <*> switch (long "skip-dhparams" <> help "Don't generate DH params for combined cert") |
104 | (long "skip-provision-check" <> help | 123 | <*> switch |
105 | (unwords | 124 | (long "staging" <> help |
106 | [ "Don't test whether HTTP provisioning works before" | 125 | (unwords |
107 | , "making ACME requests" | 126 | [ "Use staging servers instead of live servers" |
108 | ])) | 127 | , "(generated certificates will not be trusted!)" |
109 | 128 | ])) | |
110 | go :: CmdOpts -> IO (Either String ()) | 129 | <*> switch |
111 | go CmdOpts { .. } = do | 130 | (long "skip-provision-check" <> help |
131 | (unwords | ||
132 | [ "Don't test whether HTTP provisioning works before" | ||
133 | , "making ACME requests" | ||
134 | ])) | ||
135 | |||
136 | runUpdate :: UpdateOpts -> IO () | ||
137 | runUpdate UpdateOpts{..} = do | ||
138 | error "test" | ||
139 | |||
140 | runCertify :: CertifyOpts -> IO (Either String ()) | ||
141 | runCertify CertifyOpts{..} = do | ||
112 | let terms = fromMaybe defaultTerms (join $ parseAbsoluteURI <$> optTerms) | 142 | let terms = fromMaybe defaultTerms (join $ parseAbsoluteURI <$> optTerms) |
113 | directoryUrl = if optStaging then stagingDirectoryUrl else liveDirectoryUrl | 143 | directoryUrl = if optStaging then stagingDirectoryUrl else liveDirectoryUrl |
114 | domainDir = fromMaybe (head optDomains) optDomainDir | 144 | domainDir = fromMaybe (head optDomains) optDomainDir |