-- |
-- Module      : SuiteTalk.Auth.Internal
-- Copyright   : (c) 2018 Chris D'Aloisio
--
-- License     : MPL-2.0
-- Maintainer  : chris.daloisio@bellroy.com
-- Portability : portable
--
-- Contains helpers for generating a token signature for SuiteTalk authentication
--
module SuiteTalk.Auth.Internal where

import           Crypto.Hash
import           Crypto.MAC.HMAC
import qualified Data.ByteString               as B
                                                ( intercalate )
import qualified Data.ByteString.Char8         as BS
                                                ( ByteString
                                                , pack
                                                )
import           Data.Time.Clock.POSIX          ( getPOSIXTime )
import           System.Random                  ( newStdGen )

import           SuiteTalk.Auth.Types

-- * Signature generation
--
-- | Create a Signature to be used with Netsuite SOAP requests with HMAC SHA1 algorithm
generateSignature
    :: ConsumerSecret
    -> TokenSecret
    -> Account
    -> ConsumerKey
    -> TokenId
    -> Nonce
    -> Timestamp
    -> Signature
generateSignature consumerSecret tokenSecret account consumerKey tokenId nonce timestamp
    = let
          signatureData =
              generateSignatureData account consumerKey tokenId nonce timestamp
          signatureKey = generateSignatureKey consumerSecret tokenSecret
          value        = show
              $ hmacGetDigest (hmac signatureKey signatureData :: HMAC SHA1)
      in
          Signature HMACSHA256 value

-- | Generates a random alpha-numeric string of 20 characters for the request nonce
generateNonce :: IO String
generateNonce = do
    g <- newStdGen
    let randomHash = show (hash $ BS.pack $ show g :: Digest SHA1)
    pure $ take 20 randomHash

-- | Gets the current time in seconds
getCurrentTime :: IO Timestamp
getCurrentTime = do
    currentTime <- getPOSIXTime
    pure $ round $ realToFrac currentTime

-- | Create signature key according to SuiteTalk documentation (interalating with @&@)
generateSignatureKey :: ConsumerSecret -> TokenSecret -> BS.ByteString
generateSignatureKey consumerSecret tokenSecret =
    B.intercalate "&" [BS.pack consumerSecret, BS.pack tokenSecret]

-- | Create signature data according to SuiteTalk documentation (interalating with @&@)
generateSignatureData
    :: Account -> ConsumerKey -> TokenId -> Nonce -> Timestamp -> BS.ByteString
generateSignatureData account consumerKey tokenId nonce timestamp =
    B.intercalate
        "&"
        [ BS.pack account
        , BS.pack consumerKey
        , BS.pack tokenId
        , BS.pack nonce
        , BS.pack $ show timestamp
        ]