From e741ba92517716e8ee0f2a0cf41d1639e75a25cd Mon Sep 17 00:00:00 2001 From: me Date: Wed, 6 Nov 2024 00:00:44 +0200 Subject: [PATCH] not yet working but progress --- fedi.cabal | 1 + src/Fedi/Requests.hs | 19 +++++++++++++++---- src/Fedi/Routes/Inbox.hs | 31 ++++++++++++++++++++----------- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/fedi.cabal b/fedi.cabal index c907fc6..abc0b9b 100644 --- a/fedi.cabal +++ b/fedi.cabal @@ -52,6 +52,7 @@ library , wai , exceptions , req + , modern-uri , base64 , crypton , crypton-x509 diff --git a/src/Fedi/Requests.hs b/src/Fedi/Requests.hs index d8e38bf..320c21a 100644 --- a/src/Fedi/Requests.hs +++ b/src/Fedi/Requests.hs @@ -3,10 +3,12 @@ module Fedi.Requests where import Data.Aeson qualified as A +import Fedi.Helpers import Fedi.UserDetails import Fedi.Crypto import Network.HTTP.Req qualified as Req import Data.ByteString.Lazy qualified as BSL +import Text.URI qualified as URI sendPost :: (A.FromJSON output, A.ToJSON input) @@ -17,15 +19,19 @@ sendPost sendPost details url payload = do let encoded = BSL.toStrict $ A.encode payload signed <- sign details encoded + uri <- URI.mkURI $ fromString url + (url', scheme) <- maybe (throw "couldn't parse uri") pure (Req.useHttpsURI uri) + print ("url", url') Req.runReq Req.defaultHttpConfig do r <- Req.req Req.POST - (Req.https $ fromString url) + url' (Req.ReqBodyBs encoded) Req.jsonResponse - ( Req.header "ContentType" "application/activity+json" + ( scheme + <> Req.header "ContentType" "application/activity+json" <> Req.header "Digest" signed.signedDigest <> Req.header "Signature" signed.signedMessage ) @@ -33,13 +39,18 @@ sendPost details url payload = do sendGet :: (A.FromJSON a) => String -> IO a sendGet url = do + uri <- URI.mkURI $ fromString url + (url', scheme) <- maybe (throw "couldn't parse uri") pure (Req.useHttpsURI uri) + print ("url", url') + Req.runReq Req.defaultHttpConfig do r <- Req.req Req.GET - (Req.https $ fromString url) + url' Req.NoReqBody Req.jsonResponse - ( Req.header "ContentType" "application/activity+json" + ( scheme + <> Req.header "ContentType" "application/activity+json" ) pure $ Req.responseBody r diff --git a/src/Fedi/Routes/Inbox.hs b/src/Fedi/Routes/Inbox.hs index fe32574..2140c99 100644 --- a/src/Fedi/Routes/Inbox.hs +++ b/src/Fedi/Routes/Inbox.hs @@ -12,10 +12,10 @@ import Web.Twain.Types qualified as Twain import Data.Text qualified as T import Network.Wai qualified as Wai import Control.Monad.IO.Class (liftIO) -import Control.Monad.Catch (catch) +import Control.Monad.Catch (catch, displayException, SomeException) import Text.ParserCombinators.ReadP qualified as P import Data.Text.Encoding qualified as T -import Data.Text.Encoding.Base64 qualified as Base64 +import Data.ByteString.Base64 qualified as Base64 import Data.ByteString.Lazy qualified as BSL import Fedi.Crypto @@ -32,16 +32,18 @@ handleInbox handle = do activity <- checkSignatureAndParseBody response <- handle activity Twain.send response - handler `catch` \(Error e) -> do - liftIO $ print e - Twain.send $ Twain.status Twain.status500 $ Twain.text (T.pack e) + handler `catch` \(e :: SomeException) -> do + liftIO $ putStrLn (displayException e) + Twain.send $ + Twain.status Twain.status500 $ + Twain.text "Internal Server Error 500" -- | Check the signature of the sender and parse the body of the request. checkSignatureAndParseBody :: Twain.ResponderM AnyActivity checkSignatureAndParseBody = do -- get info request <- Twain.request - liftIO $ print $ Twain.requestHeaders request + liftIO $ print ("headers", Twain.requestHeaders request) body <- liftIO (Wai.strictRequestBody request) sigheader <- parseSignature =<< Twain.header "Signature" digest <- Twain.header "Digest" >>= @@ -82,20 +84,23 @@ data SignatureHeader headers :: [T.Text] , -- | Contains the signature signature :: ByteString + , components :: [(Component, String)] } + deriving Show data Component = KeyId | Headers | Signature - deriving Eq + | Other String + deriving (Eq, Show) parseSignature :: MonadThrow m => Maybe T.Text -> m SignatureHeader parseSignature minput = do input <- maybe (throw "no signature.") (pure . T.unpack) minput case P.readP_to_S parser input of [(sig, "")] -> pure sig - _ -> throw "error parsing signature." + xs -> throw $ "error parsing signature: " <> show xs where lookup' a b = maybe (fail "error parsing signature") pure $ lookup a b @@ -104,9 +109,8 @@ parseSignature minput = do keyId <- lookup' KeyId components headers <- T.split (==' ') . T.pack <$> lookup' Headers components signature <- - ( T.encodeUtf8 - . Base64.decodeBase64Lenient - . T.pack + ( Base64.decodeBase64Lenient + . fromString ) <$> lookup' Signature components pure SignatureHeader{..} component = P.choice @@ -122,4 +126,9 @@ parseSignature minput = do _ <- P.string "signature=" url <- P.between (P.char '\"') (P.char '\"') (P.munch1 (/= '\"')) pure (Signature, url) + , do + key <- P.munch1 (/= '=') + _ <- P.char '=' + value <- P.between (P.char '\"') (P.char '\"') (P.munch1 (/= '\"')) + pure (Other key, value) ]