diff --git a/src/gui/client/certificates-window.lisp b/src/gui/client/certificates-window.lisp index 92b3f7c..d772693 100644 --- a/src/gui/client/certificates-window.lisp +++ b/src/gui/client/certificates-window.lisp @@ -10,15 +10,16 @@ (gui:treeview-delete-all tree) (setf rows new-rows) (loop for row in rows do - (let* ((tree-row (make-instance 'gui:tree-item - :id (db:row-cache-key row) - :text (db:row-cache-key row) - :column-values (list (getf row :file) - (getf row :hash)) - :index gui:+treeview-last-index+))) - (gui:treeview-insert-item tree :item tree-row)))) - (gui:treeview-refit-columns-width (gui-goodies:tree certificate-frame)) - certificate-frame) + (let ((tree-row (make-instance 'gui:tree-item + :id (db:row-cache-key row) + :text (db:row-cache-key row) + :column-values (list (getf row :file) + (getf row :hash) + (getf row :key-file)) + :index gui:+treeview-last-index+))) + (gui:treeview-insert-item tree :item tree-row))) + (gui:treeview-refit-columns-width (gui-goodies:tree certificate-frame)) + certificate-frame)) (defun all-rows () (cev:enqueue-request-and-wait-results :gemini-certificates @@ -32,8 +33,9 @@ (treeview (make-instance 'gui:scrolled-treeview :master object :pack '(:side :top :expand t :fill :both) - :columns (list (_ "File") - (_ "Fingerprint"))))) + :columns (list (_ "Certificate file") + (_ "Fingerprint") + (_ "Key file"))))) (setf tree treeview) (gui:treeview-heading tree gui:+treeview-first-column-id+ :text (_ "Address")) @@ -52,6 +54,77 @@ (let ((new-rows (all-rows))) (resync-rows certificate-frame new-rows))))))) +(defun contextual-menu-clrs (treeview-widget) + (labels ((row-values () + (a:when-let* ((item (first (gui:treeview-get-selection treeview-widget)))) + (gui:column-values item))) + (key-path () + (a:when-let* ((row-values (row-values))) + (third row-values))) + (cert-path () + (a:when-let* ((row-values (row-values))) + (first row-values))) + (hash-value () + (a:when-let* ((row-values (row-values))) + (second row-values))) + (change-passphrase () + (a:when-let ((file-path (key-path))) + (handler-case + (multiple-value-bind (old-password new-password) + (gui-mw:change-password-dialog treeview-widget + (_ "Change password") + (_ "Change the password of the certificate") + (_ "Old password") + (_ "New password") + (_ "Repeat new password") + (_ "password and confirmation does not match") + :button-message (_ "OK")) + (os-utils:change-ssl-key-passphrase file-path + old-password + new-password) + (gui-goodies:info-dialog treeview-widget + (format nil + (_ "Password changed for key") + file-path))) + (error (e) + (gui-goodies:error-dialog treeview-widget (format nil "~a" e)))))) + (copy-key-path () + (a:when-let ((file-path (key-path))) + (os-utils:copy-to-clipboard file-path) + (client-main-window:print-info-message (format nil + (_ "path ~s copied to clipboard") + file-path)))) + (copy-cert-path () + (a:when-let ((file-path (cert-path))) + (os-utils:copy-to-clipboard file-path) + (client-main-window:print-info-message (format nil + (_ "path ~s copied to clipboard") + file-path)))) + (copy-hash () + (a:when-let ((hash-value (hash-value))) + (os-utils:copy-to-clipboard hash-value) + (client-main-window:print-info-message (format nil + (_ "hash ~s copied to clipboard") + hash-value))))) + (lambda (z) + (declare (ignore z)) + (let* ((popup-menu (gui:make-menu nil (_"certificate menu"))) + (x (gui:screen-mouse-x)) + (y (gui:screen-mouse-y))) + (gui:make-menubutton popup-menu + (_ "Change passphrase") + #'change-passphrase) + (gui:make-menubutton popup-menu + (_ "Copy key path to clipboard") + #'copy-key-path) + (gui:make-menubutton popup-menu + (_ "Copy certificate path to clipboard") + #'copy-cert-path) + (gui:make-menubutton popup-menu + (_ "Copy certificate's fingerprint to clipboard") + #'copy-hash) + (gui:popup popup-menu x y))))) + (defclass import-window (gui:frame) ((url-entry :initform nil @@ -219,4 +292,7 @@ (gui:grid table 0 0 :sticky :nwe) (gui:grid buttons-frame 1 0 :sticky :s) (gui:grid delete-button 0 0 :sticky :s) - (gui:grid import-button 0 1 :sticky :s)))) + (gui:grid import-button 0 1 :sticky :s) + (gui:bind (gui:treeview (gui-goodies:tree table)) + #$<3>$ + (contextual-menu-clrs (gui:treeview (gui-goodies:tree table))))))) diff --git a/src/gui/server/public-api-gemini-certificates.lisp b/src/gui/server/public-api-gemini-certificates.lisp index c2d17f0..279480a 100644 --- a/src/gui/server/public-api-gemini-certificates.lisp +++ b/src/gui/server/public-api-gemini-certificates.lisp @@ -35,11 +35,14 @@ (db:row-cache-key b))))) (certificates-with-hash (loop for certificate-row in certificates-rows collect - (let* ((cache-key (db:row-cache-key certificate-row)) - (pem-file (gemini-client::tls-cert-find cache-key)) - (hash (x509:certificate-fingerprint pem-file))) - (append (list :hash hash :file pem-file) - certificate-row))))) + (let* ((cache-key (db:row-cache-key certificate-row))) + (multiple-value-bind (pem-file key-file) + (gemini-client::tls-cert-find cache-key) + (let ((hash (x509:certificate-fingerprint pem-file))) + (append (list :hash hash + :file pem-file + :key-file key-file) + certificate-row))))))) (make-instance 'gemini-certificates :contents certificates-with-hash))) (defun invalidate-cached-value (cache-key) diff --git a/src/package.lisp b/src/package.lisp index 004b397..8fe8301 100644 --- a/src/package.lisp +++ b/src/package.lisp @@ -405,6 +405,7 @@ :user-cache-dir :cached-file-path :generate-ssl-certificate + :change-ssl-key-passphrase :send-to-pipe :open-link-with-program :open-resource-with-external-program @@ -3471,6 +3472,7 @@ :attach-tooltips :with-busy* :password-dialog + :change-password-dialog :table-frame :tree :rows