module System.X509.MacOS (
    getSystemCertificateStore,
) where

import Control.Applicative
import qualified Data.ByteString.Lazy as LBS
import Data.Either
import Data.PEM (PEM (..), pemParseLBS)
import System.Process

import Data.X509
import Data.X509.CertificateStore
import System.X509.Common (maybeSSLCertEnvOr)

rootCAKeyChain :: FilePath
rootCAKeyChain :: FilePath
rootCAKeyChain = FilePath
"/System/Library/Keychains/SystemRootCertificates.keychain"

systemKeyChain :: FilePath
systemKeyChain :: FilePath
systemKeyChain = FilePath
"/Library/Keychains/System.keychain"

listInKeyChains :: [FilePath] -> IO [SignedCertificate]
listInKeyChains :: [FilePath] -> IO [SignedCertificate]
listInKeyChains [FilePath]
keyChains = do
    (_, Just hout, _, ph) <-
        CreateProcess
-> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
createProcess
            (FilePath -> [FilePath] -> CreateProcess
proc FilePath
"security" (FilePath
"find-certificate" FilePath -> [FilePath] -> [FilePath]
forall a. a -> [a] -> [a]
: FilePath
"-pa" FilePath -> [FilePath] -> [FilePath]
forall a. a -> [a] -> [a]
: [FilePath]
keyChains))
                { std_out = CreatePipe
                }
    pems <- either error id . pemParseLBS <$> LBS.hGetContents hout
    let targets =
            [Either FilePath SignedCertificate] -> [SignedCertificate]
forall a b. [Either a b] -> [b]
rights ([Either FilePath SignedCertificate] -> [SignedCertificate])
-> [Either FilePath SignedCertificate] -> [SignedCertificate]
forall a b. (a -> b) -> a -> b
$
                (PEM -> Either FilePath SignedCertificate)
-> [PEM] -> [Either FilePath SignedCertificate]
forall a b. (a -> b) -> [a] -> [b]
map (ByteString -> Either FilePath SignedCertificate
decodeSignedCertificate (ByteString -> Either FilePath SignedCertificate)
-> (PEM -> ByteString) -> PEM -> Either FilePath SignedCertificate
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PEM -> ByteString
pemContent) ([PEM] -> [Either FilePath SignedCertificate])
-> [PEM] -> [Either FilePath SignedCertificate]
forall a b. (a -> b) -> a -> b
$
                    (PEM -> Bool) -> [PEM] -> [PEM]
forall a. (a -> Bool) -> [a] -> [a]
filter ((FilePath -> FilePath -> Bool
forall a. Eq a => a -> a -> Bool
== FilePath
"CERTIFICATE") (FilePath -> Bool) -> (PEM -> FilePath) -> PEM -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PEM -> FilePath
pemName) [PEM]
pems
    _ <- targets `seq` waitForProcess ph
    return targets

getSystemCertificateStore :: IO CertificateStore
getSystemCertificateStore :: IO CertificateStore
getSystemCertificateStore =
    IO CertificateStore -> IO CertificateStore
maybeSSLCertEnvOr
        ([SignedCertificate] -> CertificateStore
makeCertificateStore ([SignedCertificate] -> CertificateStore)
-> IO [SignedCertificate] -> IO CertificateStore
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [FilePath] -> IO [SignedCertificate]
listInKeyChains [FilePath
rootCAKeyChain, FilePath
systemKeyChain])