{-# LANGUAGE ScopedTypeVariables #-} module Fake.Provider.UserAgent where ------------------------------------------------------------------------------ import Data.Monoid import Data.Time import Text.Printf ------------------------------------------------------------------------------ import Fake.Combinators import Fake.Provider.DateTime import Fake.Provider.Locale import Fake.Types ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ -- | Fake user agent strings using a uniform distribution across the five -- major browsers. userAgent :: FGen String userAgent = oneof [ chromeUserAgent , internetExplorerUserAgent , firefoxUserAgent , safariUserAgent , operaUserAgent ] ------------------------------------------------------------------------------ -- | Fake user agent strings using a real-world distribution across the five -- major browsers. userAgentRealDist :: FGen String userAgentRealDist = frequency -- Browser stats from https://www.w3schools.com/browsers/default.asp [ (768, chromeUserAgent) , (43, internetExplorerUserAgent) , (125, firefoxUserAgent) , (33, safariUserAgent) , (16, operaUserAgent) ] ------------------------------------------------------------------------------ -- | Fake user agent strings for Chrome. chromeUserAgent :: FGen String chromeUserAgent = do plat <- fakePlatform appleA <- fakeInt 531 536 appleB <- fakeInt 0 2 let saf = show appleA <> "." <> show appleB chromeMajor <- fakeInt 13 15 chromeMinor <- fakeInt 800 899 let rest = printf "(%s) AppleWebKit/%s (KHTML, like Gecko) Chrome/%d.0.%d.0 Safari/%s" plat saf chromeMajor chromeMinor saf return $ "Mozilla/5.0 " <> rest ------------------------------------------------------------------------------ -- | Fake user agent strings for Internet Explorer. internetExplorerUserAgent :: FGen String internetExplorerUserAgent = do plat <- windowsPlatform a <- fakeInt 5 9 b <- fakeInt 3 5 c <- fakeInt 0 1 return $ printf "Mozilla/5.0 (compatible; MSIE %d.0; %s; Trident/%d.%d)" a plat b c underscoreToDash :: Char -> Char underscoreToDash '_' = '-' underscoreToDash c = c dayStr :: Day -> String dayStr = formatTime defaultTimeLocale "%Y%m%d" ------------------------------------------------------------------------------ -- | Fake user agent strings for Firefox. firefoxUserAgent :: FGen String firefoxUserAgent = do let a :: FGen String a = do d <- dayStr <$> dayBetween (fromGregorian 2011 1 1) (fromGregorian 2017 1 1) n <- fakeInt 4 15 return $ printf "Gecko/%s Firefox/%d.0" d n b :: FGen String b = do d <- dayStr <$> dayBetween (fromGregorian 2010 1 1) (fromGregorian 2017 1 1) n <- fakeInt 1 20 return $ printf "Gecko/%s Firefox/3.6.%d" d n c :: FGen String c = do d <- dayStr <$> dayBetween (fromGregorian 2010 1 1) (fromGregorian 2017 1 1) return $ printf "Gecko/%s Firefox/3.8" d ver <- oneof [a, b, c] let win :: FGen String win = do plat <- windowsPlatform l <- fmap underscoreToDash <$> fakeLocale n <- fakeInt 0 2 return $ printf "(%s; %s; rv:1.9.%d.20) %s" plat l n ver lin :: FGen String lin = do plat <- linuxPlatform n <- fakeInt 5 7 return $ printf "(%s; rv:1.9.%d.20) %s" plat n ver mac :: FGen String mac = do plat <- macPlatform n <- fakeInt 2 6 return $ printf "(%s; rv:1.9.%d.20) %s" plat n ver plat <- oneof [win, lin, mac] return $ "Mozilla/5.0 " <> plat ------------------------------------------------------------------------------ -- | Fake user agent strings for Safari. safariUserAgent :: FGen String safariUserAgent = do saf :: String <- do a <- fakeInt 531 535 b <- fakeInt 1 50 c <- fakeInt 1 7 return $ printf "%d.%d.%d" a b c twoVers <- elements [False, True] ver :: String <- if twoVers then printf "%d.%d" <$> fakeInt 4 5 <*> fakeInt 0 1 else printf "%d.0.%d" <$> fakeInt 4 5 <*> fakeInt 1 5 let win :: FGen String win = do plat <- windowsPlatform return $ printf "(Windows; U; %s) AppleWebKit/%s (KHTML, like Gecko) Version/%s Safari/%s" plat saf ver saf mac :: FGen String mac = do plat <- macPlatform n <- fakeInt 2 6 l <- fmap underscoreToDash <$> fakeLocale return $ printf "(%s rv:%d.0; %s) AppleWebKit/%s (KHTML, like Gecko) Version/%s Safari/%s" plat n l saf ver saf ipod :: FGen String ipod = do a <- fakeInt 3 4 b <- fakeInt 0 3 c <- fakeInt 3 4 d <- fakeInt 111 119 l <- fmap underscoreToDash <$> fakeLocale return $ printf "(iPod; U; CPU iPhone OS %d_%d like Mac OS X; %s) AppleWebKit/%s (KHTML, like Gecko) Version/%d.0.5 Mobile/8B%d Safari/6%s" a b l saf c d saf plat <- oneof [win, mac, ipod] return $ "Mozilla/5.0 " <> plat ------------------------------------------------------------------------------ -- | Fake user agent strings for Opera. operaUserAgent :: FGen String operaUserAgent = do let getPlat = do useLinux <- elements [False, True] if useLinux then linuxPlatform else windowsPlatform let plat :: FGen String = printf "(%s; %s) Presto/2.9.%d Version/%d.00" <$> getPlat <*> fmap (fmap underscoreToDash) fakeLocale <*> fakeInt 160 190 <*> fakeInt 10 12 printf "Opera/%d.%d.%s" <$> fakeInt 8 9 <*> fakeInt 10 99 <*> plat fakePlatform :: FGen String fakePlatform = oneof [windowsPlatform, linuxPlatform, macPlatform] windowsPlatform :: FGen String windowsPlatform = elements [ "Windows 95", "Windows 98", "Windows 98; Win 9x 4.90", "Windows CE" , "Windows NT 4.0", "Windows NT 5.0", "Windows NT 5.01" , "Windows NT 5.1", "Windows NT 5.2", "Windows NT 6.0", "Windows NT 6.1" , "Windows NT 6.2" ] linuxPlatform :: FGen String linuxPlatform = do processor <- linuxProcessor return $ "X11; Linux " <> processor macPlatform :: FGen String macPlatform = do processor <- macProcessor b <- fakeInt 5 8 c <- fakeInt 0 9 return $ printf "Macintosh; %s Mac OS X 10_%d_%d" processor b c linuxProcessor :: FGen String linuxProcessor = elements ["i686", "x86_64"] macProcessor :: FGen String macProcessor = elements ["Intel", "PPC", "U; Intel", "U; PPC"]