{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CApiFFI #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE ScopedTypeVariables #-}

-- | Module: LibSodium.Bindings.Main
-- Description: Wrappers for initialisation
-- Copyright: (C) Koz Ross 2022
-- License: BSD-3-Clause
-- Maintainer: koz.ross@retro-freedom.nz
-- Stability: Stable
-- Portability: GHC only
--
-- @libsodium@ requires initialisation before use. We provide a binding to the
-- initialisation function, as well as some high-level wrappers for applications
-- to use without needing to call an FFI wrapper.
--
-- = Note
--
-- If you are using @cryptography-libsodium@ as a dependency for a library, you
-- are probably not interested in this; it's designed for application authors who
-- need capabilities provided by @cryptography-libsodium@.
module LibSodium.Bindings.Main
  ( -- * High-level wrappers
    secureMain
  , secureMainWithError

    -- * Low-level binding
  , sodiumInit
  )
where

import Data.Kind (Type)
import Foreign.C.Types (CInt (CInt))
import System.Exit (die)

-- | Initialise all security-related functionality, then perform the given
-- action. Abort with an error message if security-related functionality cannot
-- be initialised. This will also indicate failure to the shell, as with 'die'.
--
-- = Use
--
-- > main :: IO ()
-- > main = secureMain doTheThingIActuallyWant
--
-- @since 0.0.1.0
secureMain
  :: forall (a :: Type)
   . IO a
  -- ^ Action that will perform cryptographic operations
  -> IO a
secureMain :: forall a. IO a -> IO a
secureMain = IO a -> IO a -> IO a
forall a. IO a -> IO a -> IO a
secureMainWithError (String -> IO a
forall a. String -> IO a
die String
"libsodium-bindings: Could not initialise secure functionality, aborting.")

-- | Similar to 'secureMain', but allows responding to a failure of
-- initialisation.
--
-- = Use
--
-- > main :: IO ()
-- > main = secureMainWith reportErrorWithLogging doTheThingIActuallyWant
--
-- @since 0.0.1.0
secureMainWithError
  :: forall (a :: Type)
   . IO a
  -- ^ Code to execute if there is an initialisation failure.
  -> IO a
  -- ^ Action that will perform cryptographic operations after libsodium is initialised.
  -> IO a
secureMainWithError :: forall a. IO a -> IO a -> IO a
secureMainWithError IO a
badPath IO a
goodPath = do
  !CInt
res <- IO CInt
sodiumInit
  if CInt
res CInt -> CInt -> Bool
forall a. Eq a => a -> a -> Bool
== (-CInt
1) then IO a
badPath else IO a
goodPath

-- | Initialise @libsodium@ for future use. This only needs to be called once,
-- before any use of any other functionality, but multiple calls to this
-- function are not harmful (just redundant).
--
-- /See:/ [sodium_init()](https://doc.libsodium.org/usage)
--
-- @since 0.0.1.0
foreign import capi "sodium.h sodium_init"
  sodiumInit
    :: IO CInt
    -- ^ 0 if successful, -1 on failure, 1 on repeat calls