1
0
Fork 0
mirror of https://code.sup39.dev/repos/Wqawg synced 2024-12-27 18:44:51 +09:00

Person: Port Invite and Follow handlers to new system

This commit is contained in:
Pere Lev 2023-05-30 22:02:11 +03:00
parent cc135692c0
commit 4d8e5de8b8
No known key found for this signature in database
GPG key ID: 5252C5C863E5E57D
8 changed files with 302 additions and 191 deletions

View file

@ -1851,7 +1851,8 @@ inviteC
-> AP.Invite URIMode -> AP.Invite URIMode
-> ExceptT Text Handler OutboxItemId -> ExceptT Text Handler OutboxItemId
inviteC (Entity senderPersonID senderPerson) senderActor maybeCap localRecips remoteRecips fwdHosts action invite = do inviteC (Entity senderPersonID senderPerson) senderActor maybeCap localRecips remoteRecips fwdHosts action invite = do
error "Temporarily disabled due to switch to new actor system"
{-
-- Check input -- Check input
(resource, recipient) <- parseInvite (Left senderPersonID) invite (resource, recipient) <- parseInvite (Left senderPersonID) invite
capID <- fromMaybeE maybeCap "No capability provided" capID <- fromMaybeE maybeCap "No capability provided"
@ -2054,6 +2055,7 @@ inviteC (Entity senderPersonID senderPerson) senderActor maybeCap localRecips re
hashGrantRecip (GrantRecipPerson k) = hashGrantRecip (GrantRecipPerson k) =
GrantRecipPerson <$> encodeKeyHashid k GrantRecipPerson <$> encodeKeyHashid k
-}
offerTicketC offerTicketC
:: Entity Person :: Entity Person

View file

@ -1,6 +1,7 @@
{- This file is part of Vervis. {- This file is part of Vervis.
- -
- Written in 2019, 2020, 2021, 2022 by fr33domlover <fr33domlover@riseup.net>. - Written in 2019, 2020, 2021, 2022, 2023
- by fr33domlover <fr33domlover@riseup.net>.
- -
- Copying is an act of love. Please copy, reuse and share. - Copying is an act of love. Please copy, reuse and share.
- -
@ -26,6 +27,7 @@ module Vervis.ActivityPub
, provideEmptyCollection , provideEmptyCollection
, insertEmptyOutboxItem , insertEmptyOutboxItem
, insertEmptyOutboxItem'
, verifyContentTypeAP , verifyContentTypeAP
, verifyContentTypeAP_E , verifyContentTypeAP_E
, getActivity , getActivity
@ -82,9 +84,11 @@ import qualified Database.Esqueleto as E
import Yesod.HttpSignature import Yesod.HttpSignature
import Control.Concurrent.Actor
import Database.Persist.JSON import Database.Persist.JSON
import Network.FedURI import Network.FedURI
import Network.HTTP.Digest import Network.HTTP.Digest
import Web.Actor (stageInstanceHost)
import Yesod.ActivityPub import Yesod.ActivityPub
import Yesod.MonadSite import Yesod.MonadSite
import Yesod.FedURI import Yesod.FedURI
@ -235,6 +239,15 @@ insertEmptyOutboxItem obid now = do
, outboxItemPublished = now , outboxItemPublished = now
} }
insertEmptyOutboxItem' obid now = do
h <- asksEnv stageInstanceHost
insert OutboxItem
{ outboxItemOutbox = obid
, outboxItemActivity =
persistJSONObjectFromDoc $ AP.Doc h AP.emptyActivity
, outboxItemPublished = now
}
verifyContentTypeAP :: MonadHandler m => m () verifyContentTypeAP :: MonadHandler m => m ()
verifyContentTypeAP = do verifyContentTypeAP = do
result <- runExceptT verifyContentTypeAP_E result <- runExceptT verifyContentTypeAP_E

View file

