{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
import Authenticator.Actions
import Authenticator.Options
import Authenticator.Vault
import Control.Exception
import Control.Monad
import Data.Functor
import Data.Maybe
import Data.Traversable
import Encrypted
import Prelude hiding (filter)
import System.Exit
import System.IO.Error
import Text.Printf
import qualified Crypto.Gpgme as G
import qualified Data.Aeson as J
import qualified Data.Binary as B
import qualified Data.ByteString.Lazy as BSL
import qualified Data.Text.Encoding as T
import qualified Data.Text.IO as T
import qualified Data.Yaml as Y
main :: IO ()
main = G.withCtx "~/.gnupg" "C" G.OpenPGP $ \ctx -> do
(cmd, echoPass, vault, fingerprint) <- getOptions
k <- for fingerprint $ \fing -> G.getKey ctx fing G.NoSecret >>= \case
Nothing -> do
printf "No key found for fingerprint %s!\n" (T.decodeUtf8 fing)
exitFailure
Just k' -> return k'
(e, mkNewVault) <- ((,False) <$> B.decodeFile @(Enc Vault) vault) `catch` \e ->
if isDoesNotExistError e
then case (,) <$> k <*> fingerprint of
Nothing -> do
putStrLn "No vault found; please try again with a fingerprint to create new vault."
exitFailure
Just (k', fing) -> do
printf "No vault found; generating new vault with fingerprint %s ...\n" $
T.decodeUtf8 fing
(,True) <$> mkEnc ctx k' (Vault [])
else throwIO e
e' <- case cmd of
View l filts -> (Nothing <$) . viewVault l filts =<< getEnc ctx e
Add u -> case k of
Nothing -> do
putStrLn "Adding a key requires a fingerprint."
exitFailure
Just k' -> Just <$> overEnc ctx k' e (addSecret echoPass u)
Gen n -> do
vtmsg <- genSecret n =<< getEnc ctx e
forM vtmsg $ \(s, vt) -> case k of
Nothing -> do
putStrLn "Generating a counter-based (HOTP) key requires a fingerprint."
exitFailure
Just k' -> do
putStrLn s
mkEnc ctx k' vt
Edit n -> case k of
Nothing -> do
putStrLn "Editing keys requires a fingerprint."
exitFailure
Just k' -> Just <$> overEnc ctx k' e (editSecret n)
Delete n -> case k of
Nothing -> do
putStrLn "Deleting keys requires a fingerprint."
exitFailure
Just k' -> Just <$> overEnc ctx k' e (deleteSecret n)
Dump t -> getEnc ctx e >>= \vt -> do
T.putStrLn . T.decodeUtf8 $ case t of
DTJSON -> BSL.toStrict $ J.encode vt
DTYaml -> Y.encode vt
return Nothing
case e' of
Just changed -> B.encodeFile vault changed
Nothing | mkNewVault -> B.encodeFile vault e
| otherwise -> return ()