mirror of
https://github.com/xmonad/xmonad-contrib.git
synced 2025-08-01 04:31:52 -07:00
Adds a new function to spawn a pass prompt which will use xdotool
to
type in a password, bypassing the clipboard. Also incorporate some shell escapes to properly handle pass labels with spaces and special characters in them.
This commit is contained in:
@@ -145,6 +145,13 @@
|
|||||||
|
|
||||||
- Update logout key combination (modm+shift+Q) to work with modern
|
- Update logout key combination (modm+shift+Q) to work with modern
|
||||||
|
|
||||||
|
* `XMonad.Prompt.Pass`
|
||||||
|
|
||||||
|
- New function `passTypePrompt` which uses `xdotool` to type in a password
|
||||||
|
from the store, bypassing the clipboard.
|
||||||
|
- Now handles password labels with spaces and special characters inside
|
||||||
|
them.
|
||||||
|
|
||||||
## 0.13 (February 10, 2017)
|
## 0.13 (February 10, 2017)
|
||||||
|
|
||||||
### Breaking Changes
|
### Breaking Changes
|
||||||
|
@@ -8,9 +8,10 @@
|
|||||||
-- Stability : unstable
|
-- Stability : unstable
|
||||||
-- Portability : unportable
|
-- Portability : unportable
|
||||||
--
|
--
|
||||||
-- This module provides 3 <XMonad.Prompt> to ease passwords manipulation (generate, read, remove):
|
-- This module provides 4 <XMonad.Prompt> to ease password manipulation (generate, read, remove):
|
||||||
--
|
--
|
||||||
-- - one to lookup passwords in the password-storage.
|
-- - two to lookup passwords in the password-store; one of which copies to the
|
||||||
|
-- clipboard, and the other uses @xdotool@ to type the password directly.
|
||||||
--
|
--
|
||||||
-- - one to generate a password for a given password label that the user inputs.
|
-- - one to generate a password for a given password label that the user inputs.
|
||||||
--
|
--
|
||||||
@@ -18,28 +19,26 @@
|
|||||||
--
|
--
|
||||||
-- All those prompts benefit from the completion system provided by the module <XMonad.Prompt>.
|
-- 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.
|
-- The password store is setup through an environment variable PASSWORD_STORE_DIR,
|
||||||
-- If this is set, use the content of the variable.
|
-- or @$HOME\/.password-store@ if it is unset.
|
||||||
-- Otherwise, the password store is located on user's home @$HOME\/.password-store@.
|
|
||||||
--
|
|
||||||
--
|
--
|
||||||
-- Source:
|
-- Source:
|
||||||
--
|
--
|
||||||
-- - The password storage implementation is <http://git.zx2c4.com/password-store the password-store cli>.
|
-- - The password store implementation is <http://git.zx2c4.com/password-store the password-store cli>.
|
||||||
--
|
--
|
||||||
-- - Inspired from <http://babushk.in/posts/combining-xmonad-and-pass.html>
|
-- - Inspired by <http://babushk.in/posts/combining-xmonad-and-pass.html>
|
||||||
--
|
--
|
||||||
-----------------------------------------------------------------------------
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
module XMonad.Prompt.Pass (
|
module XMonad.Prompt.Pass (
|
||||||
-- * Usages
|
-- * Usage
|
||||||
-- $usages
|
-- $usage
|
||||||
passPrompt
|
passPrompt
|
||||||
, passGeneratePrompt
|
, passGeneratePrompt
|
||||||
, passRemovePrompt
|
, passRemovePrompt
|
||||||
|
, passTypePrompt
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad (liftM)
|
|
||||||
import XMonad.Core
|
import XMonad.Core
|
||||||
import XMonad.Prompt ( XPrompt
|
import XMonad.Prompt ( XPrompt
|
||||||
, showXPrompt
|
, showXPrompt
|
||||||
@@ -54,7 +53,7 @@ import System.FilePath (takeExtension, dropExtension, combine)
|
|||||||
import System.Posix.Env (getEnv)
|
import System.Posix.Env (getEnv)
|
||||||
import XMonad.Util.Run (runProcessWithInput)
|
import XMonad.Util.Run (runProcessWithInput)
|
||||||
|
|
||||||
-- $usages
|
-- $usage
|
||||||
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
|
-- You can use this module with the following in your @~\/.xmonad\/xmonad.hs@:
|
||||||
--
|
--
|
||||||
-- > import XMonad.Prompt.Pass
|
-- > import XMonad.Prompt.Pass
|
||||||
@@ -69,17 +68,17 @@ import XMonad.Util.Run (runProcessWithInput)
|
|||||||
--
|
--
|
||||||
-- - editing your key bindings, see "XMonad.Doc.Extending#Editing_key_bindings".
|
-- - 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/>
|
-- - how to setup the password store, see <http://git.zx2c4.com/password-store/about/>
|
||||||
--
|
--
|
||||||
|
|
||||||
type Predicate = String -> String -> Bool
|
type Predicate = String -> String -> Bool
|
||||||
|
|
||||||
getPassCompl :: [String] -> Predicate -> String -> IO [String]
|
getPassCompl :: [String] -> Predicate -> String -> IO [String]
|
||||||
getPassCompl compls p s = do return $ filter (p s) compls
|
getPassCompl compls p s = pure $ filter (p s) compls
|
||||||
|
|
||||||
type PromptLabel = String
|
type PromptLabel = String
|
||||||
|
|
||||||
data Pass = Pass PromptLabel
|
newtype Pass = Pass PromptLabel
|
||||||
|
|
||||||
instance XPrompt Pass where
|
instance XPrompt Pass where
|
||||||
showXPrompt (Pass prompt) = prompt ++ ": "
|
showXPrompt (Pass prompt) = prompt ++ ": "
|
||||||
@@ -98,8 +97,8 @@ passwordStoreFolderDefault home = combine home ".password-store"
|
|||||||
passwordStoreFolder :: IO String
|
passwordStoreFolder :: IO String
|
||||||
passwordStoreFolder =
|
passwordStoreFolder =
|
||||||
getEnv "PASSWORD_STORE_DIR" >>= computePasswordStoreDir
|
getEnv "PASSWORD_STORE_DIR" >>= computePasswordStoreDir
|
||||||
where computePasswordStoreDir Nothing = liftM passwordStoreFolderDefault getHomeDirectory
|
where computePasswordStoreDir Nothing = passwordStoreFolderDefault <$> getHomeDirectory
|
||||||
computePasswordStoreDir (Just storeDir) = return storeDir
|
computePasswordStoreDir (Just storeDir) = pure storeDir
|
||||||
|
|
||||||
-- | A pass prompt factory
|
-- | A pass prompt factory
|
||||||
--
|
--
|
||||||
@@ -126,23 +125,40 @@ passGeneratePrompt = mkPassPrompt "Generate password" generatePassword
|
|||||||
passRemovePrompt :: XPConfig -> X ()
|
passRemovePrompt :: XPConfig -> X ()
|
||||||
passRemovePrompt = mkPassPrompt "Remove password" removePassword
|
passRemovePrompt = mkPassPrompt "Remove password" removePassword
|
||||||
|
|
||||||
|
-- | A prompt to type in a password for a given entry.
|
||||||
|
-- This doesn't touch the clipboard.
|
||||||
|
--
|
||||||
|
passTypePrompt :: XPConfig -> X ()
|
||||||
|
passTypePrompt = mkPassPrompt "Type password" typePassword
|
||||||
|
|
||||||
-- | Select a password.
|
-- | Select a password.
|
||||||
--
|
--
|
||||||
selectPassword :: String -> X ()
|
selectPassword :: String -> X ()
|
||||||
selectPassword passLabel = spawn $ "pass --clip " ++ passLabel
|
selectPassword passLabel = spawn $ "pass --clip \"" ++ escapeQuote passLabel ++ "\""
|
||||||
|
|
||||||
-- | Generate a 30 characters password for a given entry.
|
-- | Generate a 30 characters password for a given entry.
|
||||||
-- If the entry already exists, it is updated with a new password.
|
-- If the entry already exists, it is updated with a new password.
|
||||||
--
|
--
|
||||||
generatePassword :: String -> X ()
|
generatePassword :: String -> X ()
|
||||||
generatePassword passLabel = spawn $ "pass generate --force " ++ passLabel ++ " 30"
|
generatePassword passLabel = spawn $ "pass generate --force \"" ++ escapeQuote passLabel ++ "\" 30"
|
||||||
|
|
||||||
-- | Remove a password stored for a given entry.
|
-- | Remove a password stored for a given entry.
|
||||||
--
|
--
|
||||||
removePassword :: String -> X ()
|
removePassword :: String -> X ()
|
||||||
removePassword passLabel = spawn $ "pass rm --force " ++ passLabel
|
removePassword passLabel = spawn $ "pass rm --force \"" ++ escapeQuote passLabel ++ "\""
|
||||||
|
|
||||||
-- | Retrieve the list of passwords from the password storage 'passwordStoreDir
|
-- | Type a password stored for a given entry using xdotool.
|
||||||
|
--
|
||||||
|
typePassword :: String -> X ()
|
||||||
|
typePassword passLabel = spawn $ "xdotool type --clearmodifiers $(pass \"" ++ escapeQuote passLabel ++ "\"|head -n1)"
|
||||||
|
|
||||||
|
escapeQuote :: String -> String
|
||||||
|
escapeQuote = concatMap escape
|
||||||
|
where escape :: Char -> String
|
||||||
|
escape '"' = ['\\', '\"']
|
||||||
|
escape x = pure x
|
||||||
|
|
||||||
|
-- | Retrieve the list of passwords from the password store 'passwordStoreDir
|
||||||
getPasswords :: FilePath -> IO [String]
|
getPasswords :: FilePath -> IO [String]
|
||||||
getPasswords passwordStoreDir = do
|
getPasswords passwordStoreDir = do
|
||||||
files <- runProcessWithInput "find" [
|
files <- runProcessWithInput "find" [
|
||||||
@@ -150,7 +166,7 @@ getPasswords passwordStoreDir = do
|
|||||||
"-type", "f",
|
"-type", "f",
|
||||||
"-name", "*.gpg",
|
"-name", "*.gpg",
|
||||||
"-printf", "%P\n"] []
|
"-printf", "%P\n"] []
|
||||||
return $ map removeGpgExtension $ lines files
|
pure . map removeGpgExtension $ lines files
|
||||||
|
|
||||||
removeGpgExtension :: String -> String
|
removeGpgExtension :: String -> String
|
||||||
removeGpgExtension file | takeExtension file == ".gpg" = dropExtension file
|
removeGpgExtension file | takeExtension file == ".gpg" = dropExtension file
|
||||||
|
Reference in New Issue
Block a user