From 81f2883614c303184116449ec3583ef5c136ec2f Mon Sep 17 00:00:00 2001 From: plugd Date: Fri, 5 May 2023 10:17:17 +0200 Subject: [PATCH] Fixed small cert-related bugs, updated docs. --- ISSUES.org | 49 ++++++++++++++++++---------------- config.mk | 2 +- elpher-pkg.el | 2 +- elpher.el | 74 ++++++++++++++++++++++++++++++++------------------- elpher.texi | 42 +++++++++++++++++++++-------- 5 files changed, 106 insertions(+), 63 deletions(-) diff --git a/ISSUES.org b/ISSUES.org index ba0185c..363c25f 100644 --- a/ISSUES.org +++ b/ISSUES.org @@ -4,19 +4,6 @@ * Open Bugs -** OPEN Improve client certificate scope :gemini: -:LOGBOOK: -- State "OPEN" from [2022-10-12 Wed 09:33] -:END: - -Once activated, elpher continues to use a client certificate -for any connections to the host on which it was activated. -However, it's now common to restrict certificates also to paths -_below_ the path where the certificate was activated. - -I.e. gemini://example.com/~userA/ certificates are not applied -automatically to gemini://example.com/~userB/. - ** OPEN Sanitize certificate names :gemini: :LOGBOOK: - State "OPEN" from [2020-06-22 Mon 10:32] @@ -138,6 +125,20 @@ pop the stack, meaning that subsequent "u" commands would succeed. The fix is just to zero out the history list in the `elpher` function just as `elpher-current-page` is cleared. +** CLOSED Improve client certificate scope :gemini: +:LOGBOOK: +- State "CLOSED" from "OPEN" [2023-05-05 Fri 10:09] +- State "OPEN" from [2022-10-12 Wed 09:33] +:END: + +Once activated, elpher continues to use a client certificate +for any connections to the host on which it was activated. +However, it's now common to restrict certificates also to paths +_below_ the path where the certificate was activated. + +I.e. gemini://example.com/~userA/ certificates are not applied +automatically to gemini://example.com/~userB/. + * Open Enhancements ** OPEN Allow multiple elpher buffers [33%] @@ -151,16 +152,6 @@ this can happen: - [X] shift history out of node tree and into separate stack - [ ] make history stack variables buffer-local - [ ] have elpher-with-clean-buffer select appropriate buffer - -** OPEN Make installing existing certificates easier - :LOGBOOK: - - State "OPEN" from "CLOSED" [2020-06-22 Mon 10:34] - :END: - -It's naive to think that people don't have client certificates created -outside of elpher. Thus we need some easy way to "install" these -certificates, either by copying them or by referencing them in some -way. * Closed Enhancements @@ -329,3 +320,15 @@ and there aren't any other hotspots. - State "CLOSED" from "OPEN" [2021-08-09 Mon 17:46] :END: This used to be available, but was removed during a refactor. + + +** CLOSED Make installing existing certificates easier + :LOGBOOK: + - State "CLOSED" from "OPEN" [2023-05-05 Fri 10:10] + - State "OPEN" from "CLOSED" [2020-06-22 Mon 10:34] + :END: + +It's naive to think that people don't have client certificates created +outside of elpher. Thus we need some easy way to "install" these +certificates, either by copying them or by referencing them in some +way. diff --git a/config.mk b/config.mk index 801cb55..11af4ef 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ PKG = elpher -VERSION = 3.4.3 +VERSION = 3.5.0 INSTALLINFO = install-info MAKEINFO = makeinfo diff --git a/elpher-pkg.el b/elpher-pkg.el index bb8d23f..5cdbef2 100644 --- a/elpher-pkg.el +++ b/elpher-pkg.el @@ -1,4 +1,4 @@ -(define-package "elpher" "3.4.3" "A friendly gopher and gemini client" +(define-package "elpher" "3.5.0" "A friendly gopher and gemini client" '((emacs "27.1")) :keywords ("convenience") :authors (("Tim Vaughan" . "plugd@thelambdalab.xyz")) diff --git a/elpher.el b/elpher.el index 5f215db..608f09d 100644 --- a/elpher.el +++ b/elpher.el @@ -5,7 +5,7 @@ ;; Author: Tim Vaughan ;; Created: 11 April 2019 -;; Version: 3.4.3 +;; Version: 3.5.0 ;; Keywords: comm gopher gemini ;; Homepage: https://thelambdalab.xyz/elpher ;; Package-Requires: ((emacs "27.1")) @@ -71,7 +71,7 @@ ;;; Global constants ;; -(defconst elpher-version "3.4.3" +(defconst elpher-version "3.5.0" "Current version of elpher.") (defconst elpher-margin-width 6 @@ -241,11 +241,12 @@ meaningfully." "Label of button used to toggle formatted text." :type '(string)) -(defcustom elpher-client-certificate-map nil - "An alist representing a mapping between gemini URLs and the names -of client certificates which will be automatically activated for those -URLs. Beware that the certificates will also be active for all -subdirectories of the given URLs." +(defcustom elpher-certificate-map nil + "Register client certificates to be used for gemini URLs. +This variable contains an alist representing a mapping between gemini +URLs and the names of client certificates which will be automatically +activated for those URLs. Beware that the certificates will also be +active for all subdirectories of the given URLs." :type '(alist :key-type string :value-type string)) ;; Face customizations @@ -973,7 +974,8 @@ when the certificate is no longer needed for the current session. Otherwise, the certificate will be given a 100 year expiration period and the files will not be deleted. -The function returns a list containing the current host name, the +The function returns a list containing the URL-PREFIX of addresses +for which the certificate should be used in this session, the temporary flag, and the key and cert file names in the form required by `gnutls-boot-parameters`." (let ((exp-key-file (expand-file-name key-file)) @@ -995,7 +997,10 @@ by `gnutls-boot-parameters`." (defun elpher-generate-throwaway-certificate (url-prefix) "Generate and return details of a throwaway certificate. The key and certificate files will be deleted when they are no -longer needed for this session." +longer needed for this session. + +The certificate will be marked as applying to all addresses with URLs +starting with URL-PREFIX." (let* ((file-base (make-temp-name "elpher")) (key-file (concat temporary-file-directory file-base ".key")) (cert-file (concat temporary-file-directory file-base ".crt"))) @@ -1007,7 +1012,10 @@ The argument FILE-BASE is used as the base for the key and certificate files, while COMMON-NAME specifies the common name field of the certificate. -The key and certificate files are written to in `elpher-certificate-directory'." +The key and certificate files are written to in `elpher-certificate-directory'. + +In this session, the certificate will remain active for all addresses +having URLs starting with URL-PREFIX." (let* ((key-file (concat elpher-certificate-directory file-base ".key")) (cert-file (concat elpher-certificate-directory file-base ".crt"))) (elpher-generate-certificate common-name key-file cert-file url-prefix))) @@ -1015,19 +1023,25 @@ The key and certificate files are written to in `elpher-certificate-directory'." (defun elpher-get-existing-certificate (file-base url-prefix) "Return a certificate object corresponding to an existing certificate. It is assumed that the key files FILE-BASE.key and FILE-BASE.crt exist in -the directory `elpher-certificate-directory'." +the directory `elpher-certificate-directory'. + +In this session, the certificate will remain active for all addresses +having URLs starting with URL-PREFIX." (let* ((key-file (concat elpher-certificate-directory file-base ".key")) (cert-file (concat elpher-certificate-directory file-base ".crt"))) - (list (elpher-address-to-url (elpher-page-address elpher-current-page)) + (list url-prefix nil (expand-file-name key-file) (expand-file-name cert-file)))) -(defun elpher-install-certificate (key-file-src cert-file-src file-base) +(defun elpher-install-certificate (key-file-src cert-file-src file-base url-prefix) "Install a key+certificate file pair in `elpher-certificate-directory'. The strings KEY-FILE-SRC and CERT-FILE-SRC are the existing key and certificate files to install. The argument FILE-BASE is used as the -base for the installed key and certificate files." +base for the installed key and certificate files. + +In this session, the certificate will remain active for all addresses +having URLs starting with URL-PREFIX." (let* ((key-file (concat elpher-certificate-directory file-base ".key")) (cert-file (concat elpher-certificate-directory file-base ".crt"))) (if (or (file-exists-p key-file) @@ -1038,7 +1052,7 @@ base for the installed key and certificate files." (error "Either of the key or certificate files do not exist")) (copy-file key-file-src key-file) (copy-file cert-file-src cert-file) - (list (elpher-address-to-url (elpher-page-address elpher-current-page)) + (list url-prefix nil (expand-file-name key-file) (expand-file-name cert-file)))) @@ -1064,7 +1078,7 @@ are also deleted." (when (cadr elpher-client-certificate) (delete-file (elt elpher-client-certificate 2)) (delete-file (elt elpher-client-certificate 3))) - (setq elpher-client-certificate nil) + (setq-local elpher-client-certificate nil) (if (called-interactively-p 'any) (message "Client certificate forgotten."))))) @@ -1072,10 +1086,10 @@ are also deleted." "Retrieve the `gnutls-boot-parameters'-compatable keylist. This is obtained from the client certificate described by -`elpher-current-certificate', if one is available and the host for -that certificate matches the host in ADDRESS. +`elpher-current-certificate', if one is available and the +URL prefix for that certificate matches ADDRESS. -If `elpher-current-certificate' is non-nil, and its host name doesn't +If `elpher-current-certificate' is non-nil, and its URL prefix doesn't match that of ADDRESS, the certificate is forgotten." (if elpher-client-certificate (if (string-prefix-p (car elpher-client-certificate) @@ -1407,7 +1421,7 @@ that the response was malformed." (elpher-address-to-url (elpher-page-address elpher-current-page)))))) (unless chosen-certificate (error "Gemini server requires a client certificate and none was provided")) - (setq elpher-client-certificate chosen-certificate)) + (setq-local elpher-client-certificate chosen-certificate)) (elpher-with-clean-buffer) (elpher-get-gemini-response (elpher-page-address elpher-current-page) renderer)) (_other @@ -1417,15 +1431,18 @@ that the response was malformed." (defun elpher-acquire-client-certificate (url-prefix) "Select a pre-defined client certificate or prompt for one. In this case, \"pre-defined\" means a certificate provided by -the `elpher-client-certificate-map' variable." +the `elpher-certificate-map' variable. + +For this session, the certificate will remain active for all addresses +having URLs begining with URL-PREFIX." (let ((entry (assoc url-prefix - elpher-client-certificate-map + elpher-certificate-map #'string-prefix-p))) (if entry (let ((cert-url-prefix (car entry)) (cert-name (cadr entry))) - (message "Using certificate \"%s\" specified in elpher-client-certificate-map" - cert-name) + (message "Using certificate \"%s\" specified in elpher-certificate-map with prefix \"%s\"" + cert-name cert-url-prefix) (elpher-get-existing-certificate cert-name cert-url-prefix)) (elpher-prompt-for-client-certificate url-prefix)))) @@ -1443,7 +1460,10 @@ are the possible answers." (defun elpher-prompt-for-client-certificate (url-prefix) - "Prompt for a client certificate to use to establish a TLS connection." + "Prompt for a client certificate to use to establish a TLS connection. + +In this session, the chosen certificate will remain active for all +addresses with URLs matching URL-PREFIX." (let* ((read-answer-short t)) (pcase (read-answer "What do you want to do? " '(("throwaway" ?t @@ -1453,7 +1473,7 @@ are the possible answers." ("abort" ?a "stop immediately"))) ("throwaway" - (setq elpher-client-certificate (elpher-generate-throwaway-certificate))) + (setq-local elpher-client-certificate (elpher-generate-throwaway-certificate url-prefix))) ("persistent" (let* ((existing-certificates (elpher-list-existing-certificates)) (file-base (completing-read @@ -1462,7 +1482,7 @@ are the possible answers." (if (string-empty-p (string-trim file-base)) nil (if (member file-base existing-certificates) - (setq elpher-client-certificate + (setq-local elpher-client-certificate (elpher-get-existing-certificate file-base url-prefix)) (pcase (read-answer "Generate new certificate or install externally-generated one? " '(("new" ?n diff --git a/elpher.texi b/elpher.texi index c9e3838..8b5c65d 100644 --- a/elpher.texi +++ b/elpher.texi @@ -1,7 +1,7 @@ \input texinfo @c -*-texinfo-*- @setfilename elpher.info -@settitle Elpher Manual v3.4.1 +@settitle Elpher Manual v3.5.0 @dircategory Emacs @direntry @@ -84,6 +84,7 @@ Gemini support News +* v3.5.0:: * v3.4.0:: * v3.3.0:: * v3.2.0:: @@ -146,7 +147,7 @@ have some ideas. * Installing by hand:: Installing directly from the source @end menu -@node Installing from ELPA or MELPA, , Installation, Installation +@node Installing from ELPA or MELPA, Installing by hand, Installation, Installation @section Installing from ELPA or MELPA Elpher is available on the non-GNU ELPA package archive. If you are @@ -604,7 +605,7 @@ change as the protocol develops further. * Hiding preformatted text in text/gemini documents:: An accessibility option @end menu -@node Client Certificates for Gemini, , Gemini support, Gemini support +@node Client Certificates for Gemini, Hiding preformatted text in text/gemini documents, Gemini support, Gemini support @section Client Certificates for Gemini Gemini makes explicit use of the client certificate mechanism that TLS @@ -658,10 +659,11 @@ Alternatively, pressing the @key{i} key will cause Elpher to ask for the locations of existing key and certificate files to add to @code{elpher-certificate-directory} under the chosen name. -Once a certificate is selected, it will be used for all subsequent TLS -transactions to the host for which the certificate was created. -It is immediately ``forgotten'' when a TLS connection to another host -is attempted, or the following command is issued: +Once a certificate is selected, it will be used for all subsequent +gemini requests involving URLs begining with the URL for for which the +certificate was created. It is immediately ``forgotten'' when a TLS +connection to a non-matching URL is attempted, or the following command +is issued: @table @asis @keycmd{@key{F},elpher-forget-certificate} @@ -672,6 +674,11 @@ In either case, ``forgetting'' means that the details of the key and certificate file pair are erased from memory. Furthermore, in the case of throw-away certificates, the corresponding files are deleted. +Persistant client certificates can be added to the alist contained in the +customization variable @code{elpher-certificate-map} so that they are +automatically activated whenever a gemini page with the matching URL +prefix is visited. + @node Hiding preformatted text in text/gemini documents, , Client Certificates for Gemini, Gemini support @section Hiding preformatted text in text/gemini documents @@ -851,6 +858,7 @@ See the customization group itself for details. This chapter documents the major changes introduced by Elpher releases. @menu +* v3.5.0:: * v3.4.0:: * v3.3.0:: * v3.2.0:: @@ -858,7 +866,19 @@ This chapter documents the major changes introduced by Elpher releases. * v3.0.0:: @end menu -@node v3.4.0, , News, News +@node v3.5.0, v3.4.0, News, News +@section v3.5.0 + +@subsection Automatic activation of client certificates in gemini + +This version introduces a new customization variable +@code{elpher-certificate-map} which allows you to pre-specify +a set of gemini URLs and the client certificates which should +be used when accessing them. + +@xref{Client Certificates for Gemini} for more details. + +@node v3.4.0, v3.3.0, v3.5.0, News @section v3.4.0 @subsection Toggling preformatted text visibility @@ -873,7 +893,7 @@ block. This feature is intended to make it easier for people using screen readers to read text/gemini documents. -@node v3.3.0, , v3.4.0, News +@node v3.3.0, v3.2.0, v3.4.0, News @section v3.3.0 This version includes lots of bug fixes, as well as a couple of new @@ -895,7 +915,7 @@ characters and displays the decoded IRI. (For security reasons, the @code{elpher-info-current} command (@kbd{I}) always displays both the decoded IRI and the URI when they differ.) -@node v3.2.0, , v3.3.0, News +@node v3.2.0, v3.1.0, v3.3.0, News @section v3.2.0 This version introduces several minor changes which, together, make it @@ -922,7 +942,7 @@ of the document to be loaded as elpher's ``start page''. By default this is set to @samp{about:welcome}, but any elpher-accessible URL is valid. @pxref{Customization} for suggestions. -@node v3.1.0, , v3.2.0, News +@node v3.1.0, v3.0.0, v3.2.0, News @section v3.1.0 @subsection Bookmarks system -- 2.20.1