New module Yesod.ActivityPub, use it in Vervis.Federation for delivery POSTing

This commit is contained in:
fr33domlover 2019-04-26 03:23:49 +00:00
parent 71d21ad459
commit f346da9106
4 changed files with 79 additions and 25 deletions

View file

@ -69,6 +69,7 @@ import Network.HTTP.Signature
import Database.Persist.JSON import Database.Persist.JSON
import Network.FedURI import Network.FedURI
import Web.ActivityPub hiding (Follow) import Web.ActivityPub hiding (Follow)
import Yesod.ActivityPub
import Yesod.Auth.Unverified import Yesod.Auth.Unverified
import Yesod.FedURI import Yesod.FedURI
import Yesod.Hashids import Yesod.Hashids
@ -495,31 +496,14 @@ newtype FedError = FedError Text deriving Show
instance Exception FedError instance Exception FedError
getHttpSign
:: (MonadSite m, SiteEnv m ~ App) => m (KeyId, ByteString -> Signature)
getHttpSign = do
(akey1, akey2, new1) <- liftIO . readTVarIO =<< asksSite appActorKeys
renderUrl <- askUrlRender
let (keyID, akey) =
if new1
then (renderUrl ActorKey1R, akey1)
else (renderUrl ActorKey2R, akey2)
return (KeyId $ encodeUtf8 keyID, actorKeySign akey)
deliverHttp deliverHttp
:: (MonadSite m, SiteEnv m ~ App) :: (MonadSite m, SiteEnv m ~ App)
=> (KeyId, ByteString -> Signature) => Doc Activity
-> Doc Activity
-> Text -> Text
-> LocalURI -> LocalURI
-> m (Either APPostError (Response ())) -> m (Either APPostError (Response ()))
deliverHttp (keyid, sign) doc h luInbox = do deliverHttp doc h luInbox =
manager <- asksSite appHttpManager postActivity (l2f h luInbox) Nothing doc
let inbox = l2f h luInbox
headers = hRequestTarget :| [hHost, hDate, hActivityPubActor]
httpPostAP manager inbox headers keyid sign docActor Nothing doc
where
docActor = renderFedURI $ l2f (docHost doc) (activityActor $ docValue doc)
isInstanceErrorHttp (InvalidUrlException _ _) = False isInstanceErrorHttp (InvalidUrlException _ _) = False
isInstanceErrorHttp (HttpExceptionRequest _ hec) = isInstanceErrorHttp (HttpExceptionRequest _ hec) =
@ -1077,8 +1061,7 @@ handleOutboxNote host (Note mluNote luAttrib aud muParent muContext mpublished c
) )
-> Handler () -> Handler ()
deliverRemoteHttp obid doc (fetched, unfetched, unknown) = do deliverRemoteHttp obid doc (fetched, unfetched, unknown) = do
sign <- getHttpSign let deliver = deliverHttp doc
let deliver = deliverHttp sign doc
now <- liftIO getCurrentTime now <- liftIO getCurrentTime
traverse_ (fork . deliverFetched deliver now) fetched traverse_ (fork . deliverFetched deliver now) fetched
traverse_ (fork . deliverUnfetched deliver now) unfetched traverse_ (fork . deliverUnfetched deliver now) unfetched
@ -1221,8 +1204,7 @@ retryOutboxDelivery = do
let (linkedOld, linkedNew) = partitionEithers $ map (decideBySinceDL dropAfter now . adaptLinked) linked let (linkedOld, linkedNew) = partitionEithers $ map (decideBySinceDL dropAfter now . adaptLinked) linked
deleteWhere [DeliveryId <-. linkedOld] deleteWhere [DeliveryId <-. linkedOld]
return (groupUnlinked lonelyNew, groupLinked linkedNew) return (groupUnlinked lonelyNew, groupLinked linkedNew)
sign <- getHttpSign let deliver = deliverHttp
let deliver = deliverHttp sign
waitsDL <- traverse (fork . deliverLinked deliver now) dls waitsDL <- traverse (fork . deliverLinked deliver now) dls
waitsUDL <- traverse (fork . deliverUnlinked deliver now) udls waitsUDL <- traverse (fork . deliverUnlinked deliver now) udls
resultsDL <- sequence waitsDL resultsDL <- sequence waitsDL

View file

