Eventually-decentralized project hosting and management platform
Clone
HTTPS:
darcs clone https://vervis.peers.community/repos/WvWbo
SSH:
darcs clone USERNAME@vervis.peers.community:WvWbo
Tags
TODO
Collab.hs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | {- This file is part of Vervis.
-
- Written in 2022, 2023 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/>.
-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE UndecidableInstances #-}
module Vervis.Data.Collab
( GrantRecipBy (..)
, parseInvite
, parseJoin
, parseGrant
, parseAccept
, grantResourceActorID
)
where
import Control.Monad
import Control.Monad.Trans.Except
import Data.Barbie
import Data.Bifunctor
import Data.Bitraversable
import Data.Functor.Identity
import Data.Text (Text)
import Database.Persist.Types
import GHC.Generics
import Control.Concurrent.Actor
import Network.FedURI
import Web.Actor
import Web.Actor.Persist
import Yesod.ActivityPub
import Yesod.Actor
import Yesod.FedURI
import Yesod.Hashids
import Yesod.MonadSite (asksSite)
import qualified Web.ActivityPub as AP
import Control.Monad.Trans.Except.Local
import Vervis.Access
import Vervis.Actor
import Vervis.Data.Actor
import Vervis.FedURI
import Vervis.Foundation
import Vervis.Model
parseGrantResource (RepoR r) = Just $ GrantResourceRepo r
parseGrantResource (DeckR d) = Just $ GrantResourceDeck d
parseGrantResource (LoomR l) = Just $ GrantResourceLoom l
parseGrantResource _ = Nothing
data GrantRecipBy f = GrantRecipPerson (f Person)
deriving (Generic, FunctorB, TraversableB, ConstraintsB)
deriving instance AllBF Eq f GrantRecipBy => Eq (GrantRecipBy f)
parseGrantRecip (PersonR p) = Just $ GrantRecipPerson p
parseGrantRecip _ = Nothing
unhashGrantRecipPure ctx = f
where
f (GrantRecipPerson p) =
GrantRecipPerson <$> decodeKeyHashidPure ctx p
unhashGrantRecipOld resource = do
ctx <- asksSite siteHashidsContext
return $ unhashGrantRecipPure ctx resource
unhashGrantRecip resource = do
ctx <- asksEnv stageHashidsContext
return $ unhashGrantRecipPure ctx resource
unhashGrantRecipEOld resource e =
ExceptT $ maybe (Left e) Right <$> unhashGrantRecipOld resource
unhashGrantRecipE resource e =
ExceptT $ maybe (Left e) Right <$> unhashGrantRecip resource
verifyRole (Left AP.RoleAdmin) = pure ()
verifyRole (Right _) =
throwE "ForgeFed Admin is the only role allowed currently"
parseTopic u = do
routeOrRemote <- parseFedURIOld u
bitraverse
(\ route -> do
resourceHash <-
fromMaybeE
(parseGrantResource route)
"Not a shared resource route"
unhashGrantResourceE
resourceHash
"Contains invalid hashid"
)
pure
routeOrRemote
parseInvite
:: Either PersonId FedURI
-> AP.Invite URIMode
-> ExceptT Text Handler
( Either (GrantResourceBy Key) FedURI
, Either (GrantRecipBy Key) FedURI
)
parseInvite sender (AP.Invite instrument object target) = do
verifyRole instrument
(,) <$> nameExceptT "Invite target" (parseTopic target)
<*> nameExceptT "Invite object" (parseRecipient object)
where
parseRecipient u = do
routeOrRemote <- parseFedURIOld u
bitraverse
(\ route -> do
recipHash <-
fromMaybeE
(parseGrantRecip route)
"Not a grant recipient route"
recipKey <-
unhashGrantRecipEOld
recipHash
"Contains invalid hashid"
case recipKey of
GrantRecipPerson p | Left p == sender ->
throwE "Invite local sender and recipient are the same Person"
_ -> return recipKey
)
(\ u -> do
when (Right u == sender) $
throwE "Invite remote sender and recipient are the same actor"
return u
)
routeOrRemote
parseJoin
:: AP.Join URIMode
-> ExceptT Text Handler (Either (GrantResourceBy Key) FedURI)
parseJoin (AP.Join instrument object) = do
verifyRole instrument
nameExceptT "Join object" (parseTopic object)
parseGrant
:: AP.Grant URIMode
-> ActE
( Either (GrantResourceBy Key) FedURI
, Either (GrantRecipBy Key) FedURI
)
parseGrant (AP.Grant object context target) = do
verifyRole object
(,) <$> parseContext context
<*> parseTarget target
where
verifyRole (Left AP.RoleAdmin) = pure ()
verifyRole (Right _) =
throwE "ForgeFed Admin is the only role allowed currently"
parseContext u@(ObjURI h lu) = do
hl <- hostIsLocal h
if hl
then Left <$> do
route <-
fromMaybeE
(decodeRouteLocal lu)
"Grant context isn't a valid route"
resourceHash <-
fromMaybeE
(parseGrantResource route)
"Grant context isn't a shared resource route"
unhashGrantResourceE'
resourceHash
"Grant resource contains invalid hashid"
else pure $ Right u
where
parseGrantResource (RepoR r) = Just $ GrantResourceRepo r
parseGrantResource (DeckR d) = Just $ GrantResourceDeck d
parseGrantResource (LoomR l) = Just $ GrantResourceLoom l
parseGrantResource _ = Nothing
parseTarget u@(ObjURI h lu) = do
hl <- hostIsLocal h
if hl
then Left <$> do
route <-
fromMaybeE
(decodeRouteLocal lu)
"Grant target isn't a valid route"
recipHash <-
fromMaybeE
(parseGrantRecip route)
"Grant target isn't a grant recipient route"
unhashGrantRecipE
recipHash
"Grant target contains invalid hashid"
else pure $ Right u
parseAccept (AP.Accept object mresult) = do
verifyNothingE mresult "Accept must not contain 'result'"
first (\ (actor, _, item) -> (actor, item)) <$>
nameExceptT "Accept object" (parseActivityURI object)
grantResourceActorID :: GrantResourceBy Identity -> ActorId
grantResourceActorID (GrantResourceRepo (Identity r)) = repoActor r
grantResourceActorID (GrantResourceDeck (Identity d)) = deckActor d
grantResourceActorID (GrantResourceLoom (Identity l)) = loomActor l
|