From: Nick Bowler Date: Sat, 26 Mar 2022 01:34:12 +0000 (-0400) Subject: Update GPG instructions for packages. X-Git-Url: https://git.draconx.ca/gitweb/homepage.git/commitdiff_plain/fe387389cf437d11a969d51b5625cd6bc4ddb79f Update GPG instructions for packages. It seems the keys.gnupg.net keyserver has been dead for some time, so it is not a viable option for public key distribution. The new-ish Web Key Directory gives similar functionality but unlike third party keyservers is self-hosted. --- diff --git a/Rules b/Rules index 26bcb40..7acf71d 100644 --- a/Rules +++ b/Rules @@ -1,6 +1,6 @@ #!/usr/bin/env ruby # -# Copyright © 2018-2020 Nick Bowler +# Copyright © 2018-2022 Nick Bowler # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -68,6 +68,8 @@ preprocess do @items.create("", attrs, "#{dir}/index.lst") end + + create_wkd_items(@items["/pubring.gpg"]) end postprocess do @@ -216,6 +218,19 @@ compile '/**/*.scss' do write @item.identifier.without_ext + '.css' end +compile '/gpg/*' do + filter :wkd_export, armor: true + write "/pubring/" + @item.identifier.components.last + ".asc" +end + +compile '/gpg/*', rep: :hu do + filter :wkd_export + write "/pubring/wkd/" + @item[:wkd_hash] +end + +compile '/*.gpg' do +end + compile '/**/*.svg' do filter :scour, comment_stripping: true write @item.identifier.to_s diff --git a/content/pubring.gpg b/content/pubring.gpg new file mode 100644 index 0000000..456deef Binary files /dev/null and b/content/pubring.gpg differ diff --git a/lib/gpg-wkd.rb b/lib/gpg-wkd.rb new file mode 100644 index 0000000..c6e5fcc --- /dev/null +++ b/lib/gpg-wkd.rb @@ -0,0 +1,131 @@ +# Nick's web site: Export public keys for the Web Key Directory +# +# Copyright © 2022 Nick Bowler +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +module WKD + require 'open3' + + @@gpg2 = "/usr/bin/gpg" + @@wksclient = "/usr/libexec/gpg-wks-client" + + def WKD.gpg2; @@gpg2 end + def WKD.gpg2=(x); @@gpg2 = x end + def WKD.wksclient; @@wksclient end + def WKD.wksclient=(x); @@wksclient = x end + + # Return a list list of all UIDs known from the given GPG keyrings. + def WKD.uids_from_keyrings(*args) + uids = {} + + Open3.popen2(@@gpg2, + "--no-default-keyring", "--with-colons", "--list-keys", + *args.map { |x| "--keyring=" + (x['/'] ? x : "./" + x) } + ) do |stdin, stdout, result| + stdin.close + stdout.each do |line| + fields = line.split(":") + next if fields[0] != "uid" + fields[9].gsub!(/\\x../) { |x| x[2..].hex.chr } + uids[fields[9]] = true + end + stdout.close + + raise "gpg failed" unless result.value.success? + end + + return uids.keys + end + + # Given a list of UIDs, return a dictionary where the keys are UIDs + # and the values are the WKS hash. + def WKD.hashes_from_uids(*args) + wkd_hash = {} + + consume_output = Proc.new do |s| + while l = s.slice!(/([^\n]*)\n/) do + hash, uid = l.chomp.split(nil, 2) + wkd_hash[uid] = hash + end + end + + Open3.popen2(@@wksclient, + "--print-wkd-hash" + ) do |stdin, stdout, result| + buf = "" + args.flatten.each do |uid| + stdin.puts(uid) + stdin.flush + + loop do + buf += stdout.read_nonblock(100) + consume_output.call(buf) + rescue EOFError, IO::WaitReadable + break + end + end + stdin.close + + loop do + buf += stdout.readpartial(100) + consume_output.call(buf) + rescue EOFError + break + end + stdout.close + + raise "gpg-wks-client failed" unless result.value.success? + end + + return wkd_hash + end + +end + +# Call during preprocessing to create items for each unique UID found in the +# given keyring items. The items have the identifier /gpg/UID and the content +# is the same UID. The items are created with the :keyrings attribute set to +# the list of keyring files and :wkd_hash is for the Web Key Directory. +def create_wkd_items(keyring_items) + keyring_files = {} + [*keyring_items].each { |item| keyring_files[item.raw_filename] = true } + + wkd = WKD.hashes_from_uids(WKD.uids_from_keyrings(*keyring_files.keys)) + wkd.each do |uid, hash| + attrs = { + keyrings: keyring_files.keys, + wkd_hash: hash + } + @items.create(uid, attrs, "/gpg/" + uid) + end +end + +# Convert items created by create_wkd_items into real GPG keyrings. +class WKDExport < Nanoc::Filter + identifier :wkd_export + type :text => :binary + + def run(content, params = {}) + args = @item[:keyrings].map { |x| + "--keyring=" + (x['/'] ? x : "./" + x) + }; + args.append("--armor") if params[:armor] + + dummy, result = Open3.capture2(WKD.gpg2, "--export", + "--no-default-keyring", "--output=" + output_filename, + *args, content.chomp) + raise "gpg failed" unless result.success? + end +end diff --git a/lib/project-readme.rb b/lib/project-readme.rb index 3338e8a..ffe3e3f 100644 --- a/lib/project-readme.rb +++ b/lib/project-readme.rb @@ -1,6 +1,6 @@ # Nick's web site: Generate a project page from a submodule README.md # -# Copyright © 2021 Nick Bowler +# Copyright © 2021-2022 Nick Bowler # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -82,21 +82,25 @@ def project_readme(item = @item) obtaining += line.lstrip end + gpg_uid = "nbowler@draconx.ca" obtaining += "\n\n" + <<~EOF [gpg]: https://gnupg.org/ + [keyring]: /pubring/#{gpg_uid}.asc Use the signature file to verify that the corresponding source bundle is intact. After downloading both files, if [GnuPG][gpg] is installed, the signature can be verified with a command like: - gpg --verify #{targz}.sig + gpg --verify #{targz}.sig #{targz} If the verification fails because you don't have the required public key, that key can be imported with a command such as: - gpg --keyserver keys.gnupg.net --recv-keys 5B45D3D185B8E1F6 + gpg --locate-external-keys #{gpg_uid} - Then run the verify command again. + Then run the verify command again. Alternatively, you can + [download the public keyring][keyring] manually and import it + using `gpg --import`. EOF end