phizzle-0.1.0.1: src/Phizzle/Phizzly.hs
{-# LANGUAGE OverloadedStrings #-}
module Phizzle.Phizzly (loadPhishFile, maliciousLink) where
import qualified Data.ByteString.Lazy as LB
import Data.ByteString.Lazy (ByteString)
import qualified Data.Text as T
import Data.Text (Text)
import Text.Regex.PCRE
import Data.Aeson
import Control.Monad
import Network.URI
import Data.List (isPrefixOf, isSuffixOf)
import Phizzle.Types
-- Reads a phishtank json file as a lazy bytestring. (Internal function).
getJsonFileData :: String -> IO ByteString
getJsonFileData = LB.readFile
-- Returns either a decoded phishtank json file or an error message.
-- (Internal function).
jsonToWholePhish :: String -> IO (Either String [PhishTank])
jsonToWholePhish jData = eitherDecode <$> getJsonFileData jData
-- Loads a phishtank json file into a parsed list
loadPhishFile :: String -> IO (Either String [PhishTank])
loadPhishFile filepath = jsonToWholePhish $ filepath
-- Maybe returns a successfully parsed uri without the trailing /.
-- (Internal function).
getURIParts :: Maybe URI -> Maybe String
getURIParts uriData = let path = uriPath <$> uriData
regName = uriRegName <$> (join $ uriAuthority <$> uriData)
in ( (flip (++)) . dropSlash ) <$> path <*> regName
where
dropSlash :: String -> String
dropSlash xs
| "/" `isSuffixOf` xs = init xs
| otherwise = xs
-- Maybe returns a bool based on if a link exists in the phishtank file
-- using a regular expression pattern
maliciousLink :: String -> [PhishTank] -> IO (Maybe Bool)
maliciousLink lnk pt = do
linkExists pt
where
linkExists [] = return $ Just False
linkExists (x:xs) = let lnkParts = getURIParts $ parseURI $ lnk
in case lnkParts of
Nothing -> return Nothing
Just v -> let choppedLnk = if "www." `isPrefixOf` v
then drop 4 v
else v
in case ( (T.unpack (url x)) =~ ("^(http|https)?(://)?(www.)?" ++ choppedLnk ++ "/?$") :: Bool) of
True -> return $ Just True
False -> linkExists xs