diff options
author | Andrew Cady <d@jerkface.net> | 2016-04-09 22:01:33 -0400 |
---|---|---|
committer | Andrew Cady <d@jerkface.net> | 2016-04-09 22:01:33 -0400 |
commit | e26676c87b074b3933dd1d5c73cd62dcf2ca1995 (patch) | |
tree | f17d621018b72b0d9cc7001000687f8eaaffda4d | |
parent | 70137d8dba49353f525b4d3e93a919df80e81765 (diff) |
Specify remote provisioning paths in config file
-rw-r--r-- | acme-certify.hs | 58 |
1 files changed, 40 insertions, 18 deletions
diff --git a/acme-certify.hs b/acme-certify.hs index 5f4613f..3afcfc3 100644 --- a/acme-certify.hs +++ b/acme-certify.hs | |||
@@ -176,26 +176,29 @@ runUpdate UpdateOpts { .. } = do | |||
176 | 176 | ||
177 | Just keys <- getOrCreateKeys $ globalCertificateDir </> "rsa.key" | 177 | Just keys <- getOrCreateKeys $ globalCertificateDir </> "rsa.key" |
178 | 178 | ||
179 | 179 | let certSpecs = flip map certReqDomains $ \(host, domains) -> case dereference $ map (chooseProvisioner host) domains of | |
180 | certSpecs :: [CertSpec] <- forM certReqDomains $ \(host, domains) -> do | 180 | Just provisioners -> certSpec globalCertificateDir keys (host, provisioners) |
181 | provisioners <- mapM (chooseProvisioner host) domains | 181 | Nothing -> error "invalid configuration file" |
182 | return $ certSpec globalCertificateDir keys (host, provisioners) | ||
183 | 182 | ||
184 | mapM_ print certSpecs | 183 | mapM_ print certSpecs |
185 | 184 | ||
186 | h <- remoteTemp "localhost" "/tmp/whatevs 'bro'" "this content\ncontains stuff'" | 185 | h <- remoteTemp "localhost" "/tmp/whatevs 'bro'" "this content\ncontains stuff'" |
187 | threadDelay $ 1000*1000*10 | 186 | threadDelay $ 1000 * 1000 * 10 |
188 | removeTemp h | 187 | removeTemp h |
189 | 188 | ||
190 | error "Error: unimplemented" | 189 | error "Error: unimplemented" |
191 | 190 | ||
192 | where | 191 | where |
193 | chooseProvisioner :: String -> String -> IO (DomainName, HttpProvisioner) | 192 | dereference :: [(DomainName, Either DomainName HttpProvisioner)] -> Maybe [(DomainName, HttpProvisioner)] |
194 | chooseProvisioner host domain -- TODO: implement | 193 | dereference xs = plumb $ xs <&> fmap (either deref Just) |
195 | = do | 194 | where |
196 | let errmsg = "whatever" | 195 | deref :: DomainName -> Maybe HttpProvisioner |
197 | dir <- ensureWritableDir "/var/www/html/.well-known/acme-challenge/" errmsg | 196 | deref s = lookup s xs & preview (_Just . _Right) |
198 | return (domainName' domain, provisionViaFile dir) | 197 | plumb = traverse (\(a, b) -> fmap ((,) a) b) |
198 | |||
199 | chooseProvisioner :: String -> VHostSpec -> (DomainName, Either DomainName HttpProvisioner) | ||
200 | chooseProvisioner host (VHostSpec domain pathInfo) = | ||
201 | (domain, provisionViaRemoteFile host <$> pathInfo) | ||
199 | 202 | ||
200 | certSpec :: FilePath -> Keys -> (String, [(DomainName, HttpProvisioner)]) -> CertSpec | 203 | certSpec :: FilePath -> Keys -> (String, [(DomainName, HttpProvisioner)]) -> CertSpec |
201 | certSpec baseDir keys (host, requestDomains) = CertSpec { .. } | 204 | certSpec baseDir keys (host, requestDomains) = CertSpec { .. } |
@@ -205,10 +208,28 @@ runUpdate UpdateOpts { .. } = do | |||
205 | csUserKeys = keys | 208 | csUserKeys = keys |
206 | csCertificateDir = baseDir </> host </> (show . fst) (head requestDomains) | 209 | csCertificateDir = baseDir </> host </> (show . fst) (head requestDomains) |
207 | 210 | ||
208 | combineSubdomains :: AsPrimitive v => Text -> HashMap.HashMap Text v -> [String] | 211 | combineSubdomains :: AsPrimitive v => Text -> HashMap.HashMap Text v -> [VHostSpec] |
209 | combineSubdomains domain subs = | 212 | combineSubdomains domain subs = |
210 | map (<..> unpack domain) $ sort -- relying on the fact that '.' sorts first | 213 | map (makeVHostSpec (domainName' $ unpack domain)) $ |
211 | $ concat $ HashMap.lookup domain subs & toListOf (_Just . _String . to (words . unpack)) | 214 | sort -- relying on the fact that '.' sorts first |
215 | $ concat $ HashMap.lookup domain subs & toListOf (_Just . _String . to (words . unpack)) | ||
216 | |||
217 | data VHostSpec = VHostSpec DomainName (Either DomainName FilePath) deriving Show | ||
218 | makeVHostSpec :: DomainName -> String -> VHostSpec | ||
219 | makeVHostSpec = make | ||
220 | where | ||
221 | make (show -> parentDomain) (splitSpec -> (sub, spec)) = | ||
222 | VHostSpec (domainName' $ sub <..> parentDomain) (makeRef spec) | ||
223 | where | ||
224 | makeRef :: Either String FilePath -> Either DomainName FilePath | ||
225 | makeRef = left (\refSub -> domainName' $ refSub <..> parentDomain) | ||
226 | |||
227 | splitSpec :: String -> (String, Either String FilePath) | ||
228 | splitSpec (break (== '{') -> (a, b)) = (,) a $ | ||
229 | case b of | ||
230 | ('{':c@('/':_)) -> Right $ takeWhile (/= '}') c | ||
231 | ('{':c) -> Left $ takeWhile (/= '}') c | ||
232 | _ -> Right $ "/srv" </> a </> "public_html" | ||
212 | 233 | ||
213 | data TempRemover = TempRemover { removeTemp :: IO () } | 234 | data TempRemover = TempRemover { removeTemp :: IO () } |
214 | remoteTemp :: String -> FilePath -> String -> IO TempRemover | 235 | remoteTemp :: String -> FilePath -> String -> IO TempRemover |
@@ -226,7 +247,8 @@ provisionViaRemoteFile :: String -> FilePath -> HttpProvisioner | |||
226 | provisionViaRemoteFile = provision | 247 | provisionViaRemoteFile = provision |
227 | where | 248 | where |
228 | provision host dir (bsToS -> tok) (bsToS -> thumbtoken) = | 249 | provision host dir (bsToS -> tok) (bsToS -> thumbtoken) = |
229 | void $ allocate (liftIO $ remoteTemp host (dir </> tok) thumbtoken) removeTemp | 250 | void $ allocate (liftIO $ remoteTemp host (dir </> wk </> tok) thumbtoken) removeTemp |
251 | wk = ".well-known/acme-challenge" | ||
230 | bsToS = unpack . decodeUtf8 | 252 | bsToS = unpack . decodeUtf8 |
231 | 253 | ||
232 | runCertify :: CertifyOpts -> IO (Either String ()) | 254 | runCertify :: CertifyOpts -> IO (Either String ()) |
@@ -257,10 +279,10 @@ runCertify CertifyOpts{..} = do | |||
257 | forM_ csDomains $ uncurry canProvision >=> | 279 | forM_ csDomains $ uncurry canProvision >=> |
258 | (`unless` error "Error: cannot provision files to web server") | 280 | (`unless` error "Error: cannot provision files to web server") |
259 | 281 | ||
260 | go' directoryUrl terms email issuerCert req | 282 | fetchCertificate directoryUrl terms email issuerCert req |
261 | 283 | ||
262 | go' :: URI -> URI -> Maybe EmailAddress -> X509 -> CertSpec -> IO (Either String ()) | 284 | fetchCertificate :: URI -> URI -> Maybe EmailAddress -> X509 -> CertSpec -> IO (Either String ()) |
263 | go' directoryUrl terms email issuerCert cs@CertSpec{..} = do | 285 | fetchCertificate directoryUrl terms email issuerCert cs@CertSpec{..} = do |
264 | Just domainKeys <- getOrCreateKeys $ csCertificateDir </> "rsa.key" | 286 | Just domainKeys <- getOrCreateKeys $ csCertificateDir </> "rsa.key" |
265 | dh <- saveDhParams cs | 287 | dh <- saveDhParams cs |
266 | 288 | ||