@ -28,6 +28,7 @@ import Crypto.Hash.Algorithms
import Data.Char import Data.Char
import Data.Either (isRight) import Data.Either (isRight)
import Data.HashMap.Strict (HashMap) import Data.HashMap.Strict (HashMap)
import Data.List.NonEmpty (NonEmpty (..))
import Data.Maybe (fromJust) import Data.Maybe (fromJust)
import Data.PEM (pemContent) import Data.PEM (pemContent)
import Data.Text.Encoding (decodeUtf8') import Data.Text.Encoding (decodeUtf8')
@ -73,6 +74,7 @@ import Crypto.PublicVerifKey
import Network.FedURI import Network.FedURI
import Web.ActivityAccess import Web.ActivityAccess
import Web.ActivityPub import Web.ActivityPub
import Yesod.ActivityPub
import Yesod.Hashids import Yesod.Hashids
import Yesod.MonadSite import Yesod.MonadSite
@ -80,7 +82,7 @@ import Text.Email.Local
import Text.Jasmine.Local (discardm) import Text.Jasmine.Local (discardm)
import Vervis.Access import Vervis.Access
import Vervis.ActorKey (ActorKey) import Vervis.ActorKey
import Vervis.Import.NoFoundation hiding (Handler, Day, last, init, logWarn) import Vervis.Import.NoFoundation hiding (Handler, Day, last, init, logWarn)
import Vervis.Model.Group import Vervis.Model.Group
import Vervis.Model.Ident import Vervis.Model.Ident
@ -643,6 +645,18 @@ instance YesodRemoteActorStore App where
siteRejectOnMaxKeys = appRejectOnMaxKeys . appSettings siteRejectOnMaxKeys = appRejectOnMaxKeys . appSettings
siteActorFetchShare = appActorFetchShare siteActorFetchShare = appActorFetchShare
instance YesodActivityPub App where
sitePostSignedHeaders _ =
hRequestTarget :| [hHost, hDate, hActivityPubActor]
siteGetHttpSign = do
(akey1, akey2, new1) <- liftIO . readTVarIO =<< asksSite appActorKeys
renderUrl <- askUrlRender
let (keyID, akey) =
if new1
then (renderUrl ActorKey1R, akey1)
else (renderUrl ActorKey2R, akey2)
return (KeyId $ encodeUtf8 keyID, actorKeySign akey)
data ActorDetail = ActorDetail data ActorDetail = ActorDetail
{ actorDetailId :: FedURI { actorDetailId :: FedURI
, actorDetailInstance :: InstanceId , actorDetailInstance :: InstanceId

57
src/Yesod/ActivityPub.hs Normal file
View file

@ -0,0 +1,57 @@
{- This file is part of Vervis.
-
- Written in 2019 by fr33domlover <fr33domlover@riseup.net>.
-
- Copying is an act of love. Please copy, reuse and share.
-
- The author(s) have dedicated all copyright and related and neighboring
- rights to this software to the public domain worldwide. This software is
- distributed without any warranty.
-
- You should have received a copy of the CC0 Public Domain Dedication along
- with this software. If not, see
- <http://creativecommons.org/publicdomain/zero/1.0/>.
-}
module Yesod.ActivityPub
( YesodActivityPub (..)
, postActivity
)
where
import Prelude
import Data.ByteString (ByteString)
import Data.List.NonEmpty (NonEmpty)
import Data.Text (Text)
import Yesod.Core
import Network.HTTP.Client
import Network.HTTP.Signature
import Network.HTTP.Types.Header
import Network.FedURI
import Web.ActivityPub
import Yesod.MonadSite
class Yesod site => YesodActivityPub site where
sitePostSignedHeaders :: site -> NonEmpty HeaderName
siteGetHttpSign :: (MonadSite m, SiteEnv m ~ site)
=> m (KeyId, ByteString -> Signature)
postActivity
:: ( MonadSite m
, SiteEnv m ~ site
, HasHttpManager site
, YesodActivityPub site
)
=> FedURI
-> Maybe (Either FedURI (KeyId, ByteString))
-> Doc Activity
-> m (Either APPostError (Response ()))
postActivity inbox mrecip doc@(Doc hAct activity) = do
manager <- asksSite getHttpManager
headers <- asksSite sitePostSignedHeaders
(keyid, sign) <- siteGetHttpSign
let sender = renderFedURI $ l2f hAct (activityActor activity)
httpPostAP manager inbox headers keyid sign sender mrecip doc

View file

@ -96,6 +96,7 @@ library
Web.ActivityPub Web.ActivityPub
Web.Hashids.Local Web.Hashids.Local
Web.PathPieces.Local Web.PathPieces.Local
Yesod.ActivityPub
Yesod.Auth.Unverified Yesod.Auth.Unverified
Yesod.Auth.Unverified.Creds Yesod.Auth.Unverified.Creds
Yesod.Auth.Unverified.Internal Yesod.Auth.Unverified.Internal