packages feed

haskdeep 0.1.0.0 → 0.2.0.0

raw patch · 10 files changed

+197/−136 lines, 10 filesdep +base16-bytestringdep +cryptohash-cryptoapidep +old-localedep ~attoparsec-conduitdep ~basedep ~conduit

Dependencies added: base16-bytestring, cryptohash-cryptoapi, old-locale, time

Dependency ranges changed: attoparsec-conduit, base, conduit, crypto-api, crypto-conduit, cryptohash, filesystem-conduit, optparse-applicative

Files

+ CHANGELOG.md view
@@ -0,0 +1,11 @@+## Version 0.2.0.0 (15 Sep 2013)++- Added option -v for version information++- Added option -f and -t to filter files based on modification time++- Changed option -i (exclude based to regex) to -e++## Version 0.1.0.0 (14 Dec 2012)++- Initial release.
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2012 Mauro Taraborelli+Copyright (c) 2013 Mauro Taraborelli  All rights reserved. 
README.md view
@@ -14,15 +14,18 @@      user@host:~$ haskdeep -    Usage: haskdeep COMMAND [-c|--computation MODE] [-r|--root DIRNAME] [-k|--known FILENAME] [-i|--ignore RULE]+    Usage: haskdeep COMMAND [-c|--computation MODE] [-r|--root DIRNAME] [-k|--known FILENAME]       Computes hashes and audit a set of files      Available options:+      -h,--help                Show this help text+      -v,--version             Show version information       -c,--computation MODE    md5 | sha1 | sha256 | skein512 - default md5       -r,--root DIRNAME        Root directory - default current directory       -k,--known FILENAME      Known hashes file - default known.haskdeep-      -i,--ignore RULE         Regex to ignore files or directories-      -h,--help                Show this help text+      -e,--excl-regex REGEX    Exclude files or directories based on regex+      -f,--incl-mod-from DATE  Include files modified from yyyy-mm-ddThh:mm:ssZ+      -t,--incl-mod-upto DATE  Include files modified up to yyyy-mm-ddThh:mm:ssZ      Available commands:       compute                  Computes file hashes and saves them to known hashes file@@ -32,11 +35,11 @@  1. create known hashes of files contained in a root directory (traversed recursively) -        user@host:~$ haskdeep compute -c md5 -r myimportantfiles/ -k knownhashes.txt -i "tmp|\.log"+        user@host:~$ haskdeep compute -c md5 -r myimportantfiles/ -k knownhashes.txt -e "tmp|\.log"  2. verify a copy of the same files comparing them with known hashes -        user@host:~$ haskdeep audit -c md5 -r copyofmyimportantfiles/ -k knownhashes.txt -i "tmp|\.log"+        user@host:~$ haskdeep audit -c md5 -r copyofmyimportantfiles/ -k knownhashes.txt -e "tmp|\.log"  Licensing ---------
haskdeep.cabal view
@@ -1,10 +1,10 @@ name:                haskdeep-version:             0.1.0.0+version:             0.2.0.0 cabal-version:       >=1.8 build-type:          Simple license:             BSD3 license-file:        LICENSE-copyright:           © 2012 Mauro Taraborelli+copyright:           © 2013 Mauro Taraborelli author:              Mauro Taraborelli maintainer:          maurotaraborelli@gmail.com stability:           experimental@@ -22,15 +22,18 @@     .     > user@host:~$ haskdeep     >-    >  Usage: haskdeep COMMAND [-c|--computation MODE] [-r|--root DIRNAME] [-k|--known FILENAME] [-i|--ignore RULE]+    >  Usage: haskdeep COMMAND [-c|--computation MODE] [-r|--root DIRNAME] [-k|--known FILENAME]     >    Computes hashes and audit a set of files     >     >  Available options:+    >    -h,--help                Show this help text+    >    -v,--version             Show version information     >    -c,--computation MODE    md5 | sha1 | sha256 | skein512 - default md5     >    -r,--root DIRNAME        Root directory - default current directory     >    -k,--known FILENAME      Known hashes file - default known.haskdeep-    >    -i,--ignore RULE         Regex to ignore files or directories-    >    -h,--help                Show this help text+    >    -e,--excl-regex REGEX    Exclude files or directories based on regex+    >    -f,--incl-mod-from DATE  Include files modified from yyyy-mm-ddThh:mm:ssZ+    >    -t,--incl-mod-upto DATE  Include files modified up to yyyy-mm-ddThh:mm:ssZ     >     >  Available commands:     >    compute                  Computes file hashes and saves them to known hashes file@@ -40,16 +43,19 @@     .     1. create known hashes of files contained in a root directory (traversed recursively)     .-    >  user@host:~$ haskdeep compute -c md5 -r myimportantfiles/ -k knownhashes.txt -i "tmp|\.log"+    >  user@host:~$ haskdeep compute -c md5 -r myimportantfiles/ -k knownhashes.txt -e "tmp|\.log"     .     2. verify a copy of the same files comparing them with known hashes     .-    >  user@host:~$ haskdeep audit -c md5 -r copyofmyimportantfiles/ -k knownhashes.txt -i "tmp|\.log"+    >  user@host:~$ haskdeep audit -c md5 -r copyofmyimportantfiles/ -k knownhashes.txt -e "tmp|\.log"     .     Heavily inspired by @hashdeep@: <http://md5deep.sourceforge.net/> category:            Console, Cryptography, System extra-source-files:     README.md+    CHANGELOG.md+homepage:            https://github.com/maurotrb/haskdeep+bug-reports:         https://github.com/maurotrb/haskdeep/issues  executable haskdeep   hs-source-dirs:   src@@ -65,24 +71,32 @@     HaskDeep.KnownHash.Writer   build-depends:       attoparsec           ==0.10.*-    , attoparsec-conduit   ==0.5.*-    , base                 ==4.5.*+    , attoparsec-conduit   ==1.0.*+    , base                 ==4.*+    , base16-bytestring    ==0.1.*     , bytestring           ==0.9.*     , cereal               ==0.3.*-    , conduit              ==0.5.*+    , conduit              ==1.0.*     , containers           ==0.4.*-    , cryptohash           ==0.7.*-    , crypto-api           ==0.10.*-    , crypto-conduit       ==0.4.*-    , filesystem-conduit   ==0.5.*-    , optparse-applicative ==0.4.*+    , cryptohash           ==0.10.*+    , cryptohash-cryptoapi ==0.1.*+    , crypto-api           ==0.12.*+    , crypto-conduit       ==0.5.*+    , filesystem-conduit   ==1.0.*+    , old-locale           ==1.0.*+    , optparse-applicative ==0.5.*     , system-fileio        ==0.3.*     , system-filepath      ==0.4.*     , text                 ==0.11.*+    , time                 ==1.4.*     , regex-tdfa           ==1.1.*     , regex-tdfa-text      ==1.0.*   ghc-options: -Wall  source-repository head   type:     git-  location: git://github.com/maurotrb/haskdeep.git+  location: https://github.com/maurotrb/haskdeep.git++source-repository head+  type:     git+  location: https://maurotrb@bitbucket.org/maurotrb/haskdeep.git
src/HaskDeep/Computation.hs view
@@ -32,6 +32,7 @@ import qualified Data.Conduit.Filesystem as CF import qualified Data.Conduit.List as CL import qualified Data.Text as T+import           Data.Time (UTCTime) import qualified Filesystem as FS import           Filesystem.Path.CurrentOS (FilePath) import qualified Filesystem.Path.CurrentOS as FSC@@ -50,12 +51,15 @@ compute conf cm = CF.traverse False root $$ CL.foldM insert_hash empty_with_symbol     where       root              = rootDirectory conf-      rule              = ignoreRule conf+      regex             = excludeRegex conf+      mod_from          = includeModFrom conf+      mod_upto          = includeModUpTo conf       empty_with_symbol = HS.setSymbol (symbol cm) HS.empty        insert_hash :: HashSet -> FilePath -> IO HashSet       insert_hash hs fp = do let fpt = fpToText $ relativize root fp-                             if ignore fpt rule+                             fmt <- FS.getModified fp+                             if (excRegex fpt regex) || (excMod fmt mod_from mod_upto)                              then return hs                              else do s <- FS.getSize fp                                      h <- liftM (runComputation cm) $ C.runResourceT@@ -68,6 +72,12 @@ fpToText :: FilePath -> T.Text fpToText = either id id . FSC.toText -ignore :: T.Text -> Maybe T.Text -> Bool-ignore fpt (Just rule) = fpt =~ rule-ignore _   Nothing     = False+excRegex :: T.Text -> Maybe T.Text -> Bool+excRegex fpt (Just rule) = fpt =~ rule+excRegex _   Nothing     = False++excMod :: UTCTime -> Maybe UTCTime -> Maybe UTCTime -> Bool+excMod fmt (Just modFrom) (Just modUpTo) = (fmt < modFrom) || (fmt > modUpTo)+excMod fmt (Just modFrom) Nothing        = fmt < modFrom+excMod fmt Nothing        (Just modUpTo) = fmt > modUpTo+excMod _   Nothing        Nothing        = False
src/HaskDeep/ComputationMode.hs view
@@ -24,14 +24,9 @@     ) where -import           Data.Bits ((.&.), shiftR)--import           Crypto.Hash.MD5 (MD5)-import           Crypto.Hash.SHA1 (SHA1)-import           Crypto.Hash.SHA256 (SHA256)-import           Crypto.Hash.Skein512 (Skein512)+import           Crypto.Hash.CryptoAPI (MD5, SHA1, SHA256, Skein512_512) import           Data.ByteString (ByteString)-import qualified Data.ByteString as BS+import qualified Data.ByteString.Base16 as BB16 import qualified Data.Serialize as S import qualified Data.Text as T @@ -43,41 +38,16 @@  -- | MD5 computation. md5hash  :: ComputationMode MD5-md5hash  = ComputationMode "md5" (toHex . S.encode)+md5hash  = ComputationMode "md5" (BB16.encode . S.encode)  -- | SHA1 computation. sha1hash :: ComputationMode SHA1-sha1hash = ComputationMode "sha1" (toHex . S.encode)+sha1hash = ComputationMode "sha1" (BB16.encode . S.encode)  -- | SHA256 computation. sha256hash :: ComputationMode SHA256-sha256hash = ComputationMode "sha256" (toHex . S.encode)+sha256hash = ComputationMode "sha256" (BB16.encode . S.encode)  -- | Skein512 computation.-skein512hash :: ComputationMode Skein512-skein512hash = ComputationMode "skein512" (toHex . S.encode)---- Only with ByteString 0.10---toHex :: ByteString -> ByteString---toHex = BS.concat . BL.toChunks . BB.toLazyByteString . BA.byteStringHexFixed---- Taken from--- http://stackoverflow.com/questions/10099921/efficiently-turn-a-bytestring-into-a-hex-representation-toHex :: ByteString -> ByteString-toHex bs0 =-    fst $ BS.unfoldrN (BS.length bs0 * 2) go (Left bs0)-  where-    go (Left bs) =-        case BS.uncons bs of-            Nothing -> Nothing-            Just (w, bs') ->-                let w1 = w `shiftR` 4-                    w2 = w .&. 15-                    c1 = toC w1-                    c2 = toC w2-                 in Just (c1, Right (c2, bs'))-    go (Right (c, bs)) = Just (c, Left bs)--    toC w-        | w < 10 = w + 48-        | otherwise = w + 87+skein512hash :: ComputationMode Skein512_512+skein512hash = ComputationMode "skein512" (BB16.encode . S.encode)
src/HaskDeep/Configuration.hs view
@@ -23,14 +23,17 @@ import           Prelude hiding (FilePath)  import           Data.Text (Text)+import           Data.Time (UTCTime) import           Filesystem.Path (FilePath) import qualified Filesystem.Path.CurrentOS as FSC  -- | HaskDeep configuration. data HaskDeepConfiguration = HaskDeepConfiguration-    { rootDirectory   :: FilePath    -- ^ Root directory-    , knownHashes     :: FilePath    -- ^ Known hashes file-    , ignoreRule      :: Maybe Text  -- ^ Ignore rule (Regex)+    { rootDirectory   :: FilePath      -- ^ Root directory+    , knownHashes     :: FilePath      -- ^ Known hashes file+    , excludeRegex    :: Maybe Text    -- ^ Exclude rule (Regex)+    , includeModFrom  :: Maybe UTCTime -- ^ Include file modified from+    , includeModUpTo  :: Maybe UTCTime -- ^ Include file modified up to     }  -- | HaskDeep default configuration.@@ -38,5 +41,7 @@ defaultHaskDeepConfiguration = HaskDeepConfiguration     { rootDirectory   = FSC.decodeString "."     , knownHashes     = FSC.decodeString "known.haskdeep"-    , ignoreRule      = Nothing+    , excludeRegex    = Nothing+    , includeModFrom  = Nothing+    , includeModUpTo  = Nothing     }
src/HaskDeep/KnownHash/Writer.hs view
@@ -29,10 +29,12 @@ import qualified Data.Conduit as C import qualified Data.Conduit.Filesystem as CF import qualified Data.Conduit.List as CL+import qualified Data.Time as DT import           Data.Text () import qualified Data.Text.Encoding as TE import           Filesystem.Path () import qualified Filesystem.Path.CurrentOS as FSC+import qualified System.Locale as SL  import           HaskDeep.Configuration import           HaskDeep.HashSet (HashSet)@@ -44,24 +46,32 @@             -> IO () writeHashes conf hs = C.runResourceT $ CL.sourceList bs_known $$ CF.sinkFile (knownHashes conf)     where-      newline       = "\n" :: ByteString-      root          =  TE.encodeUtf8 $ either id id $ FSC.toText $ rootDirectory conf-      ignore        = case ignoreRule conf of-                        (Just rule) -> TE.encodeUtf8 rule-                        Nothing     -> BS.empty-      files_count   = B8.pack $ show $ HS.filesCount hs-      size_sum      = B8.pack $ show $ HS.sizeSum hs-      known_header1 = "%%%% HASHDEEP-1.0"-                      `BS.append` newline-      known_header2 = "%%%% size,"-                      `BS.append` TE.encodeUtf8 (HS.compSymbol hs)-                      `BS.append` ",filename"-                      `BS.append` newline-      bs_comments   = map (flip BS.append newline . BS.append "## ")-                      [ "Root directory: " `BS.append` root-                      , "Ignore rule   : " `BS.append` ignore-                      , "Files count   : " `BS.append` files_count-                      , "Files size    : " `BS.append` size_sum-                      , "" ]-      bs_hash_set   = map (flip BS.append newline . HS.toByteString) $ HS.toAscList hs-      bs_known      = [known_header1, known_header2] ++ bs_comments ++ bs_hash_set+      newline          = "\n" :: ByteString+      root             =  TE.encodeUtf8 $ either id id $ FSC.toText $ rootDirectory conf+      exclude_regex    = case excludeRegex conf of+                           (Just regex) -> TE.encodeUtf8 regex+                           Nothing      -> BS.empty+      include_mod_from = case includeModFrom conf of+                           (Just modFrom) -> B8.pack $ DT.formatTime SL.defaultTimeLocale "%FT%TZ" modFrom+                           Nothing        -> BS.empty+      include_mod_upto = case includeModUpTo conf of+                           (Just modUpTo) -> B8.pack $ DT.formatTime SL.defaultTimeLocale "%FT%TZ" modUpTo+                           Nothing        -> BS.empty+      files_count      = B8.pack $ show $ HS.filesCount hs+      size_sum         = B8.pack $ show $ HS.sizeSum hs+      known_header1    = "%%%% HASHDEEP-1.0"+                         `BS.append` newline+      known_header2    = "%%%% size,"+                         `BS.append` TE.encodeUtf8 (HS.compSymbol hs)+                         `BS.append` ",filename"+                         `BS.append` newline+      bs_comments      = map (flip BS.append newline . BS.append "## ")+                         [ "Root directory    : " `BS.append` root+                         , "Exclude regex     : " `BS.append` exclude_regex+                         , "Include mod. from : " `BS.append` include_mod_from+                         , "Include mod. upto : " `BS.append` include_mod_upto+                         , "Files count       : " `BS.append` files_count+                         , "Files size        : " `BS.append` size_sum+                         , "" ]+      bs_hash_set      = map (flip BS.append newline . HS.toByteString) $ HS.toAscList hs+      bs_known         = [known_header1, known_header2] ++ bs_comments ++ bs_hash_set
src/Main.hs view
@@ -25,9 +25,10 @@ import           Options  main :: IO ()-main = OA.execParser optionsPI >>= haskdeep+main = OA.customExecParser (OA.prefs OA.showHelpOnError) optionsPI >>= haskdeep  haskdeep :: Options -> IO ()+haskdeep Version                                   = putStrLn haskdeepVersion haskdeep (Options OptComputation OptMD5      conf) = execComputation conf md5hash haskdeep (Options OptComputation OptSHA1     conf) = execComputation conf sha1hash haskdeep (Options OptComputation OptSHA256   conf) = execComputation conf sha256hash
src/Options.hs view
@@ -16,6 +16,7 @@     ,OptExecution(..)     ,OptCompMode(..)     ,optionsPI+    ,haskdeepVersion     ) where @@ -23,14 +24,21 @@  import           Data.Text (Text) import qualified Data.Text as T+import           Data.Time (UTCTime)+import qualified Data.Time as DT import           Filesystem.Path.CurrentOS (FilePath) import qualified Filesystem.Path.CurrentOS as FSC import           Options.Applicative+import qualified System.Locale as SL  import           HaskDeep -data Options = Options OptExecution OptCompMode HaskDeepConfiguration+haskdeepVersion :: String+haskdeepVersion = "haskdeep 0.2.0.0 - file hashing and audit" +data Options = Version+             | Options OptExecution OptCompMode HaskDeepConfiguration+ data OptExecution = OptComputation                   | OptAudit @@ -40,62 +48,91 @@                  | OptSkein512  optionsPI :: ParserInfo Options-optionsPI = info (optionsP <**> helper)+optionsPI = info (helper <*> optionsP)             ( fullDesc-              & progDesc "Computes hashes and audit a set of files"-              & header "haskdeep - file hashing and audit" )+              <> progDesc "Computes hashes and audit a set of files"+              <> header haskdeepVersion)  configurationP :: Parser HaskDeepConfiguration configurationP = HaskDeepConfiguration                  <$> nullOption                          ( long "root"-                           & short 'r'-                           & metavar "DIRNAME"-                           & help "Root directory - default current directory"-                           & reader fpReader-                           & value (rootDirectory defaultHaskDeepConfiguration))+                           <> short 'r'+                           <> metavar "DIRNAME"+                           <> help "Root directory - default current directory"+                           <> reader fpReader+                           <> value (rootDirectory defaultHaskDeepConfiguration))                  <*> nullOption                          ( long "known"-                           & short 'k'-                           & metavar "FILENAME"-                           & help "Known hashes file - default known.haskdeep"-                           & reader fpReader-                           & value (knownHashes defaultHaskDeepConfiguration))+                           <> short 'k'+                           <> metavar "FILENAME"+                           <> help "Known hashes file - default known.haskdeep"+                           <> reader fpReader+                           <> value (knownHashes defaultHaskDeepConfiguration))                  <*> nullOption-                         ( long "ignore"-                           & short 'i'-                           & metavar "RULE"-                           & help "Regex to ignore files or directories"-                           & reader ignReader-                           & value (ignoreRule defaultHaskDeepConfiguration))+                         ( long "excl-regex"+                           <> short 'e'+                           <> metavar "REGEX"+                           <> help "Exclude files or directories based on regex"+                           <> reader regexReader+                           <> value (excludeRegex defaultHaskDeepConfiguration)+                           <> hidden )+                 <*> nullOption+                         ( long "incl-mod-from"+                           <> short 'f'+                           <> metavar "DATE"+                           <> help "Include files modified from yyyy-mm-ddThh:mm:ssZ"+                           <> reader timeReader+                           <> value (includeModFrom defaultHaskDeepConfiguration)+                           <> hidden )+                 <*> nullOption+                         ( long "incl-mod-upto"+                           <> short 't'+                           <> metavar "DATE"+                           <> help "Include files modified up to yyyy-mm-ddThh:mm:ssZ"+                           <> reader timeReader+                           <> value (includeModUpTo defaultHaskDeepConfiguration)+                           <> hidden )  optionsP :: Parser Options-optionsP = Options-           <$> subparser-                   ( command "compute"-                     (info (pure OptComputation)-                               (progDesc "Computes file hashes and saves them to known hashes file"))-                     & command "audit"-                     (info (pure OptAudit)-                               (progDesc "Audit files comparing them to known hashes")))-           <*> nullOption-                   ( long "computation"-                     & short 'c'-                     & metavar "MODE"-                     & help "md5 | sha1 | sha256 | skein512 - default md5"-                     & reader compReader-                     & value OptMD5)-           <*> configurationP+optionsP = flag' Version+                   ( long "version"+                     <> short 'v'+                     <> help "Show version information"+                     <> hidden )+           <|> ( Options+                 <$> subparser+                         ( command "compute"+                           (info (pure OptComputation)+                            (progDesc "Computes file hashes and saves them to known hashes file"))+                           <> command "audit"+                           (info (pure OptAudit)+                            (progDesc "Audit files comparing them to known hashes")))+                 <*> nullOption+                         ( long "computation"+                           <> short 'c'+                           <> metavar "MODE"+                           <> help "md5 | sha1 | sha256 | skein512 - default md5"+                           <> reader compReader+                           <> value OptMD5)+                 <*> configurationP ) -fpReader :: String -> Maybe FilePath-fpReader fp = Just $ FSC.decodeString fp+compReader :: String -> Either ParseError OptCompMode+compReader "md5"      = Right OptMD5+compReader "sha1"     = Right OptSHA1+compReader "sha256"   = Right OptSHA256+compReader "skein512" = Right OptSkein512+compReader _          = Left ShowHelpText -ignReader :: String -> Maybe (Maybe Text)-ignReader = Just . Just . T.pack+fpReader :: String -> Either ParseError FilePath+fpReader fp = Right $ FSC.decodeString fp -compReader :: String -> Maybe OptCompMode-compReader "md5"      = Just OptMD5-compReader "sha1"     = Just OptSHA1-compReader "sha256"   = Just OptSHA256-compReader "skein512" = Just OptSkein512-compReader _          = Nothing+regexReader :: String -> Either ParseError (Maybe Text)+regexReader = Right . Just . T.pack++timeReader :: String -> Either ParseError (Maybe UTCTime)+timeReader dt = case parsedTime of+                  (Just _) -> Right parsedTime+                  Nothing  -> Left ShowHelpText+    where+      parsedTime = DT.parseTime SL.defaultTimeLocale "%FT%TZ" dt