diff options
author | Andrew Cady <d@jerkface.net> | 2016-01-24 20:37:14 -0500 |
---|---|---|
committer | Andrew Cady <d@jerkface.net> | 2016-01-24 20:37:14 -0500 |
commit | df216a65fcb97bb42f66fd50fb37166b3045bd39 (patch) | |
tree | c23384958f517796f8b900b68692cf448c9d973a | |
parent | 90b9dc94d3d0c4cb13cb5e6e400ed1012747e6ff (diff) |
poll for challenge results before getting certificate
-rw-r--r-- | src/Network/ACME.hs | 37 |
1 files changed, 28 insertions, 9 deletions
diff --git a/src/Network/ACME.hs b/src/Network/ACME.hs index 5ae12f3..4df9f9b 100644 --- a/src/Network/ACME.hs +++ b/src/Network/ACME.hs | |||
@@ -47,9 +47,24 @@ certify directoryUrl keys optEmail terms requestDomains optChallengeDir csrData | |||
47 | liftIO $ BC.writeFile (coerce optChallengeDir </> BC.unpack token) thumbtoken | 47 | liftIO $ BC.writeFile (coerce optChallengeDir </> BC.unpack token) thumbtoken |
48 | notifyChallenge nextUri thumbtoken >>= statusReport >>= ncErrorReport | 48 | notifyChallenge nextUri thumbtoken >>= statusReport >>= ncErrorReport |
49 | 49 | ||
50 | forM_ requestDomains $ challengeRequest >=> statusReport >=> extractCR >=> performChallenge | 50 | challengeResultLinks <- forM requestDomains $ challengeRequest >=> statusReport >=> extractCR >=> performChallenge |
51 | 51 | ||
52 | retrieveCert csrData >>= statusReport <&> checkCertResponse | 52 | pollResults challengeResultLinks >>= |
53 | either (return . Left . ("certificate receipt was not attempted because a challenge failed: " ++)) | ||
54 | (const (retrieveCert csrData >>= statusReport <&> checkCertResponse)) | ||
55 | |||
56 | pollResults :: [Response LC.ByteString] -> ACME (Either String ()) | ||
57 | pollResults [] = return $ Right () | ||
58 | pollResults (link:links) = do | ||
59 | -- TODO: use "Retry-After" header if present | ||
60 | let Just uri = link ^? responseBody . JSON.key "uri" . _String | ||
61 | r <- liftIO $ W.get (T.unpack uri) | ||
62 | let status = r ^. responseBody . JSON.key "status" . _String | ||
63 | case status of | ||
64 | "pending" -> pollResults $ links ++ [r] | ||
65 | "valid" -> pollResults links | ||
66 | "invalid" -> return . Left $ r ^. responseBody . JSON.key "error" . to extractAcmeError | ||
67 | _ -> return . Left $ "unexpected response from ACME server: " ++ show r | ||
53 | 68 | ||
54 | data ChallengeRequest = ChallengeRequest { crUri :: String, crToken :: ByteString, crThumbToken :: ByteString } | 69 | data ChallengeRequest = ChallengeRequest { crUri :: String, crToken :: ByteString, crThumbToken :: ByteString } |
55 | 70 | ||
@@ -100,20 +115,24 @@ extractCR r = do | |||
100 | 115 | ||
101 | return $ ChallengeRequest nextU token thumbtoken | 116 | return $ ChallengeRequest nextU token thumbtoken |
102 | 117 | ||
103 | ncErrorReport :: (Show body, AsValue body, MonadIO m) => Response body -> m () | 118 | ncErrorReport :: (Show body, AsValue body, MonadIO m) => Response body -> m (Response body) |
104 | ncErrorReport r = | 119 | ncErrorReport r = do |
105 | when (Just "pending" /= r ^? responseBody . JSON.key "status" . _String) $ liftIO $ do | 120 | when (Just "pending" /= r ^? responseBody . JSON.key "status" . _String) $ liftIO $ do |
106 | putStrLn "Unexpected response to challenge-response request:" | 121 | putStrLn "Unexpected response to challenge-response request:" |
107 | print r | 122 | print r |
123 | return r | ||
124 | |||
125 | extractAcmeError :: forall s. AsValue s => s -> String | ||
126 | extractAcmeError r = summary ++ " ---- " ++ details | ||
127 | where | ||
128 | (Just summary, Just details) = (k "type", k "detail") | ||
129 | k x = r ^? JSON.key x . _String . to T.unpack | ||
108 | 130 | ||
109 | checkCertResponse :: Response LC.ByteString -> Either String LC.ByteString | 131 | checkCertResponse :: Response LC.ByteString -> Either String LC.ByteString |
110 | checkCertResponse r = | 132 | checkCertResponse r = |
111 | if isSuccess $ r ^. responseStatus . statusCode | 133 | if isSuccess $ r ^. responseStatus . statusCode |
112 | then Right $ r ^. responseBody | 134 | then Right $ r ^. responseBody |
113 | else | 135 | else Left $ r ^. responseBody . to extractAcmeError |
114 | let (summary, details) = (k "type", k "detail") | ||
115 | k x = r ^?! responseBody . JSON.key x . _String . to T.unpack | ||
116 | in Left $ summary ++ " ---- " ++ details | ||
117 | where | 136 | where |
118 | isSuccess n = n >= 200 && n <= 300 | 137 | isSuccess n = n >= 200 && n <= 300 |
119 | 138 | ||