diff options
| author | Michael Albinus | 2010-05-18 21:34:26 +0200 |
|---|---|---|
| committer | Michael Albinus | 2010-05-18 21:34:26 +0200 |
| commit | 3a8e7cbdaec8cb210c09d296bb94b6bbb2f6ab5d (patch) | |
| tree | f8d9e3049a219047387caf04ca9ba0be01ac72f6 | |
| parent | 224b70cbc50f55b8e9a65b9b8666ce2bff6d796b (diff) | |
| download | emacs-3a8e7cbdaec8cb210c09d296bb94b6bbb2f6ab5d.tar.gz emacs-3a8e7cbdaec8cb210c09d296bb94b6bbb2f6ab5d.zip | |
Add visualization code for secrets.
* net/secrets.el (secrets-mode): New major mode.
(secrets-show-secrets, secrets-show-collections)
(secrets-expand-collection, secrets-expand-item)
(secrets-tree-widget-after-toggle-function)
(secrets-tree-widget-show-password): New defuns.
| -rw-r--r-- | lisp/ChangeLog | 11 | ||||
| -rw-r--r-- | lisp/net/secrets.el | 149 |
2 files changed, 159 insertions, 1 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index cb0ca655188..9c7359caf46 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,12 @@ | |||
| 1 | 2010-05-18 Michael Albinus <michael.albinus@gmx.de> | ||
| 2 | |||
| 3 | Add visualization code for secrets. | ||
| 4 | * net/secrets.el (secrets-mode): New major mode. | ||
| 5 | (secrets-show-secrets, secrets-show-collections) | ||
| 6 | (secrets-expand-collection, secrets-expand-item) | ||
| 7 | (secrets-tree-widget-after-toggle-function) | ||
| 8 | (secrets-tree-widget-show-password): New defuns. | ||
| 9 | |||
| 1 | 2010-05-18 Stefan Monnier <monnier@iro.umontreal.ca> | 10 | 2010-05-18 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 11 | ||
| 3 | * emacs-lisp/smie.el (smie-next-sexp): Break inf-loop at BOB. | 12 | * emacs-lisp/smie.el (smie-next-sexp): Break inf-loop at BOB. |
| @@ -146,7 +155,7 @@ | |||
| 146 | 2010-05-13 Michael Albinus <michael.albinus@gmx.de> | 155 | 2010-05-13 Michael Albinus <michael.albinus@gmx.de> |
| 147 | 156 | ||
| 148 | * net/tramp.el (with-progress-reporter): Create reporter object | 157 | * net/tramp.el (with-progress-reporter): Create reporter object |
| 149 | only when the message would be displayed. Handled nested calls. | 158 | only when the message would be displayed. Handle nested calls. |
| 150 | (tramp-handle-load, tramp-handle-file-local-copy) | 159 | (tramp-handle-load, tramp-handle-file-local-copy) |
| 151 | (tramp-handle-insert-file-contents, tramp-handle-write-region) | 160 | (tramp-handle-insert-file-contents, tramp-handle-write-region) |
| 152 | (tramp-maybe-send-script, tramp-find-shell): | 161 | (tramp-maybe-send-script, tramp-find-shell): |
diff --git a/lisp/net/secrets.el b/lisp/net/secrets.el index c45f6fbb276..a7225d663e3 100644 --- a/lisp/net/secrets.el +++ b/lisp/net/secrets.el | |||
| @@ -129,6 +129,9 @@ | |||
| 129 | ;; (secrets-search-items "session" :user "joe") | 129 | ;; (secrets-search-items "session" :user "joe") |
| 130 | ;; => ("my item" "another item") | 130 | ;; => ("my item" "another item") |
| 131 | 131 | ||
| 132 | ;; Interactively, collections, items and their attributes could be | ||
| 133 | ;; inspected by the command `secrets-show-secrets'. | ||
| 134 | |||
| 132 | ;;; Code: | 135 | ;;; Code: |
| 133 | 136 | ||
| 134 | ;; It has been tested with GNOME Keyring 2.29.92. An implementation | 137 | ;; It has been tested with GNOME Keyring 2.29.92. An implementation |
| @@ -148,6 +151,13 @@ | |||
| 148 | 151 | ||
| 149 | (require 'dbus) | 152 | (require 'dbus) |
| 150 | 153 | ||
| 154 | (declare-function tree-widget-set-theme "tree-widget") | ||
| 155 | (declare-function widget-create-child-and-convert "wid-edit") | ||
| 156 | (declare-function widget-default-value-set "wid-edit") | ||
| 157 | (declare-function widget-field-end "wid-edit") | ||
| 158 | (declare-function widget-member "wid-edit") | ||
| 159 | (defvar tree-widget-after-toggle-functions) | ||
| 160 | |||
| 151 | (defvar secrets-enabled nil | 161 | (defvar secrets-enabled nil |
| 152 | "Whether there is a daemon offering the Secret Service API.") | 162 | "Whether there is a daemon offering the Secret Service API.") |
| 153 | 163 | ||
| @@ -665,6 +675,145 @@ If there is no such item, or the item doesn't own this attribute, return nil." | |||
| 665 | :session secrets-service item-path | 675 | :session secrets-service item-path |
| 666 | secrets-interface-item "Delete"))))) | 676 | secrets-interface-item "Delete"))))) |
| 667 | 677 | ||
| 678 | ;;; Visualization. | ||
| 679 | |||
| 680 | (define-derived-mode secrets-mode nil "Secrets" | ||
| 681 | "Major mode for presenting search results of a Xesam search. | ||
| 682 | In this mode, widgets represent the search results. | ||
| 683 | |||
| 684 | \\{secrets-mode-map} | ||
| 685 | Turning on Xesam mode runs the normal hook `xesam-mode-hook'. It | ||
| 686 | can be used to set `xesam-notify-function', which must a search | ||
| 687 | engine specific, widget :notify function to visualize xesam:url." | ||
| 688 | ;; Keymap. | ||
| 689 | (setq secrets-mode-map (copy-keymap special-mode-map)) | ||
| 690 | (set-keymap-parent secrets-mode-map widget-keymap) | ||
| 691 | (define-key secrets-mode-map "z" 'kill-this-buffer) | ||
| 692 | |||
| 693 | ;; When we toggle, we must set temporary widgets. | ||
| 694 | (set (make-local-variable 'tree-widget-after-toggle-functions) | ||
| 695 | '(secrets-tree-widget-after-toggle-function)) | ||
| 696 | |||
| 697 | (when (not (called-interactively-p 'interactive)) | ||
| 698 | ;; Initialize buffer. | ||
| 699 | (setq buffer-read-only t) | ||
| 700 | (let ((inhibit-read-only t)) | ||
| 701 | (erase-buffer)))) | ||
| 702 | |||
| 703 | ;; It doesn't make sense to call it interactively. | ||
| 704 | (put 'secrets-mode 'disabled t) | ||
| 705 | |||
| 706 | ;; The very first buffer created with `secrets-mode' does not have the | ||
| 707 | ;; keymap etc. So we create a dummy buffer. Stupid. | ||
| 708 | (with-temp-buffer (secrets-mode)) | ||
| 709 | |||
| 710 | ;;;###autoload | ||
| 711 | (defun secrets-show-secrets () | ||
| 712 | "Display a list of collections from the Secret Service API. | ||
| 713 | The collections are in tree view, that means they can be expanded | ||
| 714 | to the corresponding secret items, which could also be expanded | ||
| 715 | to their attributes." | ||
| 716 | (interactive) | ||
| 717 | ;; Create the search buffer. | ||
| 718 | (with-current-buffer (get-buffer-create "*Secrets*") | ||
| 719 | (switch-to-buffer-other-window (current-buffer)) | ||
| 720 | ;; Inialize buffer with `secrets-mode'. | ||
| 721 | (secrets-mode) | ||
| 722 | (secrets-show-collections))) | ||
| 723 | |||
| 724 | (defun secrets-show-collections () | ||
| 725 | "Show all available collections." | ||
| 726 | (let ((inhibit-read-only t) | ||
| 727 | (alias (secrets-get-alias "default"))) | ||
| 728 | (erase-buffer) | ||
| 729 | (tree-widget-set-theme "folder") | ||
| 730 | (dolist (coll (secrets-list-collections)) | ||
| 731 | (widget-create | ||
| 732 | `(tree-widget | ||
| 733 | :tag ,coll | ||
| 734 | :collection ,coll | ||
| 735 | :open nil | ||
| 736 | :sample-face bold | ||
| 737 | :expander secrets-expand-collection))))) | ||
| 738 | |||
| 739 | (defun secrets-expand-collection (widget) | ||
| 740 | "Expand items of collection shown as WIDGET." | ||
| 741 | (let ((coll (widget-get widget :collection))) | ||
| 742 | (mapcar | ||
| 743 | (lambda (item) | ||
| 744 | `(tree-widget | ||
| 745 | :tag ,item | ||
| 746 | :collection ,coll | ||
| 747 | :item ,item | ||
| 748 | :open nil | ||
| 749 | :sample-face bold | ||
| 750 | :expander secrets-expand-item)) | ||
| 751 | (secrets-list-items coll)))) | ||
| 752 | |||
| 753 | (defun secrets-expand-item (widget) | ||
| 754 | "Expand password and attributes of item shown as WIDGET." | ||
| 755 | (let* ((coll (widget-get widget :collection)) | ||
| 756 | (item (widget-get widget :item)) | ||
| 757 | (attributes (secrets-get-attributes coll item)) | ||
| 758 | ;; padding is needed to format attribute names. | ||
| 759 | (padding | ||
| 760 | (1+ | ||
| 761 | (apply | ||
| 762 | 'max | ||
| 763 | (cons | ||
| 764 | (length "password") | ||
| 765 | (mapcar | ||
| 766 | (lambda (attribute) (length (symbol-name (car attribute)))) | ||
| 767 | attributes)))))) | ||
| 768 | (cons | ||
| 769 | ;; The password widget. | ||
| 770 | `(editable-field :tag "password" | ||
| 771 | :secret ?* | ||
| 772 | :value ,(secrets-get-secret coll item) | ||
| 773 | :sample-face widget-button-pressed | ||
| 774 | ;; We specify :size in order to limit the field. | ||
| 775 | :size 0 | ||
| 776 | :format ,(concat | ||
| 777 | "%{%t%}:" | ||
| 778 | (make-string (- padding (length "password")) ? ) | ||
| 779 | "%v\n")) | ||
| 780 | (mapcar | ||
| 781 | (lambda (attribute) | ||
| 782 | (let ((name (symbol-name (car attribute))) | ||
| 783 | (value (cdr attribute))) | ||
| 784 | ;; The attribute widget. | ||
| 785 | `(editable-field :tag ,name | ||
| 786 | :value ,value | ||
| 787 | :sample-face widget-documentation | ||
| 788 | ;; We specify :size in order to limit the field. | ||
| 789 | :size 0 | ||
| 790 | :format ,(concat | ||
| 791 | "%{%t%}:" | ||
| 792 | (make-string (- padding (length name)) ? ) | ||
| 793 | "%v\n")))) | ||
| 794 | attributes)))) | ||
| 795 | |||
| 796 | (defun secrets-tree-widget-after-toggle-function (widget &rest ignore) | ||
| 797 | "Add a temporary widget to show the password." | ||
| 798 | (dolist (child (widget-get widget :children)) | ||
| 799 | (when (widget-member child :secret) | ||
| 800 | (goto-char (widget-field-end child)) | ||
| 801 | (widget-insert " ") | ||
| 802 | (widget-create-child-and-convert | ||
| 803 | child 'push-button | ||
| 804 | :notify 'secrets-tree-widget-show-password | ||
| 805 | "Show password"))) | ||
| 806 | (widget-setup)) | ||
| 807 | |||
| 808 | (defun secrets-tree-widget-show-password (widget &rest ignore) | ||
| 809 | "Show password, and remove temporary widget." | ||
| 810 | (let ((parent (widget-get widget :parent))) | ||
| 811 | (widget-put parent :secret nil) | ||
| 812 | (widget-default-value-set parent (widget-get parent :value)) | ||
| 813 | (widget-setup))) | ||
| 814 | |||
| 815 | ;;; Initialization. | ||
| 816 | |||
| 668 | (when (dbus-ping :session secrets-service 100) | 817 | (when (dbus-ping :session secrets-service 100) |
| 669 | 818 | ||
| 670 | ;; We must reset all variables, when there is a new instance of the | 819 | ;; We must reset all variables, when there is a new instance of the |