-- FIXME: should use a salt to defend against dictionary -- attacks on the hashed passwords. module User (UserID, Password, authenticate, addUser) where import DB import MD5 import Util import Control.Monad import Data.Map (Map) import qualified Data.Map as Map import Data.Maybe import System.IO.Unsafe newtype Users = Users (Map UserID PasswordHash) type UserID = String type Password = String type PasswordHash = String instance DBValue Users where toDB (Users us) = unlines [ u++":"++p | (u,p) <- Map.toList us ] fromDB = Just . Users . Map.fromList . map readUser . lines where readUser s = (trimSpace u, trimSpace $ drop 1 p) where (u,p) = break (==':') s authenticate :: UserID -> Password -> IO (Maybe UserID) authenticate name pwd = do Users us <- readDB userDB return $ case Map.lookup name us of Nothing -> Nothing Just h | h == hash pwd -> Just name | otherwise -> Nothing addUser :: UserID -> Password -> IO () addUser name pwd = do us <- readDB userDB setDB userDB $ f us writeDB userDB where f (Users us) = Users (Map.insert name (hash pwd) us) {-# NOINLINE userDB #-} userDB :: DB Users userDB = unsafePerformIO $ initDB "users" $ Users Map.empty