feature: add gpg (GnuPG)

This commit is contained in:
AJ ONeal
2021-11-14 08:18:32 +00:00
parent 3360eeefdf
commit 5394796d1a
6 changed files with 396 additions and 0 deletions
+152
View File
@@ -0,0 +1,152 @@
---
title: Gnu Privacy Guard
homepage: https://gnupg.org/
tagline: |
GnuPG: a complete implementation of OpenPGP (RFC4880), also known as **P**retty **G**ood **P**rivacy.
---
### Before you start
If `~/.gitconfig` exists and has both `name` and `email` fields, then a new gpg
key will be created after the install. Otherwise, you'll have to create one
yourself.
## Cheat Sheet
> Among other things, gpg is particularly useful for signing and verifying git
> commits (and emails too).
Here we'll cover:
- Important GPG Files & Directories
- Creating New Keys
- Listing Keys
- Signing Git Commits
- Exporting GPG Keys for GitHub
- Publishing GPG Keys to "the Blockchain"
- Running GPG Agent with launchd
### Files
These are the files / directories that are created and/or modified with this
install:
```txt
~/.config/envman/PATH.env
~/.local/opt/gnupg/bin/gpg
~/.local/opt/gnupg/bin/gpg-agent
~/.local/opt/gnupg/bin/pinentry-mac.app/Contents/MacOS/pinentry-mac
~/.gnupg/gpg-agent.conf
~/Library/LaunchAgent/gpg-agent.plist
```
### How to create a new GPG key
See the [Cheat Sheet](./gpg-pubkey) at [gpg-pubkey](./gpg-pubkey).
### How to List GPG Key(s)
```bash
gpg --list-secret-keys --keyid-format LONG
```
### How to configure git to sign commits
See the [Cheat Sheet](./git-gpg-init) at [gpg-pubkey](./git-gpg-init).
### How to Export GPG Key for GitHub
See the [Cheat Sheet](./gpg-pubkey) at [gpg-pubkey](./gpg-pubkey).
### How to Publish GPG Keys
GPG is the OG "blockchain", as it were.
If you'd like to publish your (public) key(s) to the public Key Servers for time
and all eternity, you can:
```bash
gpg --send-keys "${MY_KEY_ID}"
```
(no IPFS needed 😉)
### How to start gpg-agent with launchd
(**Note**: this is **done for you** on install, but provided here for reference)
It's a trick question: You can't.
You need to use `gpg-connect-agent` instead.
`~/Library/LaunchAgents/gpg-agent.plist`:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>gpg-agent</string>
<key>ProgramArguments</key>
<array>
<string>MY_HOME/.local/opt/gpg/bin/gpg-connect-agent</string>
<string>--agent-program</string>
<string>MY_HOME/.local/opt/gnupg/bin/gpg-agent</string>
<string>--homedir</string>
<string>MY_HOME/.gnupg/</string>
<string>/bye</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>WorkingDirectory</key>
<string>MY_HOME</string>
<key>StandardErrorPath</key>
<string>MY_HOME/.local/share/gpg-agent/var/log/gpg-agent.log</string>
<key>StandardOutPath</key>
<string>MY_HOME/.local/share/gpg-agent/var/log/gpg-agent.log</string>
</dict>
</plist>
```
And then start it with launchctl:
```bash
launchctl load -w ~/Library/LaunchAgents/gpg-agent.plist
```
### Troubleshooting 'gpg failed to sign the data'
`gpg` is generally expected to be used with a Desktop client. On Linux servers
you may get this error:
```txt
error: gpg failed to sign the data
fatal: failed to write commit object
```
Try to load the `gpg-agent`, set `GPG_TTY`, and then run a clearsign test.
```bash
gpg-connect-agent /bye
export GPG_TTY=$(tty)
echo "test" | gpg --clearsign
```
If that works, update your `~/.bashrc`, `~/.zshrc`, and/or
`~/.config/fish/config.fish` to include the following:
```bash
gpg-connect-agent /bye
export GPG_TTY=$(tty)
```
If this is failing on Mac or Windows, then `gpg-agent` is not starting as
expected on login (for Mac the above may work), and/or the `pinentry` command is
not in the PATH.
If you just installed `gpg`, try closing and reopening your Terminal, or
possibly rebooting.
+6
View File
@@ -0,0 +1,6 @@
#!/usr/bin/env pwsh
echo "We don't yet have a way to automate the GnuPG Tools installer at the user level. In the meantime, try this:"
echo ""
echo " https://gnupg.org/download/#binary"
echo ""
+133
View File
@@ -0,0 +1,133 @@
#!/bin/bash
set -e
set -u
function _install_gpg() {
if ! (uname -a | grep -i "darwin" > /dev/null); then
echo "No gpg installer for Linux yet. Try this instead:"
echo " sudo apt install -y gpg gnupg"
exit 1
fi
# Download the latest LTS
#curl -fsSL -o ~/Downloads/GnuPG-2.2.32.dmg 'https://sourceforge.net/projects/gpgosx/files/GnuPG-2.2.32.dmg/download'
webi_download
chmod a-w "${WEBI_PKG_DOWNLOAD}"
# Mount the DMG in /Volumes
hdiutil detach -quiet /Volumes/GnuPG* 2> /dev/null || true
hdiutil attach -quiet -readonly "${WEBI_PKG_DOWNLOAD}"
# Extract (completely) to ~/Downloads/GnuGP-VERSION.d
# (and detach the DMG)
rm -rf ~/Downloads/GnuPG-"${WEBI_VERSION}".d
pkgutil --expand-full /Volumes/GnuPG*/*.pkg ~/Downloads/GnuPG-"${WEBI_VERSION}".d
hdiutil detach -quiet /Volumes/GnuPG*
# Move to ~/.local/opt/gnugp (where it belongs!)
if [[ ! -e ~/.local/opt/gnupg-"${WEBI_VERSION}" ]]; then
mv ~/Downloads/GnuPG-"${WEBI_VERSION}".d/GnuPG.pkg/Payload/ ~/.local/opt/gnupg-"${WEBI_VERSION}"
fi
# Update symlink to latest
rm -rf ~/.local/opt/gnupg
ln -s gnupg-"${WEBI_VERSION}" ~/.local/opt/gnupg
pathman add ~/.local/opt/gnupg/bin
export PATH="$HOME/.local/opt/gnupg/bin/:$PATH"
# Prep for first use
mkdir -p ~/.gnupg/
chmod 0700 ~/.gnupg/
if [[ ! -e ~/.gnupg/gpg-agent.conf ]] || ! grep 'pinentry-program' ~/.gnupg/gpg-agent.conf; then
echo "pinentry-program $HOME/.local/opt/gnupg/bin/pinentry-mac.app/Contents/MacOS/pinentry-mac" >> ~/.gnupg/gpg-agent.conf
fi
# Start with launchd
mkdir -p ~/Library/LaunchAgents/
launchctl unload -w ~/Library/LaunchAgents/gpg-agent.plist 2> /dev/null || true
# TODO download and use sed to replace
echo '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>gpg-agent</string>
<key>ProgramArguments</key>
<array>
<string>'"${HOME}"'/.local/opt/gpg/bin/gpg-connect-agent</string>
<string>--agent-program</string>
<string>'"${HOME}"'/.local/opt/gnupg/bin/gpg-agent</string>
<string>--homedir</string>
<string>'"${HOME}"'/.gnupg/</string>
<string>/bye</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>WorkingDirectory</key>
<string>'"${HOME}"'</string>
<key>StandardErrorPath</key>
<string>'"${HOME}"'/.local/share/gpg-agent/var/log/gpg-agent.log</string>
<key>StandardOutPath</key>
<string>'"${HOME}"'/.local/share/gpg-agent/var/log/gpg-agent.log</string>
</dict>
</plist>' > ~/Library/LaunchAgents/gpg-agent.plist
launchctl load -w ~/Library/LaunchAgents/gpg-agent.plist
sleep 3
# (maybe) Create first key
if ! gpg --list-secret-keys | grep -q sec; then
_create_gpg_key
fi
}
function _create_gpg_key() {
if [[ ! -e ~/.gitconfig ]]; then
return 0
fi
MY_NAME="$(
grep 'name\s*=' ~/.gitconfig |
head -n 1 |
cut -d'=' -f2 |
sed -e 's/^[\t ]*//'
)"
if [[ -z ${MY_NAME} ]]; then
return 0
fi
MY_EMAIL="$(
grep 'email\s*=.*@' ~/.gitconfig |
tr -d '\t ' | head -n 1 |
cut -d'=' -f2
)"
if [[ -z ${MY_EMAIL} ]]; then
return 0
fi
MY_HOST="$(hostname)"
# Without passphrase:
#gpg --batch --generate-key --pinentry=loopback --passphrase=''
# With passphrase via macOS Keychain
gpg --batch --yes --generate-key << EOF
%echo Generating RSA 3072 key
Key-Type: RSA
Key-Length: 3072
Subkey-Type: RSA
Subkey-Length: 3072
Name-Real: ${MY_NAME}
Name-Comment: ${MY_HOST}
Name-Email: ${MY_EMAIL}
Expire-Date: 0
%commit
EOF
}
_install_gpg
+91
View File
@@ -0,0 +1,91 @@
'use strict';
let ltsRe = /GnuPG-(2\.2\.[\d\.]+)/;
function createRssMatcher() {
return new RegExp(
'<link>(https://sourceforge\\.net/projects/gpgosx/files/GnuPG-([\\d\\.]+)\\.dmg/download)</link>',
'g'
);
}
function createUrlMatcher() {
return new RegExp(
'https://sourceforge\\.net/projects/gpgosx/files/(GnuPG-([\\d\\.]+)\\.dmg)/download',
''
);
}
async function getRawReleases(request) {
let matcher = createRssMatcher();
let resp = await request({
url: 'https://sourceforge.net/projects/gpgosx/rss?path=/'
});
let links = [];
for (;;) {
let m = matcher.exec(resp.body);
if (!m) {
break;
}
links.push(m[1]);
}
return links;
}
function transformReleases(links) {
//console.log(JSON.stringify(links, null, 2));
//console.log(links.length);
let matcher = createUrlMatcher();
let releases = links
.map(function (link) {
// strip 'go' prefix, standardize version
let isLts = ltsRe.test(link);
let parts = link.match(matcher);
if (!parts || !parts[2]) {
return null;
}
let segs = parts[2].split('.');
let version = segs.slice(0, 3).join('.');
if (segs.length > 3) {
version += '+' + segs.slice(3);
}
return {
name: parts[1],
version: version,
// all go versions >= 1.0.0 are effectively LTS
lts: isLts,
channel: 'stable',
// TODO <pubDate>Sat, 19 Nov 2016 16:17:33 UT</pubDate>
date: '1970-01-01', // the world may never know
os: 'macos',
arch: 'amd64',
ext: 'dmg',
download: link
};
})
.filter(Boolean);
return {
releases: releases
};
}
async function getAllReleases(request) {
let releases = await getRawReleases(request);
let all = transformReleases(releases);
return all;
}
module.exports = getAllReleases;
if (module === require.main) {
getAllReleases(require('@root/request')).then(function (all) {
all = require('../_webi/normalize.js')(all);
all.releases = all.releases.slice(0, 10000);
console.info(JSON.stringify(all, null, 2));
});
}