diff --git a/src/Web/ActivityPub.hs b/src/Web/ActivityPub.hs index dbc6234..75a122d 100644 --- a/src/Web/ActivityPub.hs +++ b/src/Web/ActivityPub.hs @@ -371,13 +371,17 @@ fetchKey manager sigAlgo u = runExceptT $ do let fetch :: (MonadIO m, FromJSON a) => URI -> ExceptT String m a fetch u = ExceptT $ bimap displayException responseBody <$> httpGetAP manager u obj <- fetch u - (actor, pkey) <- + (actor, pkey, separate) <- case obj of Left' pkey -> do if publicKeyId pkey == u then return () else throwE "Public key's ID doesn't match the keyid URI" - if uriAuthority (publicKeyOwner pkey) == uriAuthority u + let authority = + case uriAuthority u of + Nothing -> error "BUG! We were supposed to verify URI authority is non-empty!" + Just a -> a + if uriAuthority (publicKeyOwner pkey) == Just authority then return () else throwE "Actor and key on different domains, we reject" actor <- fetch $ publicKeyOwner pkey @@ -385,7 +389,7 @@ fetchKey manager sigAlgo u = runExceptT $ do match (Left uri) = uri == u match (Right _) = False if match k1 || maybe False match mk2 - then return (actor, pkey) + then return (actor, pkey, True) else throwE "Actor publicKey has no URI matching pkey @id" Right' actor -> do if actorId actor == u { uriFragment = "" } @@ -399,14 +403,20 @@ fetchKey manager sigAlgo u = runExceptT $ do else Nothing case match k1 <|> (match =<< mk2) of Nothing -> throwE "keyId resolved to actor which doesn't have a key object with that ID" - Just pk -> return (actor, pk) + Just pk -> return (actor, pk, False) ExceptT . pure $ do if publicKeyShared pkey - then Left "Actor's publicKey is shared, we're rejecting it!" - else Right () - if publicKeyOwner pkey == actorId actor - then Right () - else Left "Actor's publicKey's owner doesn't match the actor's ID" + then do + if separate + then Right () + else Left "Actor's publicKey is shared, but embedded in actor document! We allow shared keys only if they're in a separate document" + let inztance = u { uriPath = "", uriQuery = "", uriFragment = "" } + if publicKeyOwner pkey == inztance + then Right () + else Left "Key is shared but its owner isn't the top-level instance URI" + else if publicKeyOwner pkey == actorId actor + then Right () + else Left "Actor's publicKey's owner doesn't match the actor's ID" case publicKeyAlgo pkey of Nothing -> Left $