@ -293,13 +293,19 @@ data VerseRemote = VerseRemote
} }
data Event data Event
= EventRemoteGrantLocalRecipFwdToFollower RemoteActivityId = EventRemoteInviteLocalRecipFwdToFollower RemoteActivityId
-- ^ A local actor has received a Grant (they're being granted some access) -- ^ A local actor has received an Invite (they're being offered some access)
-- and forwarding it to me because I'm following this local actor
| EventRemoteFollowLocalRecipFwdToFollower RemoteActivityId
-- ^ A local actor has received an Follow where they're the target,
-- and forwarding it to me because I'm following this local actor -- and forwarding it to me because I'm following this local actor
| EventRemoteFwdLocalActivity (LocalActorBy Key) OutboxItemId | EventRemoteFwdLocalActivity (LocalActorBy Key) OutboxItemId
-- EventLocalFwdRemoteActivity (LocalActorBy Key) RemoteActivityId -- EventLocalFwdRemoteActivity (LocalActorBy Key) RemoteActivityId
-- ^ A local actor is forwarding me a remote activity to add to my inbox. -- ^ A local actor is forwarding me a remote activity to add to my inbox.
-- The data is (1) who's forwarding to me (2) the remote activity -- The data is (1) who's forwarding to me (2) the remote activity
| EventAcceptRemoteFollow
-- ^ A local actor (that I'm following) has accepted a Follow from some
-- remote actor
| EventUnknown | EventUnknown
deriving Show deriving Show

View file

@ -14,6 +14,9 @@
- <http://creativecommons.org/publicdomain/zero/1.0/>. - <http://creativecommons.org/publicdomain/zero/1.0/>.
-} -}
-- for actorFollow
{-# LANGUAGE RankNTypes #-}
module Vervis.Actor.Person module Vervis.Actor.Person
( personBehavior ( personBehavior
) )
@ -29,6 +32,7 @@ import Control.Monad.Trans.Reader
import Data.Bitraversable import Data.Bitraversable
import Data.ByteString (ByteString) import Data.ByteString (ByteString)
import Data.Foldable import Data.Foldable
import Data.Maybe
import Data.Text (Text) import Data.Text (Text)
import Data.Time.Clock import Data.Time.Clock
import Data.Traversable import Data.Traversable
@ -40,6 +44,7 @@ import qualified Data.Text as T
import Control.Concurrent.Actor import Control.Concurrent.Actor
import Network.FedURI import Network.FedURI
import Web.Actor
import Web.Actor.Persist import Web.Actor.Persist
import Yesod.MonadSite import Yesod.MonadSite
@ -48,21 +53,170 @@ import qualified Web.ActivityPub as AP
import Control.Monad.Trans.Except.Local import Control.Monad.Trans.Except.Local
import Database.Persist.Local import Database.Persist.Local
import Vervis.Access
import Vervis.ActivityPub
import Vervis.Actor import Vervis.Actor
import Vervis.Actor2 import Vervis.Actor2
import Vervis.Cloth import Vervis.Cloth
import Vervis.Data.Actor
import Vervis.Data.Collab import Vervis.Data.Collab
import Vervis.Data.Discussion import Vervis.Data.Discussion
import Vervis.FedURI import Vervis.FedURI
import Vervis.Federation.Util import Vervis.Federation.Util
import Vervis.Foundation import Vervis.Foundation
import Vervis.Model import Vervis.Model
import Vervis.Recipient (makeRecipientSet, LocalStageBy (..)) import Vervis.Recipient (makeRecipientSet, LocalStageBy (..), Aud (..), collectAudience)
import Vervis.Persist.Actor import Vervis.Persist.Actor
import Vervis.Persist.Collab import Vervis.Persist.Collab
import Vervis.Persist.Discussion import Vervis.Persist.Discussion
import Vervis.Ticket import Vervis.Ticket
------------------------------------------------------------------------------
-- Following
------------------------------------------------------------------------------
actorFollow
:: (PersistRecordBackend r SqlBackend, ToBackendKey SqlBackend r)
=> (Route App -> ActE a)
-> (r -> ActorId)
-> Bool
-> (Key r -> Actor -> a -> ActDBE FollowerSetId)
-> (a -> ActDB RecipientRoutes)
-> (forall f. f r -> LocalActorBy f)
-> (a -> Act [Aud URIMode])
-> UTCTime
-> Key r
-> RemoteAuthor
-> ActivityBody
-> Maybe (RecipientRoutes, ByteString)
-> LocalURI
-> AP.Follow URIMode
-> ActE (Text, Act (), Next)
actorFollow parseFollowee grabActor unread getFollowee getSieve makeLocalActor makeAudience now recipID author body mfwd luFollow (AP.Follow uObject _ hide) = do
-- Check input
followee <- nameExceptT "Follow object" $ do
route <- do
routeOrRemote <- parseFedURI uObject
case routeOrRemote of
Left route -> pure route
Right _ -> throwE "Remote, so definitely not me/mine"
parseFollowee route
verifyNothingE
(AP.activityCapability $ actbActivity body)
"Capability not needed"
maybeFollow <- withDBExcept $ do
-- Find recipient actor in DB
recip <- lift $ getJust recipID
let recipActorID = grabActor recip
recipActor <- lift $ getJust recipActorID
-- Insert the Follow to actor's inbox
mractid <- lift $ insertToInbox now author body (actorInbox recipActor) luFollow unread
for mractid $ \ followID -> do
-- Find followee in DB
followerSetID <- getFollowee recipID recipActor followee
-- Verify not already following us
let followerID = remoteAuthorId author
maybeFollow <-
lift $ getBy $ UniqueRemoteFollow followerID followerSetID
verifyNothingE maybeFollow "You're already following this object"
-- Record the new follow in DB
acceptID <-
lift $ insertEmptyOutboxItem' (actorOutbox recipActor) now
lift $ insert_ $ RemoteFollow followerID followerSetID (not hide) followID acceptID
-- Prepare an Accept activity and insert to actor's outbox
accept@(actionAccept, localRecipsAccept, remoteRecipsAccept, fwdHostsAccept) <-
lift $ prepareAccept followee
_luAccept <- lift $ updateOutboxItem' (makeLocalActor recipID) acceptID actionAccept
sieve <- lift $ getSieve followee
return (recipActorID, followID, acceptID, sieve, accept)
case maybeFollow of
Nothing -> done "I already have this activity in my inbox"
Just (actorID, followID, acceptID, sieve, (actionAccept, localRecipsAccept, remoteRecipsAccept, fwdHostsAccept)) -> do
lift $ for_ mfwd $ \ (localRecips, sig) ->
forwardActivity
(actbBL body) localRecips sig actorID
(makeLocalActor recipID) sieve
(EventRemoteFollowLocalRecipFwdToFollower followID)
lift $ sendActivity
(makeLocalActor recipID) actorID localRecipsAccept
remoteRecipsAccept fwdHostsAccept acceptID
EventAcceptRemoteFollow actionAccept
done "Recorded Follow and published Accept"
where
prepareAccept followee = do
encodeRouteHome <- getEncodeRouteHome
ra <- getJust $ remoteAuthorId author
let ObjURI hAuthor luAuthor = remoteAuthorURI author
audSender =
AudRemote hAuthor
[luAuthor]
(maybeToList $ remoteActorFollowers ra)
audsRecip <- lift $ makeAudience followee
let (recipientSet, remoteActors, fwdHosts, audLocal, audRemote) =
collectAudience $ audSender : audsRecip
recips = map encodeRouteHome audLocal ++ audRemote
action = AP.Action
{ AP.actionCapability = Nothing
, AP.actionSummary = Nothing
, AP.actionAudience = AP.Audience recips [] [] [] [] []
, AP.actionFulfills = []
, AP.actionSpecific = AP.AcceptActivity AP.Accept
{ AP.acceptObject = ObjURI hAuthor luFollow
, AP.acceptResult = Nothing
}
}
return (action, recipientSet, remoteActors, fwdHosts)
-- Meaning: Someone is following someone
-- Behavior:
-- * Verify I'm the target
-- * Record the follow in DB
-- * Publish and send an Accept to the sender and its followers
personFollow
:: UTCTime
-> PersonId
-> RemoteAuthor
-> ActivityBody
-> Maybe (RecipientRoutes, ByteString)
-> LocalURI
-> AP.Follow URIMode
-> ActE (Text, Act (), Next)
personFollow now recipPersonID author body mfwd luFollow follow = do
recipPersonHash <- encodeKeyHashid recipPersonID
actorFollow
(\case
PersonR p | p == recipPersonHash -> pure ()
_ -> throwE "Asking to follow someone else"
)
personActor
True
(\ _recipPersonID recipPersonActor () ->
pure $ actorFollowers recipPersonActor
)
(\ () -> pure $ makeRecipientSet [] [])
LocalActorPerson
(\ () -> pure [])
now recipPersonID author body mfwd luFollow follow
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
-- Commenting -- Commenting
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
@ -147,10 +301,70 @@ personCreateNote now recipPersonID author body mfwd luCreate note = do
-- Access -- Access
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
-- Meaning: Someone invited someone to a resource
-- Behavior:
-- * Insert to my inbox
-- * If I'm the target, forward the Invite to my followers
personInvite
:: UTCTime
-> PersonId
-> RemoteAuthor
-> ActivityBody
-> Maybe (RecipientRoutes, ByteString)
-> LocalURI
-> AP.Invite URIMode
-> ActE (Text, Act (), Next)
personInvite now recipPersonID author body mfwd luInvite invite = do
-- Check input
recipient <- do
(_resource, target) <-
parseInvite (Right $ remoteAuthorURI author) invite
return target
maybeInvite <- withDBExcept $ do
-- Grab recipient person from DB
(personRecip, actorRecip) <- lift $ do
p <- getJust recipPersonID
(p,) <$> getJust (personActor p)
mractid <- lift $ insertToInbox now author body (actorInbox actorRecip) luInvite True
for mractid $ \ inviteID ->
return (personActor personRecip, inviteID)
case maybeInvite of
Nothing -> done "I already have this activity in my inbox"
Just (actorID, inviteID) -> do
let targetIsRecip =
case recipient of
Left (GrantRecipPerson p) -> p == recipPersonID
_ -> False
if not targetIsRecip
then done "I'm not the target; Inserted to inbox"
else case mfwd of
Nothing ->
done
"I'm the target; Inserted to inbox; \
\Forwarding not approved"
Just (localRecips, sig) -> do
recipHash <- encodeKeyHashid recipPersonID
let sieve =
makeRecipientSet
[]
[LocalStagePersonFollowers recipHash]
lift $ forwardActivity
(actbBL body) localRecips sig
actorID
(LocalActorPerson recipPersonID) sieve
(EventRemoteInviteLocalRecipFwdToFollower inviteID)
done
"I'm the target; Inserted to inbox; \
\Forwarded to followers if addressed"
-- Meaning: A remote actor published a Grant -- Meaning: A remote actor published a Grant
-- Behavior: -- Behavior:
-- * Insert to my inbox -- * Insert to my inbox
-- * If I'm the target, forward the Grant to my followers
personGrant personGrant
:: UTCTime :: UTCTime
-> PersonId -> PersonId
@ -182,45 +396,19 @@ personGrant now recipPersonID author body mfwd luGrant grant = do
(p,) <$> getJust (personActor p) (p,) <$> getJust (personActor p)
mractid <- lift $ insertToInbox now author body (actorInbox actorRecip) luGrant True mractid <- lift $ insertToInbox now author body (actorInbox actorRecip) luGrant True
for mractid $ \ grantID -> do for mractid $ \ grantID ->
-- If recipient is local, find it in our DB
_recipientDB <-
bitraverse
(flip getGrantRecip "Grant local target not found in DB")
pure
recipient
return (personActor personRecip, grantID) return (personActor personRecip, grantID)
case maybeGrant of case maybeGrant of
Nothing -> done "I already have this activity in my inbox" Nothing -> done "I already have this activity in my inbox"
Just (actorID, grantID) -> do Just (_actorID, _grantID) -> do
let targetIsRecip = let targetIsRecip =
case recipient of case recipient of
Left (GrantRecipPerson p) -> p == recipPersonID Left (GrantRecipPerson p) -> p == recipPersonID
_ -> False _ -> False
if not targetIsRecip if not targetIsRecip
then done "I'm not the target; Inserted to inbox" then done "I'm not the target; Inserted to inbox"
else case mfwd of else done "I'm the target; Inserted to inbox"
Nothing ->
done
"I'm the target; Inserted to inbox; \
\Forwarding not approved"
Just (localRecips, sig) -> do
recipHash <- encodeKeyHashid recipPersonID
let sieve =
makeRecipientSet
[]
[LocalStagePersonFollowers recipHash]
lift $ forwardActivity
(actbBL body) localRecips sig
actorID
(LocalActorPerson recipPersonID) sieve
(EventRemoteGrantLocalRecipFwdToFollower grantID)
done
"I'm the target; Inserted to inbox; \
\Forwarded to followers if addressed"
------------------------------------------------------------------------------ ------------------------------------------------------------------------------
-- Main behavior function -- Main behavior function
@ -242,18 +430,18 @@ insertActivityToInbox now recipActorID outboxItemID = do
personBehavior :: UTCTime -> PersonId -> Verse -> ActE (Text, Act (), Next) personBehavior :: UTCTime -> PersonId -> Verse -> ActE (Text, Act (), Next)
personBehavior now personID (Left event) = personBehavior now personID (Left event) =
case event of case event of
-- Meaning: Someone X received a Grant and forwarded it to me because -- Meaning: Someone X received an Invite and forwarded it to me because
-- I'm a follower of X -- I'm a follower of X
-- Behavior: Insert to my inbox -- Behavior: Insert to my inbox
EventRemoteGrantLocalRecipFwdToFollower grantID -> do EventRemoteInviteLocalRecipFwdToFollower inviteID -> do
lift $ withDB $ do lift $ withDB $ do
(_personRecip, actorRecip) <- do (_personRecip, actorRecip) <- do
p <- getJust personID p <- getJust personID
(p,) <$> getJust (personActor p) (p,) <$> getJust (personActor p)
let inboxID = actorInbox actorRecip let inboxID = actorInbox actorRecip
itemID <- insert $ InboxItem True now itemID <- insert $ InboxItem True now
insert_ $ InboxItemRemote inboxID grantID itemID insert_ $ InboxItemRemote inboxID inviteID itemID
done "Inserted Grant to inbox" done "Inserted Invite to inbox"
-- Meaning: A remote actor has forwarded to me a remote activity -- Meaning: A remote actor has forwarded to me a remote activity
-- Behavior: Insert it to my inbox -- Behavior: Insert it to my inbox
EventRemoteFwdLocalActivity authorByKey outboxItemID -> withDBExcept $ do EventRemoteFwdLocalActivity authorByKey outboxItemID -> withDBExcept $ do
@ -275,15 +463,13 @@ personBehavior now personID (Right (VerseRemote author body mfwd luActivity)) =
AP.CreateNote _ note -> AP.CreateNote _ note ->
personCreateNote now personID author body mfwd luActivity note personCreateNote now personID author body mfwd luActivity note
_ -> throwE "Unsupported create object type for people" _ -> throwE "Unsupported create object type for people"
{-
AP.FollowActivity follow -> AP.FollowActivity follow ->
personFollowA now personID author body mfwd luActivity follow personFollow now personID author body mfwd luActivity follow
-}
AP.GrantActivity grant -> AP.GrantActivity grant ->
personGrant now personID author body mfwd luActivity grant personGrant now personID author body mfwd luActivity grant
{-
AP.InviteActivity invite -> AP.InviteActivity invite ->
personInviteA now personID author body mfwd luActivity invite personInvite now personID author body mfwd luActivity invite
{-
AP.UndoActivity undo -> AP.UndoActivity undo ->
(,Nothing) <$> personUndoA now personID author body mfwd luActivity undo (,Nothing) <$> personUndoA now personID author body mfwd luActivity undo
-} -}

View file

@ -57,6 +57,7 @@ import Control.Monad.Trans.Except.Local
import Vervis.Access import Vervis.Access
import Vervis.Actor import Vervis.Actor
import Vervis.Actor2
import Vervis.Data.Actor import Vervis.Data.Actor
import Vervis.FedURI import Vervis.FedURI
import Vervis.Foundation import Vervis.Foundation
@ -98,15 +99,18 @@ verifyRole (Left AP.RoleAdmin) = pure ()
verifyRole (Right _) = verifyRole (Right _) =
throwE "ForgeFed Admin is the only role allowed currently" throwE "ForgeFed Admin is the only role allowed currently"
parseTopic
:: StageRoute Env ~ Route App
=> FedURI -> ActE (Either (GrantResourceBy Key) FedURI)
parseTopic u = do parseTopic u = do
routeOrRemote <- parseFedURIOld u routeOrRemote <- parseFedURI u
bitraverse bitraverse
(\ route -> do (\ route -> do
resourceHash <- resourceHash <-
fromMaybeE fromMaybeE
(parseGrantResource route) (parseGrantResource route)
"Not a shared resource route" "Not a shared resource route"
unhashGrantResourceE unhashGrantResourceE'
resourceHash resourceHash
"Contains invalid hashid" "Contains invalid hashid"
) )
@ -114,9 +118,10 @@ parseTopic u = do
routeOrRemote routeOrRemote
parseInvite parseInvite
:: Either PersonId FedURI :: StageRoute Env ~ Route App
=> Either PersonId FedURI
-> AP.Invite URIMode -> AP.Invite URIMode
-> ExceptT Text Handler -> ActE
( Either (GrantResourceBy Key) FedURI ( Either (GrantResourceBy Key) FedURI
, Either (GrantRecipBy Key) FedURI , Either (GrantRecipBy Key) FedURI
) )
@ -126,7 +131,7 @@ parseInvite sender (AP.Invite instrument object target) = do
<*> nameExceptT "Invite object" (parseRecipient object) <*> nameExceptT "Invite object" (parseRecipient object)
where where
parseRecipient u = do parseRecipient u = do
routeOrRemote <- parseFedURIOld u routeOrRemote <- parseFedURI u
bitraverse bitraverse
(\ route -> do (\ route -> do
recipHash <- recipHash <-
@ -134,7 +139,7 @@ parseInvite sender (AP.Invite instrument object target) = do
(parseGrantRecip route) (parseGrantRecip route)
"Not a grant recipient route" "Not a grant recipient route"
recipKey <- recipKey <-
unhashGrantRecipEOld unhashGrantRecipE
recipHash recipHash
"Contains invalid hashid" "Contains invalid hashid"
case recipKey of case recipKey of
@ -150,8 +155,8 @@ parseInvite sender (AP.Invite instrument object target) = do
routeOrRemote routeOrRemote
parseJoin parseJoin
:: AP.Join URIMode :: StageRoute Env ~ Route App
-> ExceptT Text Handler (Either (GrantResourceBy Key) FedURI) => AP.Join URIMode -> ActE (Either (GrantResourceBy Key) FedURI)
parseJoin (AP.Join instrument object) = do parseJoin (AP.Join instrument object) = do
verifyRole instrument verifyRole instrument
nameExceptT "Join object" (parseTopic object) nameExceptT "Join object" (parseTopic object)

View file

@ -100,7 +100,8 @@ topicInviteF
-> AP.Invite URIMode -> AP.Invite URIMode
-> ExceptT Text Handler (Text, Maybe (ExceptT Text Worker Text)) -> ExceptT Text Handler (Text, Maybe (ExceptT Text Worker Text))
topicInviteF now recipByHash author body mfwd luInvite invite = do topicInviteF now recipByHash author body mfwd luInvite invite = do
error "Temporarily disabled due to switch to new actor system"
{-
-- Check input -- Check input
uCap <- do uCap <- do
let muCap = AP.activityCapability $ actbActivity body let muCap = AP.activityCapability $ actbActivity body
@ -227,6 +228,7 @@ topicInviteF now recipByHash author body mfwd luInvite invite = do
insert_ $ CollabRecipLocal collabID personID insert_ $ CollabRecipLocal collabID personID
Right remoteActorID -> Right remoteActorID ->
insert_ $ CollabRecipRemote collabID remoteActorID insert_ $ CollabRecipRemote collabID remoteActorID
-}
topicJoinF topicJoinF
:: (PersistRecordBackend topic SqlBackend, ToBackendKey SqlBackend topic) :: (PersistRecordBackend topic SqlBackend, ToBackendKey SqlBackend topic)
@ -241,7 +243,8 @@ topicJoinF
-> AP.Join URIMode -> AP.Join URIMode
-> ExceptT Text Handler (Text, Maybe (ExceptT Text Worker Text)) -> ExceptT Text Handler (Text, Maybe (ExceptT Text Worker Text))
topicJoinF topicActor topicResource now recipHash author body mfwd luJoin join = (,Nothing) <$> do topicJoinF topicActor topicResource now recipHash author body mfwd luJoin join = (,Nothing) <$> do
error "Temporarily disabled due to switch to new actor system"
{-
-- Check input -- Check input
recipKey <- decodeKeyHashid404 recipHash recipKey <- decodeKeyHashid404 recipHash
verifyNothingE verifyNothingE
@ -306,6 +309,7 @@ topicJoinF topicActor topicResource now recipHash author body mfwd luJoin join =
let authorID = remoteAuthorId author let authorID = remoteAuthorId author
recipID <- insert $ CollabRecipRemote collabID authorID recipID <- insert $ CollabRecipRemote collabID authorID
insert_ $ CollabRecipRemoteJoin recipID fulfillsID joinID insert_ $ CollabRecipRemoteJoin recipID fulfillsID joinID
-}
repoJoinF repoJoinF
:: UTCTime :: UTCTime

View file

@ -20,12 +20,12 @@ module Vervis.Federation.Offer
--, sharerRejectF --, sharerRejectF
personFollowF --personFollowF
, deckFollowF --, deckFollowF
, loomFollowF --, loomFollowF
, repoFollowF --, repoFollowF
, personUndoF personUndoF
, deckUndoF , deckUndoF
, loomUndoF , loomUndoF
, repoUndoF , repoUndoF
@ -301,137 +301,6 @@ sharerRejectF recipHash now author body mfwd luReject (Reject (ObjURI hOffer luO
lift $ delete frrid lift $ delete frrid
-} -}
followF
:: (PersistRecordBackend r SqlBackend, ToBackendKey SqlBackend r)
=> (Route App -> ExceptT Text Handler a)
-> (r -> ActorId)
-> Bool
-> (Key r -> Actor -> a -> ExceptT Text AppDB FollowerSetId)
-> (a -> AppDB RecipientRoutes)
-> (forall f. f r -> LocalActorBy f)
-> (a -> Handler [Aud URIMode])
-> UTCTime
-> KeyHashid r
-> RemoteAuthor
-> ActivityBody
-> Maybe (RecipientRoutes, ByteString)
-> LocalURI
-> AP.Follow URIMode
-> ExceptT Text Handler (Text, Maybe (ExceptT Text Worker Text))
followF parseFollowee grabActor unread getFollowee getSieve makeLocalActor makeAudience now recipHash author body mfwd luFollow (AP.Follow uObject _ hide) = (,Nothing) <$> do
-- Check input
recipID <- decodeKeyHashid404 recipHash
followee <- nameExceptT "Follow object" $ do
route <- do
routeOrRemote <- parseFedURIOld uObject
case routeOrRemote of
Left route -> pure route
Right _ -> throwE "Remote, so definitely not me/mine"
parseFollowee route
verifyNothingE
(AP.activityCapability $ actbActivity body)
"Capability not needed"
maybeHttp <- runDBExcept $ do
-- Find recipient actor in DB, returning 404 if doesn't exist because
-- we're in the actor's inbox post handler
recip <- lift $ get404 recipID
let recipActorID = grabActor recip
recipActor <- lift $ getJust recipActorID
-- Insert the Follow to actor's inbox
mractid <- lift $ insertToInbox now author body (actorInbox recipActor) luFollow unread
for mractid $ \ followID -> do
-- Find followee in DB
followerSetID <- getFollowee recipID recipActor followee
-- Verify not already following us
let followerID = remoteAuthorId author
maybeFollow <-
lift $ getBy $ UniqueRemoteFollow followerID followerSetID
verifyNothingE maybeFollow "You're already following this object"
-- Forward the Follow activity to relevant local stages, and
-- schedule delivery for unavailable remote members of them
maybeHttpFwdFollow <- lift $ for mfwd $ \ (localRecips, sig) -> do
sieve <- getSieve followee
forwardActivityDB
(actbBL body) localRecips sig recipActorID
(makeLocalActor recipHash) sieve followID
-- Record the new follow in DB
acceptID <-
lift $ insertEmptyOutboxItem (actorOutbox recipActor) now
lift $ insert_ $ RemoteFollow followerID followerSetID (not hide) followID acceptID
-- Prepare an Accept activity and insert to actor's outbox
(actionAccept, localRecipsAccept, remoteRecipsAccept, fwdHostsAccept) <-
lift $ prepareAccept followee
_luAccept <- lift $ updateOutboxItem (makeLocalActor recipID) acceptID actionAccept
-- Deliver the Accept to local recipients, and schedule delivery
-- for unavailable remote recipients
deliverHttpAccept <-
deliverActivityDB
(makeLocalActor recipHash) recipActorID
localRecipsAccept remoteRecipsAccept fwdHostsAccept
acceptID actionAccept
-- Return instructions for HTTP inbox-forwarding of the Follow
-- activity, and for HTTP delivery of the Accept activity to
-- remote recipients
return (maybeHttpFwdFollow, deliverHttpAccept)
-- Launch asynchronous HTTP forwarding of the Follow activity and HTTP
-- delivery of the Accept activity
case maybeHttp of
Nothing ->
return "I already have this activity in my inbox, doing nothing"
Just (maybeHttpFwdFollow, deliverHttpAccept) -> do
for_ maybeHttpFwdFollow $ forkWorker "followF inbox-forwarding"
forkWorker "followF Accept HTTP delivery" deliverHttpAccept
return $
case maybeHttpFwdFollow of
Nothing -> "Recorded follow, no inbox-forwarding to do"
Just _ ->
"Recorded follow and ran inbox-forwarding of the Follow"
where
prepareAccept followee = do
encodeRouteHome <- getEncodeRouteHome
ra <- getJust $ remoteAuthorId author
let ObjURI hAuthor luAuthor = remoteAuthorURI author
audSender =
AudRemote hAuthor
[luAuthor]
(maybeToList $ remoteActorFollowers ra)
audsRecip <- lift $ makeAudience followee
let (recipientSet, remoteActors, fwdHosts, audLocal, audRemote) =
collectAudience $ audSender : audsRecip
recips = map encodeRouteHome audLocal ++ audRemote
action = AP.Action
{ AP.actionCapability = Nothing
, AP.actionSummary = Nothing
, AP.actionAudience = AP.Audience recips [] [] [] [] []
, AP.actionFulfills = []
, AP.actionSpecific = AP.AcceptActivity AP.Accept
{ AP.acceptObject = ObjURI hAuthor luFollow
, AP.acceptResult = Nothing
}
}
return (action, recipientSet, remoteActors, fwdHosts)
{- {-
followF followF
:: (Route App -> Maybe a) :: (Route App -> Maybe a)
@ -559,6 +428,7 @@ followF
return (obiid, doc) return (obiid, doc)
-} -}
{-
personFollowF personFollowF
:: UTCTime :: UTCTime
-> KeyHashid Person -> KeyHashid Person
@ -678,6 +548,7 @@ repoFollowF now recipRepoHash =
(\ () -> pure []) (\ () -> pure [])
now now
recipRepoHash recipRepoHash
-}
personUndoF personUndoF
:: UTCTime :: UTCTime

View file

@ -1,6 +1,6 @@
{- This file is part of Vervis. {- This file is part of Vervis.
- -
- Written in 2022 by fr33domlover <fr33domlover@riseup.net>. - Written in 2022, 2023 by fr33domlover <fr33domlover@riseup.net>.
- -
- Copying is an act of love. Please copy, reuse and share. - Copying is an act of love. Please copy, reuse and share.
- -
@ -21,6 +21,7 @@ module Vervis.Persist.Actor
, getRemoteActorURI , getRemoteActorURI
, insertActor , insertActor
, updateOutboxItem , updateOutboxItem
, updateOutboxItem'
, fillPerActorKeys , fillPerActorKeys
, getPersonWidgetInfo , getPersonWidgetInfo
) )
@ -42,6 +43,7 @@ import Database.Persist.Sql
import qualified Data.Text as T import qualified Data.Text as T
import qualified Database.Esqueleto as E import qualified Database.Esqueleto as E
import Control.Concurrent.Actor
import Crypto.ActorKey import Crypto.ActorKey
import Database.Persist.JSON import Database.Persist.JSON
import Network.FedURI import Network.FedURI
@ -51,10 +53,13 @@ import Yesod.Hashids
import Yesod.MonadSite import Yesod.MonadSite
import qualified Web.ActivityPub as AP import qualified Web.ActivityPub as AP
import qualified Web.Actor as WA
import qualified Web.Actor.Persist as WAP
import Control.Monad.Trans.Except.Local import Control.Monad.Trans.Except.Local
import Database.Persist.Local import Database.Persist.Local
import Vervis.Actor2 ()
import Vervis.Data.Actor import Vervis.Data.Actor
import Vervis.FedURI import Vervis.FedURI
import Vervis.Foundation import Vervis.Foundation
@ -62,6 +67,8 @@ import Vervis.Model
import Vervis.Recipient import Vervis.Recipient
import Vervis.Settings import Vervis.Settings
import qualified Vervis.Actor as VA
getLocalActor getLocalActor
:: MonadIO m => ActorId -> ReaderT SqlBackend m (LocalActorBy Key) :: MonadIO m => ActorId -> ReaderT SqlBackend m (LocalActorBy Key)
getLocalActor = fmap (bmap entityKey) . getLocalActorEnt getLocalActor = fmap (bmap entityKey) . getLocalActorEnt
@ -154,6 +161,23 @@ updateOutboxItem actorByKey itemID action = do
update itemID [OutboxItemActivity =. persistJSONObjectFromDoc doc] update itemID [OutboxItemActivity =. persistJSONObjectFromDoc doc]
return luId return luId
updateOutboxItem'
:: WA.StageRoute VA.Env ~ Route App
=> LocalActorBy Key
-> OutboxItemId
-> AP.Action URIMode
-> VA.ActDB LocalURI
updateOutboxItem' actorByKey itemID action = do
encodeRouteLocal <- WA.getEncodeRouteLocal
hLocal <- asksEnv WA.stageInstanceHost
actorByHash <- VA.hashLocalActor actorByKey
itemHash <- WAP.encodeKeyHashid itemID
let luId = encodeRouteLocal $ activityRoute actorByHash itemHash
luActor = encodeRouteLocal $ renderLocalActor actorByHash
doc = AP.Doc hLocal $ AP.makeActivity luId luActor action
update itemID [OutboxItemActivity =. persistJSONObjectFromDoc doc]
return luId
fillPerActorKeys :: Worker () fillPerActorKeys :: Worker ()
fillPerActorKeys = do fillPerActorKeys = do
perActor <- asksSite $ appPerActorKeys . appSettings perActor <- asksSite $ appPerActorKeys . appSettings