diff --git a/.github/workflows/DNS.yml b/.github/workflows/DNS.yml
index 0104595d..00d180b9 100644
--- a/.github/workflows/DNS.yml
+++ b/.github/workflows/DNS.yml
@@ -229,6 +229,7 @@ jobs:
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/freebsd-vm@v1
with:
+ debug-on-error: ${{ vars.DEBUG_ON_ERROR }}
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
prepare: pkg install -y socat curl
usesh: true
@@ -284,6 +285,7 @@ jobs:
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/openbsd-vm@v1
with:
+ debug-on-error: ${{ vars.DEBUG_ON_ERROR }}
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
prepare: pkg_add socat curl libiconv
usesh: true
@@ -339,6 +341,7 @@ jobs:
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/netbsd-vm@v1
with:
+ debug-on-error: ${{ vars.DEBUG_ON_ERROR }}
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
prepare: |
/usr/sbin/pkg_add curl socat
@@ -395,6 +398,7 @@ jobs:
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/dragonflybsd-vm@v1
with:
+ debug-on-error: ${{ vars.DEBUG_ON_ERROR }}
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
prepare: |
pkg install -y libnghttp2
@@ -430,9 +434,65 @@ jobs:
- Solaris:
+ MidnightBSD:
runs-on: ubuntu-latest
needs: DragonFlyBSD
+ env:
+ TEST_DNS : ${{ secrets.TEST_DNS }}
+ TestingDomain: ${{ secrets.TestingDomain }}
+ TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
+ TEST_DNS_NO_SUBDOMAIN: ${{ secrets.TEST_DNS_NO_SUBDOMAIN }}
+ TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
+ CASE: le_test_dnsapi
+ TEST_LOCAL: 1
+ DEBUG: ${{ secrets.DEBUG }}
+ http_proxy: ${{ secrets.http_proxy }}
+ https_proxy: ${{ secrets.https_proxy }}
+ TokenName1: ${{ secrets.TokenName1}}
+ TokenName2: ${{ secrets.TokenName2}}
+ TokenName3: ${{ secrets.TokenName3}}
+ TokenName4: ${{ secrets.TokenName4}}
+ TokenName5: ${{ secrets.TokenName5}}
+ steps:
+ - 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/midnightbsd-vm@v1
+ with:
+ debug-on-error: ${{ vars.DEBUG_ON_ERROR }}
+ envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
+ prepare: mport install socat curl || true
+ usesh: true
+ sync: nfs
+ run: |
+ if [ "${{ secrets.TokenName1}}" ] ; then
+ export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
+ fi
+ if [ "${{ secrets.TokenName2}}" ] ; then
+ export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
+ fi
+ if [ "${{ secrets.TokenName3}}" ] ; then
+ export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
+ fi
+ if [ "${{ secrets.TokenName4}}" ] ; then
+ export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
+ fi
+ if [ "${{ secrets.TokenName5}}" ] ; then
+ export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
+ fi
+ cd ../acmetest
+ ./letest.sh
+ - name: DebugOnError
+ if: ${{ failure() }}
+ run: |
+ echo "See how to debug in VM:"
+ echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM"
+
+
+
+ Solaris:
+ runs-on: ubuntu-latest
+ needs: MidnightBSD
env:
TEST_DNS : ${{ secrets.TEST_DNS }}
TestingDomain: ${{ secrets.TestingDomain }}
@@ -456,6 +516,7 @@ jobs:
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/solaris-vm@v1
with:
+ debug-on-error: ${{ vars.DEBUG_ON_ERROR }}
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy HTTPS_INSECURE TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
sync: nfs
prepare: |
@@ -514,6 +575,7 @@ jobs:
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/omnios-vm@v1
with:
+ debug-on-error: ${{ vars.DEBUG_ON_ERROR }}
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy HTTPS_INSECURE TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
sync: nfs
prepare: pkg install socat
@@ -569,6 +631,7 @@ jobs:
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/openindiana-vm@v1
with:
+ debug-on-error: ${{ vars.DEBUG_ON_ERROR }}
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy HTTPS_INSECURE TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
sync: nfs
prepare: pkg install socat
@@ -624,6 +687,7 @@ jobs:
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/haiku-vm@v1
with:
+ debug-on-error: ${{ vars.DEBUG_ON_ERROR }}
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG http_proxy https_proxy HTTPS_INSECURE TokenName1 TokenName2 TokenName3 TokenName4 TokenName5 ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
sync: rsync
copyback: false
diff --git a/.github/workflows/DragonFlyBSD.yml b/.github/workflows/DragonFlyBSD.yml
index f32d0916..c8cbc985 100644
--- a/.github/workflows/DragonFlyBSD.yml
+++ b/.github/workflows/DragonFlyBSD.yml
@@ -31,8 +31,8 @@ jobs:
CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING)
#- TEST_ACME_Server: "ZeroSSL.com"
- # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
- # CA: "ZeroSSL RSA Domain Secure Site CA"
+ # CA_ECDSA: "ZeroSSL ECC DV SSL CA 2"
+ # CA: "ZeroSSL RSA DV SSL CA 2"
# CA_EMAIL: "githubtest@acme.sh"
# TEST_PREFERRED_CHAIN: ""
runs-on: ubuntu-latest
@@ -57,6 +57,7 @@ jobs:
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/dragonflybsd-vm@v1
with:
+ debug-on-error: ${{ vars.DEBUG_ON_ERROR }}
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
nat: |
"8080": "80"
diff --git a/.github/workflows/FreeBSD.yml b/.github/workflows/FreeBSD.yml
index 09b544f6..50fcab32 100644
--- a/.github/workflows/FreeBSD.yml
+++ b/.github/workflows/FreeBSD.yml
@@ -37,8 +37,8 @@ jobs:
TEST_PREFERRED_CHAIN: (STAGING)
ACME_USE_WGET: 1
#- TEST_ACME_Server: "ZeroSSL.com"
- # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
- # CA: "ZeroSSL RSA Domain Secure Site CA"
+ # CA_ECDSA: "ZeroSSL ECC DV SSL CA 2"
+ # CA: "ZeroSSL RSA DV SSL CA 2"
# CA_EMAIL: "githubtest@acme.sh"
# TEST_PREFERRED_CHAIN: ""
runs-on: ubuntu-latest
@@ -63,6 +63,7 @@ jobs:
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/freebsd-vm@v1
with:
+ debug-on-error: ${{ vars.DEBUG_ON_ERROR }}
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
nat: |
"8080": "80"
diff --git a/.github/workflows/Haiku.yml b/.github/workflows/Haiku.yml
index 4324545e..9884ebeb 100644
--- a/.github/workflows/Haiku.yml
+++ b/.github/workflows/Haiku.yml
@@ -38,8 +38,8 @@ jobs:
TEST_PREFERRED_CHAIN: (STAGING)
ACME_USE_WGET: 1
#- TEST_ACME_Server: "ZeroSSL.com"
- # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
- # CA: "ZeroSSL RSA Domain Secure Site CA"
+ # CA_ECDSA: "ZeroSSL ECC DV SSL CA 2"
+ # CA: "ZeroSSL RSA DV SSL CA 2"
# CA_EMAIL: "githubtest@acme.sh"
# TEST_PREFERRED_CHAIN: ""
runs-on: ubuntu-latest
@@ -64,6 +64,7 @@ jobs:
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/haiku-vm@v1
with:
+ debug-on-error: ${{ vars.DEBUG_ON_ERROR }}
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
nat: |
"8080": "80"
diff --git a/.github/workflows/MacOS.yml b/.github/workflows/MacOS.yml
index 3869b504..ef9580a6 100644
--- a/.github/workflows/MacOS.yml
+++ b/.github/workflows/MacOS.yml
@@ -31,8 +31,8 @@ jobs:
CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING)
#- TEST_ACME_Server: "ZeroSSL.com"
- # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
- # CA: "ZeroSSL RSA Domain Secure Site CA"
+ # CA_ECDSA: "ZeroSSL ECC DV SSL CA 2"
+ # CA: "ZeroSSL RSA DV SSL CA 2"
# CA_EMAIL: "githubtest@acme.sh"
# TEST_PREFERRED_CHAIN: ""
runs-on: macos-latest
diff --git a/.github/workflows/MidnightBSD.yml b/.github/workflows/MidnightBSD.yml
new file mode 100644
index 00000000..15024833
--- /dev/null
+++ b/.github/workflows/MidnightBSD.yml
@@ -0,0 +1,74 @@
+name: MidnightBSD
+on:
+ push:
+ branches:
+ - '*'
+ paths:
+ - '*.sh'
+ - '.github/workflows/MidnightBSD.yml'
+
+ pull_request:
+ branches:
+ - dev
+ paths:
+ - '*.sh'
+ - '.github/workflows/MidnightBSD.yml'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.ref }}
+ cancel-in-progress: true
+
+
+
+jobs:
+ MidnightBSD:
+ strategy:
+ matrix:
+ include:
+ - TEST_ACME_Server: "LetsEncrypt.org_test"
+ CA_ECDSA: ""
+ CA: ""
+ CA_EMAIL: ""
+ TEST_PREFERRED_CHAIN: (STAGING)
+ #- TEST_ACME_Server: "ZeroSSL.com"
+ # CA_ECDSA: "ZeroSSL ECC DV SSL CA 2"
+ # CA: "ZeroSSL RSA DV SSL CA 2"
+ # CA_EMAIL: "githubtest@acme.sh"
+ # TEST_PREFERRED_CHAIN: ""
+ runs-on: ubuntu-latest
+ env:
+ TEST_LOCAL: 1
+ TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
+ CA_ECDSA: ${{ matrix.CA_ECDSA }}
+ CA: ${{ matrix.CA }}
+ CA_EMAIL: ${{ matrix.CA_EMAIL }}
+ TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
+ ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
+ steps:
+ - uses: actions/checkout@v6
+ - uses: anyvm-org/cf-tunnel@v0
+ id: tunnel
+ with:
+ protocol: http
+ port: 8080
+ - name: Set envs
+ run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
+ - name: Clone acmetest
+ run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
+ - uses: vmactions/midnightbsd-vm@v1
+ with:
+ debug-on-error: ${{ vars.DEBUG_ON_ERROR }}
+ envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
+ nat: |
+ "8080": "80"
+ prepare: mport install socat curl wget || true
+ usesh: true
+ sync: nfs
+ run: |
+ cd ../acmetest \
+ && ./letest.sh
+ - name: DebugOnError
+ if: ${{ failure() }}
+ run: |
+ echo "See how to debug in VM:"
+ echo "https://github.com/acmesh-official/acme.sh/wiki/debug-in-VM"
diff --git a/.github/workflows/NetBSD.yml b/.github/workflows/NetBSD.yml
index 4021cd7e..16d0ae2d 100644
--- a/.github/workflows/NetBSD.yml
+++ b/.github/workflows/NetBSD.yml
@@ -31,8 +31,8 @@ jobs:
CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING)
#- TEST_ACME_Server: "ZeroSSL.com"
- # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
- # CA: "ZeroSSL RSA Domain Secure Site CA"
+ # CA_ECDSA: "ZeroSSL ECC DV SSL CA 2"
+ # CA: "ZeroSSL RSA DV SSL CA 2"
# CA_EMAIL: "githubtest@acme.sh"
# TEST_PREFERRED_CHAIN: ""
runs-on: ubuntu-latest
@@ -57,6 +57,7 @@ jobs:
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/netbsd-vm@v1
with:
+ debug-on-error: ${{ vars.DEBUG_ON_ERROR }}
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
nat: |
"8080": "80"
diff --git a/.github/workflows/Omnios.yml b/.github/workflows/Omnios.yml
index a156800c..eb486b35 100644
--- a/.github/workflows/Omnios.yml
+++ b/.github/workflows/Omnios.yml
@@ -37,8 +37,8 @@ jobs:
TEST_PREFERRED_CHAIN: (STAGING)
ACME_USE_WGET: 1
#- TEST_ACME_Server: "ZeroSSL.com"
- # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
- # CA: "ZeroSSL RSA Domain Secure Site CA"
+ # CA_ECDSA: "ZeroSSL ECC DV SSL CA 2"
+ # CA: "ZeroSSL RSA DV SSL CA 2"
# CA_EMAIL: "githubtest@acme.sh"
# TEST_PREFERRED_CHAIN: ""
runs-on: ubuntu-latest
@@ -63,6 +63,7 @@ jobs:
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/omnios-vm@v1
with:
+ debug-on-error: ${{ vars.DEBUG_ON_ERROR }}
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
nat: |
"8080": "80"
diff --git a/.github/workflows/OpenBSD.yml b/.github/workflows/OpenBSD.yml
index 8a91cd2e..4fdb76c5 100644
--- a/.github/workflows/OpenBSD.yml
+++ b/.github/workflows/OpenBSD.yml
@@ -37,8 +37,8 @@ jobs:
TEST_PREFERRED_CHAIN: (STAGING)
ACME_USE_WGET: 1
#- TEST_ACME_Server: "ZeroSSL.com"
- # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
- # CA: "ZeroSSL RSA Domain Secure Site CA"
+ # CA_ECDSA: "ZeroSSL ECC DV SSL CA 2"
+ # CA: "ZeroSSL RSA DV SSL CA 2"
# CA_EMAIL: "githubtest@acme.sh"
# TEST_PREFERRED_CHAIN: ""
runs-on: ubuntu-latest
@@ -63,6 +63,7 @@ jobs:
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/openbsd-vm@v1
with:
+ debug-on-error: ${{ vars.DEBUG_ON_ERROR }}
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
nat: |
"8080": "80"
diff --git a/.github/workflows/OpenIndiana.yml b/.github/workflows/OpenIndiana.yml
index dca29741..b5061ba7 100644
--- a/.github/workflows/OpenIndiana.yml
+++ b/.github/workflows/OpenIndiana.yml
@@ -37,8 +37,8 @@ jobs:
TEST_PREFERRED_CHAIN: (STAGING)
ACME_USE_WGET: 1
#- TEST_ACME_Server: "ZeroSSL.com"
- # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
- # CA: "ZeroSSL RSA Domain Secure Site CA"
+ # CA_ECDSA: "ZeroSSL ECC DV SSL CA 2"
+ # CA: "ZeroSSL RSA DV SSL CA 2"
# CA_EMAIL: "githubtest@acme.sh"
# TEST_PREFERRED_CHAIN: ""
runs-on: ubuntu-latest
@@ -63,6 +63,7 @@ jobs:
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/openindiana-vm@v1
with:
+ debug-on-error: ${{ vars.DEBUG_ON_ERROR }}
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
nat: |
"8080": "80"
diff --git a/.github/workflows/Solaris.yml b/.github/workflows/Solaris.yml
index 397469b5..3393269a 100644
--- a/.github/workflows/Solaris.yml
+++ b/.github/workflows/Solaris.yml
@@ -37,8 +37,8 @@ jobs:
TEST_PREFERRED_CHAIN: (STAGING)
ACME_USE_WGET: 1
#- TEST_ACME_Server: "ZeroSSL.com"
- # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
- # CA: "ZeroSSL RSA Domain Secure Site CA"
+ # CA_ECDSA: "ZeroSSL ECC DV SSL CA 2"
+ # CA: "ZeroSSL RSA DV SSL CA 2"
# CA_EMAIL: "githubtest@acme.sh"
# TEST_PREFERRED_CHAIN: ""
runs-on: ubuntu-latest
@@ -63,6 +63,7 @@ jobs:
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
- uses: vmactions/solaris-vm@v1
with:
+ debug-on-error: ${{ vars.DEBUG_ON_ERROR }}
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
nat: |
"8080": "80"
diff --git a/.github/workflows/Ubuntu.yml b/.github/workflows/Ubuntu.yml
index 5ebf2d0d..36dfdbe6 100644
--- a/.github/workflows/Ubuntu.yml
+++ b/.github/workflows/Ubuntu.yml
@@ -37,8 +37,8 @@ jobs:
TEST_PREFERRED_CHAIN: (STAGING)
ACME_USE_WGET: 1
- TEST_ACME_Server: "ZeroSSL.com"
- CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
- CA: "ZeroSSL RSA Domain Secure Site CA"
+ CA_ECDSA: "ZeroSSL ECC DV SSL CA 2"
+ CA: "ZeroSSL RSA DV SSL CA 2"
CA_EMAIL: "githubtest@acme.sh"
TEST_PREFERRED_CHAIN: ""
- TEST_ACME_Server: "https://localhost:9000/acme/acme/directory"
diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml
index c628ff5b..1de120f9 100644
--- a/.github/workflows/Windows.yml
+++ b/.github/workflows/Windows.yml
@@ -31,8 +31,8 @@ jobs:
CA_EMAIL: ""
TEST_PREFERRED_CHAIN: (STAGING)
#- TEST_ACME_Server: "ZeroSSL.com"
- # CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
- # CA: "ZeroSSL RSA Domain Secure Site CA"
+ # CA_ECDSA: "ZeroSSL ECC DV SSL CA 2"
+ # CA: "ZeroSSL RSA DV SSL CA 2"
# CA_EMAIL: "githubtest@acme.sh"
# TEST_PREFERRED_CHAIN: ""
runs-on: windows-latest
diff --git a/README.md b/README.md
index 740e5ef0..188af0e1 100644
--- a/README.md
+++ b/README.md
@@ -16,6 +16,7 @@
+
@@ -95,21 +96,22 @@
|7|[](https://github.com/acmesh-official/acme.sh/actions/workflows/OpenBSD.yml)|OpenBSD
|8|[](https://github.com/acmesh-official/acme.sh/actions/workflows/NetBSD.yml)|NetBSD
|9|[](https://github.com/acmesh-official/acme.sh/actions/workflows/DragonFlyBSD.yml)|DragonFlyBSD
-|10|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Omnios.yml)|Omnios
-|11|[](https://github.com/acmesh-official/acme.sh/actions/workflows/OpenIndiana.yml)|OpenIndiana
-|12|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)| Debian
-|13|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|openSUSE
-|14|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Alpine Linux (with curl)
-|15|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Archlinux
-|16|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|fedora
-|17|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Kali Linux
-|18|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Oracle Linux
-|19|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Mageia
-|20|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Gentoo Linux
-|21|-----| Cloud Linux https://github.com/acmesh-official/acme.sh/issues/111
-|22|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/acmesh-official/acme.sh/wiki/How-to-run-on-OpenWRT)
-|23|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)| Proxmox: See Proxmox VE Wiki. Version [4.x, 5.0, 5.1](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x,_5.0_and_5.1)#Let.27s_Encrypt_using_acme.sh), version [5.2 and up](https://pve.proxmox.com/wiki/Certificate_Management)
-|24|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Haiku.yml)|Haiku OS
+|10|[](https://github.com/acmesh-official/acme.sh/actions/workflows/MidnightBSD.yml)|MidnightBSD
+|11|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Omnios.yml)|Omnios
+|12|[](https://github.com/acmesh-official/acme.sh/actions/workflows/OpenIndiana.yml)|OpenIndiana
+|13|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)| Debian
+|14|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|openSUSE
+|15|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Alpine Linux (with curl)
+|16|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Archlinux
+|17|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|fedora
+|18|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Kali Linux
+|19|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Oracle Linux
+|20|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Mageia
+|21|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Gentoo Linux
+|22|-----| Cloud Linux https://github.com/acmesh-official/acme.sh/issues/111
+|23|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/acmesh-official/acme.sh/wiki/How-to-run-on-OpenWRT)
+|24|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)| Proxmox: See Proxmox VE Wiki. Version [4.x, 5.0, 5.1](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x,_5.0_and_5.1)#Let.27s_Encrypt_using_acme.sh), version [5.2 and up](https://pve.proxmox.com/wiki/Certificate_Management)
+|25|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Haiku.yml)|Haiku OS
> ๐งช Check our [testing project](https://github.com/acmesh-official/acmetest)
diff --git a/deploy/byteplus_alb.sh b/deploy/byteplus_alb.sh
new file mode 100644
index 00000000..8443bb99
--- /dev/null
+++ b/deploy/byteplus_alb.sh
@@ -0,0 +1,394 @@
+#!/usr/bin/env sh
+# shellcheck disable=SC2034,SC2154
+#
+# acme.sh deploy hook: BytePlus Application Load Balancer (ALB)
+# https://github.com/acmesh-official/acme.sh/wiki/deployhooks
+#
+# Deploys SSL/TLS certificates issued by acme.sh to BytePlus ALB.
+# Supports automatic renewal with zero-downtime certificate rotation
+# for certificates that have already been uploaded and have a saved
+# BytePlus CertificateId.
+#
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+# โ FIRST TIME (new domain) โ
+# โ 1. acme.sh --issue -d example.com -w /var/www/html/ โ
+# โ 2. Upload/import the certificate to BytePlus ALB manually โ
+# โ 3. Save/configure the existing CertificateId for this hook โ
+# โ 4. Manually assign cert to ALB Listener (one-time only) โ
+# โ โ
+# โ RENEWAL (fully automatic after CertificateId is configured) โ
+# โ acme.sh cron triggers renew โ deploy hook runs automatically โ
+# โ โ ReplaceCertificate (UpdateMode=new) โ single API call โ
+# โ โ All attached listeners updated, old cert auto-deleted โ
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+#
+# Required environment variables:
+# export BYTEPLUS_ACCESS_KEY="AKAPxxxxxxxxxx"
+# export BYTEPLUS_SECRET_KEY="your-secret-key"
+#
+# Optional environment variables:
+# export BYTEPLUS_REGION="ap-southeast-3" # default: ap-southeast-3
+# export BYTEPLUS_HOST="alb.ap-southeast-3.byteplusapi.com" # custom API host
+# export BYTEPLUS_PROJECT_NAME="live" # default: "default" project
+# export BYTEPLUS_CERT_NAME="" # default: acme-{domain}-{YYYYMMDD-HHMM}
+# export BYTEPLUS_CERT_DESCRIPTION="" # default: empty
+# export BYTEPLUS_DELETE_OLD_CERT="true" # default: true โ auto-delete after replace
+#
+# API notes:
+# - All BytePlus ALB APIs use GET with query string parameters
+# - Request signing: HMAC-SHA256 with signed headers host;x-date
+# - PublicKey/PrivateKey are URL-encoded (RFC 3986) in query string
+# - ReplaceCertificate with UpdateMode=new uploads + replaces in 1 call
+#
+# Dependencies: curl, openssl, awk (standard on most Linux)
+#
+# Docs:
+# Signing โ https://docs.byteplus.com/en/docs/byteplus-platform/reference-how-to-calculate-a-signature
+# ALB API โ https://docs.byteplus.com/en/docs/byteplus-alb
+
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+# Constants
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+# SHA-256 hash of empty string (used for GET requests with no body)
+_BYTEPLUS_EMPTY_HASH="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
+
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+# Main deploy function โ called by acme.sh
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+byteplus_alb_deploy() {
+ _cdomain="$1"
+ _ckey="$2"
+ _ccert="$3"
+ _cca="$4"
+ _cfullchain="$5"
+
+ _debug _cdomain "$_cdomain"
+ _debug _ckey "$_ckey"
+ _debug _ccert "$_ccert"
+ _debug _cca "$_cca"
+ _debug _cfullchain "$_cfullchain"
+
+ # โโ 1. Load & validate credentials โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+ # Preserve environment values before _getdeployconf (which may reset them)
+ _env_project_name="${BYTEPLUS_PROJECT_NAME:-}"
+ _env_delete_old="${BYTEPLUS_DELETE_OLD_CERT:-}"
+
+ _getdeployconf BYTEPLUS_ACCESS_KEY
+ _getdeployconf BYTEPLUS_SECRET_KEY
+ _getdeployconf BYTEPLUS_REGION
+ _getdeployconf BYTEPLUS_HOST
+ _getdeployconf BYTEPLUS_PROJECT_NAME
+ _getdeployconf BYTEPLUS_DELETE_OLD_CERT
+ _getdeployconf BYTEPLUS_CERT_NAME
+
+ # Restore from environment if _getdeployconf cleared them
+ if [ -z "$BYTEPLUS_PROJECT_NAME" ] && [ -n "$_env_project_name" ]; then
+ _debug "Restoring BYTEPLUS_PROJECT_NAME from environment"
+ BYTEPLUS_PROJECT_NAME="$_env_project_name"
+ fi
+ if [ -z "$BYTEPLUS_DELETE_OLD_CERT" ] && [ -n "$_env_delete_old" ]; then
+ BYTEPLUS_DELETE_OLD_CERT="$_env_delete_old"
+ fi
+
+ # Validate required credentials
+ if [ -z "$BYTEPLUS_ACCESS_KEY" ]; then
+ _err "BYTEPLUS_ACCESS_KEY is not set."
+ _err "Please run: export BYTEPLUS_ACCESS_KEY=\"your-access-key\""
+ return 1
+ fi
+ if [ -z "$BYTEPLUS_SECRET_KEY" ]; then
+ _err "BYTEPLUS_SECRET_KEY is not set."
+ _err "Please run: export BYTEPLUS_SECRET_KEY=\"your-secret-key\""
+ return 1
+ fi
+
+ # Save credentials for future runs
+ _savedeployconf BYTEPLUS_ACCESS_KEY "$BYTEPLUS_ACCESS_KEY"
+ _savedeployconf BYTEPLUS_SECRET_KEY "$BYTEPLUS_SECRET_KEY"
+
+ # Region (default: ap-southeast-3)
+ BYTEPLUS_REGION="${BYTEPLUS_REGION:-ap-southeast-3}"
+ _savedeployconf BYTEPLUS_REGION "$BYTEPLUS_REGION"
+
+ # Project name
+ if [ -n "$BYTEPLUS_PROJECT_NAME" ]; then
+ _savedeployconf BYTEPLUS_PROJECT_NAME "$BYTEPLUS_PROJECT_NAME"
+ _info "Using project: $BYTEPLUS_PROJECT_NAME"
+ else
+ _info "WARNING: BYTEPLUS_PROJECT_NAME is not set. Cert will go to 'default' project."
+ fi
+
+ # Delete old cert toggle (default: true)
+ BYTEPLUS_DELETE_OLD_CERT="${BYTEPLUS_DELETE_OLD_CERT:-true}"
+ _savedeployconf BYTEPLUS_DELETE_OLD_CERT "$BYTEPLUS_DELETE_OLD_CERT"
+
+ # API host โ custom override or auto-build from region
+ if [ -n "$BYTEPLUS_HOST" ]; then
+ _BYTEPLUS_HOST="$BYTEPLUS_HOST"
+ _savedeployconf BYTEPLUS_HOST "$BYTEPLUS_HOST"
+ else
+ _BYTEPLUS_HOST="alb.${BYTEPLUS_REGION}.byteplusapi.com"
+ fi
+ _info "Using API host: $_BYTEPLUS_HOST"
+ _BYTEPLUS_SERVICE="alb"
+
+ # โโ 2. Build certificate name โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+ _date_tag=$(date -u +%Y%m%d-%H%M)
+ # Replace wildcard * and dots for a valid cert name
+ _safe_domain=$(echo "$_cdomain" | sed 's/\*\.//g' | sed 's/\./-/g')
+ # Safe identifier version for deployconf keys: map all non [A-Za-z0-9_] to _
+ _conf_key=$(echo "$_cdomain" | sed 's/^\*\.//' | sed 's/[^A-Za-z0-9_]/_/g')
+
+ if [ -z "$BYTEPLUS_CERT_NAME" ]; then
+ BYTEPLUS_CERT_NAME="acme-${_safe_domain}-${_date_tag}"
+ fi
+
+ # Enforce BytePlus naming rules: start with letter, max 128 chars
+ BYTEPLUS_CERT_NAME=$(echo "$BYTEPLUS_CERT_NAME" | sed 's/[^A-Za-z0-9._-]/-/g')
+ case "$BYTEPLUS_CERT_NAME" in
+ [A-Za-z]*) ;;
+
+ *)
+ BYTEPLUS_CERT_NAME="a$BYTEPLUS_CERT_NAME"
+ ;;
+ esac
+ BYTEPLUS_CERT_NAME=$(echo "$BYTEPLUS_CERT_NAME" | cut -c1-128)
+
+ _info "Certificate name: $BYTEPLUS_CERT_NAME"
+
+ # โโ 3. Read cert and key โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+ # BytePlus requires NO blank lines between PEM blocks in the certificate chain
+
+ _public_key=$(sed '/^[[:space:]]*$/d' "$_cfullchain" | tr -d '\r')
+ _private_key=$(sed '/^[[:space:]]*$/d' "$_ckey" | tr -d '\r')
+
+ if [ -z "$_public_key" ] || [ -z "$_private_key" ]; then
+ _err "Failed to read certificate or key file."
+ return 1
+ fi
+
+ # โโ 4. Deploy: first-time upload or renewal replace โโโโโโโโโโโโโโโโโโโโโโโโโ
+
+ _getdeployconf "BYTEPLUS_CERT_ID_${_conf_key}"
+ _old_cert_id=$(eval echo "\$BYTEPLUS_CERT_ID_${_conf_key}")
+
+ if [ -z "$_old_cert_id" ]; then
+ _byteplus_first_time_deploy
+ else
+ _byteplus_renewal_deploy
+ fi
+
+ # Check if deploy step set _new_cert_id
+ if [ -z "$_new_cert_id" ]; then
+ return 1
+ fi
+
+ # โโ 5. Save new CertificateId for next renewal โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+ _savedeployconf "BYTEPLUS_CERT_ID_${_conf_key}" "$_new_cert_id"
+ _info "Saved CertificateId '$_new_cert_id' for domain '$_cdomain'."
+
+ return 0
+}
+
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+# Deploy: First time โ UploadCertificate
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+_byteplus_first_time_deploy() {
+ _info "No previous CertificateId found."
+ _err "Refusing to upload certificate material because this hook passes PublicKey/PrivateKey as request parameters."
+ _err "Uploading a private key in the request URL can leak it via logs, proxies, and process listings."
+ _err "Please upload the certificate to BytePlus manually for the initial deployment, set BYTEPLUS_CERT_ID_${_conf_key} to that CertificateId, and rerun."
+ _err "This hook stores CertificateId values per domain using deployconf, so the variable name must include the current domain-specific suffix."
+ _err "This hook must be updated to send PublicKey and PrivateKey in a POST body before automatic first-time upload can be enabled safely."
+ return 1
+}
+
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+# Deploy: Renewal โ ReplaceCertificate (UpdateMode=new)
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+_byteplus_renewal_deploy() {
+ _info "Replacing old certificate '$_old_cert_id' (UpdateMode=new)..."
+ _err "Refusing to replace certificate material because this hook passes PublicKey/PrivateKey as request parameters."
+ _err "Uploading a private key in the request URL can leak it via logs, proxies, and process listings."
+ _err "Please replace the certificate in BytePlus manually for renewal until this hook is updated to send PublicKey and PrivateKey in a POST body safely."
+ return 1
+}
+
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+# Delete old certificate (with retry)
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+_byteplus_delete_old_cert() {
+ _del_cert_id="$1"
+
+ _info "Waiting 5s for cert status to settle..."
+ _sleep 5
+
+ _info "Deleting old certificate '$_del_cert_id'..."
+ _del_response=$(_byteplus_alb_api "DeleteCertificate" "CertificateId=${_del_cert_id}")
+
+ if echo "$_del_response" | grep -q '"Error"'; then
+ _info "Delete failed, retrying in 10s..."
+ _sleep 10
+ _del_response=$(_byteplus_alb_api "DeleteCertificate" "CertificateId=${_del_cert_id}")
+
+ if echo "$_del_response" | grep -q '"Error"'; then
+ _info "Warning: Could not delete old certificate '$_del_cert_id'."
+ _info "Error: $(_byteplus_extract_error "$_del_response")"
+ _info "Please remove it manually from BytePlus Console."
+ else
+ _info "Old certificate '$_del_cert_id' deleted (retry succeeded)."
+ fi
+ else
+ _info "Old certificate '$_del_cert_id' deleted."
+ fi
+}
+
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+# JSON response helpers
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+# Extract CertificateId from API response JSON
+_byteplus_extract_cert_id() {
+ echo "$1" | _egrep_o '"CertificateId"\s*:\s*"[^"]*"' | head -1 | _egrep_o '"[^"]*"$' | tr -d '"'
+}
+
+# Extract error message from API response JSON
+_byteplus_extract_error() {
+ _code=$(echo "$1" | _egrep_o '"Code"\s*:\s*"[^"]*"' | head -1 | _egrep_o '"[^"]*"$' | tr -d '"')
+ _msg=$(echo "$1" | _egrep_o '"Message"\s*:\s*"[^"]*"' | head -1 | _egrep_o '"[^"]*"$' | tr -d '"')
+ if [ -n "$_code" ]; then
+ printf '%s โ %s' "$_code" "$_msg"
+ else
+ printf '%s' "$1"
+ fi
+}
+
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+# BytePlus ALB API caller
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+# Usage: _byteplus_alb_api ACTION [param1=val1] [param2=val2] ...
+# All parameters sent via GET query string. Signing: HMAC-SHA256, host;x-date.
+_byteplus_alb_api() {
+ _action="$1"
+ shift
+
+ # Build query string โ all params go in URL
+ _query_params="Action=${_action}&Version=2020-04-01"
+
+ for _param in "$@"; do
+ _pname="${_param%%=*}"
+ _pval="${_param#*=}"
+ _query_params="${_query_params}&${_pname}=$(_byteplus_urlencode "$_pval")"
+ done
+
+ # Timestamps
+ _x_date=$(date -u +%Y%m%dT%H%M%SZ)
+ _date_only=$(date -u +%Y%m%d)
+
+ # Sort query params for canonical request
+ _sorted_query=$(echo "$_query_params" | tr '&' '\n' | LC_ALL=C sort | tr '\n' '&' | sed 's/&$//')
+
+ # Canonical headers โ only host and x-date
+ _canonical_headers="host:${_BYTEPLUS_HOST}
+x-date:${_x_date}
+"
+ _signed_headers="host;x-date"
+
+ # Canonical request
+ _canonical_request="GET
+/
+${_sorted_query}
+${_canonical_headers}
+${_signed_headers}
+${_BYTEPLUS_EMPTY_HASH}"
+
+ # Do not log _canonical_request because the query string may contain
+ # URL-encoded certificate or private key material.
+
+ # Hash of canonical request
+ # _digest is provided by acme.sh and works across OpenSSL versions.
+ _cr_hash=$(printf '%s' "$_canonical_request" | _digest sha256 hex)
+
+ # Credential scope
+ _credential_scope="${_date_only}/${BYTEPLUS_REGION}/${_BYTEPLUS_SERVICE}/request"
+
+ # String to sign
+ _string_to_sign="HMAC-SHA256
+${_x_date}
+${_credential_scope}
+${_cr_hash}"
+
+ _debug2 _string_to_sign "$_string_to_sign"
+
+ # Signing key derivation (HMAC chain)
+ # _hmac reads data from stdin and returns a hex digest.
+ # acme.sh's _hmac abstracts away OpenSSL version differences, so this works
+ # on both modern (-mac HMAC -macopt hexkey:) and older (-hmac) OpenSSL builds.
+ #
+ # The first step seeds the chain from the raw secret key, so we convert it
+ # to hex first with _hex_dump (also an acme.sh built-in).
+ _secret_hex=$(printf '%s' "$BYTEPLUS_SECRET_KEY" | _hex_dump | tr -d ' \n')
+ _k_date=$(printf '%s' "$_date_only" | _hmac sha256 "$_secret_hex" hex)
+ _k_region=$(printf '%s' "$BYTEPLUS_REGION" | _hmac sha256 "$_k_date" hex)
+ _k_service=$(printf '%s' "$_BYTEPLUS_SERVICE" | _hmac sha256 "$_k_region" hex)
+ _k_signing=$(printf '%s' "request" | _hmac sha256 "$_k_service" hex)
+
+ # Final signature
+ _signature=$(printf '%s' "$_string_to_sign" | _hmac sha256 "$_k_signing" hex)
+
+ # Authorization header
+ _auth="HMAC-SHA256 Credential=${BYTEPLUS_ACCESS_KEY}/${_credential_scope}, SignedHeaders=${_signed_headers}, Signature=${_signature}"
+
+ _secure_debug2 _auth "$_auth"
+
+ # Send request parameters in the POST body instead of the URL query string.
+ # This avoids exposing sensitive or large values in debug-logged URLs and
+ # reduces the risk of exceeding URL length limits.
+ _url="https://${_BYTEPLUS_HOST}/"
+ _body="$_sorted_query"
+
+ _saved_H1="${_H1:-}"
+ _saved_H2="${_H2:-}"
+ _saved_H3="${_H3:-}"
+ _saved_H4="${_H4:-}"
+ _saved_H5="${_H5:-}"
+
+ _H1="Authorization: ${_auth}"
+ _H2="X-Date: ${_x_date}"
+ _H3="Host: ${_BYTEPLUS_HOST}"
+ _H4="Content-Type: application/x-www-form-urlencoded"
+ _H5=""
+
+ _response="$(_post "$_body" "$_url" "" "POST")"
+ _request_ret="$?"
+
+ _H1="$_saved_H1"
+ _H2="$_saved_H2"
+ _H3="$_saved_H3"
+ _H4="$_saved_H4"
+ _H5="$_saved_H5"
+
+ if [ "$_request_ret" != "0" ]; then
+ _err "byteplus_alb_api request failed for [$_action]"
+ return 1
+ fi
+ _debug2 "_byteplus_alb_api response [$_action]" "$_response"
+ printf '%s' "$_response"
+}
+
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+# URL encode (RFC 3986)
+# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
+
+_byteplus_urlencode() {
+ printf '%s' "$1" | _url_encode
+}