summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2016-01-25 17:31:37 -0500
committerAndrew Cady <d@jerkface.net>2016-01-25 17:31:37 -0500
commitcf440860e186e7fd775ae27da08220d9fe5e233e (patch)
tree655fcfc417730de6616621928a817f361b40fa0d /src
parentbe7a90d29c8a6da269d54f355cee11ce6e5eabc2 (diff)
Change API of "certify"
It now expects a callback to provision the challenge responses. This needs to be improved so that it will also do cleanup.
Diffstat (limited to 'src')
-rw-r--r--src/Network/ACME.hs35
1 files changed, 26 insertions, 9 deletions
diff --git a/src/Network/ACME.hs b/src/Network/ACME.hs
index 4df9f9b..5a66028 100644
--- a/src/Network/ACME.hs
+++ b/src/Network/ACME.hs
@@ -37,21 +37,38 @@ import Text.Email.Validate
37import Text.Domain.Validate hiding (validate) 37import Text.Domain.Validate hiding (validate)
38import Network.URI 38import Network.URI
39 39
40certify :: URI -> Keys -> Maybe EmailAddress -> URI -> [DomainName] -> WritableDir -> CSR -> IO (Either String LC.ByteString) 40type HttpProvisioner = URI -> ByteString -> IO ()
41certify directoryUrl keys optEmail terms requestDomains optChallengeDir csrData = 41
42fileProvisioner :: WritableDir -> HttpProvisioner
43fileProvisioner challengeDir = BC.writeFile . uToF
44 where
45 uToF = (coerce challengeDir </>) . takeWhileEnd (/= '/') . uriPath
46 takeWhileEnd f = reverse . takeWhile f . reverse
47
48acmeChallengeURI :: DomainName -> BC.ByteString -> URI
49acmeChallengeURI dom tok = URI
50 "http:"
51 (Just $ URIAuth "" (domainToString dom) "")
52 ("/.well-known/acme-challenge" </> BC.unpack tok)
53 ""
54 ""
55
56certify :: URI -> Keys -> Maybe (URI, EmailAddress) -> HttpProvisioner -> CSR -> IO (Either String LC.ByteString)
57certify directoryUrl keys reg provision certReq =
42 58
43 runACME directoryUrl keys $ do 59 runACME directoryUrl keys $ do
44 forM_ optEmail $ register terms >=> statusReport 60 forM_ reg $ uncurry register >=> statusReport
45 61
46 let performChallenge (ChallengeRequest nextUri token thumbtoken) = do 62 let performChallenge domain (ChallengeRequest nextUri token thumbtoken) = do
47 liftIO $ BC.writeFile (coerce optChallengeDir </> BC.unpack token) thumbtoken 63 liftIO $ provision (acmeChallengeURI domain token) thumbtoken
48 notifyChallenge nextUri thumbtoken >>= statusReport >>= ncErrorReport 64 notifyChallenge nextUri thumbtoken >>= statusReport >>= ncErrorReport
49 65
50 challengeResultLinks <- forM requestDomains $ challengeRequest >=> statusReport >=> extractCR >=> performChallenge 66 challengeResultLinks <- forM (csrDomains certReq) $ \dom ->
67 challengeRequest dom >>= statusReport >>= extractCR >>= performChallenge dom
51 68
52 pollResults challengeResultLinks >>= 69 pollResults challengeResultLinks >>=
53 either (return . Left . ("certificate receipt was not attempted because a challenge failed: " ++)) 70 either (return . Left . ("certificate receipt was not attempted because a challenge failed: " ++))
54 (const (retrieveCert csrData >>= statusReport <&> checkCertResponse)) 71 (const (retrieveCert certReq >>= statusReport <&> checkCertResponse))
55 72
56pollResults :: [Response LC.ByteString] -> ACME (Either String ()) 73pollResults :: [Response LC.ByteString] -> ACME (Either String ())
57pollResults [] = return $ Right () 74pollResults [] = return $ Right ()
@@ -68,7 +85,7 @@ pollResults (link:links) = do
68 85
69data ChallengeRequest = ChallengeRequest { crUri :: String, crToken :: ByteString, crThumbToken :: ByteString } 86data ChallengeRequest = ChallengeRequest { crUri :: String, crToken :: ByteString, crThumbToken :: ByteString }
70 87
71newtype CSR = CSR ByteString 88data CSR = CSR { csrDomains :: [DomainName], csrData :: ByteString }
72 89
73newtype WritableDir = WritableDir String 90newtype WritableDir = WritableDir String
74ensureWritableDir :: FilePath -> String -> IO WritableDir 91ensureWritableDir :: FilePath -> String -> IO WritableDir
@@ -137,7 +154,7 @@ checkCertResponse r =
137 isSuccess n = n >= 200 && n <= 300 154 isSuccess n = n >= 200 && n <= 300
138 155
139retrieveCert :: (MonadReader Env m, MonadState Nonce m, MonadIO m) => CSR -> m (Response LC.ByteString) 156retrieveCert :: (MonadReader Env m, MonadState Nonce m, MonadIO m) => CSR -> m (Response LC.ByteString)
140retrieveCert input = sendPayload _newCert (csr $ coerce input) 157retrieveCert input = sendPayload _newCert (csr $ csrData input)
141 158
142notifyChallenge :: (MonadReader Env m, MonadState Nonce m, MonadIO m) => String -> ByteString -> m (Response LC.ByteString) 159notifyChallenge :: (MonadReader Env m, MonadState Nonce m, MonadIO m) => String -> ByteString -> m (Response LC.ByteString)
143notifyChallenge uri thumbtoken = sendPayload (const uri) (challenge thumbtoken) 160notifyChallenge uri thumbtoken = sendPayload (const uri) (challenge thumbtoken)