diff --git a/web/share/gpgweb.el b/web/share/gpgweb.el index e3163ff..6b6632b 100644 --- a/web/share/gpgweb.el +++ b/web/share/gpgweb.el @@ -1,553 +1,554 @@ ;;; gpgweb.el --- elisp helper code for the GnuPG web pages (if (< (string-to-number emacs-version) 24) (require 'org-exp)) ;; makeindex disabled because the generated file is created in the ;; source directory. (defun gpgweb-setup-project () "Set up an org-publish project for the gnupg.org website." (progn (require 'ox-gpgweb (concat gpgweb-root-dir "share/ox-gpgweb.el")) (aput 'org-publish-project-alist "gpgweb-org" `(:base-directory ,gpgweb-root-dir :base-extension "org" :language "en" :html-extension "html" :recursive t :publishing-directory ,gpgweb-stage-dir :publishing-function gpgweb-org-to-html :body-only t :section-numbers nil :tags nil :with-toc nil :makeindex nil :auto-sitemap nil :sitemap-title "GnuPG - Sitemap" :sitemap-sort-folders "last" :sitemap-file-entry-format "%t @@html:@@(%d)@@html:@@" :style-include-default nil :timestamp-file nil :html-head "" :html-head-include-scripts nil)) (aput 'org-publish-project-alist "gpgweb-other" `(:base-directory ,gpgweb-root-dir :base-extension "jpg\\|png\\|css\\|txt\\|rss\\|lst\\|sig\\|js\\|map\\|eot\\|ttf\\|woff\\|woff2\\|svg\\|asc" :recursive t :publishing-directory ,gpgweb-stage-dir :publishing-function org-publish-attachment :completion-function gpgweb-upload)) (aput 'org-publish-project-alist "gpgweb" '(:components ("gpgweb-org" "gpgweb-other"))) (add-hook 'org-export-before-processing-hook 'gpgweb-preprocess))) (defun gpgweb-preprocess (backend) "Insert certain stuff before processing." (let () (goto-char (point-min)) (when (re-search-forward "^#\\+GPGWEB-NEED-SWDB\\b" 2048 t) (beginning-of-line) (kill-line 1) (insert (org-file-contents (concat gpgweb-root-dir "swdb.mac") 'noerror))))) (defun gpgweb-insert-header (title committed-at custom) "Insert the header. COMMITTED-AT is the commit date string of the source file or nil if not available. If CUSTOM is true only a minimal header is set." (goto-char (point-min)) (insert " " title " ") (when (and committed-at (>= (length committed-at) 10)) (insert "\n")) (insert " ") (unless custom (insert " "))) (defconst gpgweb-gnupg-menu-alist '(("/index.html" "Home" (("/index.html" "Home") ("/news.html" "News") ("/people/index.html" "People") ("/verein/index.html" "Verein") ("/documentation/sites.html" "Sites"))) ("/donate/index.html" "Donate" (("/donate/index.html" "Donate") ("/donate/kudos.html" "List of Donors"))) ("/software/index.html" "Software" (("/software/index.html" "GnuPG") ("/software/frontends.html" "Frontends") ("/software/tools.html" "Tools") ("/software/libraries.html" "Libraries") ("/software/swlist.html" "All"))) ("/download/index.html" "Download" (("/download/index.html" "Download") ("/download/integrity_check.html" "Integrity Check") + ("/download/signature_key.html" "Release Keys") ("/download/supported_systems.html" "Supported Systems") ("/download/release_notes.html" "Release Notes") ("/download/mirrors.html" "Mirrors") ("/download/git.html" "GIT"))) ("/documentation/index.html" "Documentation" (("/documentation/howtos.html" "HOWTOs") ("/documentation/manuals.html" "Manuals") ("/documentation/guides.html" "Guides") ("/documentation/faqs.html" "FAQs") ("/documentation/mailing-lists.html" "Mailing Lists") ("/service.html" "3rd Party Support") ("/documentation/bts.html" "Bug Tracker") ("/documentation/security.html" "Security"))) ("/blog/index.html" "Blog")) "The definition of the gnupg.org menu structure.") (defconst gpgweb-gnupg-bottom-menu-alist '(("/privacy-policy.html" "Privacy Policy" ()) ("/imprint.html" "Imprint" ()) ("/misc/index.html" "Archive" ()) ("/sitemap.html" "Sitemap" ()) ("/blog/index.html" "Blog" ()) ("/ftp/index.html" "Files" ())) "The definition of the gnupg.org bottom menu structure.") (defun gpgweb--any-selected-menu-p (menu selected-file) "Return t if any item in MENU has been selected." (let ((item (car menu)) res) (when menu (when item (when (string= (car item) selected-file) (setq res t)) (when (caddr item) (when (gpgweb--any-selected-menu-p (caddr item) selected-file) (setq res t)))) (when (gpgweb--any-selected-menu-p (cdr menu) selected-file) (setq res t))) res)) (defun gpgweb--selected-top-menu (menu selected-file) "Return the selected top menu or nil." (when menu (let ((item (car menu))) (if (and item (or (string= (car item) selected-file) (gpgweb--any-selected-menu-p (caddr item) selected-file))) menu (gpgweb--selected-top-menu (cdr menu) selected-file))))) (defun gpgweb--insert-menu (menu lvl selected-file) "Helper function to insert the menu." (when menu (let ((item (car menu))) (when item (dotimes (i (1+ lvl)) (insert " ")) (if (caddr item) (progn (insert "
  • " (cadr item) "\n")) (progn (insert "
  • " (cadr item) "\n"))) (when (caddr item) (dotimes (i (1+ lvl)) (insert " ")) (insert " \n")) (dotimes (i (1+ lvl)) (insert " ")) (insert "
  • \n"))) (gpgweb--insert-menu (cdr menu) lvl selected-file))) (defun gpgweb--insert-submenu (menu selected-file) "Helper function to insert the sub-menu." (when menu (let ((item (car menu))) (when item (insert "
  • " (cadr item) "
  • \n"))) (gpgweb--insert-submenu (cdr menu) selected-file))) (defun gpgweb-insert-menu (selected-file) "Insert the menu structure into the HTML file." (goto-char (point-min)) (when (re-search-forward "^\n" nil t) (insert "
     
    ") (let ((m (caddr (car (gpgweb--selected-top-menu gpgweb-gnupg-menu-alist selected-file))))) (when m (insert "\n"))) (insert "
    "))) (defun gpgweb-blog-index (orgfile filelist) "Return the index of ORGFILE in FILELIST or nil if not found." (let (found (i 0)) (while (and filelist (not found)) (if (string= orgfile (car filelist)) (setq found i)) (setq i (1+ i)) (setq filelist (cdr filelist))) found)) (defun gpgweb-blog-prev (fileidx filelist) "Return the chronological previous file at FILEIDX from FILELIST with the suffixed replaced by \"html\"." (if (> fileidx 1) (concat (file-name-sans-extension (nth (1- fileidx) filelist)) ".html"))) (defun gpgweb-blog-next (orgfile filelist) "Return the chronological next file at FILEIDX from FILELIST with the suffixed replaced by \"html\"." (if (< fileidx (1- (length filelist))) (concat (file-name-sans-extension (nth (1+ fileidx) filelist)) ".html"))) (defun gpgweb-fixup-blog (info orgfile filelist) "Insert the blog specific content. INFO is the usual plist. ORGFILE is the name of the current source file without the directory part. If FILELIST is a list it has an ordered list of org filenames." (let ((authorstr (car (plist-get info :author))) (datestr (car (plist-get info :date)))) (goto-char (point-min)) (if (re-search-forward "^
    " nil t) (let* ((indexp (string= orgfile "index.org")) (fileidx (if (listp filelist) (if indexp (1- (length filelist)) (gpgweb-blog-index orgfile filelist)))) (prevfile (if fileidx (gpgweb-blog-prev fileidx filelist))) (nextfile (if (and fileidx (not indexp)) (gpgweb-blog-next fileidx filelist)))) (move-beginning-of-line nil) (insert "\n"))) (if (and datestr authorstr) (if (re-search-forward "^

    Posted " datestr " by " authorstr "

    \n"))))) (defun gpgweb-insert-footer (htmlfile committed-at blogmode) "Insert the footer. HTMLFILE is HTML file name and COMMITTED-AT is the commit date string of the source file or nil if not available." (let ((srcfile (concat "https://git.gnupg.org/cgi-bin/gitweb.cgi?" "p=gnupg-doc.git;a=blob;f=" (if blogmode "misc/blog.gnupg.org" "web/") ;; The replace below is a hack to cope with ;; blogmode where HTMLFILE is like "./foo.html". (replace-regexp-in-string "^\\./" "/" (file-name-sans-extension htmlfile) t) ".org")) (changed (if (and committed-at (>= (length committed-at) 10)) (substring committed-at 0 10) "[unknown]"))) (goto-char (point-max)) (insert "

      ") (gpgweb--insert-menu gpgweb-gnupg-bottom-menu-alist 0 nil) (insert "
    ") (insert "
    \"Traueranzeige:

    ") (goto-char (point-min)) (unless (search-forward "" nil t) (goto-char (point-max)) (if (string-prefix-p "verein/" htmlfile) (insert "
    \"CC  This web page is Copyright 2018--2020 GnuPG e.V. and licensed under a Creative Commons Attribution-ShareAlike 4.0 International License. See copying for details. Page source last changed on " changed ".
    \n") (insert "
    \"CC  These web pages are Copyright 1998--2020 The GnuPG Project and licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License. See copying for details. Page source last changed on " changed ".
    \n"))) (goto-char (point-max)) (insert "
    "))) (defun gpgweb-publish-find-title (file &optional reset) "Find the title of FILE in project. This is a copy of org-publish-find-title which switches the buffer into read-write mode so that it works with read-only files." (or (and (not reset) (org-publish-cache-get-file-property file :title nil t)) (let* ((org-inhibit-startup t) (visiting (find-buffer-visiting file)) (buffer (or visiting (find-file-noselect file)))) (with-current-buffer buffer (toggle-read-only 0) (let ((title (let ((property (plist-get ;; protect local variables in open buffers (if visiting (org-export-with-buffer-copy (org-export-get-environment)) (org-export-get-environment)) :title))) (if property (org-no-properties (org-element-interpret-data property)) (file-name-nondirectory (file-name-sans-extension file)))))) (unless visiting (kill-buffer buffer)) (org-publish-cache-set-file-property file :title title) title))))) (defun gpgweb-want-custom-page-p () "Return true if the current buffer indicated that it wants to be a custom page." (let ((savepoint (point)) (result)) (goto-char (point-min)) (setq result (not (not (search-forward "" nil t)))) (goto-char savepoint) result)) (defun gpgweb-postprocess-html (plist orgfile htmlfile blogmode) "Post-process the generated HTML file - Insert header and footer - Insert \"class=selected\" into the active menu entry - Fixup sitemap. If blogmode is not nil the output is rendered as a blog. BLOGMODE may then contain an ordered list of org file names which are used to create the previous and Next links for an entry." (let* ((visitingp (find-buffer-visiting htmlfile)) (work-buffer (or visitingp (find-file-noselect htmlfile))) (committed-at (shell-command-to-string (concat "git" (if blogmode (concat " -C " gpgweb-blog-dir)) " log -1 --format='%ci' -- " orgfile)))) (prog1 (with-current-buffer work-buffer (let ((fname (file-name-nondirectory htmlfile)) (fname-2 (replace-regexp-in-string ".*/gnupg-doc-stage/web/\\(.*\\)$" "\\1" htmlfile t)) (title (gpgweb-publish-find-title orgfile)) (custom (gpgweb-want-custom-page-p))) ;; Insert header, menu, and footer. (gpgweb-insert-header title committed-at custom) (unless custom (goto-char (point-min)) (unless (search-forward "" nil t) (gpgweb-insert-menu fname-2)) (if blogmode (gpgweb-fixup-blog plist (file-name-nondirectory orgfile) blogmode)) (gpgweb-insert-footer fname-2 committed-at blogmode)) ; Fixup the sitemap (when (string-equal fname "sitemap.html") (goto-char (point-min)) (while (re-search-forward "^.*
  • .*>\\(GnuPG - \\).* and ; attributes. (goto-char (point-min)) (when (search-forward "" nil t) (goto-char (point-min)) (while (re-search-forward "^ pub rsa3072 2017-03-17 [expires: 2027-03-15] Key fingerprint = 5B80 C575 4298 F0CB 55D8 ED6A BCEF 7E29 4B09 2E28 uid Andre Heinecke (Release Signing Key) #+END_EXAMPLE Here is a public key block with the above keys: #+BEGIN_EXAMPLE -----BEGIN PGP PUBLIC KEY BLOCK----- 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 dzIRiXx+Nxv1Pr9L7A4/tq8= =qzkY -----END PGP PUBLIC KEY BLOCK----- #+END_EXAMPLE +** Old Signature Keys + Releases done in the years 1996 to 2010 were signed by this key: #+BEGIN_EXAMPLE pub rsa1024/1CE0C630 2006-01-01 [expired: 2011-06-30] Key fingerprint = 7B96 D396 E647 1601 754B E4DB 53B6 20D0 1CE0 C630 uid [ expired] Werner Koch (dist sig) #+END_EXAMPLE Releases done in the years 1998 to 2005 were signed by this key: #+BEGIN_EXAMPLE pub dsa1024/57548DCD 1998-07-07 [expired: 2005-12-31] Key fingerprint = 6BD9 050F D8FC 941B 4341 2DCC 68B7 AB89 5754 8DCD uid [ expired] Werner Koch (gnupg sig) #+END_EXAMPLE For reference here is a public key block with expired keys used to sign older releases: #+begin_example -----BEGIN PGP PUBLIC KEY BLOCK----- mQENBFRQXwcBCACHWajyv6RVZVM2w2XK6uba11kqJBt15WCkGBwOeojd8BXnwLec LwNW4rmpUZk8H+Nu7jaNzwFcY/WXpQ/7nXktAvkalO1XSlFZQ7TZY65MtkFVByrn e/NuDXFWjfWtZX3qaoYA+zyUZQKbT1+m6JUpCiM7r8iGSDv9ufN5JtxfleT14ouH IHu2dqS5gl5FibhuOz5gMCkrwgVDJ69gXymNNxstNI0k9b1YsKyjOzLXWvjF19Fx NaMBFXPlXNOdD4/Hxi2yeNDerA0kGmyowsJ0M3tgaGH+aXA+OB2r9QV/n5tjp/d7 DS+yEGoicFDJwFKZjKhfRh7ewBL85Hie7llpABEBAAG0JkRhdmlkIFNoYXcgKEdu dVBHIFJlbGVhc2UgU2lnbmluZyBLZXkpiQE+BBMBAgAoBQJYn3oyAhsDBQkJunbu BgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRAEN28+4IVpWcUJB/46snb++ypP IhQjUPHVHb9U8r92QSh/XLi6xxJcqokzpif7fCvh+DrenlLOQznwB1PDPBmTlffv 2p7XvEAPMoaEOA/i67phDzsjaUrHkevsv0fAIqX8yHmVKQ773hhD+VbuO29oJ7h7 LIQ5yrJScpmNmE2FjnjcHGHnr9UaoU4RQVqA9jyHEVt+aRvKvQEzMtFlSIkn6rBN eU5HHh6oHhlzkNUP9hExRPBorodWEH0r7E2C+CORloR9ZG/EK4rU+Fkp1mdVStt2 maNfG5QxaFgseT9X+QMeD7ktht5I/t05coSL/1dKyUjiHp84K8uZIfi09LPI2dT9 ikq5JHN8zHXZmI4EQ7f6xwEEANCZGXorXMkDKpNsRnf+ZhqHOPmDcEKPDkplcCL2 PFACN7QaK4ReoWvZ4mqmVOL3ZXU51zFNI9aD3JAIToET2jr2hGYWFExdBf9eaYgB eXZGUOnbJl1VJDzWDGU6ZHNpwPiAAgYjpsoBgZCxbl7x0VtYukjc9vIkR/1GXGC4 v9ohACCBVlCZtCZXZXJuZXIgS29jaCAoZGlzdCBzaWcpIDxkZDlqbkBnbnUub3Jn Poi8BBMBAgAmAhsDBgsJCAcDAgQVAggDBBYCAwECHgECF4AFAk0tjLcFCQpUTmEA CgkQU7Yg0BzgxjDweAP9FNQyUfS25FrgbPCqOiiaCizFSOomDSQYQLZt3cVnlMQN enmA1lv2/S5OSp47UlrhjnqmuzArF55Mh5DvPChPSHDN5hZ4XxTdqmoHf50XIZfT D7HToH/7oO4+9gJb9lfLNvEddB0438Mknv6Jl1sCt6p/KLujeyA/hMAle4tntruZ AaIENaIeHhEEAP6XSuDmn2tbgzewq+Z7LOGzaYPGFEoNNVVSdPCkwhHaQgD2lPjc 2j9yg9qMO+FlNoMz+9LPbkhkNlYnuAS7zpGmgR22v94rwa4NyCxa8Wzn5ikIPBYb Z3Hf0wTsM35JG8QTXFSbgT0bY2d3ZQ20uCDzbCCL9krgiH0JgPKjRr1rAKCKyfdG 9n8xEQmZCrX5KMmAPH5zawQA4SfEZiKyogpw5N085NOJ7ujvH6d6ba5pzu45brw3 7BFbGEY8jGw5254whrtT3haD9h2fh/ZaeAmkG8o1odiZbyPVDnO9ldekhZFdK/JN HrjUFx4Yc11iJH8+IMEmwZDdpzufunCFXip7HchWJEMlbPkPOvzzH46O7rcq3Fi6 tQgEAKLt3WtSUeviiTuIFGVYdhdTaGlQhDwL5Q4TVddP4cHuZktJE41CdYzJeeps ABb4RRRfbGlvngJ68CDh46KW3R6zwZkyZTpzTB1SycxZao4ocEUWUMi/Ijbtpn2q 5/TK9vLreQUJqdApzRCeoZdArO5dsWoFhbZRCtiCNeOLyt3xtCdXZXJuZXIgS29j aCAoZ251cGcgc2lnKSA8ZGQ5am5AZ251Lm9yZz6IYQQTEQIAIQIXgAUJDhSH/QUC QbxoXgYLCQgHAwIDFQIDAxYCAQIeAQAKCRBot6uJV1SNzQSTAJ9Nd9d2oNLYI6xl GbQ5SmG5jSHjHgCdFKVbI8acpQXEo7DxPDAJIux29kc= =R+iH -----END PGP PUBLIC KEY BLOCK----- #+end_example