X-Git-Url: http://git.cielonegro.org/gitweb.cgi?a=blobdiff_plain;f=Rakka%2FAuthorization.hs;h=4ba4f12fb24c1f000bd8373d64213d678569d85f;hb=HEAD;hp=04beabae3cb676cd138d1a0b447c818ba1ee5d0c;hpb=b444493e17ad49d60464bb5cf02898bd9198af3c;p=Rakka.git diff --git a/Rakka/Authorization.hs b/Rakka/Authorization.hs index 04beaba..4ba4f12 100644 --- a/Rakka/Authorization.hs +++ b/Rakka/Authorization.hs @@ -1,75 +1,101 @@ +{-# LANGUAGE + OverloadedStrings + , UnicodeSyntax + #-} +-- FIXME: authentication module Rakka.Authorization ( AuthDB , mkAuthDB , isValidPair + , getUserList + , addUser + , delUser ) where - -import qualified Codec.Binary.Base64 as B64 -import qualified Codec.Binary.UTF8.String as UTF8 +import Control.Applicative import Control.Concurrent.STM import Control.Monad.Trans -import Data.Digest.SHA2 +import Data.ByteString (ByteString) import Data.Map (Map) import qualified Data.Map as M hiding (Map) import Data.Maybe -import Data.Word +import Data.Text (Text) +import qualified Data.Text.Encoding as T +import qualified Data.Text.IO as T +import OpenSSL.EVP.Base64 +import OpenSSL.EVP.Digest +import Prelude.Unicode import Rakka.SystemConfig import System.Directory import System.FilePath -import System.IO - data AuthDB = AuthDB { - adbFilePath :: !FilePath - , adbUserMap :: !(TVar UserMap) - , adbSyncRequest :: !(TVar Bool) + adbFilePath ∷ !FilePath + , adbUserMap ∷ !(TVar UserMap) } - -type UserMap = Map String [Word8] - +type UserMap = Map Text ByteString mkAuthDB :: FilePath -> IO AuthDB mkAuthDB lsdir = do let path = lsdir "authDB" - m <- newTVarIO =<< loadUserMap path - req <- newTVarIO False + m <- newTVarIO =<< loadUserMap path return AuthDB { - adbFilePath = path - , adbUserMap = m - , adbSyncRequest = req + adbFilePath = path + , adbUserMap = m } -isValidPair :: MonadIO m => AuthDB -> String -> String -> m Bool +isValidPair ∷ MonadIO m ⇒ AuthDB → Text → Text → m Bool isValidPair adb name pass - = let hash = toOctets $ sha256 $ UTF8.encode pass - in - liftIO $ atomically $ do m <- readTVar (adbUserMap adb) - return (M.lookup name m == Just hash) + = liftIO $ do sha1 ← fromJust <$> getDigestByName "SHA1" + let hash = digestBS' sha1 $ T.encodeUtf8 pass + atomically $ do m ← readTVar (adbUserMap adb) + pure $ M.lookup name m ≡ Just hash +getUserList ∷ MonadIO m ⇒ AuthDB → m [Text] +getUserList = liftIO ∘ atomically ∘ (M.keys <$>) ∘ readTVar ∘ adbUserMap -loadUserMap :: FilePath -> IO UserMap +addUser ∷ MonadIO m ⇒ AuthDB → Text → Text → m () +addUser adb name pass + = liftIO $ + do sha1 ← fromJust <$> getDigestByName "SHA1" + let hash = digestBS' sha1 $ T.encodeUtf8 pass + m ← atomically $ do m ← readTVar (adbUserMap adb) + let m' = M.insert name hash m + writeTVar (adbUserMap adb) m' + return m' + saveUserMap (adbFilePath adb) m + +delUser ∷ MonadIO m ⇒ AuthDB → Text → m () +delUser adb name + = liftIO $ + do m ← atomically $ do m ← readTVar (adbUserMap adb) + let m' = M.delete name m + writeTVar (adbUserMap adb) m' + return m' + saveUserMap (adbFilePath adb) m + +loadUserMap ∷ FilePath → IO UserMap loadUserMap path - = do exist <- doesFileExist path - m <- if exist then - readFile path - >>= - return . M.fromList . map decodePair . fromJust . deserializeStringPairs - else - return M.empty - return (initMap m) + = do exist ← doesFileExist path + m ← if exist then + fromJust ∘ deserializeMap id (decodeBase64BS ∘ T.encodeUtf8) + <$> T.readFile path + else + pure M.empty + sha1 ← fromJust <$> getDigestByName "SHA1" + pure $ initMap sha1 m where - decodePair :: (String, String) -> (String, [Word8]) - decodePair (name, b64Hash) - = (UTF8.decodeString name, fromJust $ B64.decode b64Hash) - - initMap :: UserMap -> UserMap - initMap m + initMap ∷ Digest → UserMap → UserMap + initMap sha1 m | M.null m = let name = "root" - hash = toOctets $ sha256 ([] :: [Word8]) + hash = digestBS' sha1 "" in M.singleton name hash | otherwise = m + +saveUserMap ∷ FilePath → UserMap → IO () +saveUserMap path + = T.writeFile path ∘ serializeMap id (T.decodeUtf8 ∘ encodeBase64BS)