module XMonad.Prompt.Pass
(
passPrompt
, passTypePrompt
, passEditPrompt
, passRemovePrompt
, passGeneratePrompt
, passGenerateAndCopyPrompt
, passOTPPrompt
) where
import System.Directory (getHomeDirectory)
import System.FilePath (combine, dropExtension, takeExtension)
import System.Posix.Env (getEnv)
import XMonad.Core
import XMonad.Prompt ( XPrompt
, showXPrompt
, commandToComplete
, nextCompletion
, getNextCompletion
, XPConfig
, mkXPrompt
, searchPredicate)
import XMonad.Util.Run (runProcessWithInput)
type Predicate = String -> String -> Bool
getPassCompl :: [String] -> Predicate -> String -> IO [String]
getPassCompl :: [String] -> Predicate -> String -> IO [String]
getPassCompl [String]
compls Predicate
p String
s = [String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return ([String] -> IO [String]) -> [String] -> IO [String]
forall a b. (a -> b) -> a -> b
$ (String -> Bool) -> [String] -> [String]
forall a. (a -> Bool) -> [a] -> [a]
filter (Predicate
p String
s) [String]
compls
type PromptLabel = String
newtype Pass = Pass PromptLabel
instance XPrompt Pass where
showXPrompt :: Pass -> String
showXPrompt (Pass String
prompt) = String
prompt String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": "
commandToComplete :: Pass -> String -> String
commandToComplete Pass
_ String
c = String
c
nextCompletion :: Pass -> String -> [String] -> String
nextCompletion Pass
_ = String -> [String] -> String
getNextCompletion
passwordStoreFolderDefault :: String -> String
passwordStoreFolderDefault :: String -> String
passwordStoreFolderDefault String
home = String -> String -> String
combine String
home String
".password-store"
passwordStoreFolder :: IO String
passwordStoreFolder :: IO String
passwordStoreFolder =
String -> IO (Maybe String)
getEnv String
"PASSWORD_STORE_DIR" IO (Maybe String) -> (Maybe String -> IO String) -> IO String
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe String -> IO String
computePasswordStoreDir
where computePasswordStoreDir :: Maybe String -> IO String
computePasswordStoreDir Maybe String
Nothing = (String -> String) -> IO String -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap String -> String
passwordStoreFolderDefault IO String
getHomeDirectory
computePasswordStoreDir (Just String
storeDir) = String -> IO String
forall (m :: * -> *) a. Monad m => a -> m a
return String
storeDir
mkPassPrompt :: PromptLabel -> (String -> X ()) -> XPConfig -> X ()
mkPassPrompt :: String -> (String -> X ()) -> XPConfig -> X ()
mkPassPrompt String
promptLabel String -> X ()
passwordFunction XPConfig
xpconfig = do
[String]
passwords <- IO [String] -> X [String]
forall (m :: * -> *) a. MonadIO m => IO a -> m a
io (IO String
passwordStoreFolder IO String -> (String -> IO [String]) -> IO [String]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> IO [String]
getPasswords)
Pass
-> XPConfig -> (String -> IO [String]) -> (String -> X ()) -> X ()
forall p.
XPrompt p =>
p
-> XPConfig -> (String -> IO [String]) -> (String -> X ()) -> X ()
mkXPrompt (String -> Pass
Pass String
promptLabel) XPConfig
xpconfig ([String] -> Predicate -> String -> IO [String]
getPassCompl [String]
passwords (Predicate -> String -> IO [String])
-> Predicate -> String -> IO [String]
forall a b. (a -> b) -> a -> b
$ XPConfig -> Predicate
searchPredicate XPConfig
xpconfig) String -> X ()
passwordFunction
passPrompt :: XPConfig -> X ()
passPrompt :: XPConfig -> X ()
passPrompt = String -> (String -> X ()) -> XPConfig -> X ()
mkPassPrompt String
"Select password" String -> X ()
selectPassword
passOTPPrompt :: XPConfig -> X ()
passOTPPrompt :: XPConfig -> X ()
passOTPPrompt = String -> (String -> X ()) -> XPConfig -> X ()
mkPassPrompt String
"Select OTP" String -> X ()
selectOTP
passGeneratePrompt :: XPConfig -> X ()
passGeneratePrompt :: XPConfig -> X ()
passGeneratePrompt = String -> (String -> X ()) -> XPConfig -> X ()
mkPassPrompt String
"Generate password" String -> X ()
generatePassword
passGenerateAndCopyPrompt :: XPConfig -> X ()
passGenerateAndCopyPrompt :: XPConfig -> X ()
passGenerateAndCopyPrompt = String -> (String -> X ()) -> XPConfig -> X ()
mkPassPrompt String
"Generate and copy password" String -> X ()
generateAndCopyPassword
passRemovePrompt :: XPConfig -> X ()
passRemovePrompt :: XPConfig -> X ()
passRemovePrompt = String -> (String -> X ()) -> XPConfig -> X ()
mkPassPrompt String
"Remove password" String -> X ()
removePassword
passTypePrompt :: XPConfig -> X ()
passTypePrompt :: XPConfig -> X ()
passTypePrompt = String -> (String -> X ()) -> XPConfig -> X ()
mkPassPrompt String
"Type password" String -> X ()
typePassword
passEditPrompt :: XPConfig -> X ()
passEditPrompt :: XPConfig -> X ()
passEditPrompt = String -> (String -> X ()) -> XPConfig -> X ()
mkPassPrompt String
"Edit password" String -> X ()
editPassword
selectPassword :: String -> X ()
selectPassword :: String -> X ()
selectPassword String
passLabel = String -> X ()
forall (m :: * -> *). MonadIO m => String -> m ()
spawn (String -> X ()) -> String -> X ()
forall a b. (a -> b) -> a -> b
$ String
"pass --clip \"" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
escapeQuote String
passLabel String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\""
selectOTP :: String -> X ()
selectOTP :: String -> X ()
selectOTP String
passLabel = String -> X ()
forall (m :: * -> *). MonadIO m => String -> m ()
spawn (String -> X ()) -> String -> X ()
forall a b. (a -> b) -> a -> b
$ String
"pass otp --clip \"" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
escapeQuote String
passLabel String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\""
generatePassword :: String -> X ()
generatePassword :: String -> X ()
generatePassword String
passLabel = String -> X ()
forall (m :: * -> *). MonadIO m => String -> m ()
spawn (String -> X ()) -> String -> X ()
forall a b. (a -> b) -> a -> b
$ String
"pass generate --force \"" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
escapeQuote String
passLabel String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\" 30"
generateAndCopyPassword :: String -> X ()
generateAndCopyPassword :: String -> X ()
generateAndCopyPassword String
passLabel = String -> X ()
forall (m :: * -> *). MonadIO m => String -> m ()
spawn (String -> X ()) -> String -> X ()
forall a b. (a -> b) -> a -> b
$ String
"pass generate --force -c \"" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
escapeQuote String
passLabel String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\" 30"
removePassword :: String -> X ()
removePassword :: String -> X ()
removePassword String
passLabel = String -> X ()
forall (m :: * -> *). MonadIO m => String -> m ()
spawn (String -> X ()) -> String -> X ()
forall a b. (a -> b) -> a -> b
$ String
"pass rm --force \"" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
escapeQuote String
passLabel String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\""
editPassword :: String -> X ()
editPassword :: String -> X ()
editPassword String
passLabel = String -> X ()
forall (m :: * -> *). MonadIO m => String -> m ()
spawn (String -> X ()) -> String -> X ()
forall a b. (a -> b) -> a -> b
$ String
"pass edit \"" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
escapeQuote String
passLabel String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\""
typePassword :: String -> X ()
typePassword :: String -> X ()
typePassword String
passLabel = String -> X ()
forall (m :: * -> *). MonadIO m => String -> m ()
spawn (String -> X ()) -> String -> X ()
forall a b. (a -> b) -> a -> b
$ String
"pass \"" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> String
escapeQuote String
passLabel
String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"\"|head -n1|tr -d '\n'|xdotool type --clearmodifiers --file -"
escapeQuote :: String -> String
escapeQuote :: String -> String
escapeQuote = (Char -> String) -> String -> String
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Char -> String
escape
where escape :: Char -> String
escape :: Char -> String
escape Char
'"' = String
"\\\""
escape Char
x = [Char
x]
getPasswords :: FilePath -> IO [String]
getPasswords :: String -> IO [String]
getPasswords String
passwordStoreDir = do
String
files <- String -> [String] -> String -> IO String
forall (m :: * -> *).
MonadIO m =>
String -> [String] -> String -> m String
runProcessWithInput String
"find" [
String
"-L",
String
passwordStoreDir,
String
"-type", String
"f",
String
"-name", String
"*.gpg",
String
"-printf", String
"%P\n"] []
[String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return ([String] -> IO [String])
-> ([String] -> [String]) -> [String] -> IO [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
removeGpgExtension ([String] -> IO [String]) -> [String] -> IO [String]
forall a b. (a -> b) -> a -> b
$ String -> [String]
lines String
files
removeGpgExtension :: String -> String
removeGpgExtension :: String -> String
removeGpgExtension String
file | String -> String
takeExtension String
file Predicate
forall a. Eq a => a -> a -> Bool
== String
".gpg" = String -> String
dropExtension String
file
| Bool
otherwise = String
file