module System.Certificate.X509.Unix
( getSystemCertificateStore
) where
import System.Directory (getDirectoryContents, doesFileExist)
import System.Environment (getEnv)
import System.FilePath ((</>))
import Data.List (isPrefixOf)
import Data.PEM (PEM(..), pemParseBS)
import Data.Either
import Data.Certificate.X509
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import Data.CertificateStore
import Control.Applicative ((<$>))
import Control.Monad (filterM)
import qualified Control.Exception as E
import Data.Char
defaultSystemPath :: FilePath
defaultSystemPath = "/etc/ssl/certs/"
envPathOverride :: String
envPathOverride = "SYSTEM_CERTIFICATE_PATH"
listDirectoryCerts :: FilePath -> IO [FilePath]
listDirectoryCerts path = (map (path </>) . filter isCert <$> getDirectoryContents path)
>>= filterM doesFileExist
where isHashedFile s = length s == 10
&& isDigit (s !! 9)
&& (s !! 8) == '.'
&& all isHexDigit (take 8 s)
isCert x = (not $ isPrefixOf "." x) && (not $ isHashedFile x)
getSystemCertificateStore :: IO CertificateStore
getSystemCertificateStore = makeCertificateStore . concat <$> (getSystemPath >>= listDirectoryCerts >>= mapM readCertificates)
getSystemPath :: IO FilePath
getSystemPath = E.catch (getEnv envPathOverride) inDefault
where
inDefault :: E.IOException -> IO FilePath
inDefault _ = return defaultSystemPath
readCertificates :: FilePath -> IO [X509]
readCertificates file = either (const []) (rights . map getCert) . pemParseBS <$> B.readFile file
where getCert pem = decodeCertificate $ L.fromChunks [pemContent pem]