aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--XMonad/Prompt/Pass.hs142
-rw-r--r--xmonad-contrib.cabal1
2 files changed, 143 insertions, 0 deletions
diff --git a/XMonad/Prompt/Pass.hs b/XMonad/Prompt/Pass.hs
new file mode 100644
index 0000000..db4ce2d
--- /dev/null
+++ b/XMonad/Prompt/Pass.hs
@@ -0,0 +1,142 @@
+-----------------------------------------------------------------------------
+-- |
+-- Module : XMonad.Prompt.Pass
+-- Copyright : (c) 2014 Igor Babuschkin, Antoine R. Dumont
+-- License : BSD3-style (see LICENSE)
+--
+-- Maintainer : Antoine R. Dumont <eniotna.t@gmail.com>
+-- Stability : unstable
+-- Portability : unportable
+--
+-- This module provides 3 <XMonad.Prompt> to ease passwords manipulation (generate, read, remove):
+--
+-- - one to lookup passwords in the password-storage.
+--
+-- - one to generate a password for a given password label that the user inputs.
+--
+-- - one to delete a stored password for a given password label that the user inputs.
+--
+-- All those prompts benefit from the completion system provided by the module <XMonad.Prompt>.
+--
+-- The password store is setuped through an environment variable PASSWORD_STORE_DIR.
+-- If this is set, use the content of the variable.
+-- Otherwise, the password store is located on user's home @$HOME\/.password-store@.
+--
+--
+-- Source:
+--
+-- - The password storage implementation is <http://git.zx2c4.com/password-store the password-store cli>.
+--
+-- - Inspired from <http://babushk.in/posts/combining-xmonad-and-pass.html>
+--
+-----------------------------------------------------------------------------
+
+module XMonad.Prompt.Pass (
+ -- * Usages
+ -- $usages
+ passPrompt
+ , passGeneratePrompt
+ , passRemovePrompt
+ ) where
+
+import Control.Monad (liftM)
+import XMonad.Core
+import XMonad.Prompt ( XPrompt
+ , showXPrompt
+ , commandToComplete
+ , nextCompletion
+ , getNextCompletion
+ , XPConfig
+ , mkXPrompt
+ , mkComplFunFromList)
+import System.Directory (getDirectoryContents, getHomeDirectory)
+import System.FilePath (takeBaseName, combine)
+import System.Posix.Env (getEnv)
+
+-- $usages
+-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
+--
+-- > import XMonad.Prompt.Pass
+--
+-- Then add a keybinding for 'passPrompt', 'passGeneratePrompt' or 'passRemovePrompt':
+--
+-- > , ((modMask x , xK_p) , passPrompt xpconfig)
+-- > , ((modMask x .|. controlMask, xK_p) , passGeneratePrompt xpconfig)
+-- > , ((modMask x .|. controlMask .|. shiftMask, xK_p), passRemovePrompt xpconfig)
+--
+-- For detailed instructions on:
+--
+-- - editing your key bindings, see "XMonad.Doc.Extending#Editing_key_bindings".
+--
+-- - how to setup the password storage, see <http://git.zx2c4.com/password-store/about/>
+--
+
+type PromptLabel = String
+
+data Pass = Pass PromptLabel
+
+instance XPrompt Pass where
+ showXPrompt (Pass prompt) = prompt ++ ": "
+ commandToComplete _ c = c
+ nextCompletion _ = getNextCompletion
+
+-- | Default password store folder in $HOME/.password-store
+--
+passwordStoreFolderDefault :: String -> String
+passwordStoreFolderDefault home = combine home ".password-store"
+
+-- | Compute the password store's location.
+-- Use the PASSWORD_STORE_DIR environment variable to set the password store.
+-- If empty, return the password store located in user's home.
+--
+passwordStoreFolder :: IO String
+passwordStoreFolder =
+ getEnv "PASSWORD_STORE_DIR" >>= computePasswordStoreDir
+ where computePasswordStoreDir Nothing = liftM passwordStoreFolderDefault getHomeDirectory
+ computePasswordStoreDir (Just storeDir) = return storeDir
+
+-- | A pass prompt factory
+--
+mkPassPrompt :: PromptLabel -> (String -> X ()) -> XPConfig -> X ()
+mkPassPrompt promptLabel passwordFunction xpconfig = do
+ passwords <- io (passwordStoreFolder >>= getPasswords)
+ mkXPrompt (Pass promptLabel) xpconfig (mkComplFunFromList passwords) passwordFunction
+
+-- | A prompt to retrieve a password from a given entry.
+--
+passPrompt :: XPConfig -> X ()
+passPrompt = mkPassPrompt "Select password" selectPassword
+
+-- | A prompt to generate a password for a given entry.
+-- This can be used to override an already stored entry.
+-- (Beware that no confirmation is asked)
+--
+passGeneratePrompt :: XPConfig -> X ()
+passGeneratePrompt = mkPassPrompt "Generate password" generatePassword
+
+-- | A prompt to remove a password for a given entry.
+-- (Beware that no confirmation is asked)
+--
+passRemovePrompt :: XPConfig -> X ()
+passRemovePrompt = mkPassPrompt "Remove password" removePassword
+
+-- | Select a password.
+--
+selectPassword :: String -> X ()
+selectPassword passLabel = spawn $ "pass --clip " ++ passLabel
+
+-- | Generate a 30 characters password for a given entry.
+-- If the entry already exists, it is updated with a new password.
+--
+generatePassword :: String -> X ()
+generatePassword passLabel = spawn $ "pass generate --force " ++ passLabel ++ " 30"
+
+-- | Remove a password stored for a given entry.
+--
+removePassword :: String -> X ()
+removePassword passLabel = spawn $ "pass rm --force " ++ passLabel
+
+-- | Retrieve the list of passwords from the password storage 'passwordStoreDir
+--
+getPasswords :: String -> IO [String]
+getPasswords passwordStoreDir = liftM (map takeBaseName) $ getDirectoryContents passwordStoreDir
diff --git a/xmonad-contrib.cabal b/xmonad-contrib.cabal
index c7c59e9..c6145e0 100644
--- a/xmonad-contrib.cabal
+++ b/xmonad-contrib.cabal
@@ -280,6 +280,7 @@ library
XMonad.Prompt.Input
XMonad.Prompt.Layout
XMonad.Prompt.Man
+ XMonad.Prompt.Pass
XMonad.Prompt.RunOrRaise
XMonad.Prompt.Shell
XMonad.Prompt.Ssh