diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5dfee21 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +# .editorconfig +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cb84d7..c3964c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,21 @@ This changlog uses the [ISO 8601 date format](https://www.iso.org/iso-8601-date- ## [Unreleased] +## [1.5.0] - 2021-07-11 + +### Added + +* zstd compression support +* Added .editorconfig +* Added key expire readme tutorial [#26](https://github.com/NicoHood/gpgit/issues/26) +* Added `--version` option +* Added `--asset` option [#32](https://github.com/NicoHood/gpgit/issues/32) +* Added `--title` option [#28](https://github.com/NicoHood/gpgit/issues/28) + +### Fixed + +* Fixed Readme Links + ## [1.4.1] - 2021-01-31 ### Changed @@ -181,7 +196,8 @@ This changlog uses the [ISO 8601 date format](https://www.iso.org/iso-8601-date- ### Added - Initial release of the software -[Unreleased]: https://github.com/NicoHood/gpgit/compare/1.4.1...HEAD +[Unreleased]: https://github.com/NicoHood/gpgit/compare/1.5.0...HEAD +[1.4.1]: https://github.com/NicoHood/gpgit/compare/1.4.1...1.5.0 [1.4.1]: https://github.com/NicoHood/gpgit/compare/1.4.0...1.4.1 [1.4.0]: https://github.com/NicoHood/gpgit/compare/1.3.4...1.4.0 [1.3.4]: https://github.com/NicoHood/gpgit/compare/1.3.3...1.3.4 diff --git a/Readme.md b/Readme.md index 16148be..1f7b62e 100644 --- a/Readme.md +++ b/Readme.md @@ -48,18 +48,71 @@ The security status of GNU/Linux projects will be tracked in the [Linux Security ## Installation -### Distribution Packages -* [Arch Linux](https://archlinux.org/packages/community/any/gpgit/) `sudo pacman -S gpgit` +### Arch Linux -### Manual Installation +GPGit is available as [official Arch Linux distribution package](https://archlinux.org/packages/community/any/gpgit/): ```bash -# Install dependencies and optional dependencies -sudo apt-get install bash gnupg2 git tar xz-utils coreutils gawk grep sed -sudo apt-get install gzip bzip lzip file jq curl +sudo pacman -S gpgit +# Optional dependencies for Github API uploading +sudo pacman -S curl jq +``` + +### Debian + +First install the following dependencies, then follow the manual installation instruction. + +```bash +# Install dependencies +sudo apt-get install bash gnupg2 git tar xz-utils coreutils gawk grep sed util-linux +# Optional dependencies +sudo apt-get install gzip bzip lzip zstd file jq curl +``` +### MacOS + +First install the following dependencies with [Homebrew](https://brew.sh/), then follow the manual installation instructions. + +```bash +# Install dependencies +brew install bash git xz gnu-getopt coreutils +# Install a GPG suite, such as https://gpgtools.org/ +brew install --ask gpg-suite +# Optional dependencies +brew install gzip bzip2 lzip zstd jq curl +``` + +### Manual Installation + +#### Dependencies + +* bash +* gnupg2 +* git +* tar +* xz +* grep +* sed +* gnu awk +* gnu getopt (util-linux) +* gnu date (coreutils) + +#### Optional Dependencies + +* gzip (Compression option) +* zstd (Compression option) +* bzip (Compression option) +* lzip (Compression option) +* file (Github API upload) +* jq (Github API upload) +* curl (Github API upload) +* shellcheck (Development: `make test`) + +#### Installation Instructions + +```bash # Download and verify source -VERSION=1.4.1 +VERSION=1.5.0 wget "https://github.com/NicoHood/gpgit/releases/download/${VERSION}/gpgit-${VERSION}.tar.xz" wget "https://github.com/NicoHood/gpgit/releases/download/${VERSION}/gpgit-${VERSION}.tar.xz.asc" gpg2 --keyserver hkps://keyserver.ubuntu.com --recv-keys 97312D5EB9D7AE7D0BD4307351DAE9B7C1AE9161 @@ -84,7 +137,7 @@ If you add and commit a `CHANGELOG.md` file to your Git with the [Keep a Changel $ gpgit --help Usage: gpgit [options] [ | ] -GPGit 1.4.1 https://github.com/NicoHood/gpgit +GPGit 1.5.0 https://github.com/NicoHood/gpgit A shell script that automates the process of signing Git sources via GPG. Mandatory arguments: @@ -99,6 +152,8 @@ Optional arguments: current working directory. -u, --local-user Use the given GPG key (same as --signingkey). -o, --output Safe all release assets to the specified . + -a, --asset Add additional Github assets, e.g. software bundles. + -t, --title Custom Github release title (instead of tag name). -p, --pre-release Flag as Github pre-release. -f, --force Force the recreation of Git tag and release assets. -i, --interactive Run in interactive mode, step-by-step. @@ -114,7 +169,7 @@ Configuration options: gpgit.signingkey , user.signingkey gpgit.output gpgit.token - gpgit.compression + gpgit.compression gpgit.hash gpgit.changelog gpgit.github @@ -137,7 +192,7 @@ GPGit guides you through 5 simple steps to get your software project ready with 2. [Publish your key](#2-publish-your-key) 1. [Send GPG key to a key server](#21-send-gpg-key-to-a-key-server) 2. [Publish full fingerprint](#22-publish-full-fingerprint) - 3. [Associate GPG key with Github](#23-associate-gpg-key-with-github) + 3. [Associate GPG key with Github](#23-associate-gpg-key-with-github) 3. [Use Git with GPG](#3-use-git-with-gpg) 1. [Configure Git GPG key](#31-configure-git-gpg-key) 2. [Enble commit signing](#32-enable-commit-signing) @@ -164,7 +219,7 @@ Here are a few examples how to keep a passphrase strong but easy to remember: ### 1.2 Key generation If you don't have a GPG key yet, create a new one first. You can use RSA (4096 bits) or ECC (Curve 25519) for a strong key. GPG offers you the option to use the most future-proof key algorithm available. Use the most recent version gnupg2, not gnupg1! -Ed25519 ECC GPG keys are currently [not supported by Github](https://help.github.com/articles/generating-a-new-gpg-key/#supported-gpg-key-algorithms). To generate an ECC key use `future-default` instead of `rsa4096` as parameter. +Ed25519 ECC GPG keys are still not supported by every software/platform. To generate an RSA key use `rsa4096` instead of `future-default` as parameter. **Make sure that your secret key is stored somewhere safe and use a unique strong password.** @@ -185,7 +240,7 @@ uid John Doe sub cv25519 2017-09-24 [E] ``` -The generated key has the fingerprint `6718A9A63030E182A86FEE152F8E73B1D445CCD3` in this example. Share it with others so they can verify your source. [[Read more]](https://wiki.archlinux.org/index.php/GnuPG#Create_key_pair) +The generated key has the fingerprint `6718A9A63030E182A86FEE152F8E73B1D445CCD3` in this example. Share it with others so they can verify your source. [[Read more]](https://wiki.archlinux.org/index.php/GnuPG#Create_a_key_pair) If you ever move your installation make sure to backup `~/.gnupg/` as it contains the **private key** and the **revocation certificate**. Handle it with care. [[Read more]](https://wiki.archlinux.org/index.php/GnuPG#Revoke_a_key) @@ -207,7 +262,7 @@ gpg2 --keyserver hkps://keyserver.ubuntu.com --recv-keys To make it easy for everyone else to find your key it is crucial that you publish the [**full fingerprint**](https://lkml.org/lkml/2016/8/15/445) on a trusted platform, such as your website or Github. To give the key more trust other users can sign your key too. [[Read more]](https://wiki.debian.org/Keysigning) ### 2.3 Associate GPG key with Github -To make Github display your commits as "verified" you also need to add your public [GPG key to your Github profile](https://github.com/settings/keys). [[Read more]](https://help.github.com/articles/generating-a-gpg-key/) +To make Github display your commits as "verified" you also need to add your public [GPG key to your Github profile](https://github.com/settings/keys). [[Read more]](https://docs.github.com/github/authenticating-to-github/adding-a-new-gpg-key-to-your-github-account) ```bash # List keys + full fingerprint @@ -267,7 +322,7 @@ git archive --format=tar --prefix gpgit-1.0.0/ 1.0.0 | xz > gpgit-1.0.0.tar.xz ### 4.2 Sign the archive Type the filename of the tarball that you want to sign and then run: ```bash -gpg2 --digest-algo SHA512 --armor --detach-sign gpgit-1.0.0.tar.xz +gpg2 --personal-digest-preferences SHA512 --armor --detach-sign gpgit-1.0.0.tar.xz ``` **Do not blindly sign the Github source downloads** unless you have compared its content with the local files via `diff.` [[Read more]](https://wiki.archlinux.org/index.php/GnuPG#Make_a_detached_signature) @@ -288,7 +343,7 @@ sha512sum gpgit-1.0.0.tar.xz > gpgit-1.0.0.tar.xz.sha512 ## 5. Upload the release ### 5.1 Configure HTTPS download server -* [Why HTTPS Matters](https://developers.google.com/web/fundamentals/security/encrypt-in-transit/why-https) +* [Why HTTPS Matters](https://web.dev/why-https-matters/) * [Let's Encrypt](https://letsencrypt.org/) * [SSL Server Test](https://www.ssllabs.com/ssltest/) @@ -306,5 +361,19 @@ The script also supports [uploading to Github](https://developer.github.com/v3/r ## Email Encryption You can also use your GPG key for email encryption with [thunderbird](https://support.mozilla.org/en-US/kb/openpgp-thunderbird-howto-and-faq). +## Update key expire date + +After renewing the GPG key expire date make sure to [publish your GPG key](https://github.com/NicoHood/gpgit#2-publish-your-key) again to the keyserver and update your website accordingly. A more detailed instruction can be found at [G-Loaded Journal](https://www.g-loaded.eu/2010/11/01/change-expiration-date-gpg-key/). + +``` +gpg2 --edit-key +gpg> expire +gpg> 1y +gpg> key 1 +gpg> expire +gpg> 1y +gpg> save +``` + ## Contact You can get securely in touch with me [here](https://contact.nicohood.de). My GPG key ID is `9731 2D5E B9D7 AE7D 0BD4 3073 51DA E9B7 C1AE 9161`. Don't hesitate to [file a bug at Github](https://github.com/NicoHood/gpgit/issues). More cool projects from me can be found [on my Website](https://www.nicohood.de). diff --git a/gpgit.sh b/gpgit.sh index e126ffb..b52104a 100755 --- a/gpgit.sh +++ b/gpgit.sh @@ -20,7 +20,7 @@ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE # OR OTHER DEALINGS IN THE SOFTWARE. -VERSION="1.4.1" +VERSION="1.5.0" # Avoid any encoding problems export LANG=C @@ -71,6 +71,8 @@ ${BOLD}Optional arguments:${ALL_OFF} current working directory. -u, --local-user Use the given GPG key (same as --signingkey). -o, --output Safe all release assets to the specified . + -a, --asset Add additional Github assets, e.g. software bundles. + -t, --title Custom Github release title (instead of tag name). -p, --pre-release Flag as Github pre-release. -f, --force Force the recreation of Git tag and release assets. -i, --interactive Run in interactive mode, step-by-step. @@ -86,7 +88,7 @@ ${BOLD}Configuration options:${ALL_OFF} gpgit.signingkey , user.signingkey gpgit.output gpgit.token - gpgit.compression + gpgit.compression gpgit.hash gpgit.changelog gpgit.github @@ -230,7 +232,7 @@ trap kill_exit SIGTERM SIGINT SIGHUP # Initialize variables unset INTERACTIVE MESSAGE KEYSERVER COMPRESSION HASH OUTPUT PROJECT SIGNINGKEY unset TOKEN GPG_USER GPG_EMAIL GITHUB_REPO_NAME GITHUB PRERELEASE BRANCH GPG_BIN -unset FORCE NEW_SIGNINGKEY REMOTE CHANGELOG CHANGELOG_FILE +unset FORCE NEW_SIGNINGKEY REMOTE CHANGELOG CHANGELOG_FILE GITHUB_TITLE declare -A GITHUB_ASSET=() declare -a HASH=() COMPRESSION=() @@ -240,10 +242,20 @@ if [[ -x /usr/local/opt/gnu-getopt/bin/getopt ]]; then export PATH="/usr/local/opt/gnu-getopt/bin/:${PATH}" fi +# Prefere gnu tools, if available (on MAC) +if [[ -x /usr/local/opt/coreutils/libexec/gnubin ]]; then + export PATH="/usr/local/opt/coreutils/libexec/gnubin/:${PATH}" +fi + +# Use gnu date on mac +if command -v gdate &> /dev/null; then + alias date="gdate" +fi + # Parse input params an ovrwrite possible default or config loaded options -GETOPT_PARAMS_SHORT="hcm:C:k:u:s:S:o:O:pnfdi" +GETOPT_PARAMS_SHORT="hvcm:C:k:u:s:S:o:O:a:t:pnfdi" GETOPT_ARGS="$(getopt -o "${GETOPT_PARAMS_SHORT}" \ - -l "help,message:,directory:,signingkey:,local-user:,gpg-sign:,output:,pre-release,no-github,force,interactive,changelog:,token:,compression:,hash:,keyserver:,github:,githubrepo:,project:,remote:,debug,color:"\ + -l "help,version,message:,directory:,signingkey:,local-user:,gpg-sign:,output:,asset:,title:,pre-release,no-github,force,interactive,changelog:,token:,compression:,hash:,keyserver:,github:,githubrepo:,project:,remote:,debug,color:"\ -n "gpgit" -- "${@}")" || die "${USAGE_SHORT}" eval set -- "${GETOPT_ARGS}" @@ -255,6 +267,10 @@ while true ; do echo "${USAGE}" >&2 exit 0 ;; + -v|--version) + echo "${VERSION}" + exit 0 + ;; -m|--message) MESSAGE+="${2}\\n" shift @@ -271,6 +287,15 @@ while true ; do SIGNINGKEY="${2}" shift ;; + -a|--asset) + [[ -f "${2}" ]] || die "Asset '${2}' not a valid file." + GITHUB_ASSET["$(basename "${2}")"]="${2}" + shift + ;; + -t|--title) + GITHUB_TITLE="${2}" + shift + ;; -p|--prerelease) PRERELEASE="true" ;; @@ -363,7 +388,7 @@ shift COMMIT="${1:-"HEAD"}" # Check if run inside Git directory -check_dependency git sed grep awk md5sum shasum || die "Please check your \$PATH variable or install the missing dependency." +check_dependency git sed grep awk md5sum shasum date || die "Please check your \$PATH variable or install the missing dependency." if [[ "$(git rev-parse --is-inside-work-tree 2>/dev/null)" != "true" ]]; then die "Not a Git repository: $(pwd)" fi @@ -408,6 +433,7 @@ GITHUB_REPO_NAME="${GITHUB_REPO_NAME:-"$(git config gpgit.githubrepo || true)"}" GITHUB_REPO_NAME="${GITHUB_REPO_NAME:-"$(git config --local "remote.${REMOTE}.url" | sed -e 's/.*github.com[:/]//' | sed -e 's/.git$//')"}" GITHUB="${GITHUB:-"$(git config gpgit.github || true)"}" GITHUB="${GITHUB:-auto}" +GITHUB_TITLE="${GITHUB_TITLE:-}" PRERELEASE="${PRERELEASE:-"false"}" GPG_BIN="$(git config gpg.program || true)" GPG_BIN="${GPG_BIN:-gpg2}" @@ -416,7 +442,7 @@ NEW_SIGNINGKEY="false" # Check if dependencies are available # Dependencies: bash, gnupg2, git, tar, xz, coreutils, gawk, grep, sed -# Optional dependencies: gzip, bzip2, lzip, file, jq, curl +# Optional dependencies: gzip, bzip2, lzip, zstd, file, jq, curl check_dependency "${GPG_BIN}" "${COMPRESSION[@]}" \ || die "Please check your \$PATH variable or install the missing dependencies." @@ -489,9 +515,19 @@ if [[ "${GITHUB}" == "true" ]]; then plain "git config --global gpgit.token " read -rs TOKEN fi +else + # Fail if Github specific options were used, but API upload is disabled. + if [[ "${PRERELEASE}" != "false" ]]; then + die "Option --prerelease can only be used when Github API upload is enabled." + fi + if [[ -n "${GITHUB_TITLE}" ]]; then + die "Option --title can only be used when Github API upload is enabled." + fi + if [[ "${#GITHUB_ASSET[@]}" -gt 0 ]]; then + die "Option --asset can only be used when Github API upload is enabled." + fi fi - #################################################################################################### msg "1. Generate a new GPG key" #################################################################################################### @@ -535,9 +571,18 @@ else GPG_USER_EMAIL="$(echo "${SIGNINGKEY_OUTPUT}" | awk -F: '$1 == "uid" {print $10; exit}')" plain "Using existing GPG key: '${GPG_USER_EMAIL}'" plain "Fingerprint: '${SIGNINGKEY}'" - interactive -fi + # Check key expire date + GPG_EXPIRE_DATE="$(echo "${SIGNINGKEY_OUTPUT}" | awk -F: '$1 == "pub" {print $7; exit}')" + CURRENT_DATE="${EPOCHSECONDS:-"$(date '+%s')"}" + if [[ "${GPG_EXPIRE_DATE}" -lt "${CURRENT_DATE}" ]]; then + die "GPG key expired on $(date -d "@${GPG_EXPIRE_DATE}" +%F)" + elif [[ "${GPG_EXPIRE_DATE}" -lt "$(( "${CURRENT_DATE}" + 7776000 ))" ]]; then + warning "GPG key will expire in less than 3 month: $(date -d "@${GPG_EXPIRE_DATE}" +%F)" + else + interactive + fi +fi #################################################################################################### msg "2. Publish your key" @@ -668,7 +713,7 @@ do if [[ "${util}" == "zip" ]]; then git archive --format=zip --prefix "${PROJECT}-${TAG}/" "refs/tags/${TAG}" > "${FILE}" else - git archive --format=tar --prefix "${PROJECT}-${TAG}/" "refs/tags/${TAG}" | "${util}" --best > "${FILE}" + git archive --format=tar --prefix "${PROJECT}-${TAG}/" "refs/tags/${TAG}" | "${util}" > "${FILE}" fi else warning "Found existing archive '${FILE}'." @@ -757,7 +802,7 @@ function github_upload_asset() # Abort in API error message="$(echo "${RESULT}" | jq -r .message)" if [[ "${message}" != "null" ]]; then - die "Github API message: '${message}' Check your token configuration: https://github.com/settings/tokens" + die "Github API message: '${message}'. Check your token configuration: https://github.com/settings/tokens" fi } @@ -803,7 +848,7 @@ else API_JSON="$(jq -n -c -M \ --arg tag_name "${TAG}" \ --arg target_commitish "${BRANCH}" \ - --arg name "${TAG}" \ + --arg name "${GITHUB_TITLE:-"${TAG}"}" \ --arg body "${MESSAGE}" \ --argjson prerelease "${PRERELEASE}" \ '{tag_name: $tag_name, target_commitish: $target_commitish, name: $name, body: $body, draft: false, prerelease: $prerelease}')" @@ -817,7 +862,7 @@ else # Abort on API error message="$(echo "${GITHUB_RELEASE}" | jq -r .message)" if [[ "${message}" != "null" ]]; then - die "Github API message: '${message}' Check your token configuration: https://github.com/settings/tokens" + die "Github API message: '${message}'. Check your token configuration: https://github.com/settings/tokens" fi # Safe new ID