packages feed

hail-0.1.0.0: Hail/Netrc.hs

{-# LANGUAGE LambdaCase #-}
module Hail.Netrc (loadCredsFromNetrc) where

import Control.Monad (join)
import Data.Foldable (find)
import Data.Maybe (fromMaybe)
import System.IO.Error (tryIOError)

import Network.NetRc
import Network.URI
import Network.Wreq (basicAuth, Auth)
import Text.Parsec.Error (ParseError)
import Data.ByteString.Char8 as BS (null, pack)
import Text.Parsec.ByteString (parseFromFile)
import Control.Lens.Operators

-- | Load credentials for a given URI from the netrc file.
--
-- Users of this function cannot distinguish a missing/malformed
-- netrc file from one without an entry for their URI.
loadCredsFromNetrc
  :: Maybe FilePath -- ^ The path to the netrc file.
                    --
                    -- Defaults to "/etc/netrc".
  -> String         -- ^ The URI to look up.
  -> IO (Maybe Auth)
loadCredsFromNetrc m_file uri =
    (tryIOError $ loadCredsFromFile file uri) <&> \case
      Right (Right m_auth) -> m_auth
      _ -> Nothing
  where
    file = fromMaybe "/etc/netrc" m_file

-- | Load credentials for a given URI from a given file.
loadCredsFromFile
  :: FilePath
  -> String -- ^ The URI to look up.
  -> IO (Either ParseError (Maybe Auth))
loadCredsFromFile file uri = lookupAuthInNetrc uri <$$> netrc
  where
    netrc = parseFromFile netRcParsec file
    -- This belongs somewhere else...
    (<$$>) = fmap . fmap

-- | Find credentials for a given URI in a 'NetRc'.
lookupAuthInNetrc
  :: String -- ^ The URI to look up.
  -> NetRc
  -> Maybe Auth
lookupAuthInNetrc uri rc =
    basicAuth <$> nrhLogin <*> nrhPassword <$> m_rcHost
  where
    -- Extract the authority from the URI
    m_authority = join $ uriAuthority <$> parseURI uri
    -- Extract the reg name from the authority
    m_regName = uriRegName <$> m_authority
    -- Predicate determining if a 'NetRcHost' matches a regName
    nameMatch regName (NetRcHost nm _ _ _ _) =
      -- A 'null' name means the default entry
      nm == regName || BS.null nm
    -- Find a matching rcHost based on the regName
    m_rcHost = case m_regName of
      Nothing -> Nothing
      Just regName -> find (nameMatch $ pack regName) $ nrHosts rc