From 0120138e8a3ccf49500ce3d788d54a79181b73e7 Mon Sep 17 00:00:00 2001 From: Robert Stoll Date: Fri, 24 Jan 2025 16:53:24 +0100 Subject: [PATCH] reset signing key every month on pull to detect revoked keys with on pull I mean, not really every month but as soon as someone uses gt pull and the last check is more than a month ago. This is our mechanism to detect revoked keys, one can disable it by setting the lastCheck sometime in the future --- .github/workflows/gt-update.yml | 4 ++-- src/common-constants.source.sh | 3 +++ src/gt-pull.sh | 39 ++++++++++++++++++++++++++++++--- src/gt-reset.sh | 7 +++--- src/paths.source.sh | 1 + 5 files changed, 46 insertions(+), 8 deletions(-) diff --git a/.github/workflows/gt-update.yml b/.github/workflows/gt-update.yml index 1a3b6e0..3c157bf 100644 --- a/.github/workflows/gt-update.yml +++ b/.github/workflows/gt-update.yml @@ -157,7 +157,7 @@ jobs: while read -r key; do keyId=$(cut -d ':' -f5 <<<"$key") expirationTimestamp=$(cut -d ':' -f7 <<<"$key") - if (( expirationTimestamp < $limitTimestamp )); then + if (( expirationTimestamp < limitTimestamp )); then expirationDate=$(date -d "@$((expirationTimestamp + 0))" +"%Y-%m-%dT%H:%M:%S") printf >&2 "\033[0;31mERROR\033[0m: expiration date (%s) of key %s is before the given limit %s\n" "$expirationDate" "$keyId" "$limitDate" ((++expired)) @@ -193,7 +193,7 @@ jobs: while read -r key; do keyId=$(cut -d ':' -f5 <<<"$key") expirationTimestamp=$(cut -d ':' -f7 <<<"$key") - if (( expirationTimestamp < $limitTimestamp )); then + if (( expirationTimestamp < limitTimestamp )); then expirationDate=$(date -d "@$((expirationTimestamp + 0))" +"%Y-%m-%dT%H:%M:%S") printf >&2 "\033[0;31mERROR\033[0m: expiration date (%s) of key %s is before the given limit %s\n" "$expirationDate" "$keyId" "$limitDate" ((++expired)) diff --git a/src/common-constants.source.sh b/src/common-constants.source.sh index 459b805..05bb39e 100644 --- a/src/common-constants.source.sh +++ b/src/common-constants.source.sh @@ -54,3 +54,6 @@ local -r signingKeyAsc='signing-key.public.asc' local -r targetFileNamePatternLong='--target-file-name' local -r targetFileNamePattern="$targetFileNamePatternLong" + +local -r gpgOnlyParamPatternLong="--gpg-only" +local -r gpgOnlyParamPattern="$gpgOnlyParamPatternLong" diff --git a/src/gt-pull.sh b/src/gt-pull.sh index 6b95940..4104497 100755 --- a/src/gt-pull.sh +++ b/src/gt-pull.sh @@ -76,8 +76,10 @@ if ! [[ -v dir_of_tegonal_scripts ]]; then source "$dir_of_tegonal_scripts/setup.sh" "$dir_of_tegonal_scripts" fi +sourceOnce "$dir_of_gt/gt-reset.sh" sourceOnce "$dir_of_gt/pulled-utils.sh" sourceOnce "$dir_of_gt/utils.sh" +sourceOnce "$dir_of_tegonal_scripts/utility/date-utils.sh" sourceOnce "$dir_of_tegonal_scripts/utility/git-utils.sh" sourceOnce "$dir_of_tegonal_scripts/utility/gpg-utils.sh" sourceOnce "$dir_of_tegonal_scripts/utility/io.sh" @@ -110,7 +112,8 @@ function gt_pull() { currentDir=$(pwd) || die "could not determine currentDir, maybe it does not exist anymore?" local -r currentDir - local pulledTsvLatestVersionPragma pulledTsvHeader signingKeyAsc targetFileNamePatternLong + local pulledTsvLatestVersionPragma pulledTsvHeader signingKeyAsc + local remoteParamPatternLong targetFileNamePatternLong workingDirParamPatternLong gpgOnlyParamPatternLong source "$dir_of_gt/common-constants.source.sh" || traceAndDie "could not source common-constants.source.sh" local -r UNSECURE_NO_VERIFY_PATTERN='--unsecure-no-verification' @@ -210,7 +213,7 @@ function gt_pull() { local -r workingDirAbsolute pullDirAbsolute checkPathNamedIsInsideOf "$pullDirAbsolute" "pull directory" "$currentDir" || return $? - local publicKeysDir repo gpgDir pulledTsv pullHookFile + local publicKeysDir repo gpgDir pulledTsv pullHookFile lastCheckFile source "$dir_of_gt/paths.source.sh" || traceAndDie "could not source paths.source.sh" if ! [[ -d $pullDirAbsolute ]]; then @@ -237,7 +240,37 @@ function gt_pull() { doVerification=false else doVerification=true - if ! [[ -d $gpgDir ]]; then + if [[ -d $gpgDir ]]; then + # if the signingKey exists, then we assume that it was fetched from the remote and in this case + # want to check periodically that it was not revoked + if [[ -f "$publicKeysDir/$signingKeyAsc" ]]; then + local lastCheckDate lastCheckTimestamp aMonthAgoTimestamp + lastCheckTimestamp=$(date -d "-2 month" +%s) + + if [[ -f $lastCheckFile ]]; then + local lastCheckDate + lastCheckDate=$(cat "$lastCheckFile") + lastCheckTimestamp=$(dateToTimestamp "$lastCheckDate") || die "looks like the date \033[0;36m%s\033[0m in %s is not in format YYYY-mm-dd" "$lastCheckDate" "$lastCheckFile" + fi + aMonthAgoTimestamp=$(date -d "-1 month" +%s) + if ((lastCheckTimestamp < aMonthAgoTimestamp)); then + local lastCheckDateInUserFormat + lastCheckDate=$(timestampToDate "$lastCheckTimestamp") + lastCheckDateInUserFormat=$(timestampToDateInUserFormat "$lastCheckTimestamp") + + printf "==================================================\n" + logInfo "time to check if the signing key of remote \033[0;36m%s\033[0m, is still valid.\nLast check was on %s. Going to execute gt reset -r %s %s true" "$remote" "$lastCheckDateInUserFormat" "$remote" "$gpgOnlyParamPatternLong" + printf "==================================================\n" + if ! gt_reset "$remoteParamPatternLong" "$remote" \ + "$workingDirParamPatternLong" "$workingDirAbsolute" \ + "$gpgOnlyParamPatternLong" "true"; then + + die "was not able to update the signing key of remote \033[0;36m%s\033[0m, check if it is still valid and if not whether you can trust the already pulled files\n In case this happens due to connection problems or the like, you can defer this check by modifying the date in %s" "$remote" "$lastCheckFile" + fi + fi + + fi + else if [[ -f $gpgDir ]]; then die "looks like the remote \033[0;36m%s\033[0m is broken there is a file at the gpg dir's location: %s" "$remote" "$gpgDir" fi diff --git a/src/gt-reset.sh b/src/gt-reset.sh index 5143564..efae8ff 100755 --- a/src/gt-reset.sh +++ b/src/gt-reset.sh @@ -68,7 +68,7 @@ function gt_reset() { # shellcheck disable=SC2034 # is passed by name to parseArguments local -ar params=( remote "$remoteParamPattern" '(optional) if set, only the remote with this name is reset, otherwise all are reset' - gpgOnly "--gpg-only" '(optional) if set to true, then only the gpg keys are reset but the files are not re-pulled -- default: false' + gpgOnly "$gpgOnlyParamPattern" '(optional) if set to true, then only the gpg keys are reset but the files are not re-pulled -- default: false' workingDir "$workingDirParamPattern" "$workingDirParamDocu" ) local -r examples=$( @@ -107,7 +107,7 @@ function gt_reset() { exitIfRemoteDirDoesNotExist "$workingDir" "$remote" exitIfRepoBrokenAndReInitIfAbsent "$workingDirAbsolute" "$remote" - local publicKeysDir gpgDir repo pullArgsFile + local publicKeysDir gpgDir repo pullArgsFile lastCheckFile source "$dir_of_gt/paths.source.sh" || traceAndDie "could not source paths.source.sh" if [[ -d $publicKeysDir ]]; then logInfo "Going to re-establish gpg trust in remote \033[0;36m%s\033[0m, removing %s" "$remote" "$publicKeysDir" @@ -120,7 +120,7 @@ function gt_reset() { local unsecureArgs if [[ -f $pullArgsFile ]]; then - unsecureArgs=$(grep -E "(--unsecure|--unsecure-no-verification)\strue" "$pullArgsFile") + unsecureArgs=$(grep -E "(--unsecure|--unsecure-no-verification)\s*true" "$pullArgsFile") else unsecureArgs="" fi @@ -164,6 +164,7 @@ function gt_reset() { exitBecauseSigningKeyNotImported "$remote" "$publicKeysDir" "$gpgDir" "$unsecureParamPatternLong" "$signingKeyAsc" fi fi + date +"%Y-%m-%d" >"$lastCheckFile" logSuccess "re-established trust in remote \033[0;36m%s\033[0m" "$remote" } diff --git a/src/paths.source.sh b/src/paths.source.sh index 2f10cec..9d25b34 100644 --- a/src/paths.source.sh +++ b/src/paths.source.sh @@ -25,3 +25,4 @@ local -r pulledTsv="$remoteDir/pulled.tsv" local -r pullArgsFile="$remoteDir/pull.args" local -r pullHookFile="$remoteDir/pull-hook.sh" local -r gitconfig="$remoteDir/gitconfig" +local -r lastCheckFile="$gpgDir/signing-key.last-check.txt"