import Control.Arrow import Control.Applicative (liftA2) import Control.Monad.Trans (lift) import Control.Concurrent (threadDelay) import qualified Control.Exception as E import Data.Maybe import Data.ByteString.Lazy (ByteString) import Data.ByteString.Lazy.Char8 (unpack) import Data.ByteString.Char8 (pack) import Network.HTTP.Conduit import Network.HTTP.Types (status200,status303) import System.Console.Haskeline import System.Environment import System.Exit import Text.Regex getResponse :: String -> IO (Response ByteString) getResponse url = do request' <- parseUrl url let request = request' {redirectCount = 0,checkStatus = \_ _ _ -> Nothing} withManager $ httpLbs request isLoggedIn :: IO (Either Bool (Response ByteString)) isLoggedIn = do res <- getResponse "http://74.125.236.51:80" return $ if responseStatus res /= status303 then Left True else Right res getMagicString :: String -> Maybe [String] getMagicString = matchRegex $ mkRegex "VALUE=\"([0-9a-f]+)\"" getKeepAlive :: String -> Maybe [String] getKeepAlive = matchRegex $ mkRegex "location.href=\"(.+?)\"" getLogout :: String -> Maybe [String] getLogout = matchRegex $ mkRegex "href=\"(.+?logout.+?)\"" keepAlive :: String -> String -> IO () keepAlive str logout = E.finally before after --Logout if exit where before = do putStrLn "Sending Request to keep Alive" _ <- getResponse str threadDelay 200000000 -- Wait 200 seconds keepAlive str logout after = do status <- logOut logout if status then putStrLn "Logged out successfully" else putStrLn "Cannot logout" usage :: IO () usage = putStrLn "Version 0.1 beta \nUsage: hwall-auth-iitk [-h] username password" readInput :: IO (String,String) readInput = runInputT defaultSettings go where go :: InputT IO (String,String) go = do uname <- getInputLine "Username " pass <- getPassword Nothing "Password " maybe (lift exitFailure) return (liftA2 (,) uname pass) parse :: [String] -> IO (String,String) -- parse [] = return ("username","password") parse ["-h"] = usage >> exitSuccess parse ["--help"] = usage >> exitSuccess parse (a:b:_) = return (a,b) -- Comment this line if your are hardcoding your username and passoword. parse _ = readInput getAuthenticationInfo :: IO (String,String) getAuthenticationInfo = getArgs >>= parse alreadyLogged :: (String,String) -> Bool -> IO () alreadyLogged auth _ = putStrLn "Already Logged in .. Trying after 60 seconds " >> threadDelay 60000000 >> firewallAuth auth logOut :: String -> IO Bool logOut url = do resp <- getResponse url return (responseStatus resp == status200 ) tryToLog :: (String,String) -> Response ByteString -> IO () tryToLog (username,password) res = do putStrLn $ "Hello " ++ username ++ "\nNow trying to login" let authLocation = lookup "Location" (read (show $ responseHeaders res) :: [(String,String)]) --print authLocation authRes <- getResponse (fromJust authLocation) -- Connecting to authentication Location let (magicString:_) = fromJust.getMagicString.unpack $ responseBody authRes --print magicString request <- parseUrl (fromJust authLocation) resp <- withManager.httpLbs $ urlEncodedBody (map (pack *** pack) [("username",username),("password",password),("magic",magicString),("4Tredir","/")]) request let body = responseBody resp --print body let (logout:_) = (fromJust.getLogout.unpack $ body) putStrLn ("Logout url is "++logout) --putStrLn $ "Logout Url" ++ (show $ responseHeaders resp) let keepAliveMatch = getKeepAlive $ unpack body case keepAliveMatch of Nothing -> putStrLn "Check Username or password" >> exitFailure Just (str:_) -> do putStrLn ("Keep Alive URL is "++str) keepAlive str logout firewallAuth :: (String,String) -> IO () firewallAuth auth = do putStrLn "Checking If already Logged in." loggedin <- isLoggedIn -- Checking If Already Logged in putStrLn "Performing operation depending on current status." either (alreadyLogged auth) (tryToLog auth) loggedin main :: IO () main = do auth <- getAuthenticationInfo -- Getting Username and password firewallAuth auth