[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
pwsafe.el
From: |
Stefan Reichör |
Subject: |
pwsafe.el |
Date: |
Thu, 13 Apr 2006 22:04:04 +0200 |
User-agent: |
Gnus/5.11 (Gnus v5.11) Emacs/22.0.50 (gnu/linux) |
;;; pwsafe.el --- emacs interface to pwsafe
;; Copyright (C) 2006 by Stefan Reichoer
;; Author: Stefan Reichoer, <address@hidden>
;; pwsafe.el is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;; pwsafe.el is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
;; Boston, MA 02111-1307, USA.
;;; Commentary:
;; pwsafe.el provides an Emacs interface for pwsafe:
;; http://nsd.dyndns.org/pwsafe, http://passwordsafe.sourceforge.net
;; The latest version of pwsafe.el can be found at:
;; http://www.xsteve.at/prg/emacs/
;; Usage:
;; put the following in your .emacs:
;; (require 'pwsafe)
;; Then run M-x pwsafe
;; - if the password database file does not yet exist it will be created now
;; - otherwise a list of nicknames for your stored passwords is shown
;; I am very interested in feedback about the usability and about
;; security concerns for this package
;; Before using pwsafe.el, I used a simple unencrypted text file
;; for my passwords. So this package enhances the security for my use case.
;;; History:
;;
;;; Code:
(defvar pwsafe-database "~/.pwsafe.dat")
(defvar pwsafe-use-long-listing nil "Display comments for the pwsafe entries.
This means that pwsafe -l is used to get the database entries.")
;; internal variables
(defvar pwsafe-password-prompt-regexp
"[Pp]ass\\(word\\|phrase\\).*:\\s *\\'"
"*Regexp matching prompts for passwords for pwsafe.")
;; taken from DVC.el
(defsubst pwsafe-face-add (str face &optional keymap menu help)
"Add to string STR the face FACE.
Optionally, also add the text properties KEYMAP, MENU and HELP.
If KEYMAP is a symbol, (symbol-value KEYMAP) is used
as a keymap; and `substitute-command-keys' result
against (format \"\\{%s}\" (symbol-name keymap)) is appended to HELP.
If HELP is nil and if MENU is non nil, the MENU title is used as HELP."
(let* ((strcpy (copy-sequence str))
(key-help (when (symbolp keymap)
(substitute-command-keys (format "\\{%s}" (symbol-name
keymap)))))
(prefix-help (if help help (when (and menu (stringp (cadr menu)))
(cadr menu))))
(long-help (if key-help
(if prefix-help (concat prefix-help "\n"
"================" "\n"
key-help) key-help)
help))
(keymap (if (symbolp keymap) (symbol-value keymap) keymap)))
(add-text-properties 0 (length strcpy)
`(face ,face
font-lock-face ,face
,@(when keymap
`(mouse-face highlight
keymap ,keymap
help-echo ,long-help))
,@(when menu
`(,dar-cmenu ,menu))
)
strcpy)
strcpy))
(defun pwsafe-process-filter (proc string)
(with-current-buffer (process-buffer proc)
(if (string-match pwsafe-password-prompt-regexp string)
(progn (string-match "^\\([^\n]+\\)\n*\\'" string)
(let ((passwd (read-passwd (match-string 1 string))))
(process-send-string proc (concat passwd "\n"))))
(insert string))
(cond ((member pwsafe-running-command '(copy-passwd copy-user-and-passwd))
(dolist (line (split-string string "\n"))
(when (string-match "\\(You are ready to paste\\|Sending
\\(username\\|password\\) for\\)" line)
(message (format "pwsafe: %s" line)))))
((eq pwsafe-running-command 'add)
;(message " pwsafe-process-filter: %s" string)
(dolist (line (split-string string "\n"))
(when (string-match "^\\(group \\[<none>\\]\\|username\\|notes\\):
" line)
(let ((answer (read-string (concat "pwsafe add " line))))
(process-send-string proc (concat answer "\n"))))
(when (string-match "Generate random password\\? \\[y\\]" line)
(process-send-string proc "y"))
(when (string-match "^type .+ length .+ bits of entropy" line)
(let ((answer (read-char-exclusive (concat "pwsafe password: "
line))))
(process-send-string proc (char-to-string answer)))))))))
(defun pwsafe-run (cmd &rest args)
(with-current-buffer (get-buffer-create "*pwsafe*")
(delete-region (point-min) (point-max)))
(let ((process (apply 'start-process "pwsafe" "*pwsafe*" "pwsafe" args)))
(setq pwsafe-running-command cmd)
(set-process-filter process 'pwsafe-process-filter)
(set-process-sentinel process 'pwsafe-process-sentinel)))
(defun pwsafe-process-sentinel (process event)
(save-excursion
(set-buffer (process-buffer process))
(cond ((string= event "finished\n")
(cond ((eq pwsafe-running-command 'createdb)
(message "Created pwsafe database %s" (expand-file-name
pwsafe-database)))
((eq pwsafe-running-command 'list)
(pwsafe-list-passwords))
((eq pwsafe-running-command 'copy-passwd)
);; do nothing here
((eq pwsafe-running-command 'copy-user-and-passwd)
);; do nothing here
((eq pwsafe-running-command 'delete)
(message "pwsafe delete finished"))
(t
(message "pwsafe process finished")))
(setq dar-running-command nil))
((string= event "killed\n")
(message "pwsafe process killed")
(setq dar-running-command nil))
((string-match "exited abnormally" event)
(while (accept-process-output process 0 100))
;; find last error message and show it.
(goto-char (point-max))
(message "pwsafe failed: %s" event)
(setq pwsafe-running-command nil))
(t
(message "pwsafe process had unknown event: %s" event)))))
(defun pwsafe-createdb ()
"Run pwsafe --createdb"
(interactive)
(let ((database-file-name (expand-file-name pwsafe-database)))
(if (file-exists-p database-file-name)
(message "The pwsafe database %s does already exist."
database-file-name)
(pwsafe-run 'createdb "--createdb" "-f" database-file-name)
(message "Created pwsafe database %s" database-file-name))))
(defun pwsafe ()
"Major mode to interact with the command line password safe pwsafe.
The following keys are defined:
\\{pwsafe-list-mode-map}"
(interactive)
(let ((database-file-name (expand-file-name pwsafe-database)))
(if (file-exists-p database-file-name)
(pwsafe-run 'list (if pwsafe-use-long-listing "-l" "") "-f"
database-file-name)
(when (yes-or-no-p (format "pwsafe database %s does not exist - create
it? " database-file-name))
(pwsafe-createdb)
(with-current-buffer (get-buffer "*pwsafe*")
(delete-region (point-min) (point-max)))
(pwsafe-list-passwords)))))
(defun pwsafe-list-passwords ()
(interactive)
(let ((pwlist)
(current-pw)
(overlay)
(start-pos))
(with-current-buffer (get-buffer "*pwsafe*")
(goto-char (- (point-max) 1))
(re-search-backward "^$")
(forward-line 1)
(while (< (point) (- (point-max) 2))
(if pwsafe-use-long-listing
(progn
(when (looking-at "^\\(.+\\) - \\(.+\\)")
(add-to-list 'pwlist (list (match-string 1) (match-string 2))))
(when (looking-at "^> \\(.+\\)")
(setcar pwlist (append (car pwlist) (list (match-string 1))))))
(add-to-list 'pwlist (list (buffer-substring-no-properties
(line-beginning-position) (line-end-position)) nil)))
(forward-line 1)))
(pop-to-buffer "*pwsafe-list*")
(let ((buffer-read-only nil))
(delete-region (point-min) (point-max))
(unless pwlist
(insert "Empty pwsafe database."))
(dolist (e (nreverse pwlist))
(setq start-pos (point))
(insert (dar-face-add (format "%s" (car e))
'font-lock-function-name-face))
(newline)
(when (nth 2 e)
(insert (format " %s\n" (nth 2 e))))
(setq overlay (make-overlay start-pos (point)))
(overlay-put overlay 'pwsafe e))
(pwsafe-list-mode)
(goto-char (point-min)))))
(defvar pwsafe-list-mode-map () "Keymap used in `pwsafe-list-mode' buffers.")
(when (not pwsafe-list-mode-map)
(setq pwsafe-list-mode-map (make-sparse-keymap))
(define-key pwsafe-list-mode-map [?q] 'bury-buffer)
(define-key pwsafe-list-mode-map [?n] 'pwsafe-next)
(define-key pwsafe-list-mode-map [?p] 'pwsafe-previous)
(define-key pwsafe-list-mode-map [?g] 'pwsafe)
(define-key pwsafe-list-mode-map [?a] 'pwsafe-add-entry)
(define-key pwsafe-list-mode-map [(control ?d)] 'pwsafe-delete-entry)
(define-key pwsafe-list-mode-map [?U] 'pwsafe-copy-user-name)
(define-key pwsafe-list-mode-map [?P] 'pwsafe-copy-password)
(define-key pwsafe-list-mode-map [?B] 'pwsafe-copy-user-name-and-password))
(easy-menu-define pwsafe-mode-menu pwsafe-list-mode-map
"`pwsafe-list-mode' menu"
'("PWsafe"
["Copy user name, then password"
pwsafe-copy-user-name-and-password t]
["Copy user name" pwsafe-copy-user-name t]
["Copy password" pwsafe-copy-password t]
["Add new entry" pwsafe-add-entry t]
["Delete entry" pwsafe-delete-entry t]
))
(defun pwsafe-list-mode ()
"Major Mode to entries from pwsafe."
(interactive)
(kill-all-local-variables)
(toggle-read-only 1)
(use-local-map pwsafe-list-mode-map)
(setq major-mode 'pwsafe-list-mode)
(setq mode-name "pwsafe-list"))
(defun pwsafe-list-line-info ()
(let ((pwsafe-info nil))
(dolist (overlay (overlays-at (point)))
(setq pwsafe-info (or pwsafe-info
(overlay-get overlay 'pwsafe))))
pwsafe-info))
(defun pwsafe-next ()
(interactive)
(let ((next (next-overlay-change (point))))
(when (< next (point-max))
(goto-char next))))
(defun pwsafe-previous ()
(interactive)
(goto-char (previous-overlay-change (point))))
(defun pwsafe-copy-user-name ()
(interactive)
(let ((info (pwsafe-list-line-info)))
(pwsafe-run 'copy-passwd "-u" "-f" (expand-file-name pwsafe-database) (car
info))))
(defun pwsafe-copy-password ()
(interactive)
(let ((info (pwsafe-list-line-info)))
(pwsafe-run 'copy-passwd "-p" "-f" (expand-file-name pwsafe-database) (car
info))))
(defun pwsafe-copy-user-name-and-password ()
(interactive)
(let ((info (pwsafe-list-line-info)))
(pwsafe-run 'copy-user-and-passwd "-u" "-p" "-f" (expand-file-name
pwsafe-database) (car info))))
(defun pwsafe-add-entry (name)
(interactive "spwsafe add bookmark name: ")
(pwsafe-run 'add "-f" (expand-file-name pwsafe-database) "--add" name))
(defun pwsafe-delete-entry ()
(interactive)
(let ((info (pwsafe-list-line-info)))
(when (yes-or-no-p (format "Delete pwsafe entry for %s? " (car info)))
(pwsafe-run 'delete "-f" (expand-file-name pwsafe-database) "--delete"
(car info)))))
(provide 'pwsafe)
;;; arch-tag: 900b1054-5492-4b81-ae06-54a5d48e6aca
;;; pwsafe.el ends here
- pwsafe.el,
Stefan Reichör <=