acme-not-a-joke-0.1.0.0: src/Acme/NotAJoke/Dancer.hs
module Acme.NotAJoke.Dancer where
import Control.Concurrent (threadDelay)
import Control.Monad (void)
import qualified Crypto.JOSE.JWK as JWK
import Data.Maybe (fromJust)
import Data.Text (Text)
import Acme.NotAJoke.Api.Account
import Acme.NotAJoke.Api.CSR
import Acme.NotAJoke.Api.Certificate
import Acme.NotAJoke.Api.Challenge (Token (..), isDNS01)
import Acme.NotAJoke.Api.Endpoint
import Acme.NotAJoke.Api.Order
import Acme.NotAJoke.Api.Validation
import Acme.NotAJoke.Client
data AcmeDancer
= AcmeDancer
{ baseUrl :: BaseUrl
, accountJwk :: JWK.JWK
, account :: Account "account-fetch"
, csr :: CSR
, order :: Order "order-create"
, handleStep :: DanceStep -> IO ()
}
data DanceStep
= Validation (Token, KeyAuthorization, ValidationProof)
| WaitingForValidation Int
| OrderIsFinalized OrderFinalized
| ValidOrder OrderInspected
| InvalidOrder OrderInspected
| OtherError Text
| Done AcmeSingle Certificate
| Prepare PrepareStep
runAcmeDance_dns01 :: AcmeDancer -> IO ()
runAcmeDance_dns01 = runAcmeDance isDNS01
runAcmeDance :: MatchChallenge -> AcmeDancer -> IO ()
runAcmeDance matchChallenge dancer = do
acme <-
prepareAcmeOrder
dancer.baseUrl
dancer.accountJwk
dancer.account
dancer.csr
dancer.order
matchChallenge
handleAcmeSingleStep
go acme
where
go acme = do
dancer.handleStep $ Validation acme.proof
_ <- acme.replyChallenge
waitForValidOrder 0 acme
handleAcmeSingleStep = dancer.handleStep . Prepare
waitForValidOrder n acme = do
dancer.handleStep (WaitingForValidation n)
recentOrder <- fromJust <$> acme.pollOrder
case Acme.NotAJoke.Api.Order.status <$> readOrderInspected recentOrder of
Just OrderPending -> waitForValidOrder (succ n) acme
Just OrderProcessing -> waitForValidOrder (succ n) acme
Just OrderReady -> do
x <- fromJust <$> acme.finalizeOrder
dancer.handleStep $ OrderIsFinalized x
waitForValidOrder (succ n) acme
Just OrderValid -> handleValid acme recentOrder
Just OrderInvalid -> dancer.handleStep $ InvalidOrder recentOrder
_ -> dancer.handleStep $ OtherError "could not inspect order"
handleValid acme o = do
dancer.handleStep $ ValidOrder o
let certUrl = certificate =<< (readOrderInspected o)
certif <- acme.fetchCertificate (fromJust certUrl)
dancer.handleStep $ Done acme (fromJust certif)
{- | A dance for running from within GHCI (i.e., printing and expecting you to
press ENTER to continue).
-}
ghciDance :: FilePath -> DanceStep -> IO ()
ghciDance certPath x =
case x of
Validation (tok, keyAuth, sha) -> do
print ("token (http01) is" :: Text, showToken tok)
print ("key authorization (http01) is" :: Text, showKeyAuth keyAuth)
print ("sha256 (dns01) is" :: Text, showProof sha)
print ("press enter to continue" :: Text)
void getLine
OrderIsFinalized o -> do
print ("finalized" :: Text, o)
ValidOrder o -> do
print ("order valid" :: Text, o)
WaitingForValidation n -> do
print ("waiting" :: Text, n)
threadDelay $ n * 1000000
Done _ cert -> do
storeCert certPath cert
print cert
InvalidOrder o -> do
print ("order invalid" :: Text, o)
OtherError txt -> do
print ("order invalid" :: Text, txt)
Prepare Starting -> do
print ("starting" :: Text)
Prepare GettingNonce -> do
print ("getting-nonce" :: Text)
Prepare (GotDirectory d) -> do
print ("listed directory" :: Text, d)
Prepare (GotAccount a) -> do
print ("got account" :: Text, a)
Prepare (GotOrder o) -> do
print ("got order" :: Text, o)
Prepare (GotAuthorization a) -> do
print ("got authorization" :: Text, a)
showToken :: Token -> Text
showToken (Token x1) = x1
showKeyAuth :: KeyAuthorization -> Text
showKeyAuth (KeyAuthorization x1) = x1
showProof :: ValidationProof -> Text
showProof (ValidationProof x1) = x1