liboath-hs-0.0.1.0: src/LibOath/Internal.hs
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-|
Module : LibOath.Internal
Description : Exports the C code functions. Use at your own risk!
Copyright : (c) Matt Parsons, 2017
License : GPL-3
Maintainer : parsonsmatt@gmail.com
Stability : experimental
Portability : POSIX
This module contains the C functions called via "inline-c". Import these to use at your own risk.
The functions are undocumented here. They are mirrored from <http://www.nongnu.org/oath-toolkit/liboath-api/liboath-oath.html the library documentation>.
-}
module LibOath.Internal where
import Data.Monoid ((<>))
import Data.ByteString (ByteString)
import Control.Monad.IO.Class (MonadIO)
import Data.Maybe (fromMaybe)
import qualified Foreign.C.String as C
import Foreign.Ptr (Ptr)
import GHC.Stack (HasCallStack)
import qualified Language.C.Inline as C
C.context (C.baseCtx <> C.bsCtx)
C.include "<liboath/oath.h>"
-- Haskell utilities
-- | The type of @liboath@ actions. This is a wrapper over 'IO' that we use
-- to help use the library safely. The library needs to be initialized and
-- finalized. The 'run' method provided in 'LibOath' handles unwrapping
-- this type safely.
newtype Action a = Action { unAction :: IO a }
deriving (Functor, Applicative, Monad, MonadIO)
-- | The type of errors returned by the @liboath@ library. Technically
-- speaking, this is the Haskell representation of the @oath_rc@ type
-- defined in @liboath/oath.h.in@, which is why it includes the 'OK'
-- constructor. The 'OK' constructor will never be returned in an error
-- case.
data Error
= OK -- ^ This will never be returned as an error.
| CryptoError
| InvalidDigits
| PrintfError
| InvalidHex
| TooSmallBuffer
| InvalidOtp
| ReplayedOtp
| BadPassword
| InvalidCounter
| InvalidTimestamp
| NoSuchFile
| UnknownUser
| FileSeekError
| FileCreateError
| FileLockError
| FileRenameError
| FileUnlinkError
| TimeError
| StrcmpError
| InvalidBase32
| Base32Overflow
| MallocError
| FileFlushError
| FileSyncError
| FileCloseError
| UnknownError
deriving (Eq, Show)
-- | A type representing 'Base32' encoded 'ByteString's.
newtype Base32 = UnsafeBase32 { unBase32 :: ByteString }
deriving (Eq, Ord, Show)
pattern Base32 a = UnsafeBase32 a
-- | This function should only be called with the return value of @liboath@
-- library calls.
fromCInt :: C.CInt -> Error
fromCInt i = case i of
0 -> OK
-1 -> CryptoError
-2 -> InvalidDigits
-3 -> PrintfError
-4 -> InvalidHex
-5 -> TooSmallBuffer
-6 -> InvalidOtp
-7 -> ReplayedOtp
-8 -> BadPassword
-9 -> InvalidCounter
-10 -> InvalidTimestamp
-11 -> NoSuchFile
-12 -> UnknownUser
-13 -> FileSeekError
-14 -> FileCreateError
-15 -> FileLockError
-16 -> FileRenameError
-17 -> FileUnlinkError
-18 -> TimeError
-19 -> StrcmpError
-20 -> InvalidBase32
-21 -> Base32Overflow
-22 -> MallocError
-23 -> FileFlushError
-24 -> FileSyncError
-25 -> FileCloseError
_ -> UnknownError
-- C Bindings
_OATH_OK :: C.CInt
_OATH_OK = 0
oath_init :: IO C.CInt
oath_init = [C.exp|int { oath_init() }|]
oath_done :: IO C.CInt
oath_done = [C.exp|int { oath_done() }|]
oath_check_version :: ByteString -> IO C.CString
oath_check_version minVersion =
[C.exp|const char * { oath_check_version($bs-ptr:minVersion) }|]
oath_strerror :: C.CInt -> IO C.CString
oath_strerror err = [C.exp|const char * { oath_strerror($(int err)) }|]
oath_base32_decode :: C.CString -> C.CSize -> Ptr C.CString -> Ptr C.CSize -> IO C.CInt
oath_base32_decode in_ inlen out outlen =
[C.exp|int {
oath_base32_decode($(const char * in_), $(size_t inlen), $(char ** out), $(size_t * outlen))
}|]
oath_base32_encode :: C.CString -> C.CSize -> Ptr C.CString -> Ptr C.CSize -> IO C.CInt
oath_base32_encode in_ inlen out outlen =
[C.exp|int {
oath_base32_encode($(const char * in_), $(size_t inlen), $(char ** out), $(size_t * outlen))
}|]
oath_totp_generate
:: C.CString -> C.CSize -> C.CTime -> C.CUInt -> C.CTime -> C.CUInt -> C.CString -> IO C.CInt
oath_totp_generate secret secretLen now timeStepSize startOffset digits outputOtp =
[C.exp|int {
oath_totp_generate(
$(const char * secret),
$(size_t secretLen),
$(time_t now),
$(unsigned int timeStepSize),
$(time_t startOffset),
$(unsigned int digits),
$(char * outputOtp)
)
}|]