packages feed

pan-os-syslog-0.1.0.0: test/Main.hs

{-# language BangPatterns #-}
{-# language MultiWayIf #-}
{-# language ScopedTypeVariables #-}
{-# language TypeApplications #-}

import Panos.Syslog (Log(..),decode)

import Control.Exception (throwIO)
import Data.Primitive (ByteArray)
import Data.Word (Word8)
import Data.Char (ord,chr)
import Data.Bytes.Types (Bytes(Bytes))

import qualified Panos.Syslog.Traffic as Traffic
import qualified Panos.Syslog.Threat as Threat
import qualified Panos.Syslog.System as System
import qualified Data.Primitive as PM
import qualified GHC.Exts as Exts
import qualified Sample as S

main :: IO ()
main = do
  putStrLn "Start"
  putStrLn "8.1-Traffic-A"
  testA
  putStrLn "8.1-Traffic-B"
  testTrafficB
  putStrLn "8.1-Threat-A"
  testB
  putStrLn "8.1-Threat-B"
  testC
  putStrLn "8.1-Threat-C"
  testD
  putStrLn "8.1-Threat-D"
  testThreatD
  putStrLn "8.1-Threat-E"
  testThreatE
  putStrLn "8.1-Threat-F"
  testThreatF
  putStrLn "8.1-Threat-G"
  testThreatG
  putStrLn "8.1-Threat-H"
  testThreatH
  putStrLn "8.1-Threat-I"
  testThreatI
  putStrLn "8.1-System-A"
  testSystemA
  putStrLn "Finished"

testA :: IO ()
testA = case decode S.traffic_8_1_A of
  Left err -> throwIO err
  Right (LogTraffic t) ->
    if | Traffic.deviceName t /= bytes "MY-DEVICE-NAME" ->
           fail $
             "wrong device name:\nexpected: " ++
             show (bytes "MY-DEVICE-NAME") ++
             "\nactually: " ++
             show (Traffic.deviceName t)
       | Traffic.packetsReceived t /= 0 ->
           fail $
             "wrong packets received: expected 0 but got " ++
             show (Traffic.packetsReceived t)
       | Traffic.bytesReceived t /= 34 ->
           fail $
             "wrong bytes received: expected 34 but got " ++
             show (Traffic.bytesReceived t)
       | otherwise -> pure ()
  Right _ -> fail "wrong log type"

testB :: IO ()
testB = case decode S.threat_8_1_A of
  Left err -> throwIO err
  Right (LogThreat t) ->
    if | Threat.contentVersion t /= bytes "AppThreat-1-6" -> fail $
           "wrong content version:\nExpected: AppThreat-1-6\nActually: " ++
           prettyBytes (Threat.contentVersion t)
       | Threat.miscellaneous t /= bytes "www.example.com/string/\"hello\"" -> fail $
           "wrong miscellaneous (URL):\nExpected: www.example.com\nActually: " ++
           prettyBytes (Threat.miscellaneous t)
       | otherwise -> pure ()
  Right _ -> fail "wrong log type"

testTrafficB :: IO ()
testTrafficB = case decode S.traffic_8_1_B of
  Left err -> throwIO err
  Right (LogTraffic t) ->
    if | Traffic.sourceUser t /= bytes "example\\jdoe" ->
           fail $
             "wrong source user:\nexpected: " ++
             show (bytes "MY-DEVICE-NAME") ++
             "\nactually: " ++
             show (Traffic.deviceName t)
       | otherwise -> pure ()
  Right _ -> fail "wrong log type"

testC :: IO ()
testC = case decode S.threat_8_1_B of
  Left err -> throwIO err
  Right (LogThreat t) ->
    if | Threat.miscellaneous t /= bytes "www.example.com/" -> fail $
           "wrong miscellaneous (URL):\nExpected: www.example.com/\nActually: " ++
           prettyBytes (Threat.miscellaneous t) ++ "\n"
       | Threat.virtualSystemName t /= bytes "the-vsys-name" -> fail $
           "wrong vsys name:\nExpected: the-vsys-name\nActually: " ++
           prettyBytes (Threat.virtualSystemName t) ++ "\n"
       | Threat.contentVersion t /= bytes "AppThreat-3-7" -> fail $
           "wrong content version:\nExpected: AppThreat-3-7\nActually: " ++
           prettyBytes (Threat.contentVersion t) ++ "\n"
       | otherwise -> pure ()
  Right _ -> fail "wrong log type"

testD :: IO ()
testD = case decode S.threat_8_1_C of
  Left err -> throwIO err
  Right (LogThreat t) ->
    if | Threat.threatId t /= 30845 -> fail $
           "wrong threat id:\nExpected: 30845\nActually: " ++
           show (Threat.threatId t) ++ "\n"
       | Threat.threatName t /= bytes "Microsoft RPC Endpoint Mapper Detection" -> fail $
           "wrong threat name:\nExpected: Microsoft RPC Endpoint Mapper Detection\nActually: " ++
           prettyBytes (Threat.threatName t) ++ "\n"
       | otherwise -> pure ()
  Right _ -> fail "wrong log type"

testThreatD :: IO ()
testThreatD = case decode S.threat_8_1_D of
  Left err -> throwIO err
  Right (LogThreat t) ->
    if | Threat.threatName t /= bytes "Email Link" -> fail $
           "wrong threat name:\nExpected: Email Link\nActually: " ++
           prettyBytes (Threat.threatName t) ++ "\n"
       | Threat.sender t /= bytes "From: \"John Doe\" <jdoe@example.com>" ->
           fail $ "wrong sender"
       | otherwise -> pure ()
  Right _ -> fail "wrong log type"

testThreatE :: IO ()
testThreatE = case decode S.threat_8_1_E of
  Left err -> throwIO err
  Right (LogThreat t) ->
    if | Threat.threatName t /= bytes "Windows Executable" -> fail $
           "wrong threat name:\nExpected: Windows Executable\nActually: " ++
           prettyBytes (Threat.threatName t) ++ "\n"
       | otherwise -> pure ()
  Right _ -> fail "wrong log type"

testThreatF :: IO ()
testThreatF = case decode S.threat_8_1_F of
  Left err -> throwIO err
  Right (LogThreat t) ->
    if | Threat.threatName t /= bytes "Temporary TMP File" ->
           fail "wrong threat name"
       | otherwise -> pure ()
  Right _ -> fail "wrong log type"

testThreatG :: IO ()
testThreatG = case decode S.threat_8_1_G of
  Left err -> throwIO err
  Right (LogThreat t) ->
    if | Threat.threatName t /= bytes "Hypertext Preprocessor PHP File" ->
           fail "wrong threat name"
       | Threat.httpHeaders t /= bytes "contextual.media.net/" ->
           fail "wrong http headers"
       | otherwise -> pure ()
  Right _ -> fail "wrong log type"

testThreatH :: IO ()
testThreatH = case decode S.threat_8_1_H of
  Left err -> throwIO err
  Right (LogThreat t) ->
    if | Threat.threatId t /= 9999 ->
           fail "wrong threat id"
       | otherwise -> pure ()
  Right _ -> fail "wrong log type"

testThreatI :: IO ()
testThreatI = case decode S.threat_8_1_I of
  Left err -> throwIO err
  Right (LogThreat t) ->
    if | Threat.threatId t /= 320511141 ->
           fail "wrong threat id"
       | otherwise -> pure ()
  Right _ -> fail "wrong log type"

testSystemA :: IO ()
testSystemA = case decode S.system_8_1_A of
  Left err -> throwIO err
  Right (LogSystem t) ->
    if | System.deviceName t /= bytes "NY-DC-FW-2" -> fail $
           "wrong device name:\nexpected: NY-DC-FW-2\nactually: " ++
           show (System.deviceName t)
       | System.description t /= bytes
           ( concat
             [ "IKE protocol IPSec SA delete message "
             , "sent to peer. SPI:0xA1CD910F."
             ]
           ) -> fail $
             "wrong description:\nexpected something about IKE\nactually: " ++
             show (System.description t)
       | otherwise -> pure ()
  Right _ -> fail "wrong log type"


bytes :: String -> Bytes
bytes s = let b = pack s in Bytes b 0 (PM.sizeofByteArray b)

pack :: String -> ByteArray
pack = Exts.fromList . map (fromIntegral @Int @Word8 . ord)

prettyBytes :: Bytes -> String
prettyBytes (Bytes arr off len) = if len > 0
  then
    let w = PM.indexByteArray arr off :: Word8
        c = if w > 31 && w < 127
              then chr (fromIntegral w)
              else 'X'
     in c : prettyBytes (Bytes arr (off + 1) (len - 1))
  else []