diff --git a/.github/workflows/DNS.yml b/.github/workflows/DNS.yml index 1a37b8a9..fbe1e61f 100644 --- a/.github/workflows/DNS.yml +++ b/.github/workflows/DNS.yml @@ -66,7 +66,7 @@ jobs: TokenName4: ${{ secrets.TokenName4}} TokenName5: ${{ secrets.TokenName5}} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Clone acmetest run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/ - name: Set env file @@ -114,7 +114,7 @@ jobs: TokenName4: ${{ secrets.TokenName4}} TokenName5: ${{ secrets.TokenName5}} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install tools run: brew install socat - name: Clone acmetest @@ -165,7 +165,7 @@ jobs: - name: Set git to use LF run: | git config --global core.autocrlf false - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install cygwin base packages with chocolatey run: | choco config get cacheLocation @@ -224,7 +224,7 @@ jobs: TokenName4: ${{ secrets.TokenName4}} TokenName5: ${{ secrets.TokenName5}} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Clone acmetest run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/ - uses: vmactions/freebsd-vm@v1 @@ -279,7 +279,7 @@ jobs: TokenName4: ${{ secrets.TokenName4}} TokenName5: ${{ secrets.TokenName5}} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Clone acmetest run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/ - uses: vmactions/openbsd-vm@v1 @@ -334,7 +334,7 @@ jobs: TokenName4: ${{ secrets.TokenName4}} TokenName5: ${{ secrets.TokenName5}} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Clone acmetest run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/ - uses: vmactions/netbsd-vm@v1 @@ -390,7 +390,7 @@ jobs: TokenName4: ${{ secrets.TokenName4}} TokenName5: ${{ secrets.TokenName5}} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Clone acmetest run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/ - uses: vmactions/dragonflybsd-vm@v1 @@ -450,7 +450,7 @@ jobs: TokenName4: ${{ secrets.TokenName4}} TokenName5: ${{ secrets.TokenName5}} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Clone acmetest run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/ - uses: vmactions/solaris-vm@v1 @@ -508,7 +508,7 @@ jobs: TokenName4: ${{ secrets.TokenName4}} TokenName5: ${{ secrets.TokenName5}} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Clone acmetest run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/ - uses: vmactions/omnios-vm@v1 @@ -563,7 +563,7 @@ jobs: TokenName4: ${{ secrets.TokenName4}} TokenName5: ${{ secrets.TokenName5}} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Clone acmetest run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/ - uses: vmactions/openindiana-vm@v1 @@ -618,7 +618,7 @@ jobs: TokenName4: ${{ secrets.TokenName4}} TokenName5: ${{ secrets.TokenName5}} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Clone acmetest run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/ - uses: vmactions/haiku-vm@v1 diff --git a/.github/workflows/DragonFlyBSD.yml b/.github/workflows/DragonFlyBSD.yml index dda8c99f..f3a85920 100644 --- a/.github/workflows/DragonFlyBSD.yml +++ b/.github/workflows/DragonFlyBSD.yml @@ -45,7 +45,7 @@ jobs: TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }} ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: vmactions/cf-tunnel@v0 id: tunnel with: diff --git a/.github/workflows/FreeBSD.yml b/.github/workflows/FreeBSD.yml index 21123c4a..e9ccf7ac 100644 --- a/.github/workflows/FreeBSD.yml +++ b/.github/workflows/FreeBSD.yml @@ -51,7 +51,7 @@ jobs: TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }} ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: vmactions/cf-tunnel@v0 id: tunnel with: diff --git a/.github/workflows/Haiku.yml b/.github/workflows/Haiku.yml index 1dbfc2c4..bfbde398 100644 --- a/.github/workflows/Haiku.yml +++ b/.github/workflows/Haiku.yml @@ -52,7 +52,7 @@ jobs: TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }} ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: vmactions/cf-tunnel@v0 id: tunnel with: diff --git a/.github/workflows/Linux.yml b/.github/workflows/Linux.yml index f3352a41..9f3d3f38 100644 --- a/.github/workflows/Linux.yml +++ b/.github/workflows/Linux.yml @@ -33,7 +33,7 @@ jobs: TEST_PREFERRED_CHAIN: (STAGING) TEST_ACME_Server: "LetsEncrypt.org_test" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Clone acmetest run: | cd .. \ diff --git a/.github/workflows/MacOS.yml b/.github/workflows/MacOS.yml index f5d73ec9..21793c3e 100644 --- a/.github/workflows/MacOS.yml +++ b/.github/workflows/MacOS.yml @@ -44,7 +44,7 @@ jobs: CA_EMAIL: ${{ matrix.CA_EMAIL }} TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install tools run: brew install socat - name: Clone acmetest diff --git a/.github/workflows/NetBSD.yml b/.github/workflows/NetBSD.yml index 40421552..e8107d91 100644 --- a/.github/workflows/NetBSD.yml +++ b/.github/workflows/NetBSD.yml @@ -45,7 +45,7 @@ jobs: TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }} ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: vmactions/cf-tunnel@v0 id: tunnel with: diff --git a/.github/workflows/Omnios.yml b/.github/workflows/Omnios.yml index 20eb24d7..a166e26b 100644 --- a/.github/workflows/Omnios.yml +++ b/.github/workflows/Omnios.yml @@ -51,7 +51,7 @@ jobs: TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }} ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: vmactions/cf-tunnel@v0 id: tunnel with: diff --git a/.github/workflows/OpenBSD.yml b/.github/workflows/OpenBSD.yml index fab6e4fd..b34c795b 100644 --- a/.github/workflows/OpenBSD.yml +++ b/.github/workflows/OpenBSD.yml @@ -51,7 +51,7 @@ jobs: TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }} ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: vmactions/cf-tunnel@v0 id: tunnel with: diff --git a/.github/workflows/OpenIndiana.yml b/.github/workflows/OpenIndiana.yml index abad376c..6447911b 100644 --- a/.github/workflows/OpenIndiana.yml +++ b/.github/workflows/OpenIndiana.yml @@ -51,7 +51,7 @@ jobs: TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }} ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: vmactions/cf-tunnel@v0 id: tunnel with: diff --git a/.github/workflows/PebbleStrict.yml b/.github/workflows/PebbleStrict.yml index 729874ce..946d993a 100644 --- a/.github/workflows/PebbleStrict.yml +++ b/.github/workflows/PebbleStrict.yml @@ -33,7 +33,7 @@ jobs: TEST_CA: "Pebble Intermediate CA" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install tools run: sudo apt-get install -y socat - name: Run Pebble @@ -58,7 +58,7 @@ jobs: TEST_IPCERT: 1 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install tools run: sudo apt-get install -y socat - name: Run Pebble diff --git a/.github/workflows/Solaris.yml b/.github/workflows/Solaris.yml index 2388da71..f5ce713b 100644 --- a/.github/workflows/Solaris.yml +++ b/.github/workflows/Solaris.yml @@ -51,7 +51,7 @@ jobs: TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }} ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - uses: vmactions/cf-tunnel@v0 id: tunnel with: diff --git a/.github/workflows/Ubuntu.yml b/.github/workflows/Ubuntu.yml index e580828f..5ebf2d0d 100644 --- a/.github/workflows/Ubuntu.yml +++ b/.github/workflows/Ubuntu.yml @@ -70,7 +70,7 @@ jobs: TestingDomain: ${{ matrix.TestingDomain }} ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install tools run: sudo apt-get install -y socat wget - name: Start StepCA diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index c1fd1085..4c195917 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -49,7 +49,7 @@ jobs: - name: Set git to use LF run: | git config --global core.autocrlf false - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install cygwin base packages with chocolatey run: | choco config get cacheLocation diff --git a/.github/workflows/dockerhub.yml b/.github/workflows/dockerhub.yml index 49173b4b..0d9046df 100644 --- a/.github/workflows/dockerhub.yml +++ b/.github/workflows/dockerhub.yml @@ -43,7 +43,7 @@ jobs: if: "contains(needs.CheckToken.outputs.hasToken, 'true')" steps: - name: checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: persist-credentials: false - name: Set up QEMU diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index 746727d4..eb10b2b0 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -22,7 +22,7 @@ jobs: ShellCheck: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install Shellcheck run: sudo apt-get install -y shellcheck - name: DoShellcheck @@ -31,7 +31,7 @@ jobs: shfmt: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Install shfmt run: curl -sSL https://github.com/mvdan/sh/releases/download/v3.1.2/shfmt_v3.1.2_linux_amd64 -o ~/shfmt && chmod +x ~/shfmt - name: shfmt diff --git a/.github/workflows/wiki-monitor.yml b/.github/workflows/wiki-monitor.yml index 59cd0e5b..a706529a 100644 --- a/.github/workflows/wiki-monitor.yml +++ b/.github/workflows/wiki-monitor.yml @@ -9,7 +9,7 @@ jobs: if: github.actor != 'neilpang' steps: - name: Checkout wiki repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: repository: ${{ github.repository }}.wiki path: wiki diff --git a/Dockerfile b/Dockerfile index 36b2adac..15439e5a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,12 +14,14 @@ RUN apk --no-cache add -f \ libidn \ jq \ yq-go \ - cronie + supercronic ENV LE_WORKING_DIR=/acmebin ENV LE_CONFIG_HOME=/acme.sh +ENV HOME=/acme.sh + ARG AUTO_UPGRADE=1 ENV AUTO_UPGRADE=$AUTO_UPGRADE @@ -30,10 +32,13 @@ COPY ./deploy /install_acme.sh/deploy COPY ./dnsapi /install_acme.sh/dnsapi COPY ./notify /install_acme.sh/notify +RUN addgroup -g 1000 acme && adduser -h $LE_CONFIG_HOME -s /bin/sh -G acme -D -H -u 1000 acme + RUN cd /install_acme.sh && ([ -f /install_acme.sh/acme.sh ] && /install_acme.sh/acme.sh --install || curl https://get.acme.sh | sh) && rm -rf /install_acme.sh/ +RUN ln -s $LE_WORKING_DIR/acme.sh /usr/local/bin/acme.sh -RUN ln -s $LE_WORKING_DIR/acme.sh /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null#> /proc/1/fd/1 2>/proc/1/fd/2#' | crontab - +RUN chown -R acme:acme $LE_CONFIG_HOME RUN for verb in help \ version \ @@ -72,7 +77,15 @@ RUN for verb in help \ RUN printf "%b" '#!'"/usr/bin/env sh\n \ if [ \"\$1\" = \"daemon\" ]; then \n \ - exec crond -n -s -m off \n \ + if [ ! -f \"\$LE_CONFIG_HOME/crontab\" ]; then \n \ + echo \"\$LE_CONFIG_HOME/crontab not found, generating one\" \n \ + time=\$(date -u \"+%s\") \n \ + random_minute=\$((\$time % 60)) \n \ + random_hour=\$((\$time / 60 % 24)) \n \ + echo \"\$random_minute \$random_hour * * * \\\"\$LE_WORKING_DIR\\\"/acme.sh --cron --home \\\"\$LE_WORKING_DIR\\\" --config-home \\\"\$LE_CONFIG_HOME\\\"\" > \"\$LE_CONFIG_HOME\"/crontab \n \ + fi \n \ + echo \"Running Supercronic using crontab at \$LE_CONFIG_HOME/crontab\" \n \ + exec -- /usr/bin/supercronic \"\$LE_CONFIG_HOME/crontab\" \n \ else \n \ exec -- \"\$@\"\n \ fi\n" >/entry.sh && chmod +x /entry.sh && chmod -R o+rwx $LE_WORKING_DIR && chmod -R o+rwx $LE_CONFIG_HOME diff --git a/acme.sh b/acme.sh index 7d9ee2d2..7a3c35a8 100755 --- a/acme.sh +++ b/acme.sh @@ -595,11 +595,6 @@ if [ "$(printf '\x41')" != 'A' ]; then _URGLY_PRINTF=1 fi -_ESCAPE_XARGS="" -if _exists xargs && [ "$(printf %s '\\x41' | xargs printf)" = 'A' ]; then - _ESCAPE_XARGS=1 -fi - _h2b() { if _exists xxd; then if _contains "$(xxd --help 2>&1)" "assumes -c30"; then @@ -618,17 +613,8 @@ _h2b() { jc="" _debug2 _URGLY_PRINTF "$_URGLY_PRINTF" if [ -z "$_URGLY_PRINTF" ]; then - if [ "$_ESCAPE_XARGS" ] && _exists xargs; then - _debug2 "xargs" - echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/\\\\\\x\1/g' | xargs printf - else - for h in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/ \1/g'); do - if [ -z "$h" ]; then - break - fi - printf "\x$h%s" - done - fi + # shellcheck disable=SC2059 + printf "$(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\{2\}\)/\\x\1/g')" else for c in $(echo "$hex" | _upper_case | sed 's/\([0-9A-F]\)/ \1/g'); do if [ -z "$ic" ]; then @@ -5675,7 +5661,7 @@ renewAll() { _set_level=${NOTIFY_LEVEL:-$NOTIFY_LEVEL_DEFAULT} _debug "_set_level" "$_set_level" export _ACME_IN_RENEWALL=1 - for di in "${CERT_HOME}"/*.*/; do + for di in "${CERT_HOME}"/*[.:]*/; do _debug di "$di" if ! [ -d "$di" ]; then _debug "Not a directory, skipping: $di" diff --git a/deploy/localcopy.sh b/deploy/localcopy.sh new file mode 100644 index 00000000..9a1a0fcf --- /dev/null +++ b/deploy/localcopy.sh @@ -0,0 +1,157 @@ +#!/usr/bin/env sh + +# Deploy-hook to very simply copy files to set directories and then +# execute whatever reloadcmd the admin needs afterwards. This can be +# useful for configurations where the "multideploy" hook (in development) +# is used or when an admin wants ACME.SH to renew certs but needs to +# manually configure deployment via an external script +# (e.g. The deploy-freenas script for TrueNAS Core/Scale +# https://github.com/danb35/deploy-freenas/ ) +# +# If the same file is configured for the certificate key +# and the certificate and/or full chain, a combined PEM file will +# be output instead. +# +# Environment variables to be utilized are as follows: +# +# DEPLOY_LOCALCOPY_CERTKEY - /path/to/target/cert.key +# DEPLOY_LOCALCOPY_CERTIFICATE - /path/to/target/cert.cer +# DEPLOY_LOCALCOPY_FULLCHAIN - /path/to/target/fullchain.cer +# DEPLOY_LOCALCOPY_CA - /path/to/target/ca.cer +# DEPLOY_LOCALCOPY_PFX - /path/to/target/cert.pfx +# DEPLOY_LOCALCOPY_RELOADCMD - "echo 'this is my cmd'" + +######## Public functions ##################### + +#domain keyfile certfile cafile fullchain +localcopy_deploy() { + _cdomain="$1" + _ckey="$2" + _ccert="$3" + _cca="$4" + _cfullchain="$5" + _cpfx="$6" + + _debug _cdomain "$_cdomain" + _debug _ckey "$_ckey" + _debug _ccert "$_ccert" + _debug _cca "$_cca" + _debug _cfullchain "$_cfullchain" + _debug _cpfx "$_cpfx" + + _getdeployconf DEPLOY_LOCALCOPY_CERTIFICATE + _getdeployconf DEPLOY_LOCALCOPY_CERTKEY + _getdeployconf DEPLOY_LOCALCOPY_FULLCHAIN + _getdeployconf DEPLOY_LOCALCOPY_CA + _getdeployconf DEPLOY_LOCALCOPY_RELOADCMD + _getdeployconf DEPLOY_LOCALCOPY_PFX + _combined_target="" + _combined_srccert="" + + # Create PEM file + if [ "$DEPLOY_LOCALCOPY_CERTKEY" ] && + { [ "$DEPLOY_LOCALCOPY_CERTKEY" = "$DEPLOY_LOCALCOPY_FULLCHAIN" ] || + [ "$DEPLOY_LOCALCOPY_CERTKEY" = "$DEPLOY_LOCALCOPY_CERTIFICATE" ]; }; then + + _combined_target="$DEPLOY_LOCALCOPY_CERTKEY" + _savedeployconf DEPLOY_LOCALCOPY_CERTKEY "$DEPLOY_LOCALCOPY_CERTKEY" + if [ "$DEPLOY_LOCALCOPY_CERTKEY" = "$DEPLOY_LOCALCOPY_CERTIFICATE" ]; then + _combined_srccert="$_ccert" + _savedeployconf DEPLOY_LOCALCOPY_CERTIFICATE "$DEPLOY_LOCALCOPY_CERTIFICATE" + DEPLOY_LOCALCOPY_CERTIFICATE="" + fi + if [ "$DEPLOY_LOCALCOPY_CERTKEY" = "$DEPLOY_LOCALCOPY_FULLCHAIN" ]; then + _combined_srccert="$_cfullchain" + _savedeployconf DEPLOY_LOCALCOPY_FULLCHAIN "$DEPLOY_LOCALCOPY_FULLCHAIN" + DEPLOY_LOCALCOPY_FULLCHAIN="" + fi + DEPLOY_LOCALCOPY_CERTKEY="" + _info "Creating combined PEM" + _debug "Creating combined PEM at $_combined_target" + if ! [ -f "$_combined_target" ]; then + touch "$_combined_target" || return 1 + chmod 600 "$_combined_target" + fi + if ! cat "$_combined_srccert" "$_ckey" >"$_combined_target"; then + _err "Failed to create PEM file" + return 1 + fi + fi + + if [ "$DEPLOY_LOCALCOPY_CERTIFICATE" ]; then + _info "Copying certificate" + _debug "Copying $_ccert to $DEPLOY_LOCALCOPY_CERTIFICATE" + if ! cat "$_ccert" >"$DEPLOY_LOCALCOPY_CERTIFICATE"; then + _err "Failed to copy certificate, aborting." + return 1 + fi + _savedeployconf DEPLOY_LOCALCOPY_CERTIFICATE "$DEPLOY_LOCALCOPY_CERTIFICATE" + fi + + if [ "$DEPLOY_LOCALCOPY_CERTKEY" ]; then + _info "Copying certificate key" + _debug "Copying $_ckey to $DEPLOY_LOCALCOPY_CERTKEY" + if ! [ -f "$DEPLOY_LOCALCOPY_CERTKEY" ]; then + touch "$DEPLOY_LOCALCOPY_CERTKEY" || return 1 + chmod 600 "$DEPLOY_LOCALCOPY_CERTKEY" + fi + if ! cat "$_ckey" >"$DEPLOY_LOCALCOPY_CERTKEY"; then + _err "Failed to copy certificate key, aborting." + return 1 + fi + _savedeployconf DEPLOY_LOCALCOPY_CERTKEY "$DEPLOY_LOCALCOPY_CERTKEY" + fi + + if [ "$DEPLOY_LOCALCOPY_FULLCHAIN" ]; then + _info "Copying fullchain" + _debug "Copying $_cfullchain to $DEPLOY_LOCALCOPY_FULLCHAIN" + if ! cat "$_cfullchain" >"$DEPLOY_LOCALCOPY_FULLCHAIN"; then + _err "Failed to copy fullchain, aborting." + return 1 + fi + _savedeployconf DEPLOY_LOCALCOPY_FULLCHAIN "$DEPLOY_LOCALCOPY_FULLCHAIN" + fi + + if [ "$DEPLOY_LOCALCOPY_CA" ]; then + _info "Copying CA" + _debug "Copying $_cca to $DEPLOY_LOCALCOPY_CA" + if ! cat "$_cca" >"$DEPLOY_LOCALCOPY_CA"; then + _err "Failed to copy CA, aborting." + return 1 + fi + _savedeployconf DEPLOY_LOCALCOPY_CA "$DEPLOY_LOCALCOPY_CA" + fi + + if [ "$DEPLOY_LOCALCOPY_PFX" ]; then + _info "Copying PFX" + _debug "Copying $_cpfx to $DEPLOY_LOCALCOPY_PFX" + if ! [ -f "$DEPLOY_LOCALCOPY_PFX" ]; then + touch "$DEPLOY_LOCALCOPY_PFX" || return 1 + chmod 600 "$DEPLOY_LOCALCOPY_PFX" + fi + if ! cat "$_cpfx" >"$DEPLOY_LOCALCOPY_PFX"; then + _err "Failed to copy PFX, aborting." + return 1 + fi + _savedeployconf DEPLOY_LOCALCOPY_PFX "$DEPLOY_LOCALCOPY_PFX" + fi + + _reload=$DEPLOY_LOCALCOPY_RELOADCMD + _debug "Running reloadcmd $_reload" + + if [ -z "$_reload" ]; then + _info "Reloadcmd not provided, skipping." + else + _info "Reloading" + if eval "$_reload"; then + _info "Reload successful." + _savedeployconf DEPLOY_LOCALCOPY_RELOADCMD "$DEPLOY_LOCALCOPY_RELOADCMD" "base64" + else + _err "Reload failed." + return 1 + fi + fi + + _info "$(__green "'localcopy' deploy success")" + return 0 +} diff --git a/deploy/panos.sh b/deploy/panos.sh index c54d21fe..019d8c62 100644 --- a/deploy/panos.sh +++ b/deploy/panos.sh @@ -207,13 +207,12 @@ panos_deploy() { fi # PANOS_KEY - _getdeployconf PANOS_KEY if [ "$PANOS_KEY" ]; then - _debug "Detected saved key." - _panos_key=$PANOS_KEY + _debug "Detected ENV variable PANOS_KEY. Saving to file." + _savedeployconf PANOS_KEY "$PANOS_KEY" 1 else - _debug "No key detected" - unset _panos_key + _debug "Attempting to load variable PANOS_KEY from file." + _getdeployconf PANOS_KEY fi # PANOS_TEMPLATE @@ -256,6 +255,7 @@ panos_deploy() { _panos_host=$PANOS_HOST _panos_user=$PANOS_USER _panos_pass=$PANOS_PASS + _panos_key=$PANOS_KEY _panos_template=$PANOS_TEMPLATE _panos_template_stack=$PANOS_TEMPLATE_STACK _panos_vsys=$PANOS_VSYS @@ -271,12 +271,6 @@ panos_deploy() { if [ -z "$_panos_host" ]; then _err "No host found. If this is your first time deploying, please set PANOS_HOST in ENV variables. You can delete it after you have successfully deployed the certs." return 1 - elif [ -z "$_panos_user" ]; then - _err "No user found. If this is your first time deploying, please set PANOS_USER in ENV variables. You can delete it after you have successfully deployed the certs." - return 1 - elif [ -z "$_panos_pass" ]; then - _err "No password found. If this is your first time deploying, please set PANOS_PASS in ENV variables. You can delete it after you have successfully deployed the certs." - return 1 else # Use certificate name based on the first domain on the certificate if no custom certificate name is set if [ -z "$_panos_certname" ]; then @@ -286,6 +280,13 @@ panos_deploy() { # Generate a new API key if no valid API key is found if [ -z "$_panos_key" ]; then + if [ -z "$_panos_user" ]; then + _err "No user found. If this is your first time deploying, please set PANOS_USER in ENV variables. You can delete it after you have successfully deployed the certs." + return 1 + elif [ -z "$_panos_pass" ]; then + _err "No password found. If this is your first time deploying, please set PANOS_PASS in ENV variables. You can delete it after you have successfully deployed the certs." + return 1 + fi _debug "**** Generating new PANOS API KEY ****" deployer keygen _savedeployconf PANOS_KEY "$_panos_key" 1 diff --git a/deploy/ssh.sh b/deploy/ssh.sh index c66e2e19..848380a5 100644 --- a/deploy/ssh.sh +++ b/deploy/ssh.sh @@ -238,6 +238,8 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d return $_err_code fi else + # If file doesn't exist, create it and change its permissions. + _cmdstr="$_cmdstr test ! -f $DEPLOY_SSH_KEYFILE && touch $DEPLOY_SSH_KEYFILE && chmod 600 $DEPLOY_SSH_KEYFILE;" # ssh echo to the file _cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $DEPLOY_SSH_KEYFILE;" _info "will copy private key to remote file $DEPLOY_SSH_KEYFILE" diff --git a/dnsapi/dns_cyon.sh b/dnsapi/dns_cyon.sh index 0c74be2a..d4b6b6e8 100644 --- a/dnsapi/dns_cyon.sh +++ b/dnsapi/dns_cyon.sh @@ -332,11 +332,11 @@ _cyon_get_response_message() { } _cyon_get_response_status() { - _egrep_o '"status":[a-zA-z0-9]*' | cut -d : -f 2 + _egrep_o '"status":[a-zA-Z0-9]*' | cut -d : -f 2 } _cyon_get_validation_status() { - _egrep_o '"valid":[a-zA-z0-9]*' | cut -d : -f 2 + _egrep_o '"valid":[a-zA-Z0-9]*' | cut -d : -f 2 } _cyon_get_response_success() { @@ -344,7 +344,7 @@ _cyon_get_response_success() { } _cyon_get_environment_change_status() { - _egrep_o '"authenticated":[a-zA-z0-9]*' | cut -d : -f 2 + _egrep_o '"authenticated":[a-zA-Z0-9]*' | cut -d : -f 2 } _cyon_check_if_2fa_missed() { diff --git a/dnsapi/dns_infomaniak.sh b/dnsapi/dns_infomaniak.sh index ea5ef461..0ae32b47 100755 --- a/dnsapi/dns_infomaniak.sh +++ b/dnsapi/dns_infomaniak.sh @@ -6,14 +6,16 @@ Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_infomaniak Options: INFOMANIAK_API_TOKEN API Token Issues: github.com/acmesh-official/acme.sh/issues/3188 + ' -# To use this API you need visit the API dashboard of your account -# once logged into https://manager.infomaniak.com add /api/dashboard to the URL -# +# To use this API you need visit the API dashboard of your account. # Note: the URL looks like this: -# https://manager.infomaniak.com/v3//api/dashboard -# Then generate a token with the scope Domain +# https://manager.infomaniak.com/v3//ng/profile/user/token/list +# Then generate a token with following scopes : +# - domain:read +# - dns:read +# - dns:write # this is given as an environment variable INFOMANIAK_API_TOKEN # base variables @@ -65,33 +67,32 @@ dns_infomaniak_add() { _debug fulldomain "$fulldomain" _debug txtvalue "$txtvalue" - fqdn=${fulldomain#_acme-challenge.} - # guess which base domain to add record to - zone_and_id=$(_find_zone "$fqdn") - if [ -z "$zone_and_id" ]; then - _err "cannot find zone to modify" + zone=$(_get_zone "$fulldomain") + if [ -z "$zone" ]; then + _err "cannot find zone:<${zone}> to modify" return 1 fi - zone=${zone_and_id% *} - domain_id=${zone_and_id#* } # extract first part of domain key=${fulldomain%."$zone"} - _debug "zone:$zone id:$domain_id key:$key" + _debug "key:$key" + _debug "txtvalue: $txtvalue" # payload data="{\"type\": \"TXT\", \"source\": \"$key\", \"target\": \"$txtvalue\", \"ttl\": $INFOMANIAK_TTL}" # API call - response=$(_post "$data" "${INFOMANIAK_API_URL}/1/domain/$domain_id/dns/record") - if [ -n "$response" ] && echo "$response" | _contains '"result":"success"'; then - _info "Record added" - _debug "Response: $response" - return 0 + response=$(_post "$data" "${INFOMANIAK_API_URL}/2/zones/${zone}/records") + if [ -n "$response" ]; then + if [ ! "$(echo "$response" | _contains '"result":"success"')" ]; then + _info "Record added" + _debug "response: $response" + return 0 + fi fi - _err "could not create record" + _err "Could not create record." _debug "Response: $response" return 1 } @@ -106,7 +107,7 @@ dns_infomaniak_rm() { if [ -z "$INFOMANIAK_API_TOKEN" ]; then INFOMANIAK_API_TOKEN="" - _err "Please provide a valid Infomaniak API token in variable INFOMANIAK_API_TOKEN" + _err "Please provide a valid Infomaniak API token in variable INFOMANIAK_API_TOKEN." return 1 fi @@ -138,63 +139,53 @@ dns_infomaniak_rm() { _debug fulldomain "$fulldomain" _debug txtvalue "$txtvalue" - fqdn=${fulldomain#_acme-challenge.} - # guess which base domain to add record to - zone_and_id=$(_find_zone "$fqdn") - if [ -z "$zone_and_id" ]; then - _err "cannot find zone to modify" + zone=$(_get_zone "$fulldomain") + if [ -z "$zone" ]; then + _err "cannot find zone:<$zone> to modify" return 1 fi - zone=${zone_and_id% *} - domain_id=${zone_and_id#* } # extract first part of domain key=${fulldomain%."$zone"} + key=$(echo "$key" | _lower_case) - _debug "zone:$zone id:$domain_id key:$key" + _debug "zone:$zone" + _debug "key:$key" # find previous record - # shellcheck disable=SC1004 - record_id=$(_get "${INFOMANIAK_API_URL}/1/domain/$domain_id/dns/record" | sed 's/.*"data":\[\(.*\)\]}/\1/; s/},{/}\ -{/g' | sed -n 's/.*"id":"*\([0-9]*\)"*.*"source_idn":"'"$fulldomain"'".*"target_idn":"'"$txtvalue"'".*/\1/p') + # shellcheck disable=SC2086 + response=$(_get "${INFOMANIAK_API_URL}/2/zones/${zone}/records" | sed 's/.*"data":\[\(.*\)\]}/\1/; s/},{/}{/g') + record_id=$(echo "$response" | sed -n 's/.*"id":"*\([0-9]*\)"*.*"source":"'"$key"'".*"target":"\\"'"$txtvalue"'\\"".*/\1/p') + _debug "key: $key" + _debug "txtvalue: $txtvalue" + _debug "record_id: $record_id" + if [ -z "$record_id" ]; then _err "could not find record to delete" + _debug "response: $response" return 1 fi - _debug "record_id: $record_id" # API call - response=$(_post "" "${INFOMANIAK_API_URL}/1/domain/$domain_id/dns/record/$record_id" "" DELETE) - if [ -n "$response" ] && echo "$response" | _contains '"result":"success"'; then - _info "Record deleted" - return 0 + response=$(_post "" "${INFOMANIAK_API_URL}/2/zones/${zone}/records/${record_id}" "" DELETE) + if [ -n "$response" ]; then + if [ ! "$(echo "$response" | _contains '"result":"success"')" ]; then + _info "Record deleted" + return 0 + fi fi - _err "could not delete record" + _err "Could not delete record." + _debug "Response: $response" return 1 } #################### Private functions below ################################## -_get_domain_id() { +_get_zone() { domain="$1" - + # Whatever the domain is, you can get the fqdn with the following. # shellcheck disable=SC1004 - _get "${INFOMANIAK_API_URL}/1/product?service_name=domain&customer_name=$domain" | sed 's/.*"data":\[{\(.*\)}\]}/\1/; s/,/\ -/g' | sed -n 's/^"id":\(.*\)/\1/p' -} - -_find_zone() { - zone="$1" - - # find domain in list, removing . parts sequentialy - while _contains "$zone" '\.'; do - _debug "testing $zone" - id=$(_get_domain_id "$zone") - if [ -n "$id" ]; then - echo "$zone $id" - return - fi - zone=${zone#*.} - done + response=$(_get "${INFOMANIAK_API_URL}/2/domains/${domain}/zones" | sed 's/.*\[{"fqdn"\:"\(.*\)/\1/') + echo "${response%%\"*}" } diff --git a/dnsapi/dns_nsupdate.sh b/dnsapi/dns_nsupdate.sh index d5dbbcbc..8d7fe2c0 100755 --- a/dnsapi/dns_nsupdate.sh +++ b/dnsapi/dns_nsupdate.sh @@ -6,7 +6,7 @@ Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_nsupdate Options: NSUPDATE_SERVER Server hostname. Default: "localhost". NSUPDATE_SERVER_PORT Server port. Default: "53". - NSUPDATE_KEY File path to TSIG key. + NSUPDATE_KEY File path to TSIG key. Default: "". Optional. NSUPDATE_ZONE Domain zone to update. Optional. ' @@ -22,8 +22,6 @@ dns_nsupdate_add() { NSUPDATE_ZONE="${NSUPDATE_ZONE:-$(_readaccountconf_mutable NSUPDATE_ZONE)}" NSUPDATE_OPT="${NSUPDATE_OPT:-$(_readaccountconf_mutable NSUPDATE_OPT)}" - _checkKeyFile || return 1 - # save the dns server and key to the account conf file. _saveaccountconf_mutable NSUPDATE_SERVER "${NSUPDATE_SERVER}" _saveaccountconf_mutable NSUPDATE_SERVER_PORT "${NSUPDATE_SERVER_PORT}" @@ -33,27 +31,52 @@ dns_nsupdate_add() { [ -n "${NSUPDATE_SERVER}" ] || NSUPDATE_SERVER="localhost" [ -n "${NSUPDATE_SERVER_PORT}" ] || NSUPDATE_SERVER_PORT=53 + [ -n "${NSUPDATE_KEY}" ] || NSUPDATE_KEY="" [ -n "${NSUPDATE_OPT}" ] || NSUPDATE_OPT="" + NSUPDATE_SERVER_LIST=$(printf "%s" "$NSUPDATE_SERVER" | tr ',' ' ') + _info "adding ${fulldomain}. 60 in txt \"${txtvalue}\"" [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_1" ] && nsdebug="-d" [ -n "$DEBUG" ] && [ "$DEBUG" -ge "$DEBUG_LEVEL_2" ] && nsdebug="-D" - if [ -z "${NSUPDATE_ZONE}" ]; then - #shellcheck disable=SC2086 - nsupdate -k "${NSUPDATE_KEY}" $nsdebug $NSUPDATE_OPT <