dispass.el/dispass.el

333 lines
11 KiB
EmacsLisp
Raw Normal View History

;;; dispass.el --- Emacs wrapper for DisPass
;; Copyright (C) 2012 Tom Willemsen <tom@ryuslash.org>
;; Author: Tom Willemsen <tom@ryuslash.org>
;; Created: Jun 8, 2012
2013-05-04 17:02:49 +02:00
;; Version: 1.1.2
;; Keywords: processes
2013-05-04 16:59:26 +02:00
;; URL: http://projects.ryuslash.org/dispass.el/
;; Permission to use, copy, modify, and distribute this software for any
;; purpose with or without fee is hereby granted, provided that the
;; above copyright notice and this permission notice appear in all
;; copies.
;; THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
;; WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
;; WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
;; AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
;; CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
;; OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
;; NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
;; CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
;;; Commentary:
2013-05-04 16:59:26 +02:00
;; dispass.el is an Emacs wrapper around DisPass
;; (http://dispass.babab.nl). For more information see the README.org
;; and NEWS files.
2012-12-03 22:51:38 +01:00
2013-05-04 16:59:26 +02:00
;; This version is written for use with DisPass v0.2.0.
;;; Code:
2013-05-04 16:59:26 +02:00
(defgroup dispass nil
"Customization options for the DisPass wrapper."
:group 'external)
(defcustom dispass-default-length 30
"The default length to use when generating passphrases."
:package-version '(dispass . "1")
:group 'dispass
:type '(integer))
(defcustom dispass-executable "dispass"
"The location of the dispass executable."
:package-version '(dispass . "0.1a7.3")
:group 'dispass
:type '(string)
:risky t)
(defcustom dispass-labels-executable nil
"The location of the dispass-label executable."
:package-version '(dispass . "1.1.3")
:group 'dispass
:type 'string
:risky t)
(make-obsolete-variable 'dispass-labels-executable
"dispass-label is no longer used by DisPass."
"dispass 1.1.3")
(defcustom dispass-labelfile nil
2013-05-04 16:59:26 +02:00
"The location of your preferred labelfile.
A value of nil means to just let DisPass figure it out."
:package-version '(dispass . "1.1.1")
:group 'dispass
:type 'file
:risky t)
(defvar dispass-labels-mode-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map tabulated-list-mode-map)
(define-key map "c" 'dispass-create)
(define-key map "a" 'dispass-add-label)
(define-key map "d" 'dispass-remove-label)
2012-07-08 18:29:45 +02:00
map)
2013-05-04 16:59:26 +02:00
"Keymap for `dispass-labels-mode'.
2013-05-04 16:59:26 +02:00
Uses `tabulated-list-mode-map' as its parent.")
;; This should be extracted from DisPass at some point.
(defconst dispass-algorithms
'("dispass1" "dispass2")
2013-05-04 16:59:26 +02:00
"The list of algorithms supported by DisPass.")
(defun dispass-process-sentinel (proc status)
"Report PROC's status change to STATUS."
(let ((status (substring status 0 -1))
(buffer (process-buffer proc)))
(unless (string-equal status "finished")
(message "dispass %s" status))
(unless (eq (current-buffer) proc)
(kill-buffer buffer))))
(defun dispass-erase-buffer (buffer)
2013-05-04 16:59:26 +02:00
"Completely erase the contents of BUFFER."
(save-current-buffer
(set-buffer buffer)
(buffer-disable-undo buffer)
(kill-buffer buffer)))
(defun dispass-label-at-point ()
"When in `dispass-labels-mode', get the label at `point'."
(let ((labels-mode-p (eq major-mode 'dispass-labels-mode)))
(tabulated-list-get-id)))
(defun dispass-process-filter-for (label)
2013-05-04 16:59:26 +02:00
"Create a specialized filter for LABEL.
This filter checks if a password has been asked for or if the
label shows up in a line, which will be the line with the
passphrase that has been generated."
`(lambda (proc string)
"Process STRING coming from PROC."
(cond ((string-match "^\\(Password[^:]*\\|Again\\): ?$" string)
(process-send-string
proc
(concat (read-passwd
(concat (replace-regexp-in-string
"^[ \t\n]+\\|[ \t\n]+$" "" string) " ")
nil) "\n")))
((string-match (concat "^[ \t]*" ,label "[ \t]*\\(.+\\)$")
string)
(let ((buffer (process-buffer proc)))
(with-current-buffer buffer
(insert (match-string 1 string))
(clipboard-kill-ring-save (point-min) (point-max))
(message "Password copied to clipboard.")))))))
(defun dispass-start-process (cmd label create length
&optional algo seqno args)
"Ask DisPass call CMD for LABEL.
2013-05-04 16:59:26 +02:00
When CREATE is non-nil send along the -c switch to make it ask
for a password twice. When LENGTH is an integer and greater than
0, we request that DisPass make the passphrase LENGTH long. ALGO
should be one of `dispass-algorithms' and requests a certain
algorithm be used by DisPass to generate the passphrase. SEQNO
asks DisPass to use SEQNO as a sequence number.
If specified add ARGS to the command."
(let ((args `(,cmd ,@args "-o"))
proc)
(when create
(setq args (append args '("-v"))))
(when (and (integerp length) (> length 0))
(setq args (append args `("-l" ,(number-to-string length)))))
(when (and algo (not (equal algo ""))
(member algo dispass-algorithms))
(setq args (append args `("-a" ,algo))))
(when (and seqno (> seqno 0))
(setq args (append args `("-s" ,(number-to-string seqno)))))
(when dispass-labelfile
(setq args (append `("-f" ,dispass-labelfile) args)))
(message "%s" `(,@args ,label))
(setq proc (apply 'start-process "dispass" "*dispass*"
dispass-executable `(,@args ,label)))
(set-process-sentinel proc 'dispass-process-sentinel)
(set-process-filter proc (dispass-process-filter-for label))))
(defun dispass-get-labels ()
"Get the list of labels and their information."
(let ((result '()))
(with-temp-buffer
(dispass-read-labels)
(while (re-search-forward
2013-02-16 10:48:01 +01:00
"^\\(\\(?:\\sw\\|\\s_\\|\\.\\)+\\)"
nil t)
(add-to-list 'result (match-string 1)))
result)))
(defun dispass-get-labels-for-display ()
"Prepare the list of labels for info table."
(let ((result '()))
(with-temp-buffer
(dispass-read-labels)
(while (re-search-forward
2013-02-16 10:48:01 +01:00
"^\\(\\(?:\\sw\\|\\s_\\|\\.\\)+\\) +\\([0-9]+\\) +\\(\\(?:\\sw\\|\\s_\\)+\\)"
nil t)
(let ((label (match-string 1))
(length (match-string 2))
(algo (match-string 3)))
(add-to-list 'result
(list label
`[(,label
face link
help-echo ,(concat "Generate passphrase for " label)
follow-link t
dispass-label ,label
dispass-length ,length
action dispass-from-button)
,length
,algo])))))
result))
(defun dispass-read-labels ()
"Load a list of all labels into a buffer."
(insert (shell-command-to-string
(concat dispass-executable
(when dispass-labelfile
(concat " -f " dispass-labelfile))
" list --script")))
(goto-char (point-min)))
;;;###autoload
(defun dispass-create (label &optional length algo seqno)
2013-05-04 16:59:26 +02:00
"Create a new password for LABEL.
Optionally also specify to make the passphrase LENGTH long, use
the ALGO algorithm with sequence number SEQNO."
(interactive (list
(read-from-minibuffer "Label: ")
current-prefix-arg
(completing-read "Algorithm: " dispass-algorithms)
(read-from-minibuffer
"Sequence no. (1): " nil nil t nil "1")))
(let ((length (or length dispass-default-length)))
(dispass-start-process "generate" label t length algo seqno)))
;;;###autoload
(defun dispass (label &optional length algo seqno)
2013-05-04 16:59:26 +02:00
"Recreate a passphrase for LABEL.
Optionally also specify to make the passphrase LENGTH long, use
the ALGO algorithm with sequence number SEQNO. This is useful
when you would like to generate a one-shot passphrase, or prefer
not to have LABEL added to your labelfile for some other reason."
(interactive (list
(completing-read
"Label: " (dispass-get-labels))
current-prefix-arg))
(when (and (called-interactively-p 'any)
(not (member label (dispass-get-labels))))
(setq algo (completing-read "Algorithm: " dispass-algorithms))
(setq seqno (read-from-minibuffer
"Sequence no. (1): " nil nil t nil "1")))
(let ((length (or length dispass-default-length)))
(dispass-start-process
"generate" label nil length algo seqno)))
2012-07-05 01:11:07 +02:00
;; Labels management
;;;###autoload
(defun dispass-add-label (label length algo &optional seqno)
2013-05-04 16:59:26 +02:00
"Add LABEL with length LENGTH and algorithm ALGO to DisPass.
Optionally also specify sequence number SEQNO."
(interactive
(list (read-from-minibuffer "Label: ")
(read-from-minibuffer
(format "Length (%d): " dispass-default-length) nil nil t nil
(number-to-string dispass-default-length))
(completing-read
"Algorithm (dispass1): "
dispass-algorithms nil nil nil nil "dispass1")
(read-from-minibuffer "Sequnce no. (1): " nil nil t nil "1")))
(shell-command
(format "%s %s add %s:%d:%s:%s"
dispass-executable
(if dispass-labelfile
(concat "-f " dispass-labelfile)
"")
label length algo seqno)))
;;;###autoload
(defun dispass-remove-label (label)
2013-05-04 16:59:26 +02:00
"Remove LABEL from DisPass.
If LABEL is not given `tabulated-list-get-id' will be used to get
the currently pointed-at label. If neither LABEL is not found an
error is thrown."
(interactive
(list (or (dispass-label-at-point)
(completing-read
"Label: " (dispass-get-labels)))))
(shell-command
(format "%s %s rm %s" dispass-executable
(if dispass-labelfile
(concat "-f " dispass-labelfile)
"")
label)))
(defun dispass-from-button (button)
"Call dispass with information from BUTTON."
(dispass (button-get button 'dispass-label)
(button-get button 'dispass-length)))
2012-07-05 01:11:07 +02:00
(defun dispass-labels--refresh ()
"Reload labels from dispass."
(setq tabulated-list-entries nil)
(let ((tmp-list '()))
(setq tabulated-list-entries (dispass-get-labels-for-display))))
2012-07-05 01:11:07 +02:00
(define-derived-mode dispass-labels-mode tabulated-list-mode "DisPass"
"Major mode for listing dispass labels.
2012-07-06 00:31:02 +02:00
\\<dispass-labels-mode-map>
\\{dispass-labels-mode-map}"
2012-07-05 01:11:07 +02:00
(setq tabulated-list-format [("Label" 30 t)
("Length" 6 nil)
("Algorithm" 0 t)]
2012-07-05 01:11:07 +02:00
tabulated-list-sort-key '("Label" . nil))
(add-hook 'tabulated-list-revert-hook 'dispass-labels--refresh)
(tabulated-list-init-header))
;;;###autoload
2012-07-05 01:11:07 +02:00
(defun dispass-list-labels ()
"Display a list of labels for dispass."
(interactive)
(let ((buffer (get-buffer-create "*DisPass Labels*")))
(with-current-buffer buffer
(dispass-labels-mode)
(dispass-labels--refresh)
(tabulated-list-print))
(switch-to-buffer-other-window buffer))
2012-07-05 01:11:07 +02:00
nil)
(provide 'dispass)
;;; dispass.el ends here
2013-05-04 16:59:26 +02:00
;; Local Variables:
;; sentence-end-double-space: t
;; End: