mirror of
https://code.sup39.dev/repos/Wqawg
synced 2024-12-28 22:24:51 +09:00
Support for instance-scope keys when verifying HTTP signature
This commit is contained in:
parent
400245cf34
commit
8166d5b5eb
5 changed files with 178 additions and 70 deletions
|
@ -41,17 +41,24 @@ Person
|
||||||
|
|
||||||
VerifKey
|
VerifKey
|
||||||
ident URI
|
ident URI
|
||||||
|
instance InstanceId
|
||||||
expires UTCTime Maybe
|
expires UTCTime Maybe
|
||||||
public PublicKey
|
public PublicKey
|
||||||
sharer RemoteSharerId
|
sharer RemoteSharerId Maybe
|
||||||
|
|
||||||
UniqueVerifKey ident
|
UniqueVerifKey ident
|
||||||
|
|
||||||
RemoteSharer
|
RemoteSharer
|
||||||
ident URI
|
ident URI
|
||||||
|
instance InstanceId
|
||||||
|
|
||||||
UniqueRemoteSharer ident
|
UniqueRemoteSharer ident
|
||||||
|
|
||||||
|
Instance
|
||||||
|
host Text
|
||||||
|
|
||||||
|
UniqueInstance host
|
||||||
|
|
||||||
SshKey
|
SshKey
|
||||||
ident KyIdent
|
ident KyIdent
|
||||||
person PersonId
|
person PersonId
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
VerifKey
|
VerifKey
|
||||||
ident String
|
ident String
|
||||||
|
instance InstanceId
|
||||||
expires UTCTime Maybe
|
expires UTCTime Maybe
|
||||||
public ByteString
|
public ByteString
|
||||||
sharer RemoteSharerId
|
sharer RemoteSharerId Maybe
|
||||||
|
|
||||||
UniqueVerifKey ident
|
UniqueVerifKey ident
|
||||||
|
|
||||||
RemoteSharer
|
RemoteSharer
|
||||||
ident String
|
ident String
|
||||||
|
instance InstanceId
|
||||||
|
|
||||||
UniqueRemoteSharer ident
|
UniqueRemoteSharer ident
|
||||||
|
|
||||||
|
Instance
|
||||||
|
host Text
|
||||||
|
|
||||||
|
UniqueInstance host
|
||||||
|
|
|
@ -18,6 +18,7 @@ module Data.Aeson.Local
|
||||||
, toEither
|
, toEither
|
||||||
, fromEither
|
, fromEither
|
||||||
, frg
|
, frg
|
||||||
|
, parseHttpsURI'
|
||||||
, parseHttpsURI
|
, parseHttpsURI
|
||||||
, renderURI
|
, renderURI
|
||||||
, (.=?)
|
, (.=?)
|
||||||
|
@ -29,7 +30,6 @@ import Prelude
|
||||||
import Control.Applicative ((<|>))
|
import Control.Applicative ((<|>))
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Data.Aeson.Types (Parser)
|
import Data.Aeson.Types (Parser)
|
||||||
import Data.Maybe (isJust)
|
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import Network.URI
|
import Network.URI
|
||||||
|
|
||||||
|
@ -56,16 +56,22 @@ fromEither (Right y) = Right' y
|
||||||
frg :: Text
|
frg :: Text
|
||||||
frg = "https://forgefed.angeley.es/ns#"
|
frg = "https://forgefed.angeley.es/ns#"
|
||||||
|
|
||||||
parseHttpsURI :: Text -> Parser URI
|
parseHttpsURI' :: Text -> Either String URI
|
||||||
parseHttpsURI t =
|
parseHttpsURI' t =
|
||||||
case parseURI $ T.unpack t of
|
case parseURI $ T.unpack t of
|
||||||
Nothing -> fail "Invalid absolute URI"
|
Nothing -> Left "Invalid absolute URI"
|
||||||
Just u ->
|
Just u ->
|
||||||
if uriScheme u == "https:"
|
if uriScheme u == "https:"
|
||||||
then if isJust $ uriAuthority u
|
then case uriAuthority u of
|
||||||
then return u
|
Just a ->
|
||||||
else fail "URI has empty authority"
|
if uriUserInfo a == "" && uriPort a == ""
|
||||||
else fail "URI scheme isn't https"
|
then Right u
|
||||||
|
else Left "URI has userinfo or port"
|
||||||
|
Nothing -> Left "URI has empty authority"
|
||||||
|
else Left "URI scheme isn't https"
|
||||||
|
|
||||||
|
parseHttpsURI :: Text -> Parser URI
|
||||||
|
parseHttpsURI = either fail return . parseHttpsURI'
|
||||||
|
|
||||||
renderURI :: URI -> String
|
renderURI :: URI -> String
|
||||||
renderURI u = uriToString id u ""
|
renderURI u = uriToString id u ""
|
||||||
|
|
|
@ -22,7 +22,9 @@ import Control.Monad.Trans.Except
|
||||||
import Control.Monad.Trans.Maybe
|
import Control.Monad.Trans.Maybe
|
||||||
import Crypto.Error (CryptoFailable (..))
|
import Crypto.Error (CryptoFailable (..))
|
||||||
import Crypto.PubKey.Ed25519 (publicKey, signature, verify)
|
import Crypto.PubKey.Ed25519 (publicKey, signature, verify)
|
||||||
|
import Data.Maybe (fromJust)
|
||||||
import Data.PEM (pemContent)
|
import Data.PEM (pemContent)
|
||||||
|
import Data.Text.Encoding (decodeUtf8')
|
||||||
import Data.Time.Interval (TimeInterval, fromTimeUnit, toTimeUnit)
|
import Data.Time.Interval (TimeInterval, fromTimeUnit, toTimeUnit)
|
||||||
import Data.Time.Units (Second, Minute, Day)
|
import Data.Time.Units (Second, Minute, Day)
|
||||||
import Database.Persist.Sql (ConnectionPool, runSqlPool)
|
import Database.Persist.Sql (ConnectionPool, runSqlPool)
|
||||||
|
@ -30,7 +32,7 @@ import Graphics.SVGFonts.ReadFont (PreparedFont)
|
||||||
import Network.HTTP.Client (Manager, HttpException, requestFromURI, responseBody)
|
import Network.HTTP.Client (Manager, HttpException, requestFromURI, responseBody)
|
||||||
import Network.HTTP.Simple (httpJSONEither, setRequestManager, addRequestHeader)
|
import Network.HTTP.Simple (httpJSONEither, setRequestManager, addRequestHeader)
|
||||||
import Network.HTTP.Types.Header (hHost)
|
import Network.HTTP.Types.Header (hHost)
|
||||||
import Network.URI (URI (uriFragment), parseURI)
|
import Network.URI (URI, uriAuthority, uriFragment, uriRegName, parseURI)
|
||||||
import Text.Shakespeare.Text (textFile)
|
import Text.Shakespeare.Text (textFile)
|
||||||
import Text.Hamlet (hamletFile)
|
import Text.Hamlet (hamletFile)
|
||||||
--import Text.Jasmine (minifym)
|
--import Text.Jasmine (minifym)
|
||||||
|
@ -57,6 +59,7 @@ import qualified Network.HTTP.Signature as S (Algorithm (..))
|
||||||
|
|
||||||
import Web.ActivityPub
|
import Web.ActivityPub
|
||||||
|
|
||||||
|
import Data.Aeson.Local (parseHttpsURI')
|
||||||
import Text.Email.Local
|
import Text.Email.Local
|
||||||
import Text.Jasmine.Local (discardm)
|
import Text.Jasmine.Local (discardm)
|
||||||
|
|
||||||
|
@ -560,7 +563,7 @@ unsafeHandler = Unsafe.fakeHandlerGetLogger appLogger
|
||||||
|
|
||||||
instance YesodHttpSig App where
|
instance YesodHttpSig App where
|
||||||
data HttpSigVerResult App = HttpSigVerResult (Either String URI)
|
data HttpSigVerResult App = HttpSigVerResult (Either String URI)
|
||||||
httpSigVerHeaders = const [hRequestTarget, hHost]
|
httpSigVerHeaders = const [hRequestTarget, hHost, "ActivityPub-Actor"]
|
||||||
httpSigVerSeconds =
|
httpSigVerSeconds =
|
||||||
fromIntegral . toSeconds . appHttpSigTimeLimit . appSettings
|
fromIntegral . toSeconds . appHttpSigTimeLimit . appSettings
|
||||||
where
|
where
|
||||||
|
@ -580,23 +583,41 @@ instance YesodHttpSig App where
|
||||||
case signature sig of
|
case signature sig of
|
||||||
CryptoPassed s -> Right s
|
CryptoPassed s -> Right s
|
||||||
CryptoFailed e -> Left "Parsing Ed25519 signature failed"
|
CryptoFailed e -> Left "Parsing Ed25519 signature failed"
|
||||||
(mvkid, key, mexpires, uActor) <- do
|
muActorHeader <- do
|
||||||
|
bs <- lookupHeaders "ActivityPub-Actor"
|
||||||
|
case bs of
|
||||||
|
[] -> return Nothing
|
||||||
|
[b] -> fmap Just . ExceptT . pure $ do
|
||||||
|
t <- first displayException $ decodeUtf8' b
|
||||||
|
parseHttpsURI' t
|
||||||
|
_ -> throwE "Multiple ActivityPub-Actor headers"
|
||||||
|
(mvkid, key, mexpires, uActor, host, shared) <- do
|
||||||
ments <- lift $ runDB $ do
|
ments <- lift $ runDB $ do
|
||||||
mvk <- getBy $ UniqueVerifKey u
|
mvk <- getBy $ UniqueVerifKey u
|
||||||
for mvk $ \ vk@(Entity _ verifkey) -> do
|
for mvk $ \ vk@(Entity _ verifkey) -> do
|
||||||
remote <- getJust $ verifKeySharer verifkey
|
mremote <- traverse getJust $ verifKeySharer verifkey
|
||||||
return (vk, remote)
|
return (vk, mremote)
|
||||||
case ments of
|
case ments of
|
||||||
Just (Entity vkid vk, remote) ->
|
Just (Entity vkid vk, mremote) -> do
|
||||||
|
(ua, s) <-
|
||||||
|
case mremote of
|
||||||
|
Just remote -> return (remoteSharerIdent remote, False)
|
||||||
|
Nothing ->
|
||||||
|
case muActorHeader of
|
||||||
|
Nothing -> throwE "Got a sig with an instance key, but actor header not specified!"
|
||||||
|
Just u -> return (u, True)
|
||||||
|
let uKey = verifKeyIdent vk
|
||||||
return
|
return
|
||||||
( Just vkid
|
( Just vkid
|
||||||
, verifKeyPublic vk
|
, verifKeyPublic vk
|
||||||
, verifKeyExpires vk
|
, verifKeyExpires vk
|
||||||
, remoteSharerIdent remote
|
, ua
|
||||||
|
, T.pack $ uriRegName $ fromJust $ uriAuthority uKey
|
||||||
|
, s
|
||||||
)
|
)
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
(k, mexp, ua) <- fetchKey' u
|
Fetched k mexp ua h s <- fetchKey' muActorHeader u
|
||||||
return (Nothing, k, mexp, ua)
|
return (Nothing, k, mexp, ua, h, s)
|
||||||
let verify' k = verify k input signature
|
let verify' k = verify k input signature
|
||||||
errSig = throwE "Ed25519 sig verification says not valid"
|
errSig = throwE "Ed25519 sig verification says not valid"
|
||||||
errTime = throwE "Key expired"
|
errTime = throwE "Key expired"
|
||||||
|
@ -609,8 +630,15 @@ instance YesodHttpSig App where
|
||||||
then return (not existsInDB, key, mexpires)
|
then return (not existsInDB, key, mexpires)
|
||||||
else if existsInDB
|
else if existsInDB
|
||||||
then do
|
then do
|
||||||
(newKey, newExp, newActor) <- fetchKey' u
|
Fetched newKey newExp newActor h s <- fetchKey' muActorHeader u
|
||||||
if newActor == uActor
|
if shared == s
|
||||||
|
then return ()
|
||||||
|
else throwE "Key scope changed, we reject that"
|
||||||
|
if shared
|
||||||
|
then if h == host
|
||||||
|
then return ()
|
||||||
|
else fail "BUG! We re-fetched a key and the host changed"
|
||||||
|
else if newActor == uActor
|
||||||
then return ()
|
then return ()
|
||||||
else throwE "Key owner changed, we reject that"
|
else throwE "Key owner changed, we reject that"
|
||||||
if stillValid newExp
|
if stillValid newExp
|
||||||
|
@ -624,18 +652,40 @@ instance YesodHttpSig App where
|
||||||
else errTime
|
else errTime
|
||||||
when write $ ExceptT $ runDB $
|
when write $ ExceptT $ runDB $
|
||||||
case mvkid of
|
case mvkid of
|
||||||
|
Nothing ->
|
||||||
|
if shared
|
||||||
|
then do
|
||||||
|
ment <- getBy $ UniqueInstance host
|
||||||
|
case ment of
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
|
iid <- insert $ Instance host
|
||||||
|
insert_ $ VerifKey u iid mexpires' key' Nothing
|
||||||
|
return $ Right ()
|
||||||
|
Just (Entity iid _) -> do
|
||||||
|
n <- count [VerifKeyInstance ==. iid, VerifKeySharer ==. Nothing]
|
||||||
|
if n < 2
|
||||||
|
then do
|
||||||
|
insert_ $ VerifKey u iid mexpires' key' Nothing
|
||||||
|
return $ Right ()
|
||||||
|
else return $ Left "We already store 2 keys"
|
||||||
|
else do
|
||||||
ment <- getBy $ UniqueRemoteSharer uActor
|
ment <- getBy $ UniqueRemoteSharer uActor
|
||||||
case ment of
|
case ment of
|
||||||
Nothing -> do
|
Nothing -> do
|
||||||
rsid <- insert $ RemoteSharer uActor
|
iid <- do
|
||||||
insert_ $ VerifKey u mexpires' key' rsid
|
ment2 <- getBy $ UniqueInstance host
|
||||||
|
case ment2 of
|
||||||
|
Nothing -> insert $ Instance host
|
||||||
|
Just (Entity i _) -> return i
|
||||||
|
rsid <- insert $ RemoteSharer uActor iid
|
||||||
|
insert_ $ VerifKey u iid mexpires' key' (Just rsid)
|
||||||
return $ Right ()
|
return $ Right ()
|
||||||
Just (Entity rsid rs) -> do
|
Just (Entity rsid rs) -> do
|
||||||
n <- count [VerifKeySharer ==. rsid]
|
n <- count [VerifKeySharer ==. Just rsid]
|
||||||
if n < 2
|
if n < 2
|
||||||
then do
|
then do
|
||||||
insert_ $ VerifKey u mexpires' key' rsid
|
let iid = remoteSharerInstance rs
|
||||||
|
insert_ $ VerifKey u iid mexpires' key' (Just rsid)
|
||||||
return $ Right ()
|
return $ Right ()
|
||||||
else return $ Left "We already store 2 keys"
|
else return $ Left "We already store 2 keys"
|
||||||
Just vkid -> do
|
Just vkid -> do
|
||||||
|
@ -644,9 +694,9 @@ instance YesodHttpSig App where
|
||||||
return $ Right ()
|
return $ Right ()
|
||||||
return uActor
|
return uActor
|
||||||
where
|
where
|
||||||
fetchKey' u = do
|
fetchKey' mua uk = do
|
||||||
manager <- getsYesod appHttpManager
|
manager <- getsYesod appHttpManager
|
||||||
ExceptT $ fetchKey manager (isJust malgo) u
|
ExceptT $ fetchKey manager (isJust malgo) mua uk
|
||||||
|
|
||||||
instance YesodBreadcrumbs App where
|
instance YesodBreadcrumbs App where
|
||||||
breadcrumb route = return $ case route of
|
breadcrumb route = return $ case route of
|
||||||
|
|
|
@ -36,6 +36,7 @@ module Web.ActivityPub
|
||||||
, APGetError (..)
|
, APGetError (..)
|
||||||
, httpGetAP
|
, httpGetAP
|
||||||
, httpPostAP
|
, httpPostAP
|
||||||
|
, Fetched (..)
|
||||||
, fetchKey
|
, fetchKey
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
|
@ -72,7 +73,7 @@ import Yesod.Core.Handler (ProvidedRep, provideRepType)
|
||||||
|
|
||||||
import qualified Crypto.PubKey.Ed25519 as E (PublicKey, publicKey)
|
import qualified Crypto.PubKey.Ed25519 as E (PublicKey, publicKey)
|
||||||
import qualified Data.HashMap.Strict as M (lookup)
|
import qualified Data.HashMap.Strict as M (lookup)
|
||||||
import qualified Data.Text as T (unpack)
|
import qualified Data.Text as T (pack, unpack)
|
||||||
import qualified Data.Vector as V (fromList, toList)
|
import qualified Data.Vector as V (fromList, toList)
|
||||||
|
|
||||||
import Data.Aeson.Local
|
import Data.Aeson.Local
|
||||||
|
@ -361,57 +362,88 @@ httpPostAP manager uri headers sign value =
|
||||||
where
|
where
|
||||||
consHeader n b r = r { requestHeaders = (n, b) : requestHeaders r }
|
consHeader n b r = r { requestHeaders = (n, b) : requestHeaders r }
|
||||||
|
|
||||||
|
-- | Result of GETing the keyId URI and processing the JSON document.
|
||||||
|
data Fetched = Fetched
|
||||||
|
{ fetchedPublicKey :: E.PublicKey
|
||||||
|
-- ^ The Ed25519 public key corresponding to the URI we requested.
|
||||||
|
, fetchedKeyExpires :: Maybe UTCTime
|
||||||
|
-- ^ Optional expiration time declared for the key we received.
|
||||||
|
, fetchedActorId :: URI
|
||||||
|
-- ^ The @id URI of the actor for whom the key's signature applies.
|
||||||
|
, fetchedHost :: Text
|
||||||
|
-- ^ The domain name of the instance from which we got the key.
|
||||||
|
, fetchedKeyShared :: Bool
|
||||||
|
-- ^ Whether the key we received is shared. A shared key can sign
|
||||||
|
-- requests for any actor on the same instance, while a personal key is
|
||||||
|
-- only for one actor. Knowing whether the key is shared will allow us
|
||||||
|
-- when receiving more requests, whether to accept signatures made on
|
||||||
|
-- different actors, or allow only a single permanent actor for the key
|
||||||
|
-- we received.
|
||||||
|
}
|
||||||
|
|
||||||
fetchKey
|
fetchKey
|
||||||
:: MonadIO m
|
:: MonadIO m
|
||||||
=> Manager
|
=> Manager
|
||||||
-> Bool
|
-> Bool
|
||||||
|
-> Maybe URI
|
||||||
-> URI
|
-> URI
|
||||||
-> m (Either String (E.PublicKey, Maybe UTCTime, URI))
|
-> m (Either String Fetched)
|
||||||
fetchKey manager sigAlgo u = runExceptT $ do
|
fetchKey manager sigAlgo muActor uKey = runExceptT $ do
|
||||||
let fetch :: (MonadIO m, FromJSON a) => URI -> ExceptT String m a
|
let fetch :: (MonadIO m, FromJSON a) => URI -> ExceptT String m a
|
||||||
fetch u = ExceptT $ bimap displayException responseBody <$> httpGetAP manager u
|
fetch u = ExceptT $ bimap displayException responseBody <$> httpGetAP manager u
|
||||||
obj <- fetch u
|
obj <- fetch uKey
|
||||||
(actor, pkey, separate) <-
|
let inztance = uKey { uriPath = "", uriQuery = "", uriFragment = "" }
|
||||||
case obj of
|
authority =
|
||||||
Left' pkey -> do
|
case uriAuthority uKey of
|
||||||
if publicKeyId pkey == u
|
|
||||||
then return ()
|
|
||||||
else throwE "Public key's ID doesn't match the keyid URI"
|
|
||||||
let authority =
|
|
||||||
case uriAuthority u of
|
|
||||||
Nothing -> error "BUG! We were supposed to verify URI authority is non-empty!"
|
Nothing -> error "BUG! We were supposed to verify URI authority is non-empty!"
|
||||||
Just a -> a
|
Just a -> a
|
||||||
|
(actor, pkey, shared) <-
|
||||||
|
case obj of
|
||||||
|
Left' pkey -> do
|
||||||
|
if publicKeyId pkey == uKey
|
||||||
|
then return ()
|
||||||
|
else throwE "Public key's ID doesn't match the keyid URI"
|
||||||
if uriAuthority (publicKeyOwner pkey) == Just authority
|
if uriAuthority (publicKeyOwner pkey) == Just authority
|
||||||
then return ()
|
then return ()
|
||||||
else throwE "Actor and key on different domains, we reject"
|
else throwE "Actor and key on different domains, we reject"
|
||||||
actor <- fetch $ publicKeyOwner pkey
|
uActor <-
|
||||||
|
if publicKeyShared pkey
|
||||||
|
then case muActor of
|
||||||
|
Nothing -> throwE "Key is shared but actor header not specified!"
|
||||||
|
Just u -> return u
|
||||||
|
else return $ publicKeyOwner pkey
|
||||||
|
actor <- fetch uActor
|
||||||
let PublicKeySet k1 mk2 = actorPublicKeys actor
|
let PublicKeySet k1 mk2 = actorPublicKeys actor
|
||||||
match (Left uri) = uri == u
|
match (Left uri) = uri == uKey
|
||||||
match (Right _) = False
|
match (Right _) = False
|
||||||
if match k1 || maybe False match mk2
|
if match k1 || maybe False match mk2
|
||||||
then return (actor, pkey, True)
|
then return (actor, pkey, publicKeyShared pkey)
|
||||||
else throwE "Actor publicKey has no URI matching pkey @id"
|
else throwE "Actor publicKey has no URI matching pkey @id"
|
||||||
Right' actor -> do
|
Right' actor -> do
|
||||||
if actorId actor == u { uriFragment = "" }
|
if actorId actor == uKey { uriFragment = "" }
|
||||||
then return ()
|
then return ()
|
||||||
else throwE "Actor ID doesn't match the keyid URI we fetched"
|
else throwE "Actor ID doesn't match the keyid URI we fetched"
|
||||||
|
case muActor of
|
||||||
|
Nothing -> return ()
|
||||||
|
Just u ->
|
||||||
|
if actorId actor == u
|
||||||
|
then return ()
|
||||||
|
else throwE "Key's owner doesn't match actor header"
|
||||||
let PublicKeySet k1 mk2 = actorPublicKeys actor
|
let PublicKeySet k1 mk2 = actorPublicKeys actor
|
||||||
match (Left _) = Nothing
|
match (Left _) = Nothing
|
||||||
match (Right pk) =
|
match (Right pk) =
|
||||||
if publicKeyId pk == u
|
if publicKeyId pk == uKey
|
||||||
then Just pk
|
then Just pk
|
||||||
else Nothing
|
else Nothing
|
||||||
case match k1 <|> (match =<< mk2) of
|
case match k1 <|> (match =<< mk2) of
|
||||||
Nothing -> throwE "keyId resolved to actor which doesn't have a key object with that ID"
|
Nothing -> throwE "keyId resolved to actor which doesn't have a key object with that ID"
|
||||||
Just pk -> return (actor, pk, False)
|
Just pk ->
|
||||||
|
if publicKeyShared pk
|
||||||
|
then throwE "Actor's publicKey is shared, but embedded in actor document! We allow shared keys only if they're in a separate document"
|
||||||
|
else return (actor, pk, False)
|
||||||
ExceptT . pure $ do
|
ExceptT . pure $ do
|
||||||
if publicKeyShared pkey
|
if shared
|
||||||
then do
|
then if publicKeyOwner pkey == inztance
|
||||||
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 ()
|
then Right ()
|
||||||
else Left "Key is shared but its owner isn't the top-level instance URI"
|
else Left "Key is shared but its owner isn't the top-level instance URI"
|
||||||
else if publicKeyOwner pkey == actorId actor
|
else if publicKeyOwner pkey == actorId actor
|
||||||
|
@ -432,5 +464,11 @@ fetchKey manager sigAlgo u = runExceptT $ do
|
||||||
then "Algo mismatch, Ed25519 in Sig but unsupported algo in actor"
|
then "Algo mismatch, Ed25519 in Sig but unsupported algo in actor"
|
||||||
else "No algo in Sig, unsupported algo in actor"
|
else "No algo in Sig, unsupported algo in actor"
|
||||||
case E.publicKey $ pemContent $ publicKeyPem pkey of
|
case E.publicKey $ pemContent $ publicKeyPem pkey of
|
||||||
CryptoPassed k -> Right (k, publicKeyExpires pkey, actorId actor)
|
CryptoPassed k -> Right Fetched
|
||||||
CryptoFailed e -> Left "Parsing Ed25519 public key failed"
|
{ fetchedPublicKey = k
|
||||||
|
, fetchedKeyExpires = publicKeyExpires pkey
|
||||||
|
, fetchedActorId = actorId actor
|
||||||
|
, fetchedHost = T.pack $ uriRegName authority
|
||||||
|
, fetchedKeyShared = shared
|
||||||
|
}
|
||||||
|
CryptoFailed _ -> Left "Parsing Ed25519 public key failed"
|
||||||
|
|
Loading…
Reference in a new issue