mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-21 06:21:39 +03:00
b167120f96
We'll see if this improves compile times at all, but I think it's worth doing as at least the most minimal form of module documentation. This was accomplished by first compiling everything with -ddump-minimal-imports, and then a bunch of scripting (with help from ormolu) **EDIT** it doesn't seem to improve CI compile times but the noise floor is high as it looks like we're not caching library dependencies anymore PR-URL: https://github.com/hasura/graphql-engine-mono/pull/2730 GitOrigin-RevId: 667eb8de1e0f1af70420cbec90402922b8b84cb4
121 lines
3.8 KiB
Haskell
121 lines
3.8 KiB
Haskell
module Hasura.Server.Auth.JWT.Internal
|
|
( parseEdDSAKey,
|
|
parseHmacKey,
|
|
parseRsaKey,
|
|
)
|
|
where
|
|
|
|
import Control.Lens
|
|
import Crypto.JOSE.Types (Base64Integer (..))
|
|
import Crypto.JWT
|
|
import Crypto.PubKey.RSA (PublicKey (..))
|
|
import Data.ASN1.BinaryEncoding (DER (..))
|
|
import Data.ASN1.Encoding (decodeASN1')
|
|
import Data.ASN1.Types
|
|
( ASN1 (End, IntVal, Start),
|
|
ASN1ConstructionType (Sequence),
|
|
fromASN1,
|
|
)
|
|
import Data.ByteString.Lazy qualified as BL
|
|
import Data.Int (Int64)
|
|
import Data.PEM qualified as PEM
|
|
import Data.Text qualified as T
|
|
import Data.Text.Conversions
|
|
import Data.X509 qualified as X509
|
|
import Hasura.Prelude
|
|
import Hasura.Server.Utils (fmapL)
|
|
|
|
-- | Helper functions to decode Text to JWK
|
|
parseHmacKey :: Text -> Int64 -> Either Text JWK
|
|
parseHmacKey key size = do
|
|
let secret = unUTF8 $ fromText key
|
|
err s = "Key size too small; should be atleast " <> show (s `div` 8) <> " characters"
|
|
if BL.length secret < size `div` 8
|
|
then Left . T.pack $ err size
|
|
else pure $ fromOctets secret
|
|
|
|
parseRsaKey :: Text -> Either Text JWK
|
|
parseRsaKey key = do
|
|
let res = fromRawPem (unUTF8 $ fromText key)
|
|
err e = "Could not decode PEM: " <> e
|
|
onLeft res (Left . err)
|
|
|
|
parseEdDSAKey :: Text -> Either Text JWK
|
|
parseEdDSAKey key = do
|
|
let res = fromRawPem (unUTF8 $ fromText key)
|
|
err e = "Could not decode PEM: " <> e
|
|
onLeft res (Left . err)
|
|
|
|
-- | Helper functions to decode PEM bytestring to RSA public key
|
|
|
|
-- try PKCS first, then x509
|
|
fromRawPem :: BL.ByteString -> Either Text JWK
|
|
fromRawPem bs =
|
|
-- pubKeyToJwk <=< fromPkcsPem
|
|
case fromPkcsPem bs of
|
|
Right pk -> pubKeyToJwk pk
|
|
Left e ->
|
|
case fromX509Pem bs of
|
|
Right pk1 -> pubKeyToJwk pk1
|
|
Left e1 -> Left (e <> " " <> e1)
|
|
|
|
-- decode a PKCS1 or PKCS8 PEM to obtain the public key
|
|
fromPkcsPem :: BL.ByteString -> Either Text X509.PubKey
|
|
fromPkcsPem bs = do
|
|
pems <- fmapL T.pack $ PEM.pemParseLBS bs
|
|
pem <- getAtleastOne "No pem found" pems
|
|
res <- fmapL tshow $ decodeASN1' DER $ PEM.pemContent pem
|
|
case res of
|
|
-- PKCS#1 format
|
|
[Start Sequence, IntVal n, IntVal e, End Sequence] ->
|
|
return $ X509.PubKeyRSA $ PublicKey (calculateSize n) n e
|
|
-- try and see if its a PKCS#8 format
|
|
asn1 -> do
|
|
(pub, xs) <- fmapL T.pack $ fromASN1 asn1
|
|
unless (null xs) (Left "Could not decode public key")
|
|
return pub
|
|
|
|
-- decode a x509 certificate containing the RSA public key or EdDSA (ed25519) public key
|
|
fromX509Pem :: BL.ByteString -> Either Text X509.PubKey
|
|
fromX509Pem s = do
|
|
-- try to parse bytestring to a [PEM]
|
|
pems <- fmapL T.pack $ PEM.pemParseLBS s
|
|
-- fail if [PEM] is empty
|
|
pem <- getAtleastOne "No pem found" pems
|
|
-- decode the bytestring to a certificate
|
|
signedExactCert <-
|
|
fmapL T.pack $
|
|
X509.decodeSignedCertificate $
|
|
PEM.pemContent pem
|
|
let cert = X509.signedObject $ X509.getSigned signedExactCert
|
|
pubKey = X509.certPubKey cert
|
|
case pubKey of
|
|
X509.PubKeyRSA pk -> return $ X509.PubKeyRSA pk
|
|
X509.PubKeyEd25519 pk -> return $ X509.PubKeyEd25519 pk
|
|
_ -> Left "Could not decode RSA or EdDSA public key from x509 cert"
|
|
|
|
pubKeyToJwk :: X509.PubKey -> Either Text JWK
|
|
pubKeyToJwk pubKey = do
|
|
jwk' <- mkJwk
|
|
return $ jwk' & jwkKeyOps .~ Just [Verify]
|
|
where
|
|
mkJwk = case pubKey of
|
|
X509.PubKeyRSA (PublicKey _ n e) ->
|
|
return $ fromKeyMaterial $ RSAKeyMaterial (rsaKeyParams n e)
|
|
X509.PubKeyEd25519 pubKeyEd ->
|
|
return $ fromKeyMaterial $ OKPKeyMaterial (Ed25519Key pubKeyEd Nothing)
|
|
_ -> Left "This key type is not supported"
|
|
rsaKeyParams n e =
|
|
RSAKeyParameters (Base64Integer n) (Base64Integer e) Nothing
|
|
|
|
getAtleastOne :: Text -> [a] -> Either Text a
|
|
getAtleastOne err [] = Left err
|
|
getAtleastOne _ (x : _) = Right x
|
|
|
|
calculateSize :: Integer -> Int
|
|
calculateSize = go 1
|
|
where
|
|
go i n
|
|
| 2 ^ (i * 8) > n = i
|
|
| otherwise = go (i + 1) n
|