module System.Executable.Hash.Internal where
import Control.Exception (SomeException, handle)
import "cryptohash" Crypto.Hash.SHA1 (hash)
import qualified Data.ByteString as BS
import Data.FileEmbed (dummySpaceWith, injectWith)
import Language.Haskell.TH (Q, Exp)
import System.Directory (doesFileExist)
injectedExecutableHash :: Q Exp
injectedExecutableHash =
[|
let bs = $(dummySpaceWith "executable-hash" 20)
in if BS.all (== toEnum (fromEnum '0')) bs
then Nothing
else Just bs
|]
injectExecutableHash :: FilePath -> IO ()
injectExecutableHash fp = handle addPathToException $ do
binary <- BS.readFile fp
let sha1 = hash binary
case injectWith "executable-hash" sha1 binary of
Nothing -> fail "Impossible: dummy space too small for executable-hash."
Just binary' -> do
BS.writeFile fp binary'
putStrLn $ "Successfully wrote " ++ fp ++ " with injected hash."
where
addPathToException ex = fail $
"While injecting hash into " ++ fp ++
", the following exception occurred: " ++ show (ex :: SomeException)
maybeInjectExecutableHash :: FilePath -> IO ()
maybeInjectExecutableHash fp = do
exists <- doesFileExist fp
if exists
then injectExecutableHash fp
else putStrLn $ concat
[ "Not injecting executable hash into "
, fp
, ", as it doesn't exist."
]