{-# 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 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 Data.Functor import Data.Maybe import qualified Data.Text.Encoding as T import qualified Data.Text.IO as T import Data.Traversable import qualified Data.Yaml as Y import Encrypted import System.Exit import System.IO.Error import Text.Printf import Prelude hiding (filter) 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 j filts -> (Nothing <$) . viewVault l j 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 ()