@@ -121,6 +121,7 @@ import Distribution.Simple.Utils
121
121
( die' , warn , notice , info , createDirectoryIfMissingVerbose )
122
122
import Distribution.Client.Utils
123
123
( determineNumJobs )
124
+ import Distribution.Parsec (explicitEitherParsec )
124
125
import Distribution.Utils.NubList
125
126
( fromNubList )
126
127
import Distribution.Verbosity
@@ -141,6 +142,7 @@ import Control.Monad.Trans (liftIO)
141
142
import Control.Exception
142
143
import Data.Either
143
144
import qualified Data.ByteString as BS
145
+ import qualified Data.ByteString.Char8 as BS8
144
146
import qualified Data.ByteString.Lazy as LBS
145
147
import qualified Data.Map as Map
146
148
import qualified Data.List.NonEmpty as NE
@@ -155,6 +157,9 @@ import System.Directory
155
157
import Network.URI
156
158
( URI (.. ), URIAuth (.. ), parseAbsoluteURI , uriToString )
157
159
160
+ import qualified Crypto.Hash.SHA256 as SHA256
161
+ import qualified Data.ByteString.Base16 as Base16
162
+ import qualified Distribution.Compat.CharParsing as P
158
163
159
164
----------------------------------------
160
165
-- Resolving configuration to settings
@@ -1099,7 +1104,7 @@ fetchAndReadSourcePackageRemoteTarball verbosity
1099
1104
distDownloadSrcDirectory
1100
1105
}
1101
1106
getTransport
1102
- tarballUri =
1107
+ origTarballUri =
1103
1108
-- The tarball download is expensive so we use another layer of file
1104
1109
-- monitor to avoid it whenever possible.
1105
1110
rerunIfChanged verbosity monitor tarballUri $ do
@@ -1109,9 +1114,29 @@ fetchAndReadSourcePackageRemoteTarball verbosity
1109
1114
liftIO $ do
1110
1115
transportCheckHttps verbosity transport tarballUri
1111
1116
notice verbosity (" Downloading " ++ show tarballUri)
1117
+
1118
+ sha256expected <-
1119
+ if null (uriFragment origTarballUri)
1120
+ then return Nothing
1121
+ else case msha256expected of
1122
+ Right hash -> return (Just hash)
1123
+ Left err -> die' verbosity $
1124
+ " Cannot parse URI fragment " ++ uriFragment origTarballUri ++
1125
+ " " ++ err
1112
1126
createDirectoryIfMissingVerbose verbosity True
1113
1127
distDownloadSrcDirectory
1114
1128
_ <- downloadURI transport verbosity tarballUri tarballFile
1129
+
1130
+ for_ sha256expected $ \ expected -> do
1131
+ contents <- LBS. readFile tarballFile
1132
+ let actual = SHA256. hashlazy contents
1133
+ unless (expected == actual) $
1134
+ die' verbosity $ unwords
1135
+ [ " SHA256 doesn't match for" , show tarballUri
1136
+ , " expected" , BS8. unpack (Base16. encode expected)
1137
+ , " actual" , BS8. unpack (Base16. encode actual)
1138
+ ]
1139
+
1115
1140
return ()
1116
1141
1117
1142
-- Read
@@ -1121,10 +1146,20 @@ fetchAndReadSourcePackageRemoteTarball verbosity
1121
1146
. uncurry (readSourcePackageCabalFile verbosity)
1122
1147
=<< extractTarballPackageCabalFile tarballFile
1123
1148
where
1149
+ tarballUri = origTarballUri { uriFragment = " " }
1150
+
1124
1151
tarballStem = distDownloadSrcDirectory
1125
1152
</> localFileNameForRemoteTarball tarballUri
1126
1153
tarballFile = tarballStem <.> " tar.gz"
1127
1154
1155
+ msha256expected :: Either String BS. ByteString
1156
+ msha256expected = explicitEitherParsec fragmentParser (uriFragment origTarballUri)
1157
+
1158
+ fragmentParser = do
1159
+ _ <- P. string " #sha256="
1160
+ str <- some P. hexDigit
1161
+ return (fst (Base16. decode (BS8. pack str)))
1162
+
1128
1163
monitor :: FileMonitor URI (PackageSpecifier (SourcePackage UnresolvedPkgLoc ))
1129
1164
monitor = newFileMonitor (tarballStem <.> " cache" )
1130
1165
0 commit comments