email ux
This commit is contained in:
parent
07b68562d3
commit
cfd5093d74
24 changed files with 712 additions and 65 deletions
4
bin/cb
4
bin/cb
|
|
@ -55,11 +55,11 @@ stdout_is_a_tty() {
|
||||||
}
|
}
|
||||||
|
|
||||||
requested_open_ended() {
|
requested_open_ended() {
|
||||||
[[ "${args[0]:-}" == "-" ]]
|
[[ ${args[0]:-} == "-" ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
requested_test_suite() {
|
requested_test_suite() {
|
||||||
[[ "${args[0]:-}" == "--test" ]]
|
[[ ${args[0]:-} == "--test" ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
enable_tee_like_chaining() {
|
enable_tee_like_chaining() {
|
||||||
|
|
|
||||||
35
bin/gpg-add-uid
Executable file
35
bin/gpg-add-uid
Executable file
|
|
@ -0,0 +1,35 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Add a new UID to an existing GPG key
|
||||||
|
# Usage: gpg-add-uid "Name" "email@example.com" [key-id]
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [[ $# -lt 2 ]]; then
|
||||||
|
echo 'Usage: gpg-add-uid "Name" "email@example.com" [key-id]'
|
||||||
|
echo ""
|
||||||
|
echo "If key-id is not provided, uses the first secret key found."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
NAME="$1"
|
||||||
|
EMAIL="$2"
|
||||||
|
KEY_ID="${3:-$(gpg --list-secret-keys --keyid-format LONG 2>/dev/null | grep '^sec' | head -1 | sed 's/.*\/\([A-F0-9]*\) .*/\1/')}"
|
||||||
|
|
||||||
|
if [[ -z $KEY_ID ]]; then
|
||||||
|
echo "Error: No GPG secret key found. Create one first with: gpg --full-generate-key"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Adding UID '$NAME <$EMAIL>' to key $KEY_ID"
|
||||||
|
|
||||||
|
# Use expect-like input via gpg --command-fd
|
||||||
|
gpg --batch --command-fd 0 --edit-key "$KEY_ID" <<EOF
|
||||||
|
adduid
|
||||||
|
$NAME
|
||||||
|
$EMAIL
|
||||||
|
|
||||||
|
O
|
||||||
|
save
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "Done! New UID added. Verify with: gpg --list-keys $KEY_ID"
|
||||||
44
bin/gpg-backup-key
Executable file
44
bin/gpg-backup-key
Executable file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Backup GPG key (both private and public) to a directory
|
||||||
|
# Usage: gpg-backup-key [output-dir] [key-id or email]
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
OUTPUT_DIR="${1:-$HOME}"
|
||||||
|
KEY_ID="${2:-}"
|
||||||
|
|
||||||
|
# If no key specified, use first secret key
|
||||||
|
if [[ -z $KEY_ID ]]; then
|
||||||
|
KEY_ID=$(gpg --list-secret-keys --keyid-format LONG 2>/dev/null | grep '^sec' | head -1 | sed 's/.*\/\([A-F0-9]*\) .*/\1/')
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z $KEY_ID ]]; then
|
||||||
|
echo "Error: No GPG key found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create output directory if needed
|
||||||
|
mkdir -p "$OUTPUT_DIR"
|
||||||
|
|
||||||
|
PRIVATE_KEY="$OUTPUT_DIR/gpg-private-key-$KEY_ID.asc"
|
||||||
|
PUBLIC_KEY="$OUTPUT_DIR/gpg-public-key-$KEY_ID.asc"
|
||||||
|
|
||||||
|
echo "Backing up GPG key $KEY_ID"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "Exporting private key to $PRIVATE_KEY..."
|
||||||
|
gpg --armor --export-secret-keys "$KEY_ID" >"$PRIVATE_KEY"
|
||||||
|
chmod 600 "$PRIVATE_KEY"
|
||||||
|
|
||||||
|
echo "Exporting public key to $PUBLIC_KEY..."
|
||||||
|
gpg --armor --export "$KEY_ID" >"$PUBLIC_KEY"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Backup complete!"
|
||||||
|
echo " Private key: $PRIVATE_KEY"
|
||||||
|
echo " Public key: $PUBLIC_KEY"
|
||||||
|
echo ""
|
||||||
|
echo "WARNING: Keep your private key safe and never share it!"
|
||||||
|
echo ""
|
||||||
|
echo "To restore, run:"
|
||||||
|
echo " gpg-restore-key $PRIVATE_KEY"
|
||||||
52
bin/gpg-delete-key
Executable file
52
bin/gpg-delete-key
Executable file
|
|
@ -0,0 +1,52 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Delete a GPG key (both secret and public)
|
||||||
|
# Usage: gpg-delete-key [key-id or email]
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
KEY_ID="${1:-}"
|
||||||
|
|
||||||
|
# If no key specified, show available keys and prompt
|
||||||
|
if [[ -z $KEY_ID ]]; then
|
||||||
|
echo "Available GPG keys:"
|
||||||
|
echo ""
|
||||||
|
gpg --list-secret-keys --keyid-format LONG 2>/dev/null || echo "No keys found"
|
||||||
|
echo ""
|
||||||
|
read -p "Enter key ID or email to delete: " KEY_ID
|
||||||
|
|
||||||
|
if [[ -z $KEY_ID ]]; then
|
||||||
|
echo "No key specified. Aborting."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get the full key fingerprint
|
||||||
|
FINGERPRINT=$(gpg --list-secret-keys --with-colons "$KEY_ID" 2>/dev/null | grep '^fpr' | head -1 | cut -d: -f10)
|
||||||
|
|
||||||
|
if [[ -z $FINGERPRINT ]]; then
|
||||||
|
echo "Error: Key not found: $KEY_ID"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Key to delete:"
|
||||||
|
echo ""
|
||||||
|
gpg --list-keys --keyid-format LONG "$KEY_ID"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
echo "WARNING: This will permanently delete the secret and public key!"
|
||||||
|
read -p "Are you sure? Type 'yes' to confirm: " CONFIRM
|
||||||
|
|
||||||
|
if [[ $CONFIRM != "yes" ]]; then
|
||||||
|
echo "Aborting."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Deleting secret key..."
|
||||||
|
gpg --batch --yes --delete-secret-keys "$FINGERPRINT"
|
||||||
|
|
||||||
|
echo "Deleting public key..."
|
||||||
|
gpg --batch --yes --delete-keys "$FINGERPRINT"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Key deleted successfully."
|
||||||
56
bin/gpg-private-key
Executable file
56
bin/gpg-private-key
Executable file
|
|
@ -0,0 +1,56 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Export GPG private key (BE CAREFUL - keep this safe!)
|
||||||
|
# Usage: gpg-private-key [-c] [key-id or email]
|
||||||
|
# -c Copy to clipboard instead of printing
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
COPY=false
|
||||||
|
KEY_ID=""
|
||||||
|
|
||||||
|
# Parse arguments
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-c | --copy)
|
||||||
|
COPY=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
KEY_ID="$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# If no key specified, use first secret key
|
||||||
|
if [[ -z $KEY_ID ]]; then
|
||||||
|
KEY_ID=$(gpg --list-secret-keys --keyid-format LONG 2>/dev/null | grep '^sec' | head -1 | sed 's/.*\/\([A-F0-9]*\) .*/\1/')
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z $KEY_ID ]]; then
|
||||||
|
echo "Error: No GPG key found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "WARNING: You are exporting your PRIVATE key!" >&2
|
||||||
|
echo "Keep this safe and never share it publicly!" >&2
|
||||||
|
echo "" >&2
|
||||||
|
|
||||||
|
if $COPY; then
|
||||||
|
if [[ "$(uname)" == "Darwin" ]]; then
|
||||||
|
gpg --armor --export-secret-keys "$KEY_ID" | pbcopy
|
||||||
|
echo "Private key copied to clipboard"
|
||||||
|
elif command -v xclip &>/dev/null; then
|
||||||
|
gpg --armor --export-secret-keys "$KEY_ID" | xclip -selection clipboard
|
||||||
|
echo "Private key copied to clipboard"
|
||||||
|
elif command -v wl-copy &>/dev/null; then
|
||||||
|
gpg --armor --export-secret-keys "$KEY_ID" | wl-copy
|
||||||
|
echo "Private key copied to clipboard"
|
||||||
|
else
|
||||||
|
echo "Error: No clipboard tool found (pbcopy, xclip, or wl-copy)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Remember to clear your clipboard after use!" >&2
|
||||||
|
else
|
||||||
|
gpg --armor --export-secret-keys "$KEY_ID"
|
||||||
|
fi
|
||||||
51
bin/gpg-public-key
Executable file
51
bin/gpg-public-key
Executable file
|
|
@ -0,0 +1,51 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Export GPG public key
|
||||||
|
# Usage: gpg-public-key [-c] [key-id or email]
|
||||||
|
# -c Copy to clipboard instead of printing
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
COPY=false
|
||||||
|
KEY_ID=""
|
||||||
|
|
||||||
|
# Parse arguments
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-c | --copy)
|
||||||
|
COPY=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
KEY_ID="$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# If no key specified, use first secret key
|
||||||
|
if [[ -z $KEY_ID ]]; then
|
||||||
|
KEY_ID=$(gpg --list-secret-keys --keyid-format LONG 2>/dev/null | grep '^sec' | head -1 | sed 's/.*\/\([A-F0-9]*\) .*/\1/')
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z $KEY_ID ]]; then
|
||||||
|
echo "Error: No GPG key found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if $COPY; then
|
||||||
|
if [[ "$(uname)" == "Darwin" ]]; then
|
||||||
|
gpg --armor --export "$KEY_ID" | pbcopy
|
||||||
|
echo "Public key copied to clipboard"
|
||||||
|
elif command -v xclip &>/dev/null; then
|
||||||
|
gpg --armor --export "$KEY_ID" | xclip -selection clipboard
|
||||||
|
echo "Public key copied to clipboard"
|
||||||
|
elif command -v wl-copy &>/dev/null; then
|
||||||
|
gpg --armor --export "$KEY_ID" | wl-copy
|
||||||
|
echo "Public key copied to clipboard"
|
||||||
|
else
|
||||||
|
echo "Error: No clipboard tool found (pbcopy, xclip, or wl-copy)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
gpg --armor --export "$KEY_ID"
|
||||||
|
fi
|
||||||
58
bin/gpg-restore-key
Executable file
58
bin/gpg-restore-key
Executable file
|
|
@ -0,0 +1,58 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Restore GPG key from backup file
|
||||||
|
# Usage: gpg-restore-key <private-key-file> [public-key-file]
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [[ $# -lt 1 ]]; then
|
||||||
|
echo "Usage: gpg-restore-key <private-key-file> [public-key-file]"
|
||||||
|
echo ""
|
||||||
|
echo "Examples:"
|
||||||
|
echo " gpg-restore-key ~/private-key-backup.asc"
|
||||||
|
echo " gpg-restore-key ~/private-key.asc ~/public-key.asc"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
PRIVATE_KEY="$1"
|
||||||
|
PUBLIC_KEY="${2:-}"
|
||||||
|
|
||||||
|
if [[ ! -f $PRIVATE_KEY ]]; then
|
||||||
|
echo "Error: File not found: $PRIVATE_KEY"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Importing private key from $PRIVATE_KEY..."
|
||||||
|
gpg --import "$PRIVATE_KEY"
|
||||||
|
|
||||||
|
if [[ -n $PUBLIC_KEY && -f $PUBLIC_KEY ]]; then
|
||||||
|
echo ""
|
||||||
|
echo "Importing public key from $PUBLIC_KEY..."
|
||||||
|
gpg --import "$PUBLIC_KEY"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get the key ID that was just imported
|
||||||
|
KEY_ID=$(gpg --list-secret-keys --keyid-format LONG 2>/dev/null | grep '^sec' | head -1 | sed 's/.*\/\([A-F0-9]*\) .*/\1/')
|
||||||
|
|
||||||
|
if [[ -z $KEY_ID ]]; then
|
||||||
|
echo "Error: Could not find imported key"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Key imported successfully!"
|
||||||
|
echo ""
|
||||||
|
gpg --list-keys --keyid-format LONG "$KEY_ID"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
read -p "Do you want to trust this key ultimately? [y/N] " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
echo "Setting ultimate trust..."
|
||||||
|
echo -e "5\ny\n" | gpg --command-fd 0 --edit-key "$KEY_ID" trust 2>/dev/null
|
||||||
|
echo "Done!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Key ID: $KEY_ID"
|
||||||
|
echo "Update your neomutt config with:"
|
||||||
|
echo " set pgp_sign_as = 0x$KEY_ID"
|
||||||
93
bin/gpg-setup
Executable file
93
bin/gpg-setup
Executable file
|
|
@ -0,0 +1,93 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Setup GPG key with all email identities
|
||||||
|
# Usage: gpg-setup
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
PRIMARY_NAME="Ray Andrew Sinurat"
|
||||||
|
PRIMARY_EMAIL="raydreww@gmail.com"
|
||||||
|
|
||||||
|
# Additional UIDs to add (name|email)
|
||||||
|
ADDITIONAL_UIDS=(
|
||||||
|
"Ray Andrew Sinurat|rayandrew@uchicago.edu"
|
||||||
|
"Ray Andrew|raydreww@gmail.com"
|
||||||
|
"Ray Andrew|rayandrew@uchicago.edu"
|
||||||
|
"Ray A. O. Sinurat|raydreww@gmail.com"
|
||||||
|
"Ray A. O. Sinurat|rayandrew@uchicago.edu"
|
||||||
|
"Ray Andrew Obaja Sinurat|raydreww@gmail.com"
|
||||||
|
"Ray Andrew Obaja Sinurat|rayandrew@uchicago.edu"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check if key already exists
|
||||||
|
if gpg --list-secret-keys "$PRIMARY_EMAIL" &>/dev/null; then
|
||||||
|
echo "GPG key for $PRIMARY_EMAIL already exists."
|
||||||
|
echo ""
|
||||||
|
gpg --list-secret-keys --keyid-format LONG "$PRIMARY_EMAIL"
|
||||||
|
echo ""
|
||||||
|
read -p "Do you want to add missing UIDs to this key? [y/N] " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Creating new GPG key for $PRIMARY_NAME <$PRIMARY_EMAIL>"
|
||||||
|
echo ""
|
||||||
|
echo "You will be prompted for a passphrase."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
gpg --full-generate-key --batch <<EOF
|
||||||
|
Key-Type: RSA
|
||||||
|
Key-Length: 4096
|
||||||
|
Subkey-Type: RSA
|
||||||
|
Subkey-Length: 4096
|
||||||
|
Name-Real: $PRIMARY_NAME
|
||||||
|
Name-Email: $PRIMARY_EMAIL
|
||||||
|
Expire-Date: 2y
|
||||||
|
%ask-passphrase
|
||||||
|
%commit
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Primary key created!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get key ID
|
||||||
|
KEY_ID=$(gpg --list-secret-keys --keyid-format LONG "$PRIMARY_EMAIL" 2>/dev/null | grep '^sec' | head -1 | sed 's/.*\/\([A-F0-9]*\) .*/\1/')
|
||||||
|
|
||||||
|
if [[ -z $KEY_ID ]]; then
|
||||||
|
echo "Error: Could not find key ID"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Key ID: $KEY_ID"
|
||||||
|
echo ""
|
||||||
|
echo "Adding additional UIDs..."
|
||||||
|
|
||||||
|
# Get existing UIDs
|
||||||
|
EXISTING_UIDS=$(gpg --list-keys "$KEY_ID" 2>/dev/null | grep '^uid' | sed 's/.*] //')
|
||||||
|
|
||||||
|
for uid in "${ADDITIONAL_UIDS[@]}"; do
|
||||||
|
NAME="${uid%|*}"
|
||||||
|
EMAIL="${uid#*|}"
|
||||||
|
UID_STRING="$NAME <$EMAIL>"
|
||||||
|
|
||||||
|
if echo "$EXISTING_UIDS" | grep -qF "$UID_STRING"; then
|
||||||
|
echo " [skip] $UID_STRING (already exists)"
|
||||||
|
else
|
||||||
|
echo " [add] $UID_STRING"
|
||||||
|
"$SCRIPT_DIR/gpg-add-uid" "$NAME" "$EMAIL" "$KEY_ID" 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Done! Final key:"
|
||||||
|
echo ""
|
||||||
|
gpg --list-keys --keyid-format LONG "$KEY_ID"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Update your neomutt config with:"
|
||||||
|
echo " set pgp_sign_as = 0x$KEY_ID"
|
||||||
|
|
@ -4,12 +4,12 @@
|
||||||
export PATH="/etc/profiles/per-user/$USER/bin:/run/current-system/sw/bin:$PATH"
|
export PATH="/etc/profiles/per-user/$USER/bin:/run/current-system/sw/bin:$PATH"
|
||||||
|
|
||||||
# Handle piped input or file argument
|
# Handle piped input or file argument
|
||||||
if [[ -n "$1" ]]; then
|
if [[ -n $1 ]]; then
|
||||||
file="$1"
|
file="$1"
|
||||||
else
|
else
|
||||||
# Read from stdin to temp file
|
# Read from stdin to temp file
|
||||||
tmpfile=$(mktemp)
|
tmpfile=$(mktemp)
|
||||||
cat > "$tmpfile"
|
cat >"$tmpfile"
|
||||||
mime=$(file --mime-type -b "$tmpfile")
|
mime=$(file --mime-type -b "$tmpfile")
|
||||||
|
|
||||||
# Add extension based on mime type
|
# Add extension based on mime type
|
||||||
|
|
@ -23,7 +23,7 @@ else
|
||||||
*) ext="" ;;
|
*) ext="" ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [[ -n "$ext" ]]; then
|
if [[ -n $ext ]]; then
|
||||||
mv "$tmpfile" "${tmpfile}${ext}"
|
mv "$tmpfile" "${tmpfile}${ext}"
|
||||||
file="${tmpfile}${ext}"
|
file="${tmpfile}${ext}"
|
||||||
else
|
else
|
||||||
|
|
@ -38,17 +38,17 @@ viewers=()
|
||||||
viewers+=("open (default app)")
|
viewers+=("open (default app)")
|
||||||
|
|
||||||
case "$mime" in
|
case "$mime" in
|
||||||
application/pdf)
|
application/pdf)
|
||||||
viewers+=("zathura")
|
viewers+=("zathura")
|
||||||
;;
|
;;
|
||||||
image/*)
|
image/*)
|
||||||
viewers+=("chafa (terminal)")
|
viewers+=("chafa (terminal)")
|
||||||
;;
|
;;
|
||||||
text/html)
|
text/html)
|
||||||
viewers+=("w3m (browser)")
|
viewers+=("w3m (browser)")
|
||||||
viewers+=("less (text)")
|
viewers+=("less (text)")
|
||||||
;;
|
;;
|
||||||
text/*)
|
text/*)
|
||||||
viewers+=("less")
|
viewers+=("less")
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
@ -57,9 +57,12 @@ esac
|
||||||
selected=$(printf '%s\n' "${viewers[@]}" | fzf --prompt="Open with: " --height=10)
|
selected=$(printf '%s\n' "${viewers[@]}" | fzf --prompt="Open with: " --height=10)
|
||||||
|
|
||||||
case "$selected" in
|
case "$selected" in
|
||||||
"open (default app)") open "$file" ;;
|
"open (default app)") open "$file" ;;
|
||||||
"chafa (terminal)") chafa "$file"; read -n 1 -s -r -p "Press any key..." ;;
|
"chafa (terminal)")
|
||||||
"zathura") zathura "$file" ;;
|
chafa "$file"
|
||||||
"w3m (browser)") w3m -T text/html "$file" ;;
|
read -n 1 -s -r -p "Press any key..."
|
||||||
"less"*) less "$file" ;;
|
;;
|
||||||
|
"zathura") zathura "$file" ;;
|
||||||
|
"w3m (browser)") w3m -T text/html "$file" ;;
|
||||||
|
"less"*) less "$file" ;;
|
||||||
esac
|
esac
|
||||||
|
|
|
||||||
|
|
@ -2,28 +2,28 @@
|
||||||
# Open attachment with correct extension based on mime type
|
# Open attachment with correct extension based on mime type
|
||||||
|
|
||||||
tmpfile=$(mktemp)
|
tmpfile=$(mktemp)
|
||||||
cat > "$tmpfile"
|
cat >"$tmpfile"
|
||||||
|
|
||||||
mime=$(file --mime-type -b "$tmpfile")
|
mime=$(file --mime-type -b "$tmpfile")
|
||||||
|
|
||||||
case "$mime" in
|
case "$mime" in
|
||||||
application/pdf) ext=".pdf" ;;
|
application/pdf) ext=".pdf" ;;
|
||||||
image/png) ext=".png" ;;
|
image/png) ext=".png" ;;
|
||||||
image/jpeg) ext=".jpg" ;;
|
image/jpeg) ext=".jpg" ;;
|
||||||
image/gif) ext=".gif" ;;
|
image/gif) ext=".gif" ;;
|
||||||
text/html) ext=".html" ;;
|
text/html) ext=".html" ;;
|
||||||
text/plain) ext=".txt" ;;
|
text/plain) ext=".txt" ;;
|
||||||
application/zip) ext=".zip" ;;
|
application/zip) ext=".zip" ;;
|
||||||
application/msword) ext=".doc" ;;
|
application/msword) ext=".doc" ;;
|
||||||
application/vnd.openxmlformats-officedocument.wordprocessingml.document) ext=".docx" ;;
|
application/vnd.openxmlformats-officedocument.wordprocessingml.document) ext=".docx" ;;
|
||||||
application/vnd.ms-excel) ext=".xls" ;;
|
application/vnd.ms-excel) ext=".xls" ;;
|
||||||
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet) ext=".xlsx" ;;
|
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet) ext=".xlsx" ;;
|
||||||
application/vnd.ms-powerpoint) ext=".ppt" ;;
|
application/vnd.ms-powerpoint) ext=".ppt" ;;
|
||||||
application/vnd.openxmlformats-officedocument.presentationml.presentation) ext=".pptx" ;;
|
application/vnd.openxmlformats-officedocument.presentationml.presentation) ext=".pptx" ;;
|
||||||
*) ext="" ;;
|
*) ext="" ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if [[ -n "$ext" ]]; then
|
if [[ -n $ext ]]; then
|
||||||
mv "$tmpfile" "${tmpfile}${ext}"
|
mv "$tmpfile" "${tmpfile}${ext}"
|
||||||
tmpfile="${tmpfile}${ext}"
|
tmpfile="${tmpfile}${ext}"
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ if [[ "$(uname)" == "Darwin" ]]; then
|
||||||
aerospace workspace 8
|
aerospace workspace 8
|
||||||
else
|
else
|
||||||
aerospace workspace 8
|
aerospace workspace 8
|
||||||
open -na Ghostty --args --title="Mail" -e /etc/profiles/per-user/rayandrew/bin/neomutt
|
open -na Ghostty --args --title="Mail" -e ~/dotfiles/bin/path-shim neomutt
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
# Linux (i3/sway)
|
# Linux (i3/sway)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
# Or: path-shim "command with args"
|
# Or: path-shim "command with args"
|
||||||
|
|
||||||
export PATH="/etc/profiles/per-user/$USER/bin:/run/current-system/sw/bin:$PATH"
|
export PATH="/etc/profiles/per-user/$USER/bin:/run/current-system/sw/bin:$PATH"
|
||||||
|
export SOPS_AGE_KEY_FILE="$HOME/.config/sops/age/keys.txt"
|
||||||
|
|
||||||
if [[ $# -eq 1 ]]; then
|
if [[ $# -eq 1 ]]; then
|
||||||
# Single argument - run it through bash to handle complex commands
|
# Single argument - run it through bash to handle complex commands
|
||||||
|
|
|
||||||
12
bin/wb
12
bin/wb
|
|
@ -6,7 +6,7 @@ BOOKMARKS_FILE="${DOTFILES}/secrets/wb.txt"
|
||||||
|
|
||||||
# Decrypt bookmarks from sops
|
# Decrypt bookmarks from sops
|
||||||
getBookmarks() {
|
getBookmarks() {
|
||||||
if [[ -f "${BOOKMARKS_FILE}" ]]; then
|
if [[ -f ${BOOKMARKS_FILE} ]]; then
|
||||||
# Unencrypted file (for development/testing)
|
# Unencrypted file (for development/testing)
|
||||||
cat "${BOOKMARKS_FILE}"
|
cat "${BOOKMARKS_FILE}"
|
||||||
elif [[ -f "${BOOKMARKS_FILE%.txt}.enc" ]]; then
|
elif [[ -f "${BOOKMARKS_FILE%.txt}.enc" ]]; then
|
||||||
|
|
@ -144,7 +144,7 @@ fuzzy() {
|
||||||
--preview='bash -c "url=\$(echo {} | cut -f2); desc=\$(echo {} | cut -f3); tags=\$(echo {} | cut -f4); echo -e \"\$url\n\nDesc: \$desc\n\nTags: \$tags\""' \
|
--preview='bash -c "url=\$(echo {} | cut -f2); desc=\$(echo {} | cut -f3); tags=\$(echo {} | cut -f4); echo -e \"\$url\n\nDesc: \$desc\n\nTags: \$tags\""' \
|
||||||
--preview-window=down:12:wrap)
|
--preview-window=down:12:wrap)
|
||||||
|
|
||||||
if [[ -n "$selected_line" ]]; then
|
if [[ -n $selected_line ]]; then
|
||||||
IFS=$'\t' read -r key url _ <<<"$selected_line"
|
IFS=$'\t' read -r key url _ <<<"$selected_line"
|
||||||
execute "$url"
|
execute "$url"
|
||||||
else
|
else
|
||||||
|
|
@ -225,7 +225,7 @@ fi
|
||||||
|
|
||||||
if [[ $editMode == 1 ]]; then
|
if [[ $editMode == 1 ]]; then
|
||||||
encFile="${BOOKMARKS_FILE%.txt}.enc"
|
encFile="${BOOKMARKS_FILE%.txt}.enc"
|
||||||
if [[ -f "$encFile" ]]; then
|
if [[ -f $encFile ]]; then
|
||||||
echo "Editing encrypted bookmarks file"
|
echo "Editing encrypted bookmarks file"
|
||||||
# Decrypt to the .txt file (matches .sops.yaml path_regex), edit, re-encrypt
|
# Decrypt to the .txt file (matches .sops.yaml path_regex), edit, re-encrypt
|
||||||
trap "rm -f '${BOOKMARKS_FILE}'" EXIT
|
trap "rm -f '${BOOKMARKS_FILE}'" EXIT
|
||||||
|
|
@ -234,7 +234,7 @@ if [[ $editMode == 1 ]]; then
|
||||||
sops --encrypt --input-type binary --output-type binary "${BOOKMARKS_FILE}" >"$encFile"
|
sops --encrypt --input-type binary --output-type binary "${BOOKMARKS_FILE}" >"$encFile"
|
||||||
rm -f "${BOOKMARKS_FILE}"
|
rm -f "${BOOKMARKS_FILE}"
|
||||||
echo "Saved and re-encrypted"
|
echo "Saved and re-encrypted"
|
||||||
elif [[ -f "${BOOKMARKS_FILE}" ]]; then
|
elif [[ -f ${BOOKMARKS_FILE} ]]; then
|
||||||
echo "Editing ${BOOKMARKS_FILE}"
|
echo "Editing ${BOOKMARKS_FILE}"
|
||||||
${EDITOR:-vim} "${BOOKMARKS_FILE}"
|
${EDITOR:-vim} "${BOOKMARKS_FILE}"
|
||||||
else
|
else
|
||||||
|
|
@ -245,7 +245,7 @@ if [[ $editMode == 1 ]]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $queryMode == 1 ]]; then
|
if [[ $queryMode == 1 ]]; then
|
||||||
if [[ -z "$q" ]]; then
|
if [[ -z $q ]]; then
|
||||||
bs=$(bks)
|
bs=$(bks)
|
||||||
else
|
else
|
||||||
bs=$(bks | grep -i "$q")
|
bs=$(bks | grep -i "$q")
|
||||||
|
|
@ -297,7 +297,7 @@ fi
|
||||||
if [ $hitCount -gt 1 ]; then
|
if [ $hitCount -gt 1 ]; then
|
||||||
exactHit=0
|
exactHit=0
|
||||||
while read -r key url misc; do
|
while read -r key url misc; do
|
||||||
if [[ "$key" == "$q" ]]; then
|
if [[ $key == "$q" ]]; then
|
||||||
exactHit=1
|
exactHit=1
|
||||||
echo "$key $url" >"$tempFile"
|
echo "$key $url" >"$tempFile"
|
||||||
break
|
break
|
||||||
|
|
|
||||||
|
|
@ -10,9 +10,10 @@ logfile ~/.local/state/msmtp.log
|
||||||
# Personal Gmail account
|
# Personal Gmail account
|
||||||
account personal
|
account personal
|
||||||
host smtp.gmail.com
|
host smtp.gmail.com
|
||||||
|
port 465
|
||||||
from raydreww@gmail.com
|
from raydreww@gmail.com
|
||||||
user raydreww@gmail.com
|
user raydreww@gmail.com
|
||||||
passwordeval "sops -d --extract '[\"personal\"]' ~/dotfiles/home/email/secrets.yaml"
|
passwordeval sops -d --extract '["personal"]' ~/dotfiles/home/email/secrets.yaml
|
||||||
tls_starttls off
|
tls_starttls off
|
||||||
|
|
||||||
# UChicago account (via DavMail)
|
# UChicago account (via DavMail)
|
||||||
|
|
@ -21,7 +22,7 @@ host 127.0.0.1
|
||||||
port 1025
|
port 1025
|
||||||
from rayandrew@uchicago.edu
|
from rayandrew@uchicago.edu
|
||||||
user rayandrew@uchicago.edu
|
user rayandrew@uchicago.edu
|
||||||
passwordeval "sops -d --extract '[\"uchicago\"]' ~/dotfiles/home/email/secrets.yaml"
|
passwordeval sops -d --extract '["uchicago"]' ~/dotfiles/home/email/secrets.yaml
|
||||||
auth plain
|
auth plain
|
||||||
tls off
|
tls off
|
||||||
tls_starttls off
|
tls_starttls off
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ set trash = '+Trash'
|
||||||
# PGP settings
|
# PGP settings
|
||||||
set use_from = yes
|
set use_from = yes
|
||||||
set pgp_verify_sig = yes
|
set pgp_verify_sig = yes
|
||||||
set pgp_sign_as = 0x07AA5254804C009F
|
set pgp_sign_as = 0xBAA368F02F486080
|
||||||
set pgp_timeout = 3600
|
set pgp_timeout = 3600
|
||||||
|
|
||||||
# Mailboxes
|
# Mailboxes
|
||||||
|
|
@ -34,5 +34,9 @@ named-mailboxes "p/important" =Important
|
||||||
named-mailboxes "p/trash" =Trash
|
named-mailboxes "p/trash" =Trash
|
||||||
named-mailboxes "p/archive" =Archive
|
named-mailboxes "p/archive" =Archive
|
||||||
|
|
||||||
|
# Virtual mailboxes (notmuch)
|
||||||
|
virtual-mailboxes "All Mail" "notmuch://?query=folder:personal/** AND date:30d.."
|
||||||
|
virtual-mailboxes "Unread" "notmuch://?query=folder:personal/** AND tag:unread"
|
||||||
|
|
||||||
# Signature
|
# Signature
|
||||||
set signature = "~/.config/neomutt/signatures/personal"
|
set signature = "~/.config/neomutt/signatures/personal"
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ set trash = '+Trash'
|
||||||
|
|
||||||
# PGP settings
|
# PGP settings
|
||||||
set use_from = yes
|
set use_from = yes
|
||||||
set pgp_sign_as = 0xEEF04CFFE9DFE5FC
|
set pgp_sign_as = 0xBAA368F02F486080
|
||||||
set pgp_verify_sig = yes
|
set pgp_verify_sig = yes
|
||||||
set pgp_timeout = 3600
|
set pgp_timeout = 3600
|
||||||
|
|
||||||
|
|
@ -35,5 +35,9 @@ named-mailboxes "u/trash" =Trash
|
||||||
named-mailboxes "u/archive" =Archive
|
named-mailboxes "u/archive" =Archive
|
||||||
named-mailboxes "u/teaching" =Teaching
|
named-mailboxes "u/teaching" =Teaching
|
||||||
|
|
||||||
|
# Virtual mailboxes (notmuch)
|
||||||
|
virtual-mailboxes "All Mail" "notmuch://?query=folder:uchicago/** AND date:30d.."
|
||||||
|
virtual-mailboxes "Unread" "notmuch://?query=folder:uchicago/** AND tag:unread"
|
||||||
|
|
||||||
# Signature
|
# Signature
|
||||||
set signature = "~/.config/neomutt/signatures/uchicago"
|
set signature = "~/.config/neomutt/signatures/uchicago"
|
||||||
|
|
|
||||||
|
|
@ -72,10 +72,10 @@ color index_date '#475e6c' default
|
||||||
color index_size '#475e6c' default
|
color index_size '#475e6c' default
|
||||||
color index_flags '#49e9a6' default '.*'
|
color index_flags '#49e9a6' default '.*'
|
||||||
|
|
||||||
# New mail - highlighted with bg_highlight
|
# New mail - gold with subtle background
|
||||||
color index '#e4b781' '#0c3f5f' "~N"
|
color index '#e4b781' '#041520' "~N"
|
||||||
color index_author '#df769b' '#0c3f5f' "~N"
|
color index_author '#df769b' '#041520' "~N"
|
||||||
color index_subject '#49d6e9' '#0c3f5f' "~N"
|
color index_subject '#e4b781' '#041520' "~N"
|
||||||
|
|
||||||
# Flagged mail
|
# Flagged mail
|
||||||
color index '#e66533' default "~F"
|
color index '#e66533' default "~F"
|
||||||
|
|
|
||||||
|
|
@ -68,3 +68,22 @@ macro attach o "<enter-command>unset wait_key<enter><pipe-entry>~/dotfiles/bin/o
|
||||||
macro attach O "<enter-command>unset wait_key<enter><pipe-entry>~/dotfiles/bin/mailcap-open<enter>" "Open with fzf picker"
|
macro attach O "<enter-command>unset wait_key<enter><pipe-entry>~/dotfiles/bin/mailcap-open<enter>" "Open with fzf picker"
|
||||||
macro attach,pager p "|git apply<enter>" "Apply git patch"
|
macro attach,pager p "|git apply<enter>" "Apply git patch"
|
||||||
macro attach,pager P "|git-apply-patch<enter>" "Apply git patch (interactive)"
|
macro attach,pager P "|git-apply-patch<enter>" "Apply git patch (interactive)"
|
||||||
|
|
||||||
|
# Notmuch search
|
||||||
|
bind index,pager \\ vfolder-from-query
|
||||||
|
macro index,pager ga "<vfolder-from-query>date:30d..<enter>" "View recent mail (30 days)"
|
||||||
|
macro index,pager gA "<vfolder-from-query>*<enter>" "View all mail"
|
||||||
|
macro index,pager gn "<vfolder-from-query>tag:unread<enter>" "View unread mail"
|
||||||
|
macro index,pager gr "<vfolder-from-query>date:7d..<enter>" "View recent mail (7 days)"
|
||||||
|
|
||||||
|
# Compose
|
||||||
|
bind index c mail
|
||||||
|
|
||||||
|
# Compose menu - PGP shortcuts
|
||||||
|
bind compose S pgp-menu
|
||||||
|
|
||||||
|
# Mark messages
|
||||||
|
bind index,pager m noop
|
||||||
|
macro index,pager mu "<enter-command>unset mark_old<enter><toggle-new><sync-mailbox>" "Mark as unread"
|
||||||
|
macro index,pager mr "<clear-flag>N<sync-mailbox>" "Mark as read"
|
||||||
|
macro index ma "<tag-pattern>.<enter><tag-prefix><clear-flag>N<untag-pattern>.<enter><sync-mailbox>" "Mark all as read"
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,18 @@
|
||||||
set header_cache = "~/.cache/neomutt/headers/"
|
set header_cache = "~/.cache/neomutt/headers/"
|
||||||
set message_cachedir = "~/.cache/neomutt/messages/"
|
set message_cachedir = "~/.cache/neomutt/messages/"
|
||||||
|
|
||||||
|
# Shell
|
||||||
|
set shell = "/bin/bash -l"
|
||||||
|
|
||||||
# Editor
|
# Editor
|
||||||
set editor = "emacs -nw"
|
set editor = "nvim"
|
||||||
set edit_headers = yes
|
set edit_headers = yes
|
||||||
|
|
||||||
# General settings
|
# General settings
|
||||||
set color_directcolor = yes
|
set color_directcolor = yes
|
||||||
set implicit_autoview = yes
|
set implicit_autoview = yes
|
||||||
set crypt_use_gpgme = yes
|
set crypt_use_gpgme = yes
|
||||||
|
unset mark_old
|
||||||
alternative_order text/enriched text/plain text
|
alternative_order text/enriched text/plain text
|
||||||
set delete = yes
|
set delete = yes
|
||||||
set abort_key = "<Esc>"
|
set abort_key = "<Esc>"
|
||||||
|
|
@ -25,8 +29,8 @@ set mail_check_stats
|
||||||
set status_chars = " *%A"
|
set status_chars = " *%A"
|
||||||
set status_format = "[ Folder: %D ] [%r%m messages%?n? (%n new)?%?d? (%d to delete)?%?t? (%t tagged)? ]%>─%?p?( %p postponed )?"
|
set status_format = "[ Folder: %D ] [%r%m messages%?n? (%n new)?%?d? (%d to delete)?%?t? (%t tagged)? ]%>─%?p?( %p postponed )?"
|
||||||
set date_format = "%d.%m.%Y %H:%M"
|
set date_format = "%d.%m.%Y %H:%M"
|
||||||
set sort = threads
|
set sort = date
|
||||||
set sort_aux = reverse-last-date-received
|
set sort_aux = date
|
||||||
set uncollapse_jump
|
set uncollapse_jump
|
||||||
set sort_re
|
set sort_re
|
||||||
set index_format = "%4C %Z %{%b %d} %-15.15L %?E?(%E)&? %s"
|
set index_format = "%4C %Z %{%b %d} %-15.15L %?E?(%E)&? %s"
|
||||||
|
|
@ -62,5 +66,14 @@ folder-hook ~/mail/personal/ "source ~/.config/neomutt/accounts/personal"
|
||||||
named-mailboxes "u" "~/mail/uchicago/Inbox"
|
named-mailboxes "u" "~/mail/uchicago/Inbox"
|
||||||
folder-hook ~/mail/uchicago/ "source ~/.config/neomutt/accounts/uchicago"
|
folder-hook ~/mail/uchicago/ "source ~/.config/neomutt/accounts/uchicago"
|
||||||
|
|
||||||
|
# Jump to last (newest) message when opening folders
|
||||||
|
folder-hook . "push <last-entry>"
|
||||||
|
|
||||||
|
# Notmuch virtual mailboxes (search across all mail)
|
||||||
|
set nm_config_file = `echo "$HOME/.config/notmuch/config"`
|
||||||
|
set nm_default_url = `echo "notmuch://$HOME/mail"`
|
||||||
|
set nm_query_type = messages
|
||||||
|
set nm_record_tags = "-inbox,sent"
|
||||||
|
|
||||||
# Source primary account (personal)
|
# Source primary account (personal)
|
||||||
source ~/.config/neomutt/accounts/personal
|
source ~/.config/neomutt/accounts/personal
|
||||||
|
|
|
||||||
17
config/notmuch/config
Normal file
17
config/notmuch/config
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
[database]
|
||||||
|
path=mail
|
||||||
|
|
||||||
|
[user]
|
||||||
|
name=Ray Andrew
|
||||||
|
primary_email=raydreww@gmail.com
|
||||||
|
other_email=rayandrew@uchicago.edu
|
||||||
|
|
||||||
|
[new]
|
||||||
|
tags=unread;inbox
|
||||||
|
ignore=.mbsyncstate;.strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr
|
||||||
|
|
||||||
|
[search]
|
||||||
|
exclude_tags=deleted;spam
|
||||||
|
|
||||||
|
[maildir]
|
||||||
|
synchronize_flags=true
|
||||||
177
docs/gpg-setup.md
Normal file
177
docs/gpg-setup.md
Normal file
|
|
@ -0,0 +1,177 @@
|
||||||
|
# GPG Setup for Email Signing
|
||||||
|
|
||||||
|
## Quick Setup (Automated)
|
||||||
|
|
||||||
|
Run the setup script to create a GPG key with all email identities:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gpg-setup
|
||||||
|
```
|
||||||
|
|
||||||
|
This will:
|
||||||
|
1. Create a 4096-bit RSA key (expires in 2 years)
|
||||||
|
2. Add all name/email variations as UIDs
|
||||||
|
3. Print the key ID to use in neomutt config
|
||||||
|
|
||||||
|
## Manual Setup
|
||||||
|
|
||||||
|
### Step 1: Create the primary key
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gpg --full-generate-key
|
||||||
|
```
|
||||||
|
|
||||||
|
When prompted:
|
||||||
|
1. Select `(1) RSA and RSA`
|
||||||
|
2. Key size: `4096`
|
||||||
|
3. Expiration: `2y` (or your preference)
|
||||||
|
4. Real name: `Ray Andrew Sinurat` (use your most formal name)
|
||||||
|
5. Email: `raydreww@gmail.com` (primary email)
|
||||||
|
6. Comment: (leave empty)
|
||||||
|
7. Enter a passphrase
|
||||||
|
|
||||||
|
### Step 2: Add additional UIDs
|
||||||
|
|
||||||
|
Add more email addresses and name variations to the same key:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gpg-add-uid "Ray Andrew Sinurat" "rayandrew@uchicago.edu"
|
||||||
|
gpg-add-uid "Ray Andrew" "raydreww@gmail.com"
|
||||||
|
gpg-add-uid "Ray Andrew" "rayandrew@uchicago.edu"
|
||||||
|
gpg-add-uid "Ray A. O. Sinurat" "raydreww@gmail.com"
|
||||||
|
gpg-add-uid "Ray A. O. Sinurat" "rayandrew@uchicago.edu"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example final key structure
|
||||||
|
|
||||||
|
```
|
||||||
|
sec rsa4096/ABCD1234EFGH5678 2024-01-01 [SC] [expires: 2026-01-01]
|
||||||
|
uid [ultimate] Ray Andrew Sinurat <raydreww@gmail.com>
|
||||||
|
uid [ultimate] Ray Andrew Sinurat <rayandrew@uchicago.edu>
|
||||||
|
uid [ultimate] Ray Andrew <raydreww@gmail.com>
|
||||||
|
uid [ultimate] Ray Andrew <rayandrew@uchicago.edu>
|
||||||
|
uid [ultimate] Ray A. O. Sinurat <raydreww@gmail.com>
|
||||||
|
uid [ultimate] Ray A. O. Sinurat <rayandrew@uchicago.edu>
|
||||||
|
ssb rsa4096/1234567890ABCDEF 2024-01-01 [E] [expires: 2026-01-01]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Get Key ID
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gpg --list-secret-keys --keyid-format LONG
|
||||||
|
```
|
||||||
|
|
||||||
|
The key ID is the part after `rsa4096/` (e.g., `ABCD1234EFGH5678`).
|
||||||
|
|
||||||
|
## Update NeoMutt Config
|
||||||
|
|
||||||
|
Use the **same key ID** for both accounts:
|
||||||
|
|
||||||
|
### Personal (`config/neomutt/accounts/personal`)
|
||||||
|
```
|
||||||
|
set pgp_sign_as = 0xYOUR_KEY_ID
|
||||||
|
```
|
||||||
|
|
||||||
|
### UChicago (`config/neomutt/accounts/uchicago`)
|
||||||
|
```
|
||||||
|
set pgp_sign_as = 0xYOUR_KEY_ID
|
||||||
|
```
|
||||||
|
|
||||||
|
## Export Public Key (for sharing)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Print to stdout
|
||||||
|
gpg-public-key
|
||||||
|
|
||||||
|
# Copy to clipboard (works on macOS, Linux with xclip or wl-copy)
|
||||||
|
gpg-public-key -c
|
||||||
|
|
||||||
|
# Export specific key
|
||||||
|
gpg-public-key raydreww@gmail.com
|
||||||
|
|
||||||
|
# Export to file
|
||||||
|
gpg-public-key > ~/public-key.asc
|
||||||
|
```
|
||||||
|
|
||||||
|
## Import Existing Keys
|
||||||
|
|
||||||
|
If you have backed up keys:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Restore from backup (imports and sets trust)
|
||||||
|
gpg-restore-key ~/private-key-backup.asc
|
||||||
|
|
||||||
|
# Or with public key too
|
||||||
|
gpg-restore-key ~/private-key.asc ~/public-key.asc
|
||||||
|
```
|
||||||
|
|
||||||
|
## Backup Keys
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Backup both keys to home directory
|
||||||
|
gpg-backup-key
|
||||||
|
|
||||||
|
# Backup to specific directory
|
||||||
|
gpg-backup-key ~/secure-backup
|
||||||
|
|
||||||
|
# Backup specific key
|
||||||
|
gpg-backup-key ~/backup raydreww@gmail.com
|
||||||
|
```
|
||||||
|
|
||||||
|
This creates:
|
||||||
|
- `gpg-private-key-<KEY_ID>.asc` (chmod 600)
|
||||||
|
- `gpg-public-key-<KEY_ID>.asc`
|
||||||
|
|
||||||
|
### Manual export
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Export private key (keep this safe!)
|
||||||
|
gpg-private-key > ~/private-key-backup.asc
|
||||||
|
|
||||||
|
# Copy private key to clipboard
|
||||||
|
gpg-private-key -c
|
||||||
|
|
||||||
|
# Export public key
|
||||||
|
gpg-public-key > ~/public-key-backup.asc
|
||||||
|
```
|
||||||
|
|
||||||
|
## GPG Agent
|
||||||
|
|
||||||
|
Make sure gpg-agent is running. It's enabled in home-manager config:
|
||||||
|
|
||||||
|
```nix
|
||||||
|
services.gpg-agent = {
|
||||||
|
enable = true;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
To manually start:
|
||||||
|
```bash
|
||||||
|
gpgconf --launch gpg-agent
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### "secret key not found"
|
||||||
|
- Check key ID matches: `gpg --list-secret-keys`
|
||||||
|
- Ensure gpg-agent is running: `gpgconf --launch gpg-agent`
|
||||||
|
- Reload agent: `gpg-connect-agent reloadagent /bye`
|
||||||
|
|
||||||
|
### Disable signing temporarily
|
||||||
|
In neomutt account file, set:
|
||||||
|
```
|
||||||
|
set crypt_autosign = no
|
||||||
|
```
|
||||||
|
|
||||||
|
## Delete Keys
|
||||||
|
|
||||||
|
To delete a GPG key (e.g., when leaving an organization):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Delete by key ID or email
|
||||||
|
gpg-delete-key 7C19EB1AF0BD68BF
|
||||||
|
gpg-delete-key raydreww@gmail.com
|
||||||
|
|
||||||
|
# Interactive mode (shows keys and prompts)
|
||||||
|
gpg-delete-key
|
||||||
|
```
|
||||||
|
|
@ -99,6 +99,8 @@
|
||||||
programs.nixfmt.enable = true;
|
programs.nixfmt.enable = true;
|
||||||
programs.stylua.enable = true;
|
programs.stylua.enable = true;
|
||||||
programs.shfmt.enable = true;
|
programs.shfmt.enable = true;
|
||||||
|
programs.shfmt.includes = [ "bin/*" ];
|
||||||
|
programs.shfmt.indent_size = 4;
|
||||||
programs.fish_indent.enable = true;
|
programs.fish_indent.enable = true;
|
||||||
programs.shellcheck.enable = true;
|
programs.shellcheck.enable = true;
|
||||||
settings.global.excludes = [ "flake.lock" ];
|
settings.global.excludes = [ "flake.lock" ];
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
davmail = mkEnableOption "Enable DavMail";
|
davmail = mkEnableOption "Enable DavMail";
|
||||||
mbsync = mkEnableOption "Enable Mbsync";
|
mbsync = mkEnableOption "Enable Mbsync";
|
||||||
neomutt = mkEnableOption "Enable NeoMutt";
|
neomutt = mkEnableOption "Enable NeoMutt";
|
||||||
|
notmuch = mkEnableOption "Enable notmuch";
|
||||||
mailcap = mkEnableOption "Enable mailcap";
|
mailcap = mkEnableOption "Enable mailcap";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -28,9 +29,13 @@
|
||||||
enable = config.custom.email.mbsync;
|
enable = config.custom.email.mbsync;
|
||||||
configFile = "${dots}/config/mbsync/mbsyncrc";
|
configFile = "${dots}/config/mbsync/mbsyncrc";
|
||||||
frequency = "*:0/1";
|
frequency = "*:0/1";
|
||||||
extraPackages = with pkgs; [ sops ];
|
extraPackages = with pkgs; [ sops ] ++ lib.optionals config.custom.email.notmuch [ notmuch ];
|
||||||
|
postExec = lib.mkIf config.custom.email.notmuch "${pkgs.notmuch}/bin/notmuch new";
|
||||||
environment = {
|
environment = {
|
||||||
SOPS_AGE_KEY_FILE = "${xdg-config-dir}/sops/age/keys.txt";
|
SOPS_AGE_KEY_FILE = "${xdg-config-dir}/sops/age/keys.txt";
|
||||||
|
}
|
||||||
|
// lib.optionalAttrs config.custom.email.notmuch {
|
||||||
|
NOTMUCH_CONFIG = "${xdg-config-dir}/notmuch/config";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -49,6 +54,9 @@
|
||||||
exec env TERM=xterm-direct ${neomutt}/bin/neomutt "$@"
|
exec env TERM=xterm-direct ${neomutt}/bin/neomutt "$@"
|
||||||
'')
|
'')
|
||||||
]
|
]
|
||||||
|
++ lib.optionals config.custom.email.notmuch [
|
||||||
|
notmuch
|
||||||
|
]
|
||||||
++ lib.optionals config.custom.email.mailcap [
|
++ lib.optionals config.custom.email.mailcap [
|
||||||
mailcap
|
mailcap
|
||||||
w3m # HTML rendering
|
w3m # HTML rendering
|
||||||
|
|
@ -61,6 +69,9 @@
|
||||||
"msmtp".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/msmtp";
|
"msmtp".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/msmtp";
|
||||||
"neomutt".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/neomutt";
|
"neomutt".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/neomutt";
|
||||||
"isyncrc".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/mbsync/mbsyncrc";
|
"isyncrc".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/mbsync/mbsyncrc";
|
||||||
|
}
|
||||||
|
// lib.optionalAttrs config.custom.email.notmuch {
|
||||||
|
"notmuch/config".source = config.lib.file.mkOutOfStoreSymlink "${dots}/config/notmuch/config";
|
||||||
};
|
};
|
||||||
|
|
||||||
# mailcap symlink
|
# mailcap symlink
|
||||||
|
|
@ -76,5 +87,10 @@
|
||||||
mkdir -p ~/.cache/neomutt/messages
|
mkdir -p ~/.cache/neomutt/messages
|
||||||
mkdir -p ~/.local/state
|
mkdir -p ~/.local/state
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
# Set NOTMUCH_CONFIG environment variable
|
||||||
|
custom.environment.variables = lib.mkIf config.custom.email.notmuch {
|
||||||
|
NOTMUCH_CONFIG = "${xdg-config-dir}/notmuch/config";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,7 @@
|
||||||
neomutt = true;
|
neomutt = true;
|
||||||
mbsync = true;
|
mbsync = true;
|
||||||
mailcap = true;
|
mailcap = true;
|
||||||
|
notmuch = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue