{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveFoldable #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE UndecidableInstances #-} module StrongSwan.SQL.Types where import Control.Exception (Exception, throw) import Data.ASN1.Types (ASN1) import Data.ByteString.Char8 (ByteString, pack, unpack) import Data.Default (Default(..)) import Data.IP (IP(..), IPv4, IPv6, fromIPv4, toIPv4, fromIPv6b, toIPv6b) import Data.Text (Text) import Data.Typeable (Typeable) import Data.Word (Word8, Word16, Word32) import Network.Socket (PortNumber) import qualified Data.ByteString as B import qualified Data.Text as T import qualified Database.MySQL.Base as SQL data Error = UnknownCharacterEncoding Int | UnknownSAMode Int | UnknownSAAction Int | UnknownCertPolicy Int | UnknownAuthMethod Int | UnknownEAPType Int | UnknownTrafficSelectorType Int | UnknownTrafficSelectorKind Int | UnknownSharedSecretType Int | InvalidValueForType String String | SQLValuesMismatch String String | NotFound Text | MultipleResults Text String | FailedOperation Text deriving (Typeable, Show) instance Exception Error data Result a = Result { lastModifiedKey :: a, response :: SQL.OK } data MySQLCharacterEncoding = UTF8MB4 -- ^ utf8mb4_unicode_ci | UTF8 -- ^ utf8_general_ci | UCS2 -- ^ ucs2_general_ci | UTF16 -- ^ utf16_general_ci | UTF16LE -- ^ utf16le_general_ci | UTF32 -- ^ utf32_general_ci deriving Show instance Enum MySQLCharacterEncoding where fromEnum UTF8MB4 = 224 fromEnum UTF8 = 33 fromEnum UCS2 = 35 fromEnum UTF16 = 54 fromEnum UTF16LE = 56 fromEnum UTF32 = 60 toEnum 224 = UTF8MB4 toEnum 33 = UTF8 toEnum 35 = UCS2 toEnum 54 = UTF16 toEnum 56 = UTF16LE toEnum 60 = UTF32 toEnum x = throw $ UnknownCharacterEncoding x data Identity = AnyID (Maybe Int) -- Matches any ID (/%any/) | IPv4AddrID (Maybe Int) IPv4 -- IPv4 Address | NameID (Maybe Int) Text -- Fully qualified Domain Name | EmailID (Maybe Int) Text Text -- ^ RFC 822 Email Address /mailbox/@/domain/ | IPv6AddrID (Maybe Int) IPv6 -- IPv6 Address | ASN1ID (Maybe Int) [ASN1] -- DER encoded ASN.1 distinguished name | OpaqueID (Maybe Int) ByteString -- Opaque octet string as ID deriving (Eq) instance Show Identity where show (AnyID iD) = "%any (" ++ show iD ++ ")" show (IPv4AddrID iD ipv4) = "ipv4: " ++ show ipv4 ++ " (" ++ show iD ++ ")" show (NameID iD name) = "fqdn: " ++ T.unpack name ++ " (" ++ show iD ++ ")" show (EmailID iD mbox domain) = "email: " ++ T.unpack mbox ++ '@':T.unpack domain ++ " (" ++ show iD ++ ")" show (IPv6AddrID iD ipv6) = "ipv6: " ++ show ipv6 ++ " (" ++ show iD ++ ")" show (ASN1ID iD asn1s) = "asn1: " ++ show asn1s ++ " (" ++ show iD ++ ")" show (OpaqueID iD bytes) = "opaque:" ++ unpack bytes ++ " (" ++ show iD ++ ")" getIdentityId :: Identity -> Maybe Int getIdentityId (AnyID iD) = iD getIdentityId (IPv4AddrID iD _) = iD getIdentityId (NameID iD _) = iD getIdentityId (EmailID iD _ _) = iD getIdentityId (IPv6AddrID iD _) = iD getIdentityId (ASN1ID iD _) = iD getIdentityId (OpaqueID iD _) = iD setIdentityId :: Identity -> Int -> Identity setIdentityId (AnyID _) iD = AnyID (Just iD) setIdentityId (IPv4AddrID _ x) iD = IPv4AddrID (Just iD) x setIdentityId (NameID _ x) iD = NameID (Just iD) x setIdentityId (EmailID _ x y) iD = EmailID (Just iD) x y setIdentityId (IPv6AddrID _ x) iD = IPv6AddrID (Just iD) x setIdentityId (ASN1ID _ x) iD = ASN1ID (Just iD) x setIdentityId (OpaqueID _ x) iD = OpaqueID (Just iD) x instance Default Identity where def = AnyID Nothing data Value (a :: k -> SQL.MySQLValue) where TinyInt :: Word8 -> Value 'SQL.MySQLInt8U SmallInt :: Word16 -> Value 'SQL.MySQLInt16U IntWord32 :: Word32 -> Value 'SQL.MySQLInt32U VarBinary :: ByteString -> Value 'SQL.MySQLBytes VarChar :: Text -> Value 'SQL.MySQLText NullChar :: Value 'SQL.MySQLText class TinyInt a where toTinyInt :: a -> Value 'SQL.MySQLInt8U fromTinyInt :: Value 'SQL.MySQLInt8U -> a instance TinyInt Bool where toTinyInt False = TinyInt 0 toTinyInt True = TinyInt 1 fromTinyInt (TinyInt 0) = False fromTinyInt (TinyInt _) = True instance TinyInt Word8 where toTinyInt = TinyInt fromTinyInt (TinyInt x) = x toSQLEnum :: (Enum a) => a -> Value 'SQL.MySQLInt8U toSQLEnum = TinyInt . fromIntegral . fromEnum fromSQLEnum :: (Enum a) => Value 'SQL.MySQLInt8U -> a fromSQLEnum (TinyInt x) = toEnum $ fromIntegral x instance TinyInt SAAction where toTinyInt = toSQLEnum fromTinyInt = fromSQLEnum instance TinyInt SAMode where toTinyInt = toSQLEnum fromTinyInt = fromSQLEnum instance TinyInt CertPolicy where toTinyInt = toSQLEnum fromTinyInt = fromSQLEnum instance TinyInt AuthMethod where toTinyInt = toSQLEnum fromTinyInt = fromSQLEnum instance TinyInt EAPType where toTinyInt = toSQLEnum fromTinyInt = fromSQLEnum instance TinyInt TrafficSelectorType where toTinyInt = toSQLEnum fromTinyInt = fromSQLEnum instance TinyInt TrafficSelectorKind where toTinyInt = toSQLEnum fromTinyInt = fromSQLEnum instance TinyInt SharedSecretType where toTinyInt = toSQLEnum fromTinyInt = fromSQLEnum class SmallInt a where toSmallInt :: a -> Value 'SQL.MySQLInt16U fromSmallInt :: Value 'SQL.MySQLInt16U -> a instance SmallInt Word16 where toSmallInt = SmallInt fromSmallInt (SmallInt x) = x instance SmallInt PortNumber where toSmallInt = SmallInt . fromIntegral fromSmallInt (SmallInt x) = fromIntegral x class IntWord32 a where toInt :: a -> Value 'SQL.MySQLInt32U fromInt :: Value 'SQL.MySQLInt32U -> a instance (Integral n) => IntWord32 n where toInt = IntWord32 . fromIntegral fromInt (IntWord32 x) = fromIntegral x class VarChar a where toVarChar :: Maybe a -> Value 'SQL.MySQLText fromVarChar :: Value 'SQL.MySQLText -> Maybe a instance VarChar Text where toVarChar Nothing = NullChar toVarChar (Just text) = VarChar text fromVarChar (VarChar text) = Just text fromVarChar NullChar = Nothing class VarBinary a where toVarBinary :: a -> Value 'SQL.MySQLBytes fromVarBinary :: Value 'SQL.MySQLBytes -> a instance VarBinary String where toVarBinary = VarBinary . pack fromVarBinary (VarBinary bytes) = unpack bytes instance VarBinary Text where toVarBinary = VarBinary . pack . T.unpack fromVarBinary (VarBinary bytes) = T.pack $ unpack bytes instance VarBinary ByteString where toVarBinary = VarBinary fromVarBinary (VarBinary bytes) = bytes instance VarBinary IPv4 where toVarBinary = VarBinary . B.pack . fmap fromIntegral . fromIPv4 fromVarBinary (VarBinary bytes) = toIPv4 . fmap fromIntegral $ B.unpack bytes instance VarBinary IPv6 where toVarBinary = VarBinary . B.pack . fmap fromIntegral . fromIPv6b fromVarBinary (VarBinary bytes) = toIPv6b . fmap fromIntegral $ B.unpack bytes instance VarBinary IP where toVarBinary (IPv4 addr) = toVarBinary addr toVarBinary (IPv6 addr) = toVarBinary addr fromVarBinary value@(VarBinary bytes) | B.length bytes == 4 = IPv4 $ fromVarBinary value | otherwise = IPv6 $ fromVarBinary value data SAMode = Transport | Tunnel | Beet | Pass | Drop deriving (Eq, Show) instance Enum SAMode where fromEnum Transport = 1 fromEnum Tunnel = 2 fromEnum Beet = 3 fromEnum Pass = 4 fromEnum Drop = 5 toEnum 1 = Transport toEnum 2 = Tunnel toEnum 3 = Beet toEnum 4 = Pass toEnum 5 = Drop toEnum x = throw $ UnknownSAMode x data SAAction = None | Route | Restart deriving (Eq, Show) instance Enum SAAction where fromEnum None = 0 fromEnum Route = 1 fromEnum Restart = 2 toEnum 0 = None toEnum 1 = Route toEnum 2 = Restart toEnum x = throw $ UnknownSAAction x data CertPolicy = AlwaysSend | SendIfAsked | NeverSend deriving (Eq, Show) instance Enum CertPolicy where fromEnum AlwaysSend = 0 fromEnum SendIfAsked = 1 fromEnum NeverSend = 2 toEnum 0 = AlwaysSend toEnum 1 = SendIfAsked toEnum 2 = NeverSend toEnum x = throw $ UnknownCertPolicy x data AuthMethod = AnyAuth | PubKey | PSK | EAP | XAUTH deriving (Eq, Show) instance Enum AuthMethod where fromEnum AnyAuth = 0 fromEnum PubKey = 1 fromEnum PSK = 2 fromEnum EAP = 3 fromEnum XAUTH = 4 toEnum 0 = AnyAuth toEnum 1 = PubKey toEnum 2 = PSK toEnum 3 = EAP toEnum 4 = XAUTH toEnum x = throw $ UnknownAuthMethod x data EAPType = EAPUnspecified | EAPMD5 | EAPGTC | EAPTLS | EAPSIM | EAPTTLS | EAPAKA | EAPMSCHAPV2 | EAPTNC | EAPRADIUS deriving (Eq, Show) instance Enum EAPType where fromEnum EAPUnspecified = 0 fromEnum EAPMD5 = 4 fromEnum EAPGTC = 6 fromEnum EAPTLS = 13 fromEnum EAPSIM = 18 fromEnum EAPTTLS = 21 fromEnum EAPAKA = 23 fromEnum EAPMSCHAPV2 = 26 fromEnum EAPTNC = 38 fromEnum EAPRADIUS = 253 toEnum 0 = EAPUnspecified toEnum 4 = EAPMD5 toEnum 6 = EAPGTC toEnum 13 = EAPTLS toEnum 18 = EAPSIM toEnum 21 = EAPTTLS toEnum 23 = EAPAKA toEnum 26 = EAPMSCHAPV2 toEnum 38 = EAPTNC toEnum 253 = EAPRADIUS toEnum x = throw $ UnknownEAPType x data TrafficSelectorType = IPv4AddrRange | IPv6AddrRange deriving (Eq, Show) instance Enum TrafficSelectorType where fromEnum IPv4AddrRange = 7 fromEnum IPv6AddrRange = 8 toEnum 7 = IPv4AddrRange toEnum 8 = IPv6AddrRange toEnum x = throw $ UnknownTrafficSelectorType x data TrafficSelectorKind = LocalTS | RemoteTS | LocalDynamicTS | RemoteDynamicTS deriving (Eq, Show) instance Enum TrafficSelectorKind where fromEnum LocalTS = 0 fromEnum RemoteTS = 1 fromEnum LocalDynamicTS = 2 fromEnum RemoteDynamicTS = 3 toEnum 0 = LocalTS toEnum 1 = RemoteTS toEnum 2 = LocalDynamicTS toEnum 3 = RemoteDynamicTS toEnum x = throw $ UnknownTrafficSelectorKind x data SharedSecretType = SharedIKE | SharedEAP | SharedRSA | SharedPIN deriving (Eq, Show) instance Enum SharedSecretType where fromEnum SharedIKE = 1 fromEnum SharedEAP = 2 fromEnum SharedRSA = 3 fromEnum SharedPIN = 4 toEnum 1 = SharedIKE toEnum 2 = SharedEAP toEnum 3 = SharedRSA toEnum 4 = SharedPIN toEnum x = throw $ UnknownSharedSecretType x instance Bounded SharedSecretType where minBound = SharedIKE maxBound = SharedPIN data IKEConfig = IKEConfig { _ikeId :: Maybe Int, _ikeReqCert :: Bool, _ikeForceEncap :: Bool, _ikeLocalAddress :: Text, _ikeRemoteAddress :: Text } deriving (Eq, Show) instance Default IKEConfig where def = IKEConfig { _ikeId = Nothing, _ikeReqCert = True, _ikeForceEncap = False, _ikeLocalAddress = "0.0.0.0", _ikeRemoteAddress = "0.0.0.0" } data ChildSAConfig = ChildSAConfig { _childSAId :: Maybe Int, _childSAName :: Text, _childSALifeTime :: Word32, _childSARekeyTime :: Word32, _childSAJitter :: Word32, _childSAUpDown :: Maybe Text, _childSAHostAccess :: Bool, _childSAMode :: SAMode, _childSAStartAction :: SAAction, _childSADPDAction :: SAAction, _childSACloseAction :: SAAction, _childSAIPCompression :: Bool, _childSAReqID :: Word32, _childSAMark :: Maybe Text } deriving (Eq, Show) instance Default ChildSAConfig where def = ChildSAConfig { _childSAId = Nothing, _childSAName = "", _childSALifeTime = 1500, _childSARekeyTime = 1200, _childSAJitter = 60, _childSAUpDown = Nothing, _childSAHostAccess = False, _childSAMode = Tunnel, _childSAStartAction = None, _childSADPDAction = None, _childSACloseAction = None, _childSAIPCompression = False, _childSAReqID = 0, _childSAMark = Nothing } data PeerConfig = PeerConfig { _peerCfgId :: Maybe Int, _peerCfgName :: Text, _peerCfgIKEVersion :: Word8, _peerCfgIKEConfigId :: Maybe Int, _peerCfgLocalId :: Maybe Int, _peerCfgRemoteId :: Maybe Int, _peerCfgCertPolicy :: CertPolicy, _peerCfgUniqueIds :: Bool, _peerCfgAuthMethod :: AuthMethod, _peerCfgEAPType :: EAPType, _peerCfgEAPVendor :: Word16, _peerCfgKeyingTries :: Word8, _peerCfgRekeyTime :: Word32, _peerCfgReauthTime :: Word32, _peerCfgJitter :: Word32, _peerCfgOverTime :: Word32, _peerCfgMobike :: Bool, _peerCfgDPDDelay :: Word32, _peerCfgVirtual :: Maybe Text, _peerCfgPool :: Maybe Text, _peerCfgMediation :: Bool, _peerCfgMediatedBy :: Int, _peerCfgPeerId :: Int } deriving (Eq, Show) instance Default PeerConfig where def = PeerConfig { _peerCfgId = Nothing, _peerCfgName = "", _peerCfgIKEVersion = 2, _peerCfgIKEConfigId = Nothing, _peerCfgLocalId = Nothing, _peerCfgRemoteId = Nothing, _peerCfgCertPolicy = SendIfAsked, _peerCfgUniqueIds = True, _peerCfgAuthMethod = PubKey, _peerCfgEAPType = EAPUnspecified, _peerCfgEAPVendor = 0, _peerCfgKeyingTries = 3, _peerCfgRekeyTime = 7200, _peerCfgReauthTime = 0, _peerCfgJitter = 180, _peerCfgOverTime = 300, _peerCfgMobike = True, _peerCfgDPDDelay = 120, _peerCfgVirtual = Nothing, _peerCfgPool = Nothing, _peerCfgMediation = False, _peerCfgMediatedBy = 0, _peerCfgPeerId = 0 } data Peer2ChildConfig = Peer2ChildConfig { p2cPeerCfgId :: Int, p2cChildCfgId :: Int } deriving Show data TrafficSelector = TrafficSelector { _tsId :: Maybe Int, _tsType :: TrafficSelectorType, _tsProtocol :: Word16, _tsStartAddr :: IP, _tsEndAddr :: IP, _tsStartPort :: PortNumber, _tsEndPort :: PortNumber } deriving (Eq, Show) instance Default TrafficSelector where def = TrafficSelector { _tsId = Nothing, _tsType = IPv4AddrRange, _tsProtocol = 0, _tsStartAddr = "0.0.0.0", _tsEndAddr = "255.255.255.255", _tsStartPort = 0, _tsEndPort = 65535 } data Child2TSConfig = Child2TSConfig { c2tsChildCfgId :: Int, c2tsTrafficSelectorCfgId :: Int, c2tsTrafficSelectorKind :: TrafficSelectorKind } deriving Show data SharedSecret = SharedSecret { _ssId :: Maybe Int, _ssType :: SharedSecretType, _ssData :: ByteString } deriving Show instance Default SharedSecret where def = SharedSecret Nothing SharedIKE "" data SharedSecretIdentity = SharedSecretIdentity { _sharedSecretId :: Int, _identityId :: Int } data PreparedStatements a = PreparedStatements { updateChildSAStmt :: a, createChildSAStmt :: a, findChildSAStmt :: a, findChildSAByNameStmt :: a, deleteChildSAStmt :: a, updateIKEStmt :: a, createIKEStmt :: a, findIKEStmt :: a, deleteIKEStmt :: a, updatePeerStmt :: a, createPeerStmt :: a, findPeerStmt :: a, findPeerByNameStmt :: a, deletePeerStmt :: a, updateP2CStmt :: a, createP2CStmt :: a, findP2CStmt :: a, deleteP2CStmt :: a, updateTSStmt :: a, createTSStmt :: a, findTSStmt :: a, deleteTSStmt :: a, updateC2TSStmt :: a, createC2TSStmt :: a, findC2TSStmt :: a, deleteC2TSStmt :: a, updateIdentityStmt :: a, createIdentityStmt :: a, findIdentityStmt :: a, findIdentityBySelfStmt :: a, deleteIdentityStmt :: a, updateSharedSecretStmt :: a, createSharedSecretStmt :: a, findSharedSecretStmt :: a, deleteSharedSecretStmt :: a, updateSSIdentityStmt :: a, createSSIdentityStmt :: a, findSSIdentityStmt :: a, deleteSSIdentityStmt :: a, createIPSecStmt :: a, findIPSecStmt :: a, deleteIPSecStmt :: a } deriving (Show, Functor, Foldable) -- | The managed IPsec configuration type encompasses a complete set of elements which are pushed and interlinked -- as necessary by the /Managed/ API (see above). Note that there are lenses available to facilitate accessing all -- these fields (see "StrongSwan.SQL.Lenses") data IPSecSettings = IPSecSettings { _getIPSecCfgName :: Text, _getIKEConfig :: IKEConfig, _getChildSAConfig :: ChildSAConfig, _getPeerConfig :: PeerConfig, _getLocalTrafficSelector :: TrafficSelector, _getRemoteTrafficSelector :: TrafficSelector, _getLocalIdentity :: Identity, _getRemoteIdentity :: Identity } deriving (Eq, Show) instance Default IPSecSettings where def = IPSecSettings "" def def def def def def def