rofi-extras/app/pinentry-rofi.hs

104 lines
3.1 KiB
Haskell
Raw Normal View History

2021-06-25 23:42:29 -04:00
--------------------------------------------------------------------------------
2023-02-13 22:19:49 -05:00
-- rofi-pinentry - a simply pinentry proxy for bitwarden
2021-06-25 23:42:29 -04:00
--
-- Rather than prompt the user like all the other pinentry programs, call the
-- bitwarden deamon and prompt for a password there
module Main where
2023-02-13 22:19:49 -05:00
import Bitwarden.Internal
import qualified Data.Text.IO as TI
import Data.Yaml
import RIO
2023-02-22 22:44:44 -05:00
import RIO.Directory
2023-02-13 22:19:49 -05:00
import qualified RIO.List as L
import qualified RIO.Text as T
import System.FilePath.Posix
import System.Posix.Process
2023-02-22 22:44:44 -05:00
import UnliftIO.Environment
2021-06-25 23:42:29 -04:00
main :: IO ()
2023-02-22 22:44:44 -05:00
main = runSimpleApp $ do
2021-06-26 16:09:49 -04:00
hSetBuffering stdout LineBuffering
2023-02-22 22:44:44 -05:00
logInfo "OK Pleased to meet you"
pinentryLoop =<< readPinConf
2023-02-13 23:31:50 -05:00
newtype PinConf = PinConf {pcBwName :: T.Text} deriving (Eq, Show)
instance FromJSON PinConf where
parseJSON (Object o) = PinConf <$> o .:? "bitwarden-name" .!= "gnupg"
2023-02-13 22:19:49 -05:00
parseJSON _ = fail "pinentry yaml parse error"
2023-02-22 22:44:44 -05:00
readPinConf :: RIO SimpleApp PinConf
readPinConf = do
2023-02-22 22:44:44 -05:00
c <- liftIO . decodeFileEither =<< pinConfDir
case c of
2023-02-22 22:44:44 -05:00
Left e -> do
logError $ displayShow e
exitWith (ExitFailure 1)
Right r -> return r
2023-02-22 22:44:44 -05:00
pinConfDir :: RIO SimpleApp FilePath
pinConfDir = maybe defHome (return . (</> confname)) =<< lookupEnv "GNUPGHOME"
where
defHome = (</> ".gnupg" </> confname) <$> getHomeDirectory
confname = "pinentry-rofi.yml"
2021-06-25 23:42:29 -04:00
2023-02-22 22:44:44 -05:00
pinentryLoop :: PinConf -> RIO SimpleApp ()
pinentryLoop p = do
2023-02-22 22:44:44 -05:00
processLine p . T.words =<< liftIO TI.getLine
pinentryLoop p
2021-06-25 23:42:29 -04:00
2023-02-22 22:44:44 -05:00
processLine :: PinConf -> [T.Text] -> RIO SimpleApp ()
2023-02-13 22:19:49 -05:00
processLine _ [] = noop
processLine _ ["BYE"] = exitSuccess
processLine p ["GETPIN"] = getPin p
processLine _ ["GETINFO", o] = processGetInfo o
2021-06-25 23:42:29 -04:00
-- TODO this might be important
2023-02-13 22:19:49 -05:00
processLine _ ["OPTION", o] = processOption o
2021-06-26 16:09:49 -04:00
-- these should all do nothing
2023-02-13 22:19:49 -05:00
processLine _ ("SETDESC" : _) = noop
processLine _ ("SETOK" : _) = noop
processLine _ ("SETNOTOK" : _) = noop
processLine _ ("SETCANCEL" : _) = noop
processLine _ ("SETPROMPT" : _) = noop
processLine _ ("SETERROR" : _) = noop
2021-06-25 23:42:29 -04:00
-- CONFIRM can take a flag
2023-02-13 22:19:49 -05:00
processLine _ ["CONFIRM"] = noop
processLine _ ["CONFIRM", "--one-button", _] = noop
2023-02-13 22:19:49 -05:00
processLine _ ss = unknownCommand $ T.unwords ss
2021-06-25 23:42:29 -04:00
2023-02-22 22:44:44 -05:00
unknownCommand :: T.Text -> RIO SimpleApp ()
unknownCommand c = putStrLnT $ T.append "ERR 275 Unknown command " c
2021-06-25 23:42:29 -04:00
2023-02-22 22:44:44 -05:00
getPin :: PinConf -> RIO SimpleApp ()
getPin p = do
2021-06-25 23:57:37 -04:00
its <- getItems
2023-02-13 23:31:50 -05:00
let w = (password . login) =<< L.find (\i -> pcBwName p == name i) its
maybe err send w
2021-06-25 23:57:37 -04:00
where
2023-02-22 22:44:44 -05:00
err = putStrLnT "ERR 83886179 Operation canceled <rofi>"
2021-06-26 16:09:49 -04:00
-- these are the only supported options for GETINFO; anything else is an error
2023-02-22 22:44:44 -05:00
processGetInfo :: T.Text -> RIO SimpleApp ()
processGetInfo "pid" = send . T.pack . show =<< liftIO getProcessID
2021-06-26 16:09:49 -04:00
processGetInfo "version" = noop
2023-02-13 22:19:49 -05:00
processGetInfo "flavor" = noop
2021-06-26 16:09:49 -04:00
processGetInfo "ttyinfo" = noop
2023-02-22 22:44:44 -05:00
processGetInfo _ = putStrLnT "ERR 83886360 IPC parameter error <rofi>"
2021-06-25 23:42:29 -04:00
2023-02-22 22:44:44 -05:00
processOption :: T.Text -> RIO SimpleApp ()
2021-06-26 16:09:49 -04:00
processOption _ = noop
2023-02-22 22:44:44 -05:00
send :: T.Text -> RIO SimpleApp ()
send s = putStrLnT (T.append "D " s) >> ok
2021-06-25 23:42:29 -04:00
2023-02-22 22:44:44 -05:00
noop :: RIO SimpleApp ()
2021-06-25 23:42:29 -04:00
noop = ok
2023-02-22 22:44:44 -05:00
ok :: RIO SimpleApp ()
ok = putStrLnT "OK"
putStrLnT :: MonadIO m => T.Text -> m ()
putStrLnT = liftIO . TI.putStrLn