module Storage.Hashed.Hash( Hash(..), encodeBase64u, decodeBase64u
, encodeBase16, decodeBase16, sha256, rawHash
, match ) where
import qualified Bundled.SHA256 as SHA
import qualified Data.ByteString as BS
import qualified Data.ByteString.Internal as BSI
import qualified Data.ByteString.Lazy as BL
import qualified Codec.Binary.Base64Url as B64U
import qualified Codec.Binary.Base16 as B16
import Data.Maybe( isJust, fromJust )
import Data.Char( toLower, toUpper )
import Data.Data( Data )
import Data.Typeable( Typeable )
data Hash = SHA256 !BS.ByteString
| SHA1 !BS.ByteString
| NoHash
deriving (Show, Eq, Ord, Read, Typeable, Data)
base16 :: BS.ByteString -> BS.ByteString
debase16 :: BS.ByteString -> Maybe BS.ByteString
base64u :: BS.ByteString -> BS.ByteString
debase64u :: BS.ByteString -> Maybe BS.ByteString
base16 = BS.pack . map (BSI.c2w . toLower) . B16.encode . BS.unpack
base64u = BS.pack . map BSI.c2w . B64U.encode . BS.unpack
debase64u bs = case B64U.decode $ map BSI.w2c $ BS.unpack bs of
Just s -> Just $ BS.pack s
Nothing -> Nothing
debase16 bs = case B16.decode $ map (toUpper . BSI.w2c) $ BS.unpack bs of
Just s -> Just $ BS.pack s
Nothing -> Nothing
encodeBase64u :: Hash -> BS.ByteString
encodeBase64u (SHA256 bs) = base64u bs
encodeBase64u (SHA1 bs) = base64u bs
encodeBase64u NoHash = BS.empty
encodeBase16 :: Hash -> BS.ByteString
encodeBase16 (SHA256 bs) = base16 bs
encodeBase16 (SHA1 bs) = base16 bs
encodeBase16 NoHash = BS.empty
decodeBase64u :: BS.ByteString -> Hash
decodeBase64u bs
| BS.length bs == 44 && isJust (debase64u bs) = SHA256 (fromJust $ debase64u bs)
| BS.length bs == 28 && isJust (debase64u bs) = SHA1 (fromJust $ debase64u bs)
| otherwise = NoHash
decodeBase16 :: BS.ByteString -> Hash
decodeBase16 bs | BS.length bs == 64 && isJust (debase16 bs) = SHA256 (fromJust $ debase16 bs)
| BS.length bs == 40 && isJust (debase16 bs) = SHA1 (fromJust $ debase16 bs)
| otherwise = NoHash
sha256 :: BL.ByteString -> Hash
sha256 bits = SHA256 (SHA.sha256 $ BS.concat $ BL.toChunks bits)
rawHash :: Hash -> BS.ByteString
rawHash NoHash = error "Cannot obtain raw hash from NoHash."
rawHash (SHA1 s) = s
rawHash (SHA256 s) = s
match :: Hash -> Hash -> Bool
NoHash `match` _ = False
_ `match` NoHash = False
x `match` y = x == y