Put inbox activity auth code in a dedicated function in Vervis.Federation

This commit is contained in:
fr33domlover 2019-04-26 21:41:01 +00:00
parent 9d5399d636
commit 342467297a
2 changed files with 53 additions and 44 deletions

View file

@ -18,6 +18,7 @@ module Vervis.Federation
, fixRunningDeliveries , fixRunningDeliveries
, handleOutboxNote , handleOutboxNote
, retryOutboxDelivery , retryOutboxDelivery
, authenticateActivity
) )
where where
@ -32,7 +33,7 @@ import Control.Monad.Logger.CallStack
import Control.Monad.Trans.Except import Control.Monad.Trans.Except
import Control.Monad.Trans.Maybe import Control.Monad.Trans.Maybe
import Control.Monad.Trans.Reader import Control.Monad.Trans.Reader
import Data.Aeson (Object) import Data.Aeson
import Data.Bifunctor import Data.Bifunctor
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
import Data.Either import Data.Either
@ -50,7 +51,6 @@ import Data.Tuple
import Database.Persist hiding (deleteBy) import Database.Persist hiding (deleteBy)
import Database.Persist.Sql hiding (deleteBy) import Database.Persist.Sql hiding (deleteBy)
import Network.HTTP.Client import Network.HTTP.Client
import Network.HTTP.Signature
import Network.HTTP.Types.Header import Network.HTTP.Types.Header
import Network.HTTP.Types.URI import Network.HTTP.Types.URI
import Network.TLS import Network.TLS
@ -65,6 +65,7 @@ import qualified Data.Text as T
import qualified Database.Esqueleto as E import qualified Database.Esqueleto as E
import Network.HTTP.Signature import Network.HTTP.Signature
import Yesod.HttpSignature
import Database.Persist.JSON import Database.Persist.JSON
import Network.FedURI import Network.FedURI
@ -75,6 +76,7 @@ import Yesod.FedURI
import Yesod.Hashids import Yesod.Hashids
import Yesod.MonadSite import Yesod.MonadSite
import Data.Aeson.Local
import Data.Either.Local import Data.Either.Local
import Data.List.Local import Data.List.Local
import Data.List.NonEmpty.Local import Data.List.NonEmpty.Local
@ -1310,3 +1312,49 @@ retryOutboxDelivery = do
unless (and results) $ unless (and results) $
logError $ "Periodic UDL delivery error for host " <> h logError $ "Periodic UDL delivery error for host " <> h
return True return True
authenticateActivity
:: UTCTime
-> [ByteString]
-> ExceptT Text Handler (InstanceId, Object, Activity)
authenticateActivity now ctypes = do
verifyContentType
HttpSigVerResult result <-
ExceptT $
first (T.pack . displayException) <$>
verifyRequestSignature now
ActivityDetail uSender iid _raid body _keyid _digest <- ExceptT $ pure $ first T.pack result
WithValue raw (Doc hActivity activity) <-
case eitherDecode' body of
Left s -> throwE $ "Parsing activity failed: " <> T.pack s
Right wv -> return wv
let (hSender, luSender) = f2l uSender
unless (hSender == hActivity) $
throwE $ T.concat
[ "Activity host <", hActivity
, "> doesn't match signature key host <", hSender, ">"
]
unless (activityActor activity == luSender) $
throwE $ T.concat
[ "Activity's actor <"
, renderFedURI $ l2f hActivity $ activityActor activity
, "> != Signature key's actor <", renderFedURI uSender, ">"
]
return (iid, raw, activity)
where
verifyContentType =
case ctypes of
[] -> throwE "Content-Type not specified"
[x] | x == typeAS -> return ()
| x == typeAS2 -> return ()
| otherwise ->
throwE $ "Not a recognized AP Content-Type: " <>
case decodeUtf8' x of
Left _ -> T.pack (show x)
Right t -> t
_ -> throwE "More than one Content-Type specified"
where
typeAS = "application/activity+json"
typeAS2 =
"application/ld+json; \
\profile=\"https://www.w3.org/ns/activitystreams\""

View file

@ -140,53 +140,14 @@ postSharerInboxR shrRecip = do
unless federation badMethod unless federation badMethod
contentTypes <- lookupHeaders "Content-Type" contentTypes <- lookupHeaders "Content-Type"
now <- liftIO getCurrentTime now <- liftIO getCurrentTime
result <- go now contentTypes result <- runExceptT $ do
(iid, raw, activity) <- authenticateActivity now contentTypes
(raw,) <$> handleSharerInbox now shrRecip iid raw activity
recordActivity now result contentTypes recordActivity now result contentTypes
case result of case result of
Left _ -> sendResponseStatus badRequest400 () Left _ -> sendResponseStatus badRequest400 ()
Right _ -> return () Right _ -> return ()
where where
go now ctypes = runExceptT $ do
verifyContentType
HttpSigVerResult result <-
ExceptT $
first (T.pack . displayException) <$>
verifyRequestSignature now
ActivityDetail uSender iid _raid body _keyid _digest <- ExceptT $ pure $ first T.pack result
WithValue raw (Doc hActivity activity) <-
case eitherDecode' body of
Left s -> throwE $ "Parsing activity failed: " <> T.pack s
Right wv -> return wv
let (hSender, luSender) = f2l uSender
unless (hSender == hActivity) $
throwE $ T.concat
[ "Activity host <", hActivity
, "> doesn't match signature key host <", hSender, ">"
]
unless (activityActor activity == luSender) $
throwE $ T.concat
[ "Activity's actor <"
, renderFedURI $ l2f hActivity $ activityActor activity
, "> != Signature key's actor <", renderFedURI uSender, ">"
]
(raw,) <$> handleSharerInbox now shrRecip iid raw activity
where
verifyContentType =
case ctypes of
[] -> throwE "Content-Type not specified"
[x] | x == typeAS -> return ()
| x == typeAS2 -> return ()
| otherwise ->
throwE $ "Not a recognized AP Content-Type: " <>
case decodeUtf8' x of
Left _ -> T.pack (show x)
Right t -> t
_ -> throwE "More than one Content-Type specified"
where
typeAS = "application/activity+json"
typeAS2 =
"application/ld+json; \
\profile=\"https://www.w3.org/ns/activitystreams\""
recordActivity now result contentTypes = do recordActivity now result contentTypes = do
macts <- getsYesod appActivities macts <- getsYesod appActivities
for_ macts $ \ (size, acts) -> for_ macts $ \ (size, acts) ->