mirror of
https://github.com/acmesh-official/acme.sh.git
synced 2025-06-16 20:52:42 +00:00
Merge branch 'acmesh-official:master' into deploy_to_plex
This commit is contained in:
commit
fad63bdbc9
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@ -3,7 +3,7 @@
|
|||||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||||
patreon: # Replace with a single Patreon username
|
patreon: # Replace with a single Patreon username
|
||||||
open_collective: acmesh
|
open_collective: acmesh
|
||||||
ko_fi: # Replace with a single Ko-fi username
|
ko_fi: neilpang
|
||||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
liberapay: # Replace with a single Liberapay username
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
350
.github/workflows/DNS.yml
vendored
350
.github/workflows/DNS.yml
vendored
@ -11,6 +11,9 @@ on:
|
|||||||
- 'dnsapi/*.sh'
|
- 'dnsapi/*.sh'
|
||||||
- '.github/workflows/DNS.yml'
|
- '.github/workflows/DNS.yml'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
CheckToken:
|
CheckToken:
|
||||||
@ -53,11 +56,18 @@ jobs:
|
|||||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||||
CASE: le_test_dnsapi
|
CASE: le_test_dnsapi
|
||||||
TEST_LOCAL: 1
|
TEST_LOCAL: 1
|
||||||
DEBUG: 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:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Clone acmetest
|
- name: Clone acmetest
|
||||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||||
- name: Set env file
|
- name: Set env file
|
||||||
run: |
|
run: |
|
||||||
cd ../acmetest
|
cd ../acmetest
|
||||||
@ -76,11 +86,13 @@ jobs:
|
|||||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||||
echo "${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}" >> docker.env
|
echo "${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}" >> docker.env
|
||||||
fi
|
fi
|
||||||
echo "TEST_DNS_NO_WILDCARD" >> docker.env
|
|
||||||
echo "TEST_DNS_SLEEP" >> docker.env
|
|
||||||
- name: Run acmetest
|
- name: Run acmetest
|
||||||
run: cd ../acmetest && ./rundocker.sh testall
|
run: cd ../acmetest && ./rundocker.sh testall
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MacOS:
|
MacOS:
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
needs: Docker
|
needs: Docker
|
||||||
@ -92,33 +104,43 @@ jobs:
|
|||||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||||
CASE: le_test_dnsapi
|
CASE: le_test_dnsapi
|
||||||
TEST_LOCAL: 1
|
TEST_LOCAL: 1
|
||||||
DEBUG: 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:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Install tools
|
- name: Install tools
|
||||||
run: brew install socat
|
run: brew install socat
|
||||||
- name: Clone acmetest
|
- name: Clone acmetest
|
||||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||||
- name: Run acmetest
|
- name: Run acmetest
|
||||||
run: |
|
run: |
|
||||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||||
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||||
export ${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}
|
export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||||
export ${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}
|
export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||||
export ${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}
|
export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||||
export ${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}
|
export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
|
||||||
fi
|
fi
|
||||||
cd ../acmetest
|
cd ../acmetest
|
||||||
./letest.sh
|
./letest.sh
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Windows:
|
Windows:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
needs: MacOS
|
needs: MacOS
|
||||||
@ -130,12 +152,19 @@ jobs:
|
|||||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||||
CASE: le_test_dnsapi
|
CASE: le_test_dnsapi
|
||||||
TEST_LOCAL: 1
|
TEST_LOCAL: 1
|
||||||
DEBUG: 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:
|
steps:
|
||||||
- name: Set git to use LF
|
- name: Set git to use LF
|
||||||
run: |
|
run: |
|
||||||
git config --global core.autocrlf false
|
git config --global core.autocrlf false
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Install cygwin base packages with chocolatey
|
- name: Install cygwin base packages with chocolatey
|
||||||
run: |
|
run: |
|
||||||
choco config get cacheLocation
|
choco config get cacheLocation
|
||||||
@ -143,37 +172,39 @@ jobs:
|
|||||||
shell: cmd
|
shell: cmd
|
||||||
- name: Install cygwin additional packages
|
- name: Install cygwin additional packages
|
||||||
run: |
|
run: |
|
||||||
C:\tools\cygwin\cygwinsetup.exe -qgnNdO -R C:/tools/cygwin -s http://mirrors.kernel.org/sourceware/cygwin/ -P socat,curl,cron,unzip,git
|
C:\tools\cygwin\cygwinsetup.exe -qgnNdO -R C:/tools/cygwin -s https://mirrors.kernel.org/sourceware/cygwin/ -P socat,curl,cron,unzip,git
|
||||||
shell: cmd
|
shell: cmd
|
||||||
- name: Set ENV
|
- name: Set ENV
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: |
|
run: |
|
||||||
echo PATH=C:\tools\cygwin\bin;C:\tools\cygwin\usr\bin >> %GITHUB_ENV%
|
echo PATH=C:\tools\cygwin\bin;C:\tools\cygwin\usr\bin >> %GITHUB_ENV%
|
||||||
- name: Clone acmetest
|
- name: Clone acmetest
|
||||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||||
- name: Run acmetest
|
- name: Run acmetest
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||||
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||||
export ${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}
|
export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||||
export ${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}
|
export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||||
export ${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}
|
export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||||
export ${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}
|
export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
|
||||||
fi
|
fi
|
||||||
cd ../acmetest
|
cd ../acmetest
|
||||||
./letest.sh
|
./letest.sh
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
FreeBSD:
|
FreeBSD:
|
||||||
runs-on: macos-10.15
|
runs-on: ubuntu-latest
|
||||||
needs: Windows
|
needs: Windows
|
||||||
env:
|
env:
|
||||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||||
@ -183,37 +214,48 @@ jobs:
|
|||||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||||
CASE: le_test_dnsapi
|
CASE: le_test_dnsapi
|
||||||
TEST_LOCAL: 1
|
TEST_LOCAL: 1
|
||||||
DEBUG: 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:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Clone acmetest
|
- name: Clone acmetest
|
||||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||||
- uses: vmactions/freebsd-vm@v0.1.4
|
- uses: vmactions/freebsd-vm@v1
|
||||||
with:
|
with:
|
||||||
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
|
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
|
prepare: pkg install -y socat curl
|
||||||
usesh: true
|
usesh: true
|
||||||
|
copyback: false
|
||||||
run: |
|
run: |
|
||||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||||
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||||
export ${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}
|
export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||||
export ${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}
|
export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||||
export ${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}
|
export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||||
export ${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}
|
export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
|
||||||
fi
|
fi
|
||||||
cd ../acmetest
|
cd ../acmetest
|
||||||
./letest.sh
|
./letest.sh
|
||||||
|
|
||||||
Solaris:
|
|
||||||
runs-on: macos-10.15
|
|
||||||
|
|
||||||
|
OpenBSD:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
needs: FreeBSD
|
needs: FreeBSD
|
||||||
env:
|
env:
|
||||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||||
@ -223,32 +265,250 @@ jobs:
|
|||||||
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||||
CASE: le_test_dnsapi
|
CASE: le_test_dnsapi
|
||||||
TEST_LOCAL: 1
|
TEST_LOCAL: 1
|
||||||
DEBUG: 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:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Clone acmetest
|
- name: Clone acmetest
|
||||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||||
- uses: vmactions/solaris-vm@v0.0.5
|
- uses: vmactions/openbsd-vm@v1
|
||||||
with:
|
with:
|
||||||
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_NO_SUBDOMAIN TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
|
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
|
||||||
|
usesh: true
|
||||||
|
copyback: false
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NetBSD:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: OpenBSD
|
||||||
|
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@v4
|
||||||
|
- 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
|
||||||
|
with:
|
||||||
|
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
|
||||||
|
usesh: true
|
||||||
|
copyback: false
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DragonFlyBSD:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: NetBSD
|
||||||
|
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@v4
|
||||||
|
- 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
|
||||||
|
with:
|
||||||
|
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 curl socat libnghttp2
|
||||||
|
usesh: true
|
||||||
|
copyback: false
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Solaris:
|
||||||
|
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 }}
|
||||||
|
HTTPS_INSECURE: 1 # always set to 1 to ignore https error, since Solaris doesn't accept the expired ISRG X1 root
|
||||||
|
TokenName1: ${{ secrets.TokenName1}}
|
||||||
|
TokenName2: ${{ secrets.TokenName2}}
|
||||||
|
TokenName3: ${{ secrets.TokenName3}}
|
||||||
|
TokenName4: ${{ secrets.TokenName4}}
|
||||||
|
TokenName5: ${{ secrets.TokenName5}}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- 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
|
||||||
|
with:
|
||||||
|
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}}'
|
||||||
|
copyback: false
|
||||||
prepare: pkgutil -y -i socat
|
prepare: pkgutil -y -i socat
|
||||||
run: |
|
run: |
|
||||||
pkg set-mediator -v -I default@1.1 openssl
|
pkg set-mediator -v -I default@1.1 openssl
|
||||||
export PATH=/usr/gnu/bin:$PATH
|
export PATH=/usr/gnu/bin:$PATH
|
||||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||||
export ${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}
|
export ${{ secrets.TokenName1}}="${{ secrets.TokenValue1}}"
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||||
export ${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}
|
export ${{ secrets.TokenName2}}="${{ secrets.TokenValue2}}"
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||||
export ${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}
|
export ${{ secrets.TokenName3}}="${{ secrets.TokenValue3}}"
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||||
export ${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}
|
export ${{ secrets.TokenName4}}="${{ secrets.TokenValue4}}"
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||||
export ${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}
|
export ${{ secrets.TokenName5}}="${{ secrets.TokenValue5}}"
|
||||||
fi
|
fi
|
||||||
cd ../acmetest
|
cd ../acmetest
|
||||||
./letest.sh
|
./letest.sh
|
||||||
|
|
||||||
|
|
||||||
|
Omnios:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: Solaris
|
||||||
|
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 }}
|
||||||
|
HTTPS_INSECURE: 1 # always set to 1 to ignore https error, since Omnios doesn't accept the expired ISRG X1 root
|
||||||
|
TokenName1: ${{ secrets.TokenName1}}
|
||||||
|
TokenName2: ${{ secrets.TokenName2}}
|
||||||
|
TokenName3: ${{ secrets.TokenName3}}
|
||||||
|
TokenName4: ${{ secrets.TokenName4}}
|
||||||
|
TokenName5: ${{ secrets.TokenName5}}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- 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
|
||||||
|
with:
|
||||||
|
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}}'
|
||||||
|
copyback: false
|
||||||
|
prepare: pkg install socat
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
71
.github/workflows/DragonFlyBSD.yml
vendored
Normal file
71
.github/workflows/DragonFlyBSD.yml
vendored
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
name: DragonFlyBSD
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '*'
|
||||||
|
paths:
|
||||||
|
- '*.sh'
|
||||||
|
- '.github/workflows/DragonFlyBSD.yml'
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
paths:
|
||||||
|
- '*.sh'
|
||||||
|
- '.github/workflows/DragonFlyBSD.yml'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
DragonFlyBSD:
|
||||||
|
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 Domain Secure Site CA"
|
||||||
|
# CA: "ZeroSSL RSA Domain Secure Site CA"
|
||||||
|
# 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@v4
|
||||||
|
- uses: vmactions/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/dragonflybsd-vm@v1
|
||||||
|
with:
|
||||||
|
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
|
||||||
|
nat: |
|
||||||
|
"8080": "80"
|
||||||
|
prepare: |
|
||||||
|
pkg install -y curl socat libnghttp2
|
||||||
|
usesh: true
|
||||||
|
copyback: false
|
||||||
|
run: |
|
||||||
|
cd ../acmetest \
|
||||||
|
&& ./letest.sh
|
||||||
|
|
||||||
|
|
39
.github/workflows/FreeBSD.yml
vendored
39
.github/workflows/FreeBSD.yml
vendored
@ -14,6 +14,11 @@ on:
|
|||||||
- '*.sh'
|
- '*.sh'
|
||||||
- '.github/workflows/FreeBSD.yml'
|
- '.github/workflows/FreeBSD.yml'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
FreeBSD:
|
FreeBSD:
|
||||||
@ -24,13 +29,19 @@ jobs:
|
|||||||
CA_ECDSA: ""
|
CA_ECDSA: ""
|
||||||
CA: ""
|
CA: ""
|
||||||
CA_EMAIL: ""
|
CA_EMAIL: ""
|
||||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
TEST_PREFERRED_CHAIN: (STAGING)
|
||||||
- TEST_ACME_Server: "ZeroSSL.com"
|
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||||
CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
|
CA_ECDSA: ""
|
||||||
CA: "ZeroSSL RSA Domain Secure Site CA"
|
CA: ""
|
||||||
CA_EMAIL: "githubtest@acme.sh"
|
CA_EMAIL: ""
|
||||||
TEST_PREFERRED_CHAIN: ""
|
TEST_PREFERRED_CHAIN: (STAGING)
|
||||||
runs-on: macos-10.15
|
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_EMAIL: "githubtest@acme.sh"
|
||||||
|
# TEST_PREFERRED_CHAIN: ""
|
||||||
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
TEST_LOCAL: 1
|
TEST_LOCAL: 1
|
||||||
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
|
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
|
||||||
@ -38,9 +49,10 @@ jobs:
|
|||||||
CA: ${{ matrix.CA }}
|
CA: ${{ matrix.CA }}
|
||||||
CA_EMAIL: ${{ matrix.CA_EMAIL }}
|
CA_EMAIL: ${{ matrix.CA_EMAIL }}
|
||||||
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
|
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
|
||||||
|
ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- uses: vmactions/cf-tunnel@v0.0.3
|
- uses: vmactions/cf-tunnel@v0
|
||||||
id: tunnel
|
id: tunnel
|
||||||
with:
|
with:
|
||||||
protocol: http
|
protocol: http
|
||||||
@ -48,14 +60,15 @@ jobs:
|
|||||||
- name: Set envs
|
- name: Set envs
|
||||||
run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
|
run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
|
||||||
- name: Clone acmetest
|
- name: Clone acmetest
|
||||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||||
- uses: vmactions/freebsd-vm@v0.1.5
|
- uses: vmactions/freebsd-vm@v1
|
||||||
with:
|
with:
|
||||||
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN'
|
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
|
||||||
nat: |
|
nat: |
|
||||||
"8080": "80"
|
"8080": "80"
|
||||||
prepare: pkg install -y socat curl
|
prepare: pkg install -y socat curl wget
|
||||||
usesh: true
|
usesh: true
|
||||||
|
copyback: false
|
||||||
run: |
|
run: |
|
||||||
cd ../acmetest \
|
cd ../acmetest \
|
||||||
&& ./letest.sh
|
&& ./letest.sh
|
||||||
|
15
.github/workflows/Linux.yml
vendored
15
.github/workflows/Linux.yml
vendored
@ -15,22 +15,29 @@ on:
|
|||||||
- '.github/workflows/Linux.yml'
|
- '.github/workflows/Linux.yml'
|
||||||
|
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Linux:
|
Linux:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: ["ubuntu:latest", "debian:latest", "almalinux:latest", "fedora:latest", "centos:latest", "opensuse/leap:latest", "alpine:latest", "oraclelinux:8", "kalilinux/kali", "archlinux:latest", "mageia", "gentoo/stage3"]
|
os: ["ubuntu:latest", "debian:latest", "almalinux:latest", "fedora:latest", "opensuse/leap:latest", "alpine:latest", "oraclelinux:8", "kalilinux/kali", "archlinux:latest", "mageia", "gentoo/stage3"]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
TEST_LOCAL: 1
|
TEST_LOCAL: 1
|
||||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
TEST_PREFERRED_CHAIN: (STAGING)
|
||||||
|
TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Clone acmetest
|
- name: Clone acmetest
|
||||||
run: |
|
run: |
|
||||||
cd .. \
|
cd .. \
|
||||||
&& git clone https://github.com/acmesh-official/acmetest.git \
|
&& git clone --depth=1 https://github.com/acmesh-official/acmetest.git \
|
||||||
&& cp -r acme.sh acmetest/
|
&& cp -r acme.sh acmetest/
|
||||||
- name: Run acmetest
|
- name: Run acmetest
|
||||||
run: |
|
run: |
|
||||||
|
21
.github/workflows/MacOS.yml
vendored
21
.github/workflows/MacOS.yml
vendored
@ -14,6 +14,11 @@ on:
|
|||||||
- '*.sh'
|
- '*.sh'
|
||||||
- '.github/workflows/MacOS.yml'
|
- '.github/workflows/MacOS.yml'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
MacOS:
|
MacOS:
|
||||||
@ -24,12 +29,12 @@ jobs:
|
|||||||
CA_ECDSA: ""
|
CA_ECDSA: ""
|
||||||
CA: ""
|
CA: ""
|
||||||
CA_EMAIL: ""
|
CA_EMAIL: ""
|
||||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
TEST_PREFERRED_CHAIN: (STAGING)
|
||||||
- TEST_ACME_Server: "ZeroSSL.com"
|
#- TEST_ACME_Server: "ZeroSSL.com"
|
||||||
CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
|
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
|
||||||
CA: "ZeroSSL RSA Domain Secure Site CA"
|
# CA: "ZeroSSL RSA Domain Secure Site CA"
|
||||||
CA_EMAIL: "githubtest@acme.sh"
|
# CA_EMAIL: "githubtest@acme.sh"
|
||||||
TEST_PREFERRED_CHAIN: ""
|
# TEST_PREFERRED_CHAIN: ""
|
||||||
runs-on: macos-latest
|
runs-on: macos-latest
|
||||||
env:
|
env:
|
||||||
TEST_LOCAL: 1
|
TEST_LOCAL: 1
|
||||||
@ -39,13 +44,13 @@ jobs:
|
|||||||
CA_EMAIL: ${{ matrix.CA_EMAIL }}
|
CA_EMAIL: ${{ matrix.CA_EMAIL }}
|
||||||
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
|
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Install tools
|
- name: Install tools
|
||||||
run: brew install socat
|
run: brew install socat
|
||||||
- name: Clone acmetest
|
- name: Clone acmetest
|
||||||
run: |
|
run: |
|
||||||
cd .. \
|
cd .. \
|
||||||
&& git clone https://github.com/acmesh-official/acmetest.git \
|
&& git clone --depth=1 https://github.com/acmesh-official/acmetest.git \
|
||||||
&& cp -r acme.sh acmetest/
|
&& cp -r acme.sh acmetest/
|
||||||
- name: Run acmetest
|
- name: Run acmetest
|
||||||
run: |
|
run: |
|
||||||
|
71
.github/workflows/NetBSD.yml
vendored
Normal file
71
.github/workflows/NetBSD.yml
vendored
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
name: NetBSD
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '*'
|
||||||
|
paths:
|
||||||
|
- '*.sh'
|
||||||
|
- '.github/workflows/NetBSD.yml'
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
paths:
|
||||||
|
- '*.sh'
|
||||||
|
- '.github/workflows/NetBSD.yml'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
NetBSD:
|
||||||
|
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 Domain Secure Site CA"
|
||||||
|
# CA: "ZeroSSL RSA Domain Secure Site CA"
|
||||||
|
# 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@v4
|
||||||
|
- uses: vmactions/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/netbsd-vm@v1
|
||||||
|
with:
|
||||||
|
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
|
||||||
|
nat: |
|
||||||
|
"8080": "80"
|
||||||
|
prepare: |
|
||||||
|
/usr/sbin/pkg_add curl socat
|
||||||
|
usesh: true
|
||||||
|
copyback: false
|
||||||
|
run: |
|
||||||
|
cd ../acmetest \
|
||||||
|
&& ./letest.sh
|
||||||
|
|
||||||
|
|
75
.github/workflows/Omnios.yml
vendored
Normal file
75
.github/workflows/Omnios.yml
vendored
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
name: Omnios
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '*'
|
||||||
|
paths:
|
||||||
|
- '*.sh'
|
||||||
|
- '.github/workflows/Omnios.yml'
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
paths:
|
||||||
|
- '*.sh'
|
||||||
|
- '.github/workflows/Omnios.yml'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Omnios:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||||
|
CA_ECDSA: ""
|
||||||
|
CA: ""
|
||||||
|
CA_EMAIL: ""
|
||||||
|
TEST_PREFERRED_CHAIN: (STAGING)
|
||||||
|
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||||
|
CA_ECDSA: ""
|
||||||
|
CA: ""
|
||||||
|
CA_EMAIL: ""
|
||||||
|
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_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@v4
|
||||||
|
- uses: vmactions/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/omnios-vm@v1
|
||||||
|
with:
|
||||||
|
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
|
||||||
|
nat: |
|
||||||
|
"8080": "80"
|
||||||
|
prepare: pkg install socat wget
|
||||||
|
copyback: false
|
||||||
|
run: |
|
||||||
|
cd ../acmetest \
|
||||||
|
&& ./letest.sh
|
||||||
|
|
||||||
|
|
76
.github/workflows/OpenBSD.yml
vendored
Normal file
76
.github/workflows/OpenBSD.yml
vendored
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
name: OpenBSD
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '*'
|
||||||
|
paths:
|
||||||
|
- '*.sh'
|
||||||
|
- '.github/workflows/OpenBSD.yml'
|
||||||
|
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
paths:
|
||||||
|
- '*.sh'
|
||||||
|
- '.github/workflows/OpenBSD.yml'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
OpenBSD:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||||
|
CA_ECDSA: ""
|
||||||
|
CA: ""
|
||||||
|
CA_EMAIL: ""
|
||||||
|
TEST_PREFERRED_CHAIN: (STAGING)
|
||||||
|
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||||
|
CA_ECDSA: ""
|
||||||
|
CA: ""
|
||||||
|
CA_EMAIL: ""
|
||||||
|
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_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@v4
|
||||||
|
- uses: vmactions/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/openbsd-vm@v1
|
||||||
|
with:
|
||||||
|
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
|
||||||
|
nat: |
|
||||||
|
"8080": "80"
|
||||||
|
prepare: pkg_add socat curl wget libnghttp2
|
||||||
|
usesh: true
|
||||||
|
copyback: false
|
||||||
|
run: |
|
||||||
|
cd ../acmetest \
|
||||||
|
&& ./letest.sh
|
||||||
|
|
||||||
|
|
26
.github/workflows/PebbleStrict.yml
vendored
26
.github/workflows/PebbleStrict.yml
vendored
@ -13,6 +13,13 @@ on:
|
|||||||
- '*.sh'
|
- '*.sh'
|
||||||
- '.github/workflows/PebbleStrict.yml'
|
- '.github/workflows/PebbleStrict.yml'
|
||||||
|
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
PebbleStrict:
|
PebbleStrict:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -26,23 +33,23 @@ jobs:
|
|||||||
TEST_CA: "Pebble Intermediate CA"
|
TEST_CA: "Pebble Intermediate CA"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Install tools
|
- name: Install tools
|
||||||
run: sudo apt-get install -y socat
|
run: sudo apt-get install -y socat
|
||||||
- name: Run Pebble
|
- name: Run Pebble
|
||||||
run: cd .. && curl https://raw.githubusercontent.com/letsencrypt/pebble/master/docker-compose.yml >docker-compose.yml && docker-compose up -d
|
run: cd .. && curl https://raw.githubusercontent.com/letsencrypt/pebble/master/docker-compose.yml >docker-compose.yml && docker compose up -d
|
||||||
- name: Set up Pebble
|
- name: Set up Pebble
|
||||||
run: curl --request POST --data '{"ip":"10.30.50.1"}' http://localhost:8055/set-default-ipv4
|
run: curl --request POST --data '{"ip":"10.30.50.1"}' http://localhost:8055/set-default-ipv4
|
||||||
- name: Clone acmetest
|
- name: Clone acmetest
|
||||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||||
- name: Run acmetest
|
- name: Run acmetest
|
||||||
run: cd ../acmetest && ./letest.sh
|
run: cd ../acmetest && ./letest.sh
|
||||||
|
|
||||||
PebbleStrict_IPCert:
|
PebbleStrict_IPCert:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
TestingDomain: 10.30.50.1
|
TestingDomain: 1.23.45.67
|
||||||
ACME_DIRECTORY: https://localhost:14000/dir
|
TEST_ACME_Server: https://localhost:14000/dir
|
||||||
HTTPS_INSECURE: 1
|
HTTPS_INSECURE: 1
|
||||||
Le_HTTPPort: 5002
|
Le_HTTPPort: 5002
|
||||||
Le_TLSPort: 5001
|
Le_TLSPort: 5001
|
||||||
@ -51,12 +58,15 @@ jobs:
|
|||||||
TEST_IPCERT: 1
|
TEST_IPCERT: 1
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Install tools
|
- name: Install tools
|
||||||
run: sudo apt-get install -y socat
|
run: sudo apt-get install -y socat
|
||||||
- name: Run Pebble
|
- name: Run Pebble
|
||||||
run: cd .. && curl https://raw.githubusercontent.com/letsencrypt/pebble/master/docker-compose.yml >docker-compose.yml && docker-compose up -d
|
run: |
|
||||||
|
docker run --rm -itd --name=pebble \
|
||||||
|
-e PEBBLE_VA_ALWAYS_VALID=1 \
|
||||||
|
-p 14000:14000 -p 15000:15000 letsencrypt/pebble:latest pebble -config /test/config/pebble-config.json -strict
|
||||||
- name: Clone acmetest
|
- name: Clone acmetest
|
||||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||||
- name: Run acmetest
|
- name: Run acmetest
|
||||||
run: cd ../acmetest && ./letest.sh
|
run: cd ../acmetest && ./letest.sh
|
40
.github/workflows/Solaris.yml
vendored
40
.github/workflows/Solaris.yml
vendored
@ -14,6 +14,11 @@ on:
|
|||||||
- '*.sh'
|
- '*.sh'
|
||||||
- '.github/workflows/Solaris.yml'
|
- '.github/workflows/Solaris.yml'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Solaris:
|
Solaris:
|
||||||
@ -24,13 +29,19 @@ jobs:
|
|||||||
CA_ECDSA: ""
|
CA_ECDSA: ""
|
||||||
CA: ""
|
CA: ""
|
||||||
CA_EMAIL: ""
|
CA_EMAIL: ""
|
||||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
TEST_PREFERRED_CHAIN: (STAGING)
|
||||||
- TEST_ACME_Server: "ZeroSSL.com"
|
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||||
CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
|
CA_ECDSA: ""
|
||||||
CA: "ZeroSSL RSA Domain Secure Site CA"
|
CA: ""
|
||||||
CA_EMAIL: "githubtest@acme.sh"
|
CA_EMAIL: ""
|
||||||
TEST_PREFERRED_CHAIN: ""
|
TEST_PREFERRED_CHAIN: (STAGING)
|
||||||
runs-on: macos-10.15
|
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_EMAIL: "githubtest@acme.sh"
|
||||||
|
# TEST_PREFERRED_CHAIN: ""
|
||||||
|
runs-on: ubuntu-latest
|
||||||
env:
|
env:
|
||||||
TEST_LOCAL: 1
|
TEST_LOCAL: 1
|
||||||
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
|
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
|
||||||
@ -38,9 +49,10 @@ jobs:
|
|||||||
CA: ${{ matrix.CA }}
|
CA: ${{ matrix.CA }}
|
||||||
CA_EMAIL: ${{ matrix.CA_EMAIL }}
|
CA_EMAIL: ${{ matrix.CA_EMAIL }}
|
||||||
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
|
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
|
||||||
|
ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- uses: vmactions/cf-tunnel@v0.0.3
|
- uses: vmactions/cf-tunnel@v0
|
||||||
id: tunnel
|
id: tunnel
|
||||||
with:
|
with:
|
||||||
protocol: http
|
protocol: http
|
||||||
@ -48,14 +60,16 @@ jobs:
|
|||||||
- name: Set envs
|
- name: Set envs
|
||||||
run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
|
run: echo "TestingDomain=${{steps.tunnel.outputs.server}}" >> $GITHUB_ENV
|
||||||
- name: Clone acmetest
|
- name: Clone acmetest
|
||||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||||
- uses: vmactions/solaris-vm@v0.0.5
|
- uses: vmactions/solaris-vm@v1
|
||||||
with:
|
with:
|
||||||
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN'
|
envs: 'TEST_LOCAL TestingDomain TEST_ACME_Server CA_ECDSA CA CA_EMAIL TEST_PREFERRED_CHAIN ACME_USE_WGET'
|
||||||
nat: |
|
nat: |
|
||||||
"8080": "80"
|
"8080": "80"
|
||||||
prepare: pkgutil -y -i socat curl
|
prepare: pkgutil -y -i socat curl wget
|
||||||
|
copyback: false
|
||||||
run: |
|
run: |
|
||||||
cd ../acmetest \
|
cd ../acmetest \
|
||||||
&& ./letest.sh
|
&& ./letest.sh
|
||||||
|
|
||||||
|
|
||||||
|
29
.github/workflows/Ubuntu.yml
vendored
29
.github/workflows/Ubuntu.yml
vendored
@ -14,6 +14,11 @@ on:
|
|||||||
- '*.sh'
|
- '*.sh'
|
||||||
- '.github/workflows/Ubuntu.yml'
|
- '.github/workflows/Ubuntu.yml'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Ubuntu:
|
Ubuntu:
|
||||||
@ -24,7 +29,13 @@ jobs:
|
|||||||
CA_ECDSA: ""
|
CA_ECDSA: ""
|
||||||
CA: ""
|
CA: ""
|
||||||
CA_EMAIL: ""
|
CA_EMAIL: ""
|
||||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
TEST_PREFERRED_CHAIN: (STAGING)
|
||||||
|
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
||||||
|
CA_ECDSA: ""
|
||||||
|
CA: ""
|
||||||
|
CA_EMAIL: ""
|
||||||
|
TEST_PREFERRED_CHAIN: (STAGING)
|
||||||
|
ACME_USE_WGET: 1
|
||||||
- TEST_ACME_Server: "ZeroSSL.com"
|
- TEST_ACME_Server: "ZeroSSL.com"
|
||||||
CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
|
CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
|
||||||
CA: "ZeroSSL RSA Domain Secure Site CA"
|
CA: "ZeroSSL RSA Domain Secure Site CA"
|
||||||
@ -57,10 +68,11 @@ jobs:
|
|||||||
NO_REVOKE: ${{ matrix.NO_REVOKE }}
|
NO_REVOKE: ${{ matrix.NO_REVOKE }}
|
||||||
TEST_IPCERT: ${{ matrix.TEST_IPCERT }}
|
TEST_IPCERT: ${{ matrix.TEST_IPCERT }}
|
||||||
TestingDomain: ${{ matrix.TestingDomain }}
|
TestingDomain: ${{ matrix.TestingDomain }}
|
||||||
|
ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Install tools
|
- name: Install tools
|
||||||
run: sudo apt-get install -y socat
|
run: sudo apt-get install -y socat wget
|
||||||
- name: Start StepCA
|
- name: Start StepCA
|
||||||
if: ${{ matrix.TEST_ACME_Server=='https://localhost:9000/acme/acme/directory' }}
|
if: ${{ matrix.TEST_ACME_Server=='https://localhost:9000/acme/acme/directory' }}
|
||||||
run: |
|
run: |
|
||||||
@ -68,15 +80,20 @@ jobs:
|
|||||||
-p 9000:9000 \
|
-p 9000:9000 \
|
||||||
-e "DOCKER_STEPCA_INIT_NAME=Smallstep" \
|
-e "DOCKER_STEPCA_INIT_NAME=Smallstep" \
|
||||||
-e "DOCKER_STEPCA_INIT_DNS_NAMES=localhost,$(hostname -f)" \
|
-e "DOCKER_STEPCA_INIT_DNS_NAMES=localhost,$(hostname -f)" \
|
||||||
|
-e "DOCKER_STEPCA_INIT_REMOTE_MANAGEMENT=true" \
|
||||||
|
-e "DOCKER_STEPCA_INIT_PASSWORD=test" \
|
||||||
--name stepca \
|
--name stepca \
|
||||||
smallstep/step-ca \
|
smallstep/step-ca:0.23.1
|
||||||
&& sleep 5 && docker exec stepca step ca provisioner add acme --type ACME \
|
|
||||||
|
sleep 5
|
||||||
|
docker exec stepca bash -c "echo test >test" \
|
||||||
|
&& docker exec stepca step ca provisioner add acme --type ACME --admin-subject step --admin-password-file=/home/step/test \
|
||||||
&& docker exec stepca kill -1 1 \
|
&& docker exec stepca kill -1 1 \
|
||||||
&& docker exec stepca cat /home/step/certs/root_ca.crt | sudo bash -c "cat - >>/etc/ssl/certs/ca-certificates.crt"
|
&& docker exec stepca cat /home/step/certs/root_ca.crt | sudo bash -c "cat - >>/etc/ssl/certs/ca-certificates.crt"
|
||||||
- name: Clone acmetest
|
- name: Clone acmetest
|
||||||
run: |
|
run: |
|
||||||
cd .. \
|
cd .. \
|
||||||
&& git clone https://github.com/acmesh-official/acmetest.git \
|
&& git clone --depth=1 https://github.com/acmesh-official/acmetest.git \
|
||||||
&& cp -r acme.sh acmetest/
|
&& cp -r acme.sh acmetest/
|
||||||
- name: Run acmetest
|
- name: Run acmetest
|
||||||
run: |
|
run: |
|
||||||
|
23
.github/workflows/Windows.yml
vendored
23
.github/workflows/Windows.yml
vendored
@ -15,6 +15,11 @@ on:
|
|||||||
- '.github/workflows/Windows.yml'
|
- '.github/workflows/Windows.yml'
|
||||||
|
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Windows:
|
Windows:
|
||||||
strategy:
|
strategy:
|
||||||
@ -24,12 +29,12 @@ jobs:
|
|||||||
CA_ECDSA: ""
|
CA_ECDSA: ""
|
||||||
CA: ""
|
CA: ""
|
||||||
CA_EMAIL: ""
|
CA_EMAIL: ""
|
||||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
TEST_PREFERRED_CHAIN: (STAGING)
|
||||||
- TEST_ACME_Server: "ZeroSSL.com"
|
#- TEST_ACME_Server: "ZeroSSL.com"
|
||||||
CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
|
# CA_ECDSA: "ZeroSSL ECC Domain Secure Site CA"
|
||||||
CA: "ZeroSSL RSA Domain Secure Site CA"
|
# CA: "ZeroSSL RSA Domain Secure Site CA"
|
||||||
CA_EMAIL: "githubtest@acme.sh"
|
# CA_EMAIL: "githubtest@acme.sh"
|
||||||
TEST_PREFERRED_CHAIN: ""
|
# TEST_PREFERRED_CHAIN: ""
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
env:
|
env:
|
||||||
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
|
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
|
||||||
@ -44,7 +49,7 @@ jobs:
|
|||||||
- name: Set git to use LF
|
- name: Set git to use LF
|
||||||
run: |
|
run: |
|
||||||
git config --global core.autocrlf false
|
git config --global core.autocrlf false
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Install cygwin base packages with chocolatey
|
- name: Install cygwin base packages with chocolatey
|
||||||
run: |
|
run: |
|
||||||
choco config get cacheLocation
|
choco config get cacheLocation
|
||||||
@ -52,7 +57,7 @@ jobs:
|
|||||||
shell: cmd
|
shell: cmd
|
||||||
- name: Install cygwin additional packages
|
- name: Install cygwin additional packages
|
||||||
run: |
|
run: |
|
||||||
C:\tools\cygwin\cygwinsetup.exe -qgnNdO -R C:/tools/cygwin -s http://mirrors.kernel.org/sourceware/cygwin/ -P socat,curl,cron,unzip,git,xxd
|
C:\tools\cygwin\cygwinsetup.exe -qgnNdO -R C:/tools/cygwin -s https://mirrors.kernel.org/sourceware/cygwin/ -P socat,curl,cron,unzip,git,xxd
|
||||||
shell: cmd
|
shell: cmd
|
||||||
- name: Set ENV
|
- name: Set ENV
|
||||||
shell: cmd
|
shell: cmd
|
||||||
@ -64,7 +69,7 @@ jobs:
|
|||||||
echo "PATH=%PATH%"
|
echo "PATH=%PATH%"
|
||||||
- name: Clone acmetest
|
- name: Clone acmetest
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||||
- name: Run acmetest
|
- name: Run acmetest
|
||||||
shell: cmd
|
shell: cmd
|
||||||
run: cd ../acmetest && bash.exe -c ./letest.sh
|
run: cd ../acmetest && bash.exe -c ./letest.sh
|
||||||
|
14
.github/workflows/dockerhub.yml
vendored
14
.github/workflows/dockerhub.yml
vendored
@ -11,6 +11,10 @@ on:
|
|||||||
- "Dockerfile"
|
- "Dockerfile"
|
||||||
- '.github/workflows/dockerhub.yml'
|
- '.github/workflows/dockerhub.yml'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
CheckToken:
|
CheckToken:
|
||||||
@ -24,9 +28,9 @@ jobs:
|
|||||||
id: step_one
|
id: step_one
|
||||||
run: |
|
run: |
|
||||||
if [ "$DOCKER_PASSWORD" ] ; then
|
if [ "$DOCKER_PASSWORD" ] ; then
|
||||||
echo "::set-output name=hasToken::true"
|
echo "hasToken=true" >>$GITHUB_OUTPUT
|
||||||
else
|
else
|
||||||
echo "::set-output name=hasToken::false"
|
echo "hasToken=false" >>$GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
- name: Check the value
|
- name: Check the value
|
||||||
run: echo ${{ steps.step_one.outputs.hasToken }}
|
run: echo ${{ steps.step_one.outputs.hasToken }}
|
||||||
@ -37,11 +41,11 @@ jobs:
|
|||||||
if: "contains(needs.CheckToken.outputs.hasToken, 'true')"
|
if: "contains(needs.CheckToken.outputs.hasToken, 'true')"
|
||||||
steps:
|
steps:
|
||||||
- name: checkout code
|
- name: checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v4
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v2
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v1
|
uses: docker/setup-buildx-action@v2
|
||||||
- name: login to docker hub
|
- name: login to docker hub
|
||||||
run: |
|
run: |
|
||||||
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
|
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
|
||||||
|
19
.github/workflows/issue.yml
vendored
Normal file
19
.github/workflows/issue.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
name: "Update issues"
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [opened]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
comment:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/github-script@v6
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
github.rest.issues.createComment({
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
body: "Please upgrade to the latest code and try again first. Maybe it's already fixed. ```acme.sh --upgrade``` If it's still not working, please provide the log with `--debug 2`, otherwise, nobody can help you."
|
||||||
|
|
||||||
|
})
|
30
.github/workflows/pr_dns.yml
vendored
Normal file
30
.github/workflows/pr_dns.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
name: Check dns api
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
paths:
|
||||||
|
- 'dnsapi/*.sh'
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
welcome:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/github-script@v6
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
body: `**Welcome**
|
||||||
|
First thing: don't send PR to the master branch, please send to the dev branch instead.
|
||||||
|
Please make sure you've read our [DNS API Dev Guide](../wiki/DNS-API-Dev-Guide) and [DNS-API-Test](../wiki/DNS-API-Test).
|
||||||
|
Then reply on this message, otherwise, your code will not be reviewed or merged.
|
||||||
|
We look forward to reviewing your Pull request shortly ✨
|
||||||
|
注意: 必须通过了 [DNS-API-Test](../wiki/DNS-API-Test) 才会被 review. 无论是修改, 还是新加的 dns api, 都必须确保通过这个测试.
|
||||||
|
`
|
||||||
|
})
|
||||||
|
|
30
.github/workflows/pr_notify.yml
vendored
Normal file
30
.github/workflows/pr_notify.yml
vendored
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
name: Check dns api
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types:
|
||||||
|
- opened
|
||||||
|
branches:
|
||||||
|
- 'dev'
|
||||||
|
paths:
|
||||||
|
- 'notify/*.sh'
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
welcome:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/github-script@v6
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
body: `**Welcome**
|
||||||
|
Please make sure you've read our [Code-of-conduct](../wiki/Code-of-conduct) and add the usage here: [notify](../wiki/notify).
|
||||||
|
Then reply on this message, otherwise, your code will not be reviewed or merged.
|
||||||
|
We look forward to reviewing your Pull request shortly ✨
|
||||||
|
`
|
||||||
|
})
|
||||||
|
|
11
.github/workflows/shellcheck.yml
vendored
11
.github/workflows/shellcheck.yml
vendored
@ -13,20 +13,25 @@ on:
|
|||||||
- '**.sh'
|
- '**.sh'
|
||||||
- '.github/workflows/shellcheck.yml'
|
- '.github/workflows/shellcheck.yml'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
ShellCheck:
|
ShellCheck:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Install Shellcheck
|
- name: Install Shellcheck
|
||||||
run: sudo apt-get install -y shellcheck
|
run: sudo apt-get install -y shellcheck
|
||||||
- name: DoShellcheck
|
- name: DoShellcheck
|
||||||
run: shellcheck -V && shellcheck -e SC2181 **/*.sh && echo "shellcheck OK"
|
run: shellcheck -V && shellcheck -e SC2181 -e SC2089 **/*.sh && echo "shellcheck OK"
|
||||||
|
|
||||||
shfmt:
|
shfmt:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
- name: Install shfmt
|
- 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
|
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
|
- name: shfmt
|
||||||
|
13
Dockerfile
13
Dockerfile
@ -1,4 +1,4 @@
|
|||||||
FROM alpine:3.15
|
FROM alpine:3.17
|
||||||
|
|
||||||
RUN apk --no-cache add -f \
|
RUN apk --no-cache add -f \
|
||||||
openssl \
|
openssl \
|
||||||
@ -11,7 +11,9 @@ RUN apk --no-cache add -f \
|
|||||||
tzdata \
|
tzdata \
|
||||||
oath-toolkit-oathtool \
|
oath-toolkit-oathtool \
|
||||||
tar \
|
tar \
|
||||||
libidn
|
libidn \
|
||||||
|
jq \
|
||||||
|
cronie
|
||||||
|
|
||||||
ENV LE_CONFIG_HOME /acme.sh
|
ENV LE_CONFIG_HOME /acme.sh
|
||||||
|
|
||||||
@ -24,7 +26,7 @@ COPY ./ /install_acme.sh/
|
|||||||
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 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 /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null##' | crontab -
|
RUN ln -s /root/.acme.sh/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 for verb in help \
|
RUN for verb in help \
|
||||||
version \
|
version \
|
||||||
@ -63,11 +65,10 @@ RUN for verb in help \
|
|||||||
|
|
||||||
RUN printf "%b" '#!'"/usr/bin/env sh\n \
|
RUN printf "%b" '#!'"/usr/bin/env sh\n \
|
||||||
if [ \"\$1\" = \"daemon\" ]; then \n \
|
if [ \"\$1\" = \"daemon\" ]; then \n \
|
||||||
trap \"echo stop && killall crond && exit 0\" SIGTERM SIGINT \n \
|
exec crond -n -s -m off \n \
|
||||||
crond && while true; do sleep 1; done;\n \
|
|
||||||
else \n \
|
else \n \
|
||||||
exec -- \"\$@\"\n \
|
exec -- \"\$@\"\n \
|
||||||
fi" >/entry.sh && chmod +x /entry.sh
|
fi\n" >/entry.sh && chmod +x /entry.sh
|
||||||
|
|
||||||
VOLUME /acme.sh
|
VOLUME /acme.sh
|
||||||
|
|
||||||
|
54
README.md
54
README.md
@ -1,10 +1,14 @@
|
|||||||
# An ACME Shell script: acme.sh
|
# An ACME Shell script: acme.sh
|
||||||
|
|
||||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/FreeBSD.yml)
|
[](https://github.com/acmesh-official/acme.sh/actions/workflows/FreeBSD.yml)
|
||||||
|
[](https://github.com/acmesh-official/acme.sh/actions/workflows/OpenBSD.yml)
|
||||||
|
[](https://github.com/acmesh-official/acme.sh/actions/workflows/NetBSD.yml)
|
||||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/MacOS.yml)
|
[](https://github.com/acmesh-official/acme.sh/actions/workflows/MacOS.yml)
|
||||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Ubuntu.yml)
|
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Ubuntu.yml)
|
||||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Windows.yml)
|
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Windows.yml)
|
||||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Solaris.yml)
|
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Solaris.yml)
|
||||||
|
[](https://github.com/acmesh-official/acme.sh/actions/workflows/DragonFlyBSD.yml)
|
||||||
|
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Omnios.yml)
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||
@ -47,14 +51,12 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
|
|||||||
- [ruby-china.org](https://ruby-china.org/topics/31983)
|
- [ruby-china.org](https://ruby-china.org/topics/31983)
|
||||||
- [Proxmox](https://pve.proxmox.com/wiki/Certificate_Management)
|
- [Proxmox](https://pve.proxmox.com/wiki/Certificate_Management)
|
||||||
- [pfsense](https://github.com/pfsense/FreeBSD-ports/pull/89)
|
- [pfsense](https://github.com/pfsense/FreeBSD-ports/pull/89)
|
||||||
- [webfaction](https://community.webfaction.com/questions/19988/using-letsencrypt)
|
|
||||||
- [Loadbalancer.org](https://www.loadbalancer.org/blog/loadbalancer-org-with-lets-encrypt-quick-and-dirty)
|
- [Loadbalancer.org](https://www.loadbalancer.org/blog/loadbalancer-org-with-lets-encrypt-quick-and-dirty)
|
||||||
- [discourse.org](https://meta.discourse.org/t/setting-up-lets-encrypt/40709)
|
- [discourse.org](https://meta.discourse.org/t/setting-up-lets-encrypt/40709)
|
||||||
- [Centminmod](https://centminmod.com/letsencrypt-acmetool-https.html)
|
- [Centminmod](https://centminmod.com/letsencrypt-acmetool-https.html)
|
||||||
- [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297)
|
- [splynx](https://forum.splynx.com/t/free-ssl-cert-for-splynx-lets-encrypt/297)
|
||||||
- [archlinux](https://www.archlinux.org/packages/community/any/acme.sh)
|
|
||||||
- [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient)
|
- [opnsense.org](https://github.com/opnsense/plugins/tree/master/security/acme-client/src/opnsense/scripts/OPNsense/AcmeClient)
|
||||||
- [CentOS Web Panel](http://centos-webpanel.com/)
|
- [CentOS Web Panel](https://control-webpanel.com)
|
||||||
- [lnmp.org](https://lnmp.org/)
|
- [lnmp.org](https://lnmp.org/)
|
||||||
- [more...](https://github.com/acmesh-official/acme.sh/wiki/Blogs-and-tutorials)
|
- [more...](https://github.com/acmesh-official/acme.sh/wiki/Blogs-and-tutorials)
|
||||||
|
|
||||||
@ -68,21 +70,24 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
|
|||||||
|4|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Solaris.yml)|Solaris
|
|4|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Solaris.yml)|Solaris
|
||||||
|5|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Ubuntu.yml)| Ubuntu
|
|5|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Ubuntu.yml)| Ubuntu
|
||||||
|6|NA|pfsense
|
|6|NA|pfsense
|
||||||
|7|NA|OpenBSD
|
|7|[](https://github.com/acmesh-official/acme.sh/actions/workflows/OpenBSD.yml)|OpenBSD
|
||||||
|8|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)| Debian
|
|8|[](https://github.com/acmesh-official/acme.sh/actions/workflows/NetBSD.yml)|NetBSD
|
||||||
|9|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|CentOS
|
|9|[](https://github.com/acmesh-official/acme.sh/actions/workflows/DragonFlyBSD.yml)|DragonFlyBSD
|
||||||
|10|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|openSUSE
|
|10|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Omnios.yml)|Omnios
|
||||||
|11|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Alpine Linux (with curl)
|
|11|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)| Debian
|
||||||
|12|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Archlinux
|
|12|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|CentOS
|
||||||
|13|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|fedora
|
|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)|Kali Linux
|
|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)|Oracle Linux
|
|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)|Mageia
|
|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)|Gentoo Linux
|
|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)|ClearLinux
|
|18|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Oracle Linux
|
||||||
|19|-----| Cloud Linux https://github.com/acmesh-official/acme.sh/issues/111
|
|19|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Mageia
|
||||||
|20|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/acmesh-official/acme.sh/wiki/How-to-run-on-OpenWRT)
|
|10|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Gentoo Linux
|
||||||
|21|[](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)
|
|11|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|ClearLinux
|
||||||
|
|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)
|
||||||
|
|
||||||
|
|
||||||
Check our [testing project](https://github.com/acmesh-official/acmetest):
|
Check our [testing project](https://github.com/acmesh-official/acmetest):
|
||||||
@ -95,6 +100,7 @@ https://github.com/acmesh-official/acmetest
|
|||||||
- Letsencrypt.org CA
|
- Letsencrypt.org CA
|
||||||
- [BuyPass.com CA](https://github.com/acmesh-official/acme.sh/wiki/BuyPass.com-CA)
|
- [BuyPass.com CA](https://github.com/acmesh-official/acme.sh/wiki/BuyPass.com-CA)
|
||||||
- [SSL.com CA](https://github.com/acmesh-official/acme.sh/wiki/SSL.com-CA)
|
- [SSL.com CA](https://github.com/acmesh-official/acme.sh/wiki/SSL.com-CA)
|
||||||
|
- [Google.com Public CA](https://github.com/acmesh-official/acme.sh/wiki/Google-Public-CA)
|
||||||
- [Pebble strict Mode](https://github.com/letsencrypt/pebble)
|
- [Pebble strict Mode](https://github.com/letsencrypt/pebble)
|
||||||
- Any other [RFC8555](https://tools.ietf.org/html/rfc8555)-compliant CA
|
- Any other [RFC8555](https://tools.ietf.org/html/rfc8555)-compliant CA
|
||||||
|
|
||||||
@ -354,10 +360,6 @@ Ok, it's done.
|
|||||||
|
|
||||||
# 10. Issue ECC certificates
|
# 10. Issue ECC certificates
|
||||||
|
|
||||||
`Let's Encrypt` can now issue **ECDSA** certificates.
|
|
||||||
|
|
||||||
And we support them too!
|
|
||||||
|
|
||||||
Just set the `keylength` parameter with a prefix `ec-`.
|
Just set the `keylength` parameter with a prefix `ec-`.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
@ -378,10 +380,12 @@ Please look at the `keylength` parameter above.
|
|||||||
|
|
||||||
Valid values are:
|
Valid values are:
|
||||||
|
|
||||||
1. **ec-256 (prime256v1, "ECDSA P-256")**
|
1. **ec-256 (prime256v1, "ECDSA P-256", which is the default key type)**
|
||||||
2. **ec-384 (secp384r1, "ECDSA P-384")**
|
2. **ec-384 (secp384r1, "ECDSA P-384")**
|
||||||
3. **ec-521 (secp521r1, "ECDSA P-521", which is not supported by Let's Encrypt yet.)**
|
3. **ec-521 (secp521r1, "ECDSA P-521", which is not supported by Let's Encrypt yet.)**
|
||||||
|
4. **2048 (RSA2048)**
|
||||||
|
5. **3072 (RSA3072)**
|
||||||
|
6. **4096 (RSA4096)**
|
||||||
|
|
||||||
|
|
||||||
# 11. Issue Wildcard certificates
|
# 11. Issue Wildcard certificates
|
||||||
@ -502,6 +506,8 @@ Support this project with your organization. Your logo will show up here with a
|
|||||||
<a href="https://opencollective.com/acmesh/organization/8/website"><img src="https://opencollective.com/acmesh/organization/8/avatar.svg"></a>
|
<a href="https://opencollective.com/acmesh/organization/8/website"><img src="https://opencollective.com/acmesh/organization/8/avatar.svg"></a>
|
||||||
<a href="https://opencollective.com/acmesh/organization/9/website"><img src="https://opencollective.com/acmesh/organization/9/avatar.svg"></a>
|
<a href="https://opencollective.com/acmesh/organization/9/website"><img src="https://opencollective.com/acmesh/organization/9/avatar.svg"></a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# 19. License & Others
|
# 19. License & Others
|
||||||
|
|
||||||
License is GPLv3
|
License is GPLv3
|
||||||
|
@ -3,18 +3,29 @@
|
|||||||
# Uses command line uapi. --user option is needed only if run as root.
|
# Uses command line uapi. --user option is needed only if run as root.
|
||||||
# Returns 0 when success.
|
# Returns 0 when success.
|
||||||
#
|
#
|
||||||
|
# Configure DEPLOY_CPANEL_AUTO_<...> options to enable or restrict automatic
|
||||||
|
# detection of deployment targets through UAPI (if not set, defaults below are used.)
|
||||||
|
# - ENABLED : 'true' for multi-site / wildcard capability; otherwise single-site mode.
|
||||||
|
# - NOMATCH : 'true' to allow deployment to sites that do not match the certificate.
|
||||||
|
# - INCLUDE : Comma-separated list - sites must match this field.
|
||||||
|
# - EXCLUDE : Comma-separated list - sites must NOT match this field.
|
||||||
|
# INCLUDE/EXCLUDE both support non-lexical, glob-style matches using '*'
|
||||||
|
#
|
||||||
# Please note that I am no longer using Github. If you want to report an issue
|
# Please note that I am no longer using Github. If you want to report an issue
|
||||||
# or contact me, visit https://forum.webseodesigners.com/web-design-seo-and-hosting-f16/
|
# or contact me, visit https://forum.webseodesigners.com/web-design-seo-and-hosting-f16/
|
||||||
#
|
#
|
||||||
# Written by Santeri Kannisto <santeri.kannisto@webseodesigners.com>
|
# Written by Santeri Kannisto <santeri.kannisto@webseodesigners.com>
|
||||||
# Public domain, 2017-2018
|
# Public domain, 2017-2018
|
||||||
|
#
|
||||||
#export DEPLOY_CPANEL_USER=myusername
|
# export DEPLOY_CPANEL_USER=myusername
|
||||||
|
# export DEPLOY_CPANEL_AUTO_ENABLED='true'
|
||||||
|
# export DEPLOY_CPANEL_AUTO_NOMATCH='false'
|
||||||
|
# export DEPLOY_CPANEL_AUTO_INCLUDE='*'
|
||||||
|
# export DEPLOY_CPANEL_AUTO_EXCLUDE=''
|
||||||
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
#domain keyfile certfile cafile fullchain
|
#domain keyfile certfile cafile fullchain
|
||||||
|
|
||||||
cpanel_uapi_deploy() {
|
cpanel_uapi_deploy() {
|
||||||
_cdomain="$1"
|
_cdomain="$1"
|
||||||
_ckey="$2"
|
_ckey="$2"
|
||||||
@ -22,6 +33,9 @@ cpanel_uapi_deploy() {
|
|||||||
_cca="$4"
|
_cca="$4"
|
||||||
_cfullchain="$5"
|
_cfullchain="$5"
|
||||||
|
|
||||||
|
# re-declare vars inherited from acme.sh but not passed to make ShellCheck happy
|
||||||
|
: "${Le_Alt:=""}"
|
||||||
|
|
||||||
_debug _cdomain "$_cdomain"
|
_debug _cdomain "$_cdomain"
|
||||||
_debug _ckey "$_ckey"
|
_debug _ckey "$_ckey"
|
||||||
_debug _ccert "$_ccert"
|
_debug _ccert "$_ccert"
|
||||||
@ -32,25 +46,120 @@ cpanel_uapi_deploy() {
|
|||||||
_err "The command uapi is not found."
|
_err "The command uapi is not found."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# declare useful constants
|
||||||
|
uapi_error_response='status: 0'
|
||||||
|
|
||||||
# read cert and key files and urlencode both
|
# read cert and key files and urlencode both
|
||||||
_cert=$(_url_encode <"$_ccert")
|
_cert=$(_url_encode <"$_ccert")
|
||||||
_key=$(_url_encode <"$_ckey")
|
_key=$(_url_encode <"$_ckey")
|
||||||
|
|
||||||
_debug _cert "$_cert"
|
_debug2 _cert "$_cert"
|
||||||
_debug _key "$_key"
|
_debug2 _key "$_key"
|
||||||
|
|
||||||
if [ "$(id -u)" = 0 ]; then
|
if [ "$(id -u)" = 0 ]; then
|
||||||
if [ -z "$DEPLOY_CPANEL_USER" ]; then
|
_getdeployconf DEPLOY_CPANEL_USER
|
||||||
|
# fallback to _readdomainconf for old installs
|
||||||
|
if [ -z "${DEPLOY_CPANEL_USER:=$(_readdomainconf DEPLOY_CPANEL_USER)}" ]; then
|
||||||
_err "It seems that you are root, please define the target user name: export DEPLOY_CPANEL_USER=username"
|
_err "It seems that you are root, please define the target user name: export DEPLOY_CPANEL_USER=username"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_savedomainconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER"
|
_debug DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER"
|
||||||
_response=$(uapi --user="$DEPLOY_CPANEL_USER" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
_savedeployconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER"
|
||||||
|
|
||||||
|
_uapi_user="$DEPLOY_CPANEL_USER"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Load all AUTO envars and set defaults - see above for usage
|
||||||
|
__cpanel_initautoparam ENABLED 'true'
|
||||||
|
__cpanel_initautoparam NOMATCH 'false'
|
||||||
|
__cpanel_initautoparam INCLUDE '*'
|
||||||
|
__cpanel_initautoparam EXCLUDE ''
|
||||||
|
|
||||||
|
# Auto mode
|
||||||
|
if [ "$DEPLOY_CPANEL_AUTO_ENABLED" = "true" ]; then
|
||||||
|
# call API for site config
|
||||||
|
_response=$(uapi DomainInfo list_domains)
|
||||||
|
# exit if error in response
|
||||||
|
if [ -z "$_response" ] || [ "${_response#*"$uapi_error_response"}" != "$_response" ]; then
|
||||||
|
_err "Error in deploying certificate - cannot retrieve sitelist:"
|
||||||
|
_err "\n$_response"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# parse response to create site list
|
||||||
|
sitelist=$(__cpanel_parse_response "$_response")
|
||||||
|
_debug "UAPI sites found: $sitelist"
|
||||||
|
|
||||||
|
# filter sitelist using configured domains
|
||||||
|
# skip if NOMATCH is "true"
|
||||||
|
if [ "$DEPLOY_CPANEL_AUTO_NOMATCH" = "true" ]; then
|
||||||
|
_debug "DEPLOY_CPANEL_AUTO_NOMATCH is true"
|
||||||
|
_info "UAPI nomatch mode is enabled - Will not validate sites are valid for the certificate"
|
||||||
|
else
|
||||||
|
_debug "DEPLOY_CPANEL_AUTO_NOMATCH is false"
|
||||||
|
d="$(echo "${Le_Alt}," | sed -e "s/^$_cdomain,//" -e "s/,$_cdomain,/,/")"
|
||||||
|
d="$(echo "$_cdomain,$d" | tr ',' '\n' | sed -e 's/\./\\./g' -e 's/\*/\[\^\.\]\*/g')"
|
||||||
|
sitelist="$(echo "$sitelist" | grep -ix "$d")"
|
||||||
|
_debug2 "Matched UAPI sites: $sitelist"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# filter sites that do not match $DEPLOY_CPANEL_AUTO_INCLUDE
|
||||||
|
_info "Applying sitelist filter DEPLOY_CPANEL_AUTO_INCLUDE: $DEPLOY_CPANEL_AUTO_INCLUDE"
|
||||||
|
sitelist="$(echo "$sitelist" | grep -ix "$(echo "$DEPLOY_CPANEL_AUTO_INCLUDE" | tr ',' '\n' | sed -e 's/\./\\./g' -e 's/\*/\.\*/g')")"
|
||||||
|
_debug2 "Remaining sites: $sitelist"
|
||||||
|
|
||||||
|
# filter sites that match $DEPLOY_CPANEL_AUTO_EXCLUDE
|
||||||
|
_info "Applying sitelist filter DEPLOY_CPANEL_AUTO_EXCLUDE: $DEPLOY_CPANEL_AUTO_EXCLUDE"
|
||||||
|
sitelist="$(echo "$sitelist" | grep -vix "$(echo "$DEPLOY_CPANEL_AUTO_EXCLUDE" | tr ',' '\n' | sed -e 's/\./\\./g' -e 's/\*/\.\*/g')")"
|
||||||
|
_debug2 "Remaining sites: $sitelist"
|
||||||
|
|
||||||
|
# counter for success / failure check
|
||||||
|
successes=0
|
||||||
|
if [ -n "$sitelist" ]; then
|
||||||
|
sitetotal="$(echo "$sitelist" | wc -l)"
|
||||||
|
_debug "$sitetotal sites to deploy"
|
||||||
|
else
|
||||||
|
sitetotal=0
|
||||||
|
_debug "No sites to deploy"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# for each site: call uapi to publish cert and log result. Only return failure if all fail
|
||||||
|
for site in $sitelist; do
|
||||||
|
# call uapi to publish cert, check response for errors and log them.
|
||||||
|
if [ -n "$_uapi_user" ]; then
|
||||||
|
_response=$(uapi --user="$_uapi_user" SSL install_ssl domain="$site" cert="$_cert" key="$_key")
|
||||||
|
else
|
||||||
|
_response=$(uapi SSL install_ssl domain="$site" cert="$_cert" key="$_key")
|
||||||
|
fi
|
||||||
|
if [ "${_response#*"$uapi_error_response"}" != "$_response" ]; then
|
||||||
|
_err "Error in deploying certificate to $site:"
|
||||||
|
_err "$_response"
|
||||||
|
else
|
||||||
|
successes=$((successes + 1))
|
||||||
|
_debug "$_response"
|
||||||
|
_info "Succcessfully deployed to $site"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# Raise error if all updates fail
|
||||||
|
if [ "$sitetotal" -gt 0 ] && [ "$successes" -eq 0 ]; then
|
||||||
|
_err "Could not deploy to any of $sitetotal sites via UAPI"
|
||||||
|
_debug "successes: $successes, sitetotal: $sitetotal"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info "Successfully deployed certificate to $successes of $sitetotal sites via UAPI"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
# "classic" mode - will only try to deploy to the primary domain; will not check UAPI first
|
||||||
|
if [ -n "$_uapi_user" ]; then
|
||||||
|
_response=$(uapi --user="$_uapi_user" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
||||||
else
|
else
|
||||||
_response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
_response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
||||||
fi
|
fi
|
||||||
error_response="status: 0"
|
|
||||||
if test "${_response#*$error_response}" != "$_response"; then
|
if [ "${_response#*"$uapi_error_response"}" != "$_response" ]; then
|
||||||
_err "Error in deploying certificate:"
|
_err "Error in deploying certificate:"
|
||||||
_err "$_response"
|
_err "$_response"
|
||||||
return 1
|
return 1
|
||||||
@ -59,4 +168,44 @@ cpanel_uapi_deploy() {
|
|||||||
_debug response "$_response"
|
_debug response "$_response"
|
||||||
_info "Certificate successfully deployed"
|
_info "Certificate successfully deployed"
|
||||||
return 0
|
return 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
######## Private functions #####################
|
||||||
|
|
||||||
|
# Internal utility to process YML from UAPI - looks at main_domain, sub_domains, addon domains and parked domains
|
||||||
|
#[response]
|
||||||
|
__cpanel_parse_response() {
|
||||||
|
if [ $# -gt 0 ]; then resp="$*"; else resp="$(cat)"; fi
|
||||||
|
|
||||||
|
echo "$resp" |
|
||||||
|
sed -En \
|
||||||
|
-e 's/\r$//' \
|
||||||
|
-e 's/^( *)([_.[:alnum:]]+) *: *(.*)/\1,\2,\3/p' \
|
||||||
|
-e 's/^( *)- (.*)/\1,-,\2/p' |
|
||||||
|
awk -F, '{
|
||||||
|
level = length($1)/2;
|
||||||
|
section[level] = $2;
|
||||||
|
for (i in section) {if (i > level) {delete section[i]}}
|
||||||
|
if (length($3) > 0) {
|
||||||
|
prefix="";
|
||||||
|
for (i=0; i < level; i++)
|
||||||
|
{ prefix = (prefix)(section[i])("/") }
|
||||||
|
printf("%s%s=%s\n", prefix, $2, $3);
|
||||||
|
}
|
||||||
|
}' |
|
||||||
|
sed -En -e 's/^result\/data\/(main_domain|sub_domains\/-|addon_domains\/-|parked_domains\/-)=(.*)$/\2/p'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Load parameter by prefix+name - fallback to default if not set, and save to config
|
||||||
|
#pname pdefault
|
||||||
|
__cpanel_initautoparam() {
|
||||||
|
pname="$1"
|
||||||
|
pdefault="$2"
|
||||||
|
pkey="DEPLOY_CPANEL_AUTO_$pname"
|
||||||
|
|
||||||
|
_getdeployconf "$pkey"
|
||||||
|
[ -n "$(eval echo "\"\$$pkey\"")" ] || eval "$pkey=\"$pdefault\""
|
||||||
|
_debug2 "$pkey" "$(eval echo "\"\$$pkey\"")"
|
||||||
|
_savedeployconf "$pkey" "$(eval echo "\"\$$pkey\"")"
|
||||||
}
|
}
|
||||||
|
@ -273,16 +273,27 @@ _check_curl_version() {
|
|||||||
_minor="$(_getfield "$_cversion" 2 '.')"
|
_minor="$(_getfield "$_cversion" 2 '.')"
|
||||||
_debug2 "_minor" "$_minor"
|
_debug2 "_minor" "$_minor"
|
||||||
|
|
||||||
if [ "$_major$_minor" -lt "740" ]; then
|
if [ "$_major" -ge "8" ]; then
|
||||||
|
#ok
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [ "$_major" = "7" ]; then
|
||||||
|
if [ "$_minor" -lt "40" ]; then
|
||||||
_err "curl v$_cversion doesn't support unit socket"
|
_err "curl v$_cversion doesn't support unit socket"
|
||||||
_err "Please upgrade to curl 7.40 or later."
|
_err "Please upgrade to curl 7.40 or later."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
if [ "$_major$_minor" -lt "750" ]; then
|
if [ "$_minor" -lt "50" ]; then
|
||||||
_debug "Use short host name"
|
_debug "Use short host name"
|
||||||
export _CURL_NO_HOST=1
|
export _CURL_NO_HOST=1
|
||||||
else
|
else
|
||||||
export _CURL_NO_HOST=
|
export _CURL_NO_HOST=
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
|
else
|
||||||
|
_err "curl v$_cversion doesn't support unit socket"
|
||||||
|
_err "Please upgrade to curl 7.40 or later."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
# Here is the script to deploy the cert to G-Core CDN service (https://gcorelabs.com/ru/) using the G-Core Labs API (https://docs.gcorelabs.com/cdn/).
|
# Here is the script to deploy the cert to G-Core CDN service (https://gcore.com/) using the G-Core Labs API (https://apidocs.gcore.com/cdn).
|
||||||
# Returns 0 when success.
|
# Returns 0 when success.
|
||||||
#
|
#
|
||||||
# Written by temoffey <temofffey@gmail.com>
|
# Written by temoffey <temofffey@gmail.com>
|
||||||
# Public domain, 2019
|
# Public domain, 2019
|
||||||
|
# Update by DreamOfIce <admin@dreamofice.cn> in 2023
|
||||||
|
|
||||||
#export DEPLOY_GCORE_CDN_USERNAME=myusername
|
#export DEPLOY_GCORE_CDN_USERNAME=myusername
|
||||||
#export DEPLOY_GCORE_CDN_PASSWORD=mypassword
|
#export DEPLOY_GCORE_CDN_PASSWORD=mypassword
|
||||||
@ -56,7 +57,7 @@ gcore_cdn_deploy() {
|
|||||||
_request="{\"username\":\"$Le_Deploy_gcore_cdn_username\",\"password\":\"$Le_Deploy_gcore_cdn_password\"}"
|
_request="{\"username\":\"$Le_Deploy_gcore_cdn_username\",\"password\":\"$Le_Deploy_gcore_cdn_password\"}"
|
||||||
_debug _request "$_request"
|
_debug _request "$_request"
|
||||||
export _H1="Content-Type:application/json"
|
export _H1="Content-Type:application/json"
|
||||||
_response=$(_post "$_request" "https://api.gcdn.co/auth/jwt/login")
|
_response=$(_post "$_request" "https://api.gcore.com/auth/jwt/login")
|
||||||
_debug _response "$_response"
|
_debug _response "$_response"
|
||||||
_regex=".*\"access\":\"\([-._0-9A-Za-z]*\)\".*$"
|
_regex=".*\"access\":\"\([-._0-9A-Za-z]*\)\".*$"
|
||||||
_debug _regex "$_regex"
|
_debug _regex "$_regex"
|
||||||
@ -69,8 +70,8 @@ gcore_cdn_deploy() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
_info "Find CDN resource with cname $_cdomain"
|
_info "Find CDN resource with cname $_cdomain"
|
||||||
export _H2="Authorization:Token $_token"
|
export _H2="Authorization:Bearer $_token"
|
||||||
_response=$(_get "https://api.gcdn.co/resources")
|
_response=$(_get "https://api.gcore.com/cdn/resources")
|
||||||
_debug _response "$_response"
|
_debug _response "$_response"
|
||||||
_regex="\"primary_resource\":null},"
|
_regex="\"primary_resource\":null},"
|
||||||
_debug _regex "$_regex"
|
_debug _regex "$_regex"
|
||||||
@ -102,7 +103,7 @@ gcore_cdn_deploy() {
|
|||||||
_date=$(date "+%d.%m.%Y %H:%M:%S")
|
_date=$(date "+%d.%m.%Y %H:%M:%S")
|
||||||
_request="{\"name\":\"$_cdomain ($_date)\",\"sslCertificate\":\"$_fullchain\",\"sslPrivateKey\":\"$_key\"}"
|
_request="{\"name\":\"$_cdomain ($_date)\",\"sslCertificate\":\"$_fullchain\",\"sslPrivateKey\":\"$_key\"}"
|
||||||
_debug _request "$_request"
|
_debug _request "$_request"
|
||||||
_response=$(_post "$_request" "https://api.gcdn.co/sslData")
|
_response=$(_post "$_request" "https://api.gcore.com/cdn/sslData")
|
||||||
_debug _response "$_response"
|
_debug _response "$_response"
|
||||||
_regex=".*\"id\":\([0-9]*\).*$"
|
_regex=".*\"id\":\([0-9]*\).*$"
|
||||||
_debug _regex "$_regex"
|
_debug _regex "$_regex"
|
||||||
@ -117,7 +118,7 @@ gcore_cdn_deploy() {
|
|||||||
_info "Update CDN resource"
|
_info "Update CDN resource"
|
||||||
_request="{\"originGroup\":$_originGroup,\"sslData\":$_sslDataAdd}"
|
_request="{\"originGroup\":$_originGroup,\"sslData\":$_sslDataAdd}"
|
||||||
_debug _request "$_request"
|
_debug _request "$_request"
|
||||||
_response=$(_post "$_request" "https://api.gcdn.co/resources/$_resourceId" '' "PUT")
|
_response=$(_post "$_request" "https://api.gcore.com/cdn/resources/$_resourceId" '' "PUT")
|
||||||
_debug _response "$_response"
|
_debug _response "$_response"
|
||||||
_regex=".*\"sslData\":\([0-9]*\).*$"
|
_regex=".*\"sslData\":\([0-9]*\).*$"
|
||||||
_debug _regex "$_regex"
|
_debug _regex "$_regex"
|
||||||
@ -133,7 +134,7 @@ gcore_cdn_deploy() {
|
|||||||
_info "Not found old SSL certificate"
|
_info "Not found old SSL certificate"
|
||||||
else
|
else
|
||||||
_info "Delete old SSL certificate"
|
_info "Delete old SSL certificate"
|
||||||
_response=$(_post '' "https://api.gcdn.co/sslData/$_sslDataOld" '' "DELETE")
|
_response=$(_post '' "https://api.gcore.com/cdn/sslData/$_sslDataOld" '' "DELETE")
|
||||||
_debug _response "$_response"
|
_debug _response "$_response"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ gitlab_deploy() {
|
|||||||
|
|
||||||
error_response="error"
|
error_response="error"
|
||||||
|
|
||||||
if test "${_response#*$error_response}" != "$_response"; then
|
if test "${_response#*"$error_response"}" != "$_response"; then
|
||||||
_err "Error in deploying certificate:"
|
_err "Error in deploying certificate:"
|
||||||
_err "$_response"
|
_err "$_response"
|
||||||
return 1
|
return 1
|
||||||
|
@ -36,6 +36,19 @@
|
|||||||
# Note: This functionality requires HAProxy was compiled against
|
# Note: This functionality requires HAProxy was compiled against
|
||||||
# a version of OpenSSL that supports this.
|
# a version of OpenSSL that supports this.
|
||||||
#
|
#
|
||||||
|
# export DEPLOY_HAPROXY_HOT_UPDATE="yes"
|
||||||
|
# export DEPLOY_HAPROXY_STATS_SOCKET="UNIX:/run/haproxy/admin.sock"
|
||||||
|
#
|
||||||
|
# OPTIONAL: Deploy the certificate over the HAProxy stats socket without
|
||||||
|
# needing to reload HAProxy. Default is "no".
|
||||||
|
#
|
||||||
|
# Require the socat binary. DEPLOY_HAPROXY_STATS_SOCKET variable uses the socat
|
||||||
|
# address format.
|
||||||
|
#
|
||||||
|
# export DEPLOY_HAPROXY_MASTER_CLI="UNIX:/run/haproxy-master.sock"
|
||||||
|
#
|
||||||
|
# OPTIONAL: To use the master CLI with DEPLOY_HAPROXY_HOT_UPDATE="yes" instead
|
||||||
|
# of a stats socket, use this variable.
|
||||||
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
@ -46,6 +59,7 @@ haproxy_deploy() {
|
|||||||
_ccert="$3"
|
_ccert="$3"
|
||||||
_cca="$4"
|
_cca="$4"
|
||||||
_cfullchain="$5"
|
_cfullchain="$5"
|
||||||
|
_cmdpfx=""
|
||||||
|
|
||||||
# Some defaults
|
# Some defaults
|
||||||
DEPLOY_HAPROXY_PEM_PATH_DEFAULT="/etc/haproxy"
|
DEPLOY_HAPROXY_PEM_PATH_DEFAULT="/etc/haproxy"
|
||||||
@ -53,6 +67,8 @@ haproxy_deploy() {
|
|||||||
DEPLOY_HAPROXY_BUNDLE_DEFAULT="no"
|
DEPLOY_HAPROXY_BUNDLE_DEFAULT="no"
|
||||||
DEPLOY_HAPROXY_ISSUER_DEFAULT="no"
|
DEPLOY_HAPROXY_ISSUER_DEFAULT="no"
|
||||||
DEPLOY_HAPROXY_RELOAD_DEFAULT="true"
|
DEPLOY_HAPROXY_RELOAD_DEFAULT="true"
|
||||||
|
DEPLOY_HAPROXY_HOT_UPDATE_DEFAULT="no"
|
||||||
|
DEPLOY_HAPROXY_STATS_SOCKET_DEFAULT="UNIX:/run/haproxy/admin.sock"
|
||||||
|
|
||||||
_debug _cdomain "${_cdomain}"
|
_debug _cdomain "${_cdomain}"
|
||||||
_debug _ckey "${_ckey}"
|
_debug _ckey "${_ckey}"
|
||||||
@ -86,6 +102,11 @@ haproxy_deploy() {
|
|||||||
_savedomainconf Le_Deploy_haproxy_pem_name "${Le_Deploy_haproxy_pem_name}"
|
_savedomainconf Le_Deploy_haproxy_pem_name "${Le_Deploy_haproxy_pem_name}"
|
||||||
elif [ -z "${Le_Deploy_haproxy_pem_name}" ]; then
|
elif [ -z "${Le_Deploy_haproxy_pem_name}" ]; then
|
||||||
Le_Deploy_haproxy_pem_name="${DEPLOY_HAPROXY_PEM_NAME_DEFAULT}"
|
Le_Deploy_haproxy_pem_name="${DEPLOY_HAPROXY_PEM_NAME_DEFAULT}"
|
||||||
|
# We better not have '*' as the first character
|
||||||
|
if [ "${Le_Deploy_haproxy_pem_name%%"${Le_Deploy_haproxy_pem_name#?}"}" = '*' ]; then
|
||||||
|
# removes the first characters and add a _ instead
|
||||||
|
Le_Deploy_haproxy_pem_name="_${Le_Deploy_haproxy_pem_name#?}"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# BUNDLE is optional. If not provided then assume "${DEPLOY_HAPROXY_BUNDLE_DEFAULT}"
|
# BUNDLE is optional. If not provided then assume "${DEPLOY_HAPROXY_BUNDLE_DEFAULT}"
|
||||||
@ -118,6 +139,36 @@ haproxy_deploy() {
|
|||||||
Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD_DEFAULT}"
|
Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD_DEFAULT}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# HOT_UPDATE is optional. If not provided then assume "${DEPLOY_HAPROXY_HOT_UPDATE_DEFAULT}"
|
||||||
|
_getdeployconf DEPLOY_HAPROXY_HOT_UPDATE
|
||||||
|
_debug2 DEPLOY_HAPROXY_HOT_UPDATE "${DEPLOY_HAPROXY_HOT_UPDATE}"
|
||||||
|
if [ -n "${DEPLOY_HAPROXY_HOT_UPDATE}" ]; then
|
||||||
|
Le_Deploy_haproxy_hot_update="${DEPLOY_HAPROXY_HOT_UPDATE}"
|
||||||
|
_savedomainconf Le_Deploy_haproxy_hot_update "${Le_Deploy_haproxy_hot_update}"
|
||||||
|
elif [ -z "${Le_Deploy_haproxy_hot_update}" ]; then
|
||||||
|
Le_Deploy_haproxy_hot_update="${DEPLOY_HAPROXY_HOT_UPDATE_DEFAULT}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# STATS_SOCKET is optional. If not provided then assume "${DEPLOY_HAPROXY_STATS_SOCKET_DEFAULT}"
|
||||||
|
_getdeployconf DEPLOY_HAPROXY_STATS_SOCKET
|
||||||
|
_debug2 DEPLOY_HAPROXY_STATS_SOCKET "${DEPLOY_HAPROXY_STATS_SOCKET}"
|
||||||
|
if [ -n "${DEPLOY_HAPROXY_STATS_SOCKET}" ]; then
|
||||||
|
Le_Deploy_haproxy_stats_socket="${DEPLOY_HAPROXY_STATS_SOCKET}"
|
||||||
|
_savedomainconf Le_Deploy_haproxy_stats_socket "${Le_Deploy_haproxy_stats_socket}"
|
||||||
|
elif [ -z "${Le_Deploy_haproxy_stats_socket}" ]; then
|
||||||
|
Le_Deploy_haproxy_stats_socket="${DEPLOY_HAPROXY_STATS_SOCKET_DEFAULT}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# MASTER_CLI is optional. No defaults are used. When the master CLI is used,
|
||||||
|
# all commands are sent with a prefix.
|
||||||
|
_getdeployconf DEPLOY_HAPROXY_MASTER_CLI
|
||||||
|
_debug2 DEPLOY_HAPROXY_MASTER_CLI "${DEPLOY_HAPROXY_MASTER_CLI}"
|
||||||
|
if [ -n "${DEPLOY_HAPROXY_MASTER_CLI}" ]; then
|
||||||
|
Le_Deploy_haproxy_stats_socket="${DEPLOY_HAPROXY_MASTER_CLI}"
|
||||||
|
_savedomainconf Le_Deploy_haproxy_stats_socket "${Le_Deploy_haproxy_stats_socket}"
|
||||||
|
_cmdpfx="@1 " # command prefix used for master CLI only.
|
||||||
|
fi
|
||||||
|
|
||||||
# Set the suffix depending if we are creating a bundle or not
|
# Set the suffix depending if we are creating a bundle or not
|
||||||
if [ "${Le_Deploy_haproxy_bundle}" = "yes" ]; then
|
if [ "${Le_Deploy_haproxy_bundle}" = "yes" ]; then
|
||||||
_info "Bundle creation requested"
|
_info "Bundle creation requested"
|
||||||
@ -142,12 +193,13 @@ haproxy_deploy() {
|
|||||||
_issuer="${_pem}.issuer"
|
_issuer="${_pem}.issuer"
|
||||||
_ocsp="${_pem}.ocsp"
|
_ocsp="${_pem}.ocsp"
|
||||||
_reload="${Le_Deploy_haproxy_reload}"
|
_reload="${Le_Deploy_haproxy_reload}"
|
||||||
|
_statssock="${Le_Deploy_haproxy_stats_socket}"
|
||||||
|
|
||||||
_info "Deploying PEM file"
|
_info "Deploying PEM file"
|
||||||
# Create a temporary PEM file
|
# Create a temporary PEM file
|
||||||
_temppem="$(_mktemp)"
|
_temppem="$(_mktemp)"
|
||||||
_debug _temppem "${_temppem}"
|
_debug _temppem "${_temppem}"
|
||||||
cat "${_ckey}" "${_ccert}" "${_cca}" >"${_temppem}"
|
cat "${_ccert}" "${_cca}" "${_ckey}" | grep . >"${_temppem}"
|
||||||
_ret="$?"
|
_ret="$?"
|
||||||
|
|
||||||
# Check that we could create the temporary file
|
# Check that we could create the temporary file
|
||||||
@ -265,6 +317,76 @@ haproxy_deploy() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "${Le_Deploy_haproxy_hot_update}" = "yes" ]; then
|
||||||
|
# set the socket name for messages
|
||||||
|
if [ -n "${_cmdpfx}" ]; then
|
||||||
|
_socketname="master CLI"
|
||||||
|
else
|
||||||
|
_socketname="stats socket"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Update certificate over HAProxy stats socket or master CLI.
|
||||||
|
if _exists socat; then
|
||||||
|
# look for the certificate on the stats socket, to chose between updating or creating one
|
||||||
|
_socat_cert_cmd="echo '${_cmdpfx}show ssl cert' | socat '${_statssock}' - | grep -q '^${_pem}$'"
|
||||||
|
_debug _socat_cert_cmd "${_socat_cert_cmd}"
|
||||||
|
eval "${_socat_cert_cmd}"
|
||||||
|
_ret=$?
|
||||||
|
if [ "${_ret}" != "0" ]; then
|
||||||
|
_newcert="1"
|
||||||
|
_info "Creating new certificate '${_pem}' over HAProxy ${_socketname}."
|
||||||
|
# certificate wasn't found, it's a new one. We should check if the crt-list exists and creates/inserts the certificate.
|
||||||
|
_socat_crtlist_show_cmd="echo '${_cmdpfx}show ssl crt-list' | socat '${_statssock}' - | grep -q '^${Le_Deploy_haproxy_pem_path}$'"
|
||||||
|
_debug _socat_crtlist_show_cmd "${_socat_crtlist_show_cmd}"
|
||||||
|
eval "${_socat_crtlist_show_cmd}"
|
||||||
|
_ret=$?
|
||||||
|
if [ "${_ret}" != "0" ]; then
|
||||||
|
_err "Couldn't find '${Le_Deploy_haproxy_pem_path}' in haproxy 'show ssl crt-list'"
|
||||||
|
return "${_ret}"
|
||||||
|
fi
|
||||||
|
# create a new certificate
|
||||||
|
_socat_new_cmd="echo '${_cmdpfx}new ssl cert ${_pem}' | socat '${_statssock}' - | grep -q 'New empty'"
|
||||||
|
_debug _socat_new_cmd "${_socat_new_cmd}"
|
||||||
|
eval "${_socat_new_cmd}"
|
||||||
|
_ret=$?
|
||||||
|
if [ "${_ret}" != "0" ]; then
|
||||||
|
_err "Couldn't create '${_pem}' in haproxy"
|
||||||
|
return "${_ret}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
_info "Update existing certificate '${_pem}' over HAProxy ${_socketname}."
|
||||||
|
fi
|
||||||
|
_socat_cert_set_cmd="echo -e '${_cmdpfx}set ssl cert ${_pem} <<\n$(cat "${_pem}")\n' | socat '${_statssock}' - | grep -q 'Transaction created'"
|
||||||
|
_debug _socat_cert_set_cmd "${_socat_cert_set_cmd}"
|
||||||
|
eval "${_socat_cert_set_cmd}"
|
||||||
|
_ret=$?
|
||||||
|
if [ "${_ret}" != "0" ]; then
|
||||||
|
_err "Can't update '${_pem}' in haproxy"
|
||||||
|
return "${_ret}"
|
||||||
|
fi
|
||||||
|
_socat_cert_commit_cmd="echo '${_cmdpfx}commit ssl cert ${_pem}' | socat '${_statssock}' - | grep -q '^Success!$'"
|
||||||
|
_debug _socat_cert_commit_cmd "${_socat_cert_commit_cmd}"
|
||||||
|
eval "${_socat_cert_commit_cmd}"
|
||||||
|
_ret=$?
|
||||||
|
if [ "${_ret}" != "0" ]; then
|
||||||
|
_err "Can't commit '${_pem}' in haproxy"
|
||||||
|
return ${_ret}
|
||||||
|
fi
|
||||||
|
if [ "${_newcert}" = "1" ]; then
|
||||||
|
# if this is a new certificate, it needs to be inserted into the crt-list`
|
||||||
|
_socat_cert_add_cmd="echo '${_cmdpfx}add ssl crt-list ${Le_Deploy_haproxy_pem_path} ${_pem}' | socat '${_statssock}' - | grep -q 'Success!'"
|
||||||
|
_debug _socat_cert_add_cmd "${_socat_cert_add_cmd}"
|
||||||
|
eval "${_socat_cert_add_cmd}"
|
||||||
|
_ret=$?
|
||||||
|
if [ "${_ret}" != "0" ]; then
|
||||||
|
_err "Can't update '${_pem}' in haproxy"
|
||||||
|
return "${_ret}"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
_err "'socat' is not available, couldn't update over ${_socketname}"
|
||||||
|
fi
|
||||||
|
else
|
||||||
# Reload HAProxy
|
# Reload HAProxy
|
||||||
_debug _reload "${_reload}"
|
_debug _reload "${_reload}"
|
||||||
eval "${_reload}"
|
eval "${_reload}"
|
||||||
@ -275,6 +397,7 @@ haproxy_deploy() {
|
|||||||
else
|
else
|
||||||
_info "Reload successful"
|
_info "Reload successful"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -20,18 +20,23 @@ mailcow_deploy() {
|
|||||||
_debug _cca "$_cca"
|
_debug _cca "$_cca"
|
||||||
_debug _cfullchain "$_cfullchain"
|
_debug _cfullchain "$_cfullchain"
|
||||||
|
|
||||||
_mailcow_path="${DEPLOY_MAILCOW_PATH}"
|
_getdeployconf DEPLOY_MAILCOW_PATH
|
||||||
|
_getdeployconf DEPLOY_MAILCOW_RELOAD
|
||||||
|
|
||||||
if [ -z "$_mailcow_path" ]; then
|
_debug DEPLOY_MAILCOW_PATH "$DEPLOY_MAILCOW_PATH"
|
||||||
|
_debug DEPLOY_MAILCOW_RELOAD "$DEPLOY_MAILCOW_RELOAD"
|
||||||
|
|
||||||
|
if [ -z "$DEPLOY_MAILCOW_PATH" ]; then
|
||||||
_err "Mailcow path is not found, please define DEPLOY_MAILCOW_PATH."
|
_err "Mailcow path is not found, please define DEPLOY_MAILCOW_PATH."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#Tests if _ssl_path is the mailcow root directory.
|
_savedeployconf DEPLOY_MAILCOW_PATH "$DEPLOY_MAILCOW_PATH"
|
||||||
if [ -f "${_mailcow_path}/generate_config.sh" ]; then
|
[ -n "$DEPLOY_MAILCOW_RELOAD" ] && _savedeployconf DEPLOY_MAILCOW_RELOAD "$DEPLOY_MAILCOW_RELOAD"
|
||||||
_ssl_path="${_mailcow_path}/data/assets/ssl/"
|
|
||||||
else
|
_ssl_path="$DEPLOY_MAILCOW_PATH"
|
||||||
_ssl_path="${_mailcow_path}"
|
if [ -f "$DEPLOY_MAILCOW_PATH/generate_config.sh" ]; then
|
||||||
|
_ssl_path="$DEPLOY_MAILCOW_PATH/data/assets/ssl/"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -d "$_ssl_path" ]; then
|
if [ ! -d "$_ssl_path" ]; then
|
||||||
@ -39,31 +44,20 @@ mailcow_deploy() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ECC or RSA
|
|
||||||
if [ -z "${Le_Keylength}" ]; then
|
|
||||||
Le_Keylength=""
|
|
||||||
fi
|
|
||||||
if _isEccKey "${Le_Keylength}"; then
|
|
||||||
_info "ECC key type detected"
|
|
||||||
_cert_name_prefix="ecdsa-"
|
|
||||||
else
|
|
||||||
_info "RSA key type detected"
|
|
||||||
_cert_name_prefix=""
|
|
||||||
fi
|
|
||||||
_info "Copying key and cert"
|
_info "Copying key and cert"
|
||||||
_real_key="$_ssl_path/${_cert_name_prefix}key.pem"
|
_real_key="$_ssl_path/key.pem"
|
||||||
if ! cat "$_ckey" >"$_real_key"; then
|
if ! cat "$_ckey" >"$_real_key"; then
|
||||||
_err "Error: write key file to: $_real_key"
|
_err "Error: write key file to: $_real_key"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_real_fullchain="$_ssl_path/${_cert_name_prefix}cert.pem"
|
_real_fullchain="$_ssl_path/cert.pem"
|
||||||
if ! cat "$_cfullchain" >"$_real_fullchain"; then
|
if ! cat "$_cfullchain" >"$_real_fullchain"; then
|
||||||
_err "Error: write cert file to: $_real_fullchain"
|
_err "Error: write cert file to: $_real_fullchain"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
DEFAULT_MAILCOW_RELOAD="docker restart $(docker ps -qaf name=postfix-mailcow); docker restart $(docker ps -qaf name=nginx-mailcow); docker restart $(docker ps -qaf name=dovecot-mailcow)"
|
DEFAULT_MAILCOW_RELOAD="docker restart \$(docker ps --quiet --filter name=nginx-mailcow --filter name=dovecot-mailcow --filter name=postfix-mailcow)"
|
||||||
_reload="${DEPLOY_MAILCOW_RELOAD:-$DEFAULT_MAILCOW_RELOAD}"
|
_reload="${DEPLOY_MAILCOW_RELOAD:-$DEFAULT_MAILCOW_RELOAD}"
|
||||||
|
|
||||||
_info "Run reload: $_reload"
|
_info "Run reload: $_reload"
|
||||||
|
156
deploy/openmediavault.sh
Normal file
156
deploy/openmediavault.sh
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
# This deploy hook is tested on OpenMediaVault 5.x. It supports both local and remote deployment.
|
||||||
|
# The way it works is that if a cert with the matching domain name is not found, it will firstly create a dummy cert to get its uuid, and then replace it with your cert.
|
||||||
|
#
|
||||||
|
# DEPLOY_OMV_WEBUI_ADMIN - This is OMV web gui admin account. Default value is admin. It's required as the user parameter (-u) for the omv-rpc command.
|
||||||
|
# DEPLOY_OMV_HOST and DEPLOY_OMV_SSH_USER are optional. They are used for remote deployment through ssh (support public key authentication only). Per design, OMV web gui admin doesn't have ssh permission, so another account is needed for ssh.
|
||||||
|
#
|
||||||
|
# returns 0 means success, otherwise error.
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
|
||||||
|
#domain keyfile certfile cafile fullchain
|
||||||
|
openmediavault_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"
|
||||||
|
|
||||||
|
_getdeployconf DEPLOY_OMV_WEBUI_ADMIN
|
||||||
|
|
||||||
|
if [ -z "$DEPLOY_OMV_WEBUI_ADMIN" ]; then
|
||||||
|
DEPLOY_OMV_WEBUI_ADMIN="admin"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_savedeployconf DEPLOY_OMV_WEBUI_ADMIN "$DEPLOY_OMV_WEBUI_ADMIN"
|
||||||
|
|
||||||
|
_getdeployconf DEPLOY_OMV_HOST
|
||||||
|
_getdeployconf DEPLOY_OMV_SSH_USER
|
||||||
|
|
||||||
|
if [ -n "$DEPLOY_OMV_HOST" ] && [ -n "$DEPLOY_OMV_SSH_USER" ]; then
|
||||||
|
_info "[OMV deploy-hook] Deploy certificate remotely through ssh."
|
||||||
|
_savedeployconf DEPLOY_OMV_HOST "$DEPLOY_OMV_HOST"
|
||||||
|
_savedeployconf DEPLOY_OMV_SSH_USER "$DEPLOY_OMV_SSH_USER"
|
||||||
|
else
|
||||||
|
_info "[OMV deploy-hook] Deploy certificate locally."
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$DEPLOY_OMV_HOST" ] && [ -n "$DEPLOY_OMV_SSH_USER" ]; then
|
||||||
|
|
||||||
|
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'getList' '{\"start\": 0, \"limit\": -1}' | jq -r '.data[] | select(.name==\"/CN='$_cdomain'\") | .uuid'"
|
||||||
|
# shellcheck disable=SC2029
|
||||||
|
_uuid=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
|
||||||
|
_debug _command "$_command"
|
||||||
|
|
||||||
|
if [ -z "$_uuid" ]; then
|
||||||
|
_info "[OMV deploy-hook] Domain $_cdomain has no certificate in openmediavault, creating it!"
|
||||||
|
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'create' '{\"cn\": \"test.example.com\", \"size\": 4096, \"days\": 3650, \"c\": \"\", \"st\": \"\", \"l\": \"\", \"o\": \"\", \"ou\": \"\", \"email\": \"\"}' | jq -r '.uuid'"
|
||||||
|
# shellcheck disable=SC2029
|
||||||
|
_uuid=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
|
||||||
|
_debug _command "$_command"
|
||||||
|
|
||||||
|
if [ -z "$_uuid" ]; then
|
||||||
|
_err "[OMV deploy-hook] An error occured while creating the certificate"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info "[OMV deploy-hook] Domain $_cdomain has uuid: $_uuid"
|
||||||
|
_fullchain=$(jq <"$_cfullchain" -aRs .)
|
||||||
|
_key=$(jq <"$_ckey" -aRs .)
|
||||||
|
|
||||||
|
_debug _fullchain "$_fullchain"
|
||||||
|
_debug _key "$_key"
|
||||||
|
|
||||||
|
_info "[OMV deploy-hook] Updating key and certificate in openmediavault"
|
||||||
|
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'set' '{\"uuid\":\"$_uuid\", \"certificate\":$_fullchain, \"privatekey\":$_key, \"comment\":\"acme.sh deployed $(date)\"}'"
|
||||||
|
# shellcheck disable=SC2029
|
||||||
|
_result=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
|
||||||
|
|
||||||
|
_debug _command "$_command"
|
||||||
|
_debug _result "$_result"
|
||||||
|
|
||||||
|
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'WebGui' 'setSettings' \$(omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'WebGui' 'getSettings' | jq -c '.sslcertificateref=\"$_uuid\"')"
|
||||||
|
# shellcheck disable=SC2029
|
||||||
|
_result=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
|
||||||
|
|
||||||
|
_debug _command "$_command"
|
||||||
|
_debug _result "$_result"
|
||||||
|
|
||||||
|
_info "[OMV deploy-hook] Asking openmediavault to apply changes... (this could take some time, hang in there)"
|
||||||
|
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'Config' 'applyChanges' '{\"modules\":[], \"force\": false}'"
|
||||||
|
# shellcheck disable=SC2029
|
||||||
|
_result=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
|
||||||
|
|
||||||
|
_debug _command "$_command"
|
||||||
|
_debug _result "$_result"
|
||||||
|
|
||||||
|
_info "[OMV deploy-hook] Asking nginx to reload"
|
||||||
|
_command="nginx -s reload"
|
||||||
|
# shellcheck disable=SC2029
|
||||||
|
_result=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
|
||||||
|
|
||||||
|
_debug _command "$_command"
|
||||||
|
_debug _result "$_result"
|
||||||
|
|
||||||
|
else
|
||||||
|
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
_uuid=$(omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'getList' '{"start": 0, "limit": -1}' | jq -r '.data[] | select(.name=="/CN='$_cdomain'") | .uuid')
|
||||||
|
if [ -z "$_uuid" ]; then
|
||||||
|
_info "[OMV deploy-hook] Domain $_cdomain has no certificate in openmediavault, creating it!"
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
_uuid=$(omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'create' '{"cn": "test.example.com", "size": 4096, "days": 3650, "c": "", "st": "", "l": "", "o": "", "ou": "", "email": ""}' | jq -r '.uuid')
|
||||||
|
|
||||||
|
if [ -z "$_uuid" ]; then
|
||||||
|
_err "[OMB deploy-hook] An error occured while creating the certificate"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info "[OMV deploy-hook] Domain $_cdomain has uuid: $_uuid"
|
||||||
|
_fullchain=$(jq <"$_cfullchain" -aRs .)
|
||||||
|
_key=$(jq <"$_ckey" -aRs .)
|
||||||
|
|
||||||
|
_debug _fullchain "$_fullchain"
|
||||||
|
_debug _key "$_key"
|
||||||
|
|
||||||
|
_info "[OMV deploy-hook] Updating key and certificate in openmediavault"
|
||||||
|
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'set' '{\"uuid\":\"$_uuid\", \"certificate\":$_fullchain, \"privatekey\":$_key, \"comment\":\"acme.sh deployed $(date)\"}'"
|
||||||
|
_result=$(eval "$_command")
|
||||||
|
|
||||||
|
_debug _command "$_command"
|
||||||
|
_debug _result "$_result"
|
||||||
|
|
||||||
|
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'WebGui' 'setSettings' \$(omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'WebGui' 'getSettings' | jq -c '.sslcertificateref=\"$_uuid\"')"
|
||||||
|
_result=$(eval "$_command")
|
||||||
|
|
||||||
|
_debug _command "$_command"
|
||||||
|
_debug _result "$_result"
|
||||||
|
|
||||||
|
_info "[OMV deploy-hook] Asking openmediavault to apply changes... (this could take some time, hang in there)"
|
||||||
|
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'Config' 'applyChanges' '{\"modules\":[], \"force\": false}'"
|
||||||
|
_result=$(eval "$_command")
|
||||||
|
|
||||||
|
_debug _command "$_command"
|
||||||
|
_debug _result "$_result"
|
||||||
|
|
||||||
|
_info "[OMV deploy-hook] Asking nginx to reload"
|
||||||
|
_command="nginx -s reload"
|
||||||
|
_result=$(eval "$_command")
|
||||||
|
|
||||||
|
_debug _command "$_command"
|
||||||
|
_debug _result "$_result"
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
179
deploy/panos.sh
179
deploy/panos.sh
@ -7,11 +7,18 @@
|
|||||||
#
|
#
|
||||||
# Firewall admin with superuser and IP address is required.
|
# Firewall admin with superuser and IP address is required.
|
||||||
#
|
#
|
||||||
# export PANOS_USER="" # required
|
# REQURED:
|
||||||
# export PANOS_PASS="" # required
|
# export PANOS_HOST=""
|
||||||
# export PANOS_HOST="" # required
|
# export PANOS_USER="" #User *MUST* have Commit and Import Permissions in XML API for Admin Role
|
||||||
|
# export PANOS_PASS=""
|
||||||
|
#
|
||||||
|
# OPTIONAL
|
||||||
|
# export PANOS_TEMPLATE="" #Template Name of panorama managed devices
|
||||||
|
#
|
||||||
|
# The script will automatically generate a new API key if
|
||||||
|
# no key is found, or if a saved key has expired or is invalid.
|
||||||
|
|
||||||
# This function is to parse the XML
|
# This function is to parse the XML response from the firewall
|
||||||
parse_response() {
|
parse_response() {
|
||||||
type=$2
|
type=$2
|
||||||
if [ "$type" = 'keygen' ]; then
|
if [ "$type" = 'keygen' ]; then
|
||||||
@ -23,25 +30,46 @@ parse_response() {
|
|||||||
message="PAN-OS Key could not be set."
|
message="PAN-OS Key could not be set."
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
status=$(echo "$1" | sed 's/^.*"\([a-z]*\)".*/\1/g')
|
status=$(echo "$1" | tr -d '\n' | sed 's/^.*"\([a-z]*\)".*/\1/g')
|
||||||
message=$(echo "$1" | sed 's/^.*<result>\(.*\)<\/result.*/\1/g')
|
message=$(echo "$1" | tr -d '\n' | sed 's/.*\(<result>\|<msg>\|<line>\)\([^<]*\).*/\2/g')
|
||||||
|
_debug "Firewall message: $message"
|
||||||
|
if [ "$type" = 'keytest' ] && [ "$status" != "success" ]; then
|
||||||
|
_debug "**** API Key has EXPIRED or is INVALID ****"
|
||||||
|
unset _panos_key
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#This function is used to deploy to the firewall
|
||||||
deployer() {
|
deployer() {
|
||||||
content=""
|
content=""
|
||||||
type=$1 # Types are keygen, cert, key, commit
|
type=$1 # Types are keytest, keygen, cert, key, commit
|
||||||
_debug "**** Deploying $type *****"
|
|
||||||
panos_url="https://$_panos_host/api/"
|
panos_url="https://$_panos_host/api/"
|
||||||
|
|
||||||
|
#Test API Key by performing a lookup
|
||||||
|
if [ "$type" = 'keytest' ]; then
|
||||||
|
_debug "**** Testing saved API Key ****"
|
||||||
|
_H1="Content-Type: application/x-www-form-urlencoded"
|
||||||
|
# Get Version Info to test key
|
||||||
|
content="type=version&key=$_panos_key"
|
||||||
|
## Exclude all scopes for the empty commit
|
||||||
|
#_exclude_scope="<policy-and-objects>exclude</policy-and-objects><device-and-network>exclude</device-and-network><shared-object>exclude</shared-object>"
|
||||||
|
#content="type=commit&action=partial&key=$_panos_key&cmd=<commit><partial>$_exclude_scope<admin><member>acmekeytest</member></admin></partial></commit>"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate API Key
|
||||||
if [ "$type" = 'keygen' ]; then
|
if [ "$type" = 'keygen' ]; then
|
||||||
|
_debug "**** Generating new API Key ****"
|
||||||
_H1="Content-Type: application/x-www-form-urlencoded"
|
_H1="Content-Type: application/x-www-form-urlencoded"
|
||||||
content="type=keygen&user=$_panos_user&password=$_panos_pass"
|
content="type=keygen&user=$_panos_user&password=$_panos_pass"
|
||||||
# content="$content${nl}--$delim${nl}Content-Disposition: form-data; type=\"keygen\"; user=\"$_panos_user\"; password=\"$_panos_pass\"${nl}Content-Type: application/octet-stream${nl}${nl}"
|
# content="$content${nl}--$delim${nl}Content-Disposition: form-data; type=\"keygen\"; user=\"$_panos_user\"; password=\"$_panos_pass\"${nl}Content-Type: application/octet-stream${nl}${nl}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Deploy Cert or Key
|
||||||
if [ "$type" = 'cert' ] || [ "$type" = 'key' ]; then
|
if [ "$type" = 'cert' ] || [ "$type" = 'key' ]; then
|
||||||
#Generate DEIM
|
_debug "**** Deploying $type ****"
|
||||||
|
#Generate DELIM
|
||||||
delim="-----MultipartDelimiter$(date "+%s%N")"
|
delim="-----MultipartDelimiter$(date "+%s%N")"
|
||||||
nl="\015\012"
|
nl="\015\012"
|
||||||
#Set Header
|
#Set Header
|
||||||
@ -53,6 +81,9 @@ deployer() {
|
|||||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"\r\n\r\n$_panos_key"
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"\r\n\r\n$_panos_key"
|
||||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"format\"\r\n\r\npem"
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"format\"\r\n\r\npem"
|
||||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")"
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_cfullchain")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cfullchain")"
|
||||||
|
if [ "$_panos_template" ]; then
|
||||||
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"target-tpl\"\r\n\r\n$_panos_template"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
if [ "$type" = 'key' ]; then
|
if [ "$type" = 'key' ]; then
|
||||||
panos_url="${panos_url}?type=import"
|
panos_url="${panos_url}?type=import"
|
||||||
@ -61,7 +92,10 @@ deployer() {
|
|||||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"\r\n\r\n$_panos_key"
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"\r\n\r\n$_panos_key"
|
||||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"format\"\r\n\r\npem"
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"format\"\r\n\r\npem"
|
||||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"passphrase\"\r\n\r\n123456"
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"passphrase\"\r\n\r\n123456"
|
||||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_cdomain.key")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
|
||||||
|
if [ "$_panos_template" ]; then
|
||||||
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"target-tpl\"\r\n\r\n$_panos_template"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
#Close multipart
|
#Close multipart
|
||||||
content="$content${nl}--$delim--${nl}${nl}"
|
content="$content${nl}--$delim--${nl}${nl}"
|
||||||
@ -69,16 +103,25 @@ deployer() {
|
|||||||
content=$(printf %b "$content")
|
content=$(printf %b "$content")
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Commit changes
|
||||||
if [ "$type" = 'commit' ]; then
|
if [ "$type" = 'commit' ]; then
|
||||||
|
_debug "**** Committing changes ****"
|
||||||
export _H1="Content-Type: application/x-www-form-urlencoded"
|
export _H1="Content-Type: application/x-www-form-urlencoded"
|
||||||
cmd=$(printf "%s" "<commit><partial><$_panos_user></$_panos_user></partial></commit>" | _url_encode)
|
#Check for force commit - will commit ALL uncommited changes to the firewall. Use with caution!
|
||||||
content="type=commit&key=$_panos_key&cmd=$cmd"
|
if [ "$FORCE" ]; then
|
||||||
|
_debug "Force switch detected. Committing ALL changes to the firewall."
|
||||||
|
cmd=$(printf "%s" "<commit><partial><force><admin><member>$_panos_user</member></admin></force></partial></commit>" | _url_encode)
|
||||||
|
else
|
||||||
|
_exclude_scope="<policy-and-objects>exclude</policy-and-objects><device-and-network>exclude</device-and-network>"
|
||||||
|
cmd=$(printf "%s" "<commit><partial>$_exclude_scope<admin><member>$_panos_user</member></admin></partial></commit>" | _url_encode)
|
||||||
fi
|
fi
|
||||||
|
content="type=commit&action=partial&key=$_panos_key&cmd=$cmd"
|
||||||
|
fi
|
||||||
|
|
||||||
response=$(_post "$content" "$panos_url" "" "POST")
|
response=$(_post "$content" "$panos_url" "" "POST")
|
||||||
parse_response "$response" "$type"
|
parse_response "$response" "$type"
|
||||||
# Saving response to variables
|
# Saving response to variables
|
||||||
response_status=$status
|
response_status=$status
|
||||||
#DEBUG
|
|
||||||
_debug response_status "$response_status"
|
_debug response_status "$response_status"
|
||||||
if [ "$response_status" = "success" ]; then
|
if [ "$response_status" = "success" ]; then
|
||||||
_debug "Successfully deployed $type"
|
_debug "Successfully deployed $type"
|
||||||
@ -92,43 +135,95 @@ deployer() {
|
|||||||
|
|
||||||
# This is the main function that will call the other functions to deploy everything.
|
# This is the main function that will call the other functions to deploy everything.
|
||||||
panos_deploy() {
|
panos_deploy() {
|
||||||
_cdomain="$1"
|
_cdomain=$(echo "$1" | sed 's/*/WILDCARD_/g') #Wildcard Safe Filename
|
||||||
_ckey="$2"
|
_ckey="$2"
|
||||||
_cfullchain="$5"
|
_cfullchain="$5"
|
||||||
# PANOS ENV VAR check
|
|
||||||
if [ -z "$PANOS_USER" ] || [ -z "$PANOS_PASS" ] || [ -z "$PANOS_HOST" ]; then
|
# VALID FILE CHECK
|
||||||
_debug "No ENV variables found lets check for saved variables"
|
if [ ! -f "$_ckey" ] || [ ! -f "$_cfullchain" ]; then
|
||||||
_getdeployconf PANOS_USER
|
_err "Unable to find a valid key and/or cert. If this is an ECDSA/ECC cert, use the --ecc flag when deploying."
|
||||||
_getdeployconf PANOS_PASS
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# PANOS_HOST
|
||||||
|
if [ "$PANOS_HOST" ]; then
|
||||||
|
_debug "Detected ENV variable PANOS_HOST. Saving to file."
|
||||||
|
_savedeployconf PANOS_HOST "$PANOS_HOST" 1
|
||||||
|
else
|
||||||
|
_debug "Attempting to load variable PANOS_HOST from file."
|
||||||
_getdeployconf PANOS_HOST
|
_getdeployconf PANOS_HOST
|
||||||
|
fi
|
||||||
|
|
||||||
|
# PANOS USER
|
||||||
|
if [ "$PANOS_USER" ]; then
|
||||||
|
_debug "Detected ENV variable PANOS_USER. Saving to file."
|
||||||
|
_savedeployconf PANOS_USER "$PANOS_USER" 1
|
||||||
|
else
|
||||||
|
_debug "Attempting to load variable PANOS_USER from file."
|
||||||
|
_getdeployconf PANOS_USER
|
||||||
|
fi
|
||||||
|
|
||||||
|
# PANOS_PASS
|
||||||
|
if [ "$PANOS_PASS" ]; then
|
||||||
|
_debug "Detected ENV variable PANOS_PASS. Saving to file."
|
||||||
|
_savedeployconf PANOS_PASS "$PANOS_PASS" 1
|
||||||
|
else
|
||||||
|
_debug "Attempting to load variable PANOS_PASS from file."
|
||||||
|
_getdeployconf PANOS_PASS
|
||||||
|
fi
|
||||||
|
|
||||||
|
# PANOS_KEY
|
||||||
|
_getdeployconf PANOS_KEY
|
||||||
|
if [ "$PANOS_KEY" ]; then
|
||||||
|
_debug "Detected saved key."
|
||||||
|
_panos_key=$PANOS_KEY
|
||||||
|
else
|
||||||
|
_debug "No key detected"
|
||||||
|
unset _panos_key
|
||||||
|
fi
|
||||||
|
|
||||||
|
# PANOS_TEMPLATE
|
||||||
|
if [ "$PANOS_TEMPLATE" ]; then
|
||||||
|
_debug "Detected ENV variable PANOS_TEMPLATE. Saving to file."
|
||||||
|
_savedeployconf PANOS_TEMPLATE "$PANOS_TEMPLATE" 1
|
||||||
|
else
|
||||||
|
_debug "Attempting to load variable PANOS_TEMPLATE from file."
|
||||||
|
_getdeployconf PANOS_TEMPLATE
|
||||||
|
fi
|
||||||
|
|
||||||
|
#Store variables
|
||||||
|
_panos_host=$PANOS_HOST
|
||||||
_panos_user=$PANOS_USER
|
_panos_user=$PANOS_USER
|
||||||
_panos_pass=$PANOS_PASS
|
_panos_pass=$PANOS_PASS
|
||||||
_panos_host=$PANOS_HOST
|
_panos_template=$PANOS_TEMPLATE
|
||||||
if [ -z "$_panos_user" ] && [ -z "$_panos_pass" ] && [ -z "$_panos_host" ]; then
|
|
||||||
_err "No host, user and pass found.. If this is the first time deploying please set PANOS_HOST, PANOS_USER and PANOS_PASS in environment variables. Delete them after you have succesfully deployed certs."
|
#Test API Key if found. If the key is invalid, the variable _panos_key will be unset.
|
||||||
|
if [ "$_panos_host" ] && [ "$_panos_key" ]; then
|
||||||
|
_debug "**** Testing API KEY ****"
|
||||||
|
deployer keytest
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for valid variables
|
||||||
|
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
|
return 1
|
||||||
else
|
else
|
||||||
_debug "Using saved env variables."
|
# Generate a new API key if no valid API key is found
|
||||||
fi
|
|
||||||
else
|
|
||||||
_debug "Detected ENV variables to be saved to the deploy conf."
|
|
||||||
# Encrypt and save user
|
|
||||||
_savedeployconf PANOS_USER "$PANOS_USER" 1
|
|
||||||
_savedeployconf PANOS_PASS "$PANOS_PASS" 1
|
|
||||||
_savedeployconf PANOS_HOST "$PANOS_HOST" 1
|
|
||||||
_panos_user="$PANOS_USER"
|
|
||||||
_panos_pass="$PANOS_PASS"
|
|
||||||
_panos_host="$PANOS_HOST"
|
|
||||||
fi
|
|
||||||
_debug "Let's use username and pass to generate token."
|
|
||||||
if [ -z "$_panos_user" ] || [ -z "$_panos_pass" ] || [ -z "$_panos_host" ]; then
|
|
||||||
_err "Please pass username and password and host as env variables PANOS_USER, PANOS_PASS and PANOS_HOST"
|
|
||||||
return 1
|
|
||||||
else
|
|
||||||
_debug "Getting PANOS KEY"
|
|
||||||
deployer keygen
|
|
||||||
if [ -z "$_panos_key" ]; then
|
if [ -z "$_panos_key" ]; then
|
||||||
_err "Missing apikey."
|
_debug "**** Generating new PANOS API KEY ****"
|
||||||
|
deployer keygen
|
||||||
|
_savedeployconf PANOS_KEY "$_panos_key" 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Confirm that a valid key was generated
|
||||||
|
if [ -z "$_panos_key" ]; then
|
||||||
|
_err "Unable to generate an API key. The user and pass may be invalid or not authorized to generate a new key. Please check the PANOS_USER and PANOS_PASS credentials and try again"
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
deployer cert
|
deployer cert
|
||||||
|
132
deploy/proxmoxve.sh
Normal file
132
deploy/proxmoxve.sh
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
# Deploy certificates to a proxmox virtual environment node using the API.
|
||||||
|
#
|
||||||
|
# Environment variables that can be set are:
|
||||||
|
# `DEPLOY_PROXMOXVE_SERVER`: The hostname of the proxmox ve node. Defaults to
|
||||||
|
# _cdomain.
|
||||||
|
# `DEPLOY_PROXMOXVE_SERVER_PORT`: The port number the management interface is on.
|
||||||
|
# Defaults to 8006.
|
||||||
|
# `DEPLOY_PROXMOXVE_NODE_NAME`: The name of the node we'll be connecting to.
|
||||||
|
# Defaults to the host portion of the server
|
||||||
|
# domain name.
|
||||||
|
# `DEPLOY_PROXMOXVE_USER`: The user we'll connect as. Defaults to root.
|
||||||
|
# `DEPLOY_PROXMOXVE_USER_REALM`: The authentication realm the user authenticates
|
||||||
|
# with. Defaults to pam.
|
||||||
|
# `DEPLOY_PROXMOXVE_API_TOKEN_NAME`: The name of the API token created for the
|
||||||
|
# user account. Defaults to acme.
|
||||||
|
# `DEPLOY_PROXMOXVE_API_TOKEN_KEY`: The API token. Required.
|
||||||
|
|
||||||
|
proxmoxve_deploy() {
|
||||||
|
_cdomain="$1"
|
||||||
|
_ckey="$2"
|
||||||
|
_ccert="$3"
|
||||||
|
_cca="$4"
|
||||||
|
_cfullchain="$5"
|
||||||
|
|
||||||
|
_debug _cdomain "$_cdomain"
|
||||||
|
_debug2 _ckey "$_ckey"
|
||||||
|
_debug _ccert "$_ccert"
|
||||||
|
_debug _cca "$_cca"
|
||||||
|
_debug _cfullchain "$_cfullchain"
|
||||||
|
|
||||||
|
# "Sane" defaults.
|
||||||
|
_getdeployconf DEPLOY_PROXMOXVE_SERVER
|
||||||
|
if [ -z "$DEPLOY_PROXMOXVE_SERVER" ]; then
|
||||||
|
_target_hostname="$_cdomain"
|
||||||
|
else
|
||||||
|
_target_hostname="$DEPLOY_PROXMOXVE_SERVER"
|
||||||
|
_savedeployconf DEPLOY_PROXMOXVE_SERVER "$DEPLOY_PROXMOXVE_SERVER"
|
||||||
|
fi
|
||||||
|
_debug2 DEPLOY_PROXMOXVE_SERVER "$_target_hostname"
|
||||||
|
|
||||||
|
_getdeployconf DEPLOY_PROXMOXVE_SERVER_PORT
|
||||||
|
if [ -z "$DEPLOY_PROXMOXVE_SERVER_PORT" ]; then
|
||||||
|
_target_port="8006"
|
||||||
|
else
|
||||||
|
_target_port="$DEPLOY_PROXMOXVE_SERVER_PORT"
|
||||||
|
_savedeployconf DEPLOY_PROXMOXVE_SERVER_PORT "$DEPLOY_PROXMOXVE_SERVER_PORT"
|
||||||
|
fi
|
||||||
|
_debug2 DEPLOY_PROXMOXVE_SERVER_PORT "$_target_port"
|
||||||
|
|
||||||
|
_getdeployconf DEPLOY_PROXMOXVE_NODE_NAME
|
||||||
|
if [ -z "$DEPLOY_PROXMOXVE_NODE_NAME" ]; then
|
||||||
|
_node_name=$(echo "$_target_hostname" | cut -d. -f1)
|
||||||
|
else
|
||||||
|
_node_name="$DEPLOY_PROXMOXVE_NODE_NAME"
|
||||||
|
_savedeployconf DEPLOY_PROXMOXVE_NODE_NAME "$DEPLOY_PROXMOXVE_NODE_NAME"
|
||||||
|
fi
|
||||||
|
_debug2 DEPLOY_PROXMOXVE_NODE_NAME "$_node_name"
|
||||||
|
|
||||||
|
# Complete URL.
|
||||||
|
_target_url="https://${_target_hostname}:${_target_port}/api2/json/nodes/${_node_name}/certificates/custom"
|
||||||
|
_debug TARGET_URL "$_target_url"
|
||||||
|
|
||||||
|
# More "sane" defaults.
|
||||||
|
_getdeployconf DEPLOY_PROXMOXVE_USER
|
||||||
|
if [ -z "$DEPLOY_PROXMOXVE_USER" ]; then
|
||||||
|
_proxmoxve_user="root"
|
||||||
|
else
|
||||||
|
_proxmoxve_user="$DEPLOY_PROXMOXVE_USER"
|
||||||
|
_savedeployconf DEPLOY_PROXMOXVE_USER "$DEPLOY_PROXMOXVE_USER"
|
||||||
|
fi
|
||||||
|
_debug2 DEPLOY_PROXMOXVE_USER "$_proxmoxve_user"
|
||||||
|
|
||||||
|
_getdeployconf DEPLOY_PROXMOXVE_USER_REALM
|
||||||
|
if [ -z "$DEPLOY_PROXMOXVE_USER_REALM" ]; then
|
||||||
|
_proxmoxve_user_realm="pam"
|
||||||
|
else
|
||||||
|
_proxmoxve_user_realm="$DEPLOY_PROXMOXVE_USER_REALM"
|
||||||
|
_savedeployconf DEPLOY_PROXMOXVE_USER_REALM "$DEPLOY_PROXMOXVE_USER_REALM"
|
||||||
|
fi
|
||||||
|
_debug2 DEPLOY_PROXMOXVE_USER_REALM "$_proxmoxve_user_realm"
|
||||||
|
|
||||||
|
_getdeployconf DEPLOY_PROXMOXVE_API_TOKEN_NAME
|
||||||
|
if [ -z "$DEPLOY_PROXMOXVE_API_TOKEN_NAME" ]; then
|
||||||
|
_proxmoxve_api_token_name="acme"
|
||||||
|
else
|
||||||
|
_proxmoxve_api_token_name="$DEPLOY_PROXMOXVE_API_TOKEN_NAME"
|
||||||
|
_savedeployconf DEPLOY_PROXMOXVE_API_TOKEN_NAME "$DEPLOY_PROXMOXVE_API_TOKEN_NAME"
|
||||||
|
fi
|
||||||
|
_debug2 DEPLOY_PROXMOXVE_API_TOKEN_NAME "$_proxmoxve_api_token_name"
|
||||||
|
|
||||||
|
# This is required.
|
||||||
|
_getdeployconf DEPLOY_PROXMOXVE_API_TOKEN_KEY
|
||||||
|
if [ -z "$DEPLOY_PROXMOXVE_API_TOKEN_KEY" ]; then
|
||||||
|
_err "API key not provided."
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
_proxmoxve_api_token_key="$DEPLOY_PROXMOXVE_API_TOKEN_KEY"
|
||||||
|
_savedeployconf DEPLOY_PROXMOXVE_API_TOKEN_KEY "$DEPLOY_PROXMOXVE_API_TOKEN_KEY"
|
||||||
|
fi
|
||||||
|
_debug2 DEPLOY_PROXMOXVE_API_TOKEN_KEY "$_proxmoxve_api_token_key"
|
||||||
|
|
||||||
|
# PVE API Token header value. Used in "Authorization: PVEAPIToken".
|
||||||
|
_proxmoxve_header_api_token="${_proxmoxve_user}@${_proxmoxve_user_realm}!${_proxmoxve_api_token_name}=${_proxmoxve_api_token_key}"
|
||||||
|
_debug2 "Auth Header" "$_proxmoxve_header_api_token"
|
||||||
|
|
||||||
|
# Ugly. I hate putting heredocs inside functions because heredocs don't
|
||||||
|
# account for whitespace correctly but it _does_ work and is several times
|
||||||
|
# cleaner than anything else I had here.
|
||||||
|
#
|
||||||
|
# This dumps the json payload to a variable that should be passable to the
|
||||||
|
# _psot function.
|
||||||
|
_json_payload=$(
|
||||||
|
cat <<HEREDOC
|
||||||
|
{
|
||||||
|
"certificates": "$(tr '\n' ':' <"$_cfullchain" | sed 's/:/\\n/g')",
|
||||||
|
"key": "$(tr '\n' ':' <"$_ckey" | sed 's/:/\\n/g')",
|
||||||
|
"node":"$_node_name",
|
||||||
|
"restart":"1",
|
||||||
|
"force":"1"
|
||||||
|
}
|
||||||
|
HEREDOC
|
||||||
|
)
|
||||||
|
_debug2 Payload "$_json_payload"
|
||||||
|
|
||||||
|
_info "Push certificates to server"
|
||||||
|
export HTTPS_INSECURE=1
|
||||||
|
export _H1="Authorization: PVEAPIToken=${_proxmoxve_header_api_token}"
|
||||||
|
_post "$_json_payload" "$_target_url" "" POST "application/json"
|
||||||
|
|
||||||
|
}
|
@ -53,7 +53,7 @@ qiniu_deploy() {
|
|||||||
sslcert_access_token="$(_make_access_token "$sslcert_path")"
|
sslcert_access_token="$(_make_access_token "$sslcert_path")"
|
||||||
_debug sslcert_access_token "$sslcert_access_token"
|
_debug sslcert_access_token "$sslcert_access_token"
|
||||||
export _H1="Authorization: QBox $sslcert_access_token"
|
export _H1="Authorization: QBox $sslcert_access_token"
|
||||||
sslcert_response=$(_post "$sslcerl_body" "$QINIU_API_BASE$sslcert_path" 0 "POST" "application/json" | _dbase64 "multiline")
|
sslcert_response=$(_post "$sslcerl_body" "$QINIU_API_BASE$sslcert_path" 0 "POST" "application/json" | _dbase64)
|
||||||
|
|
||||||
if ! _contains "$sslcert_response" "certID"; then
|
if ! _contains "$sslcert_response" "certID"; then
|
||||||
_err "Error in creating certificate:"
|
_err "Error in creating certificate:"
|
||||||
@ -75,7 +75,7 @@ qiniu_deploy() {
|
|||||||
update_access_token="$(_make_access_token "$update_path")"
|
update_access_token="$(_make_access_token "$update_path")"
|
||||||
_debug update_access_token "$update_access_token"
|
_debug update_access_token "$update_access_token"
|
||||||
export _H1="Authorization: QBox $update_access_token"
|
export _H1="Authorization: QBox $update_access_token"
|
||||||
update_response=$(_post "$update_body" "$QINIU_API_BASE$update_path" 0 "PUT" "application/json" | _dbase64 "multiline")
|
update_response=$(_post "$update_body" "$QINIU_API_BASE$update_path" 0 "PUT" "application/json" | _dbase64)
|
||||||
|
|
||||||
if _contains "$update_response" "error"; then
|
if _contains "$update_response" "error"; then
|
||||||
_err "Error in updating domain $domain httpsconf:"
|
_err "Error in updating domain $domain httpsconf:"
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
# ```sh
|
# ```sh
|
||||||
# export ROUTER_OS_USERNAME=certuser
|
# export ROUTER_OS_USERNAME=certuser
|
||||||
# export ROUTER_OS_HOST=router.example.com
|
# export ROUTER_OS_HOST=router.example.com
|
||||||
|
# export ROUTER_OS_PORT=22
|
||||||
#
|
#
|
||||||
# acme.sh --deploy -d ftp.example.com --deploy-hook routeros
|
# acme.sh --deploy -d ftp.example.com --deploy-hook routeros
|
||||||
# ```
|
# ```
|
||||||
@ -48,6 +49,16 @@
|
|||||||
# One optional thing to do as well is to create a script that updates
|
# One optional thing to do as well is to create a script that updates
|
||||||
# all the required services and run that script in a single command.
|
# all the required services and run that script in a single command.
|
||||||
#
|
#
|
||||||
|
# To adopt parameters to `scp` and/or `ssh` set the optional
|
||||||
|
# `ROUTER_OS_SSH_CMD` and `ROUTER_OS_SCP_CMD` variables accordingly,
|
||||||
|
# see ssh(1) and scp(1) for parameters to those commands.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# ```ssh
|
||||||
|
# export ROUTER_OS_SSH_CMD="ssh -i /acme.sh/.ssh/router.example.com -o UserKnownHostsFile=/acme.sh/.ssh/known_hosts"
|
||||||
|
# export ROUTER_OS_SCP_CMD="scp -i /acme.sh/.ssh/router.example.com -o UserKnownHostsFile=/acme.sh/.ssh/known_hosts"
|
||||||
|
# ````
|
||||||
|
#
|
||||||
# returns 0 means success, otherwise error.
|
# returns 0 means success, otherwise error.
|
||||||
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
@ -59,6 +70,7 @@ routeros_deploy() {
|
|||||||
_ccert="$3"
|
_ccert="$3"
|
||||||
_cca="$4"
|
_cca="$4"
|
||||||
_cfullchain="$5"
|
_cfullchain="$5"
|
||||||
|
_err_code=0
|
||||||
|
|
||||||
_debug _cdomain "$_cdomain"
|
_debug _cdomain "$_cdomain"
|
||||||
_debug _ckey "$_ckey"
|
_debug _ckey "$_ckey"
|
||||||
@ -80,6 +92,27 @@ routeros_deploy() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
_getdeployconf ROUTER_OS_PORT
|
||||||
|
|
||||||
|
if [ -z "$ROUTER_OS_PORT" ]; then
|
||||||
|
_debug "Using default port 22 as ROUTER_OS_PORT, please set if not correct."
|
||||||
|
ROUTER_OS_PORT=22
|
||||||
|
fi
|
||||||
|
|
||||||
|
_getdeployconf ROUTER_OS_SSH_CMD
|
||||||
|
|
||||||
|
if [ -z "$ROUTER_OS_SSH_CMD" ]; then
|
||||||
|
_debug "Use default ssh setup."
|
||||||
|
ROUTER_OS_SSH_CMD="ssh -p $ROUTER_OS_PORT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_getdeployconf ROUTER_OS_SCP_CMD
|
||||||
|
|
||||||
|
if [ -z "$ROUTER_OS_SCP_CMD" ]; then
|
||||||
|
_debug "USe default scp setup."
|
||||||
|
ROUTER_OS_SCP_CMD="scp -P $ROUTER_OS_PORT"
|
||||||
|
fi
|
||||||
|
|
||||||
_getdeployconf ROUTER_OS_ADDITIONAL_SERVICES
|
_getdeployconf ROUTER_OS_ADDITIONAL_SERVICES
|
||||||
|
|
||||||
if [ -z "$ROUTER_OS_ADDITIONAL_SERVICES" ]; then
|
if [ -z "$ROUTER_OS_ADDITIONAL_SERVICES" ]; then
|
||||||
@ -89,33 +122,83 @@ routeros_deploy() {
|
|||||||
|
|
||||||
_savedeployconf ROUTER_OS_HOST "$ROUTER_OS_HOST"
|
_savedeployconf ROUTER_OS_HOST "$ROUTER_OS_HOST"
|
||||||
_savedeployconf ROUTER_OS_USERNAME "$ROUTER_OS_USERNAME"
|
_savedeployconf ROUTER_OS_USERNAME "$ROUTER_OS_USERNAME"
|
||||||
|
_savedeployconf ROUTER_OS_PORT "$ROUTER_OS_PORT"
|
||||||
|
_savedeployconf ROUTER_OS_SSH_CMD "$ROUTER_OS_SSH_CMD"
|
||||||
|
_savedeployconf ROUTER_OS_SCP_CMD "$ROUTER_OS_SCP_CMD"
|
||||||
_savedeployconf ROUTER_OS_ADDITIONAL_SERVICES "$ROUTER_OS_ADDITIONAL_SERVICES"
|
_savedeployconf ROUTER_OS_ADDITIONAL_SERVICES "$ROUTER_OS_ADDITIONAL_SERVICES"
|
||||||
|
|
||||||
_info "Trying to push key '$_ckey' to router"
|
# push key to routeros
|
||||||
scp "$_ckey" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.key"
|
if ! _scp_certificate "$_ckey" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.key"; then
|
||||||
_info "Trying to push cert '$_cfullchain' to router"
|
return $_err_code
|
||||||
scp "$_cfullchain" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.cer"
|
fi
|
||||||
DEPLOY_SCRIPT_CMD="/system script add name=\"LE Cert Deploy - $_cdomain\" owner=admin policy=ftp,read,write,password,sensitive \
|
|
||||||
source=\"## generated by routeros deploy script in acme.sh;\
|
# push certificate chain to routeros
|
||||||
\n/certificate remove [ find name=$_cdomain.cer_0 ];\
|
if ! _scp_certificate "$_cfullchain" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.cer"; then
|
||||||
|
return $_err_code
|
||||||
|
fi
|
||||||
|
|
||||||
|
DEPLOY_SCRIPT_CMD=":do {/system script remove \"LECertDeploy-$_cdomain\" } on-error={ }; \
|
||||||
|
/system script add name=\"LECertDeploy-$_cdomain\" owner=$ROUTER_OS_USERNAME \
|
||||||
|
comment=\"generated by routeros deploy script in acme.sh\" \
|
||||||
|
source=\"/certificate remove [ find name=$_cdomain.cer_0 ];\
|
||||||
\n/certificate remove [ find name=$_cdomain.cer_1 ];\
|
\n/certificate remove [ find name=$_cdomain.cer_1 ];\
|
||||||
|
\n/certificate remove [ find name=$_cdomain.cer_2 ];\
|
||||||
\ndelay 1;\
|
\ndelay 1;\
|
||||||
\n/certificate import file-name=$_cdomain.cer passphrase=\\\"\\\";\
|
\n/certificate import file-name=$_cdomain.cer passphrase=\\\"\\\";\
|
||||||
\n/certificate import file-name=$_cdomain.key passphrase=\\\"\\\";\
|
\n/certificate import file-name=$_cdomain.key passphrase=\\\"\\\";\
|
||||||
\ndelay 1;\
|
\ndelay 1;\
|
||||||
\n/file remove $_cdomain.cer;\
|
\n:do {/file remove $_cdomain.cer; } on-error={ }\
|
||||||
\n/file remove $_cdomain.key;\
|
\n:do {/file remove $_cdomain.key; } on-error={ }\
|
||||||
\ndelay 2;\
|
\ndelay 2;\
|
||||||
\n/ip service set www-ssl certificate=$_cdomain.cer_0;\
|
\n/ip service set www-ssl certificate=$_cdomain.cer_0;\
|
||||||
\n$ROUTER_OS_ADDITIONAL_SERVICES;\
|
\n$ROUTER_OS_ADDITIONAL_SERVICES;\
|
||||||
\n\"
|
\n\"
|
||||||
"
|
"
|
||||||
# shellcheck disable=SC2029
|
|
||||||
ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "$DEPLOY_SCRIPT_CMD"
|
if ! _ssh_remote_cmd "$DEPLOY_SCRIPT_CMD"; then
|
||||||
# shellcheck disable=SC2029
|
return $_err_code
|
||||||
ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script run \"LE Cert Deploy - $_cdomain\""
|
fi
|
||||||
# shellcheck disable=SC2029
|
|
||||||
ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script remove \"LE Cert Deploy - $_cdomain\""
|
if ! _ssh_remote_cmd "/system script run \"LECertDeploy-$_cdomain\""; then
|
||||||
|
return $_err_code
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _ssh_remote_cmd "/system script remove \"LECertDeploy-$_cdomain\""; then
|
||||||
|
return $_err_code
|
||||||
|
fi
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# inspired by deploy/ssh.sh
|
||||||
|
_ssh_remote_cmd() {
|
||||||
|
_cmd="$1"
|
||||||
|
_secure_debug "Remote commands to execute: $_cmd"
|
||||||
|
_info "Submitting sequence of commands to routeros"
|
||||||
|
# quotations in bash cmd below intended. Squash travis spellcheck error
|
||||||
|
# shellcheck disable=SC2029
|
||||||
|
$ROUTER_OS_SSH_CMD "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "$_cmd"
|
||||||
|
_err_code="$?"
|
||||||
|
|
||||||
|
if [ "$_err_code" != "0" ]; then
|
||||||
|
_err "Error code $_err_code returned from routeros"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $_err_code
|
||||||
|
}
|
||||||
|
|
||||||
|
_scp_certificate() {
|
||||||
|
_src="$1"
|
||||||
|
_dst="$2"
|
||||||
|
_secure_debug "scp '$_src' to '$_dst'"
|
||||||
|
_info "Push key '$_src' to routeros"
|
||||||
|
|
||||||
|
$ROUTER_OS_SCP_CMD "$_src" "$_dst"
|
||||||
|
_err_code="$?"
|
||||||
|
|
||||||
|
if [ "$_err_code" != "0" ]; then
|
||||||
|
_err "Error code $_err_code returned from scp"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $_err_code
|
||||||
|
}
|
||||||
|
403
deploy/ssh.sh
403
deploy/ssh.sh
@ -14,7 +14,7 @@
|
|||||||
# The following examples are for QNAP NAS running QTS 4.2
|
# The following examples are for QNAP NAS running QTS 4.2
|
||||||
# export DEPLOY_SSH_CMD="" # defaults to "ssh -T"
|
# export DEPLOY_SSH_CMD="" # defaults to "ssh -T"
|
||||||
# export DEPLOY_SSH_USER="admin" # required
|
# export DEPLOY_SSH_USER="admin" # required
|
||||||
# export DEPLOY_SSH_SERVER="qnap" # defaults to domain name
|
# export DEPLOY_SSH_SERVER="host1 host2:8022 192.168.0.1:9022" # defaults to domain name, support multiple servers with optional port
|
||||||
# export DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem"
|
# export DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem"
|
||||||
# export DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem"
|
# export DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem"
|
||||||
# export DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem"
|
# export DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem"
|
||||||
@ -23,6 +23,8 @@
|
|||||||
# export DEPLOY_SSH_BACKUP="" # yes or no, default to yes or previously saved value
|
# export DEPLOY_SSH_BACKUP="" # yes or no, default to yes or previously saved value
|
||||||
# export DEPLOY_SSH_BACKUP_PATH=".acme_ssh_deploy" # path on remote system. Defaults to .acme_ssh_deploy
|
# export DEPLOY_SSH_BACKUP_PATH=".acme_ssh_deploy" # path on remote system. Defaults to .acme_ssh_deploy
|
||||||
# export DEPLOY_SSH_MULTI_CALL="" # yes or no, default to no or previously saved value
|
# export DEPLOY_SSH_MULTI_CALL="" # yes or no, default to no or previously saved value
|
||||||
|
# export DEPLOY_SSH_USE_SCP="" yes or no, default to no
|
||||||
|
# export DEPLOY_SSH_SCP_CMD="" defaults to "scp -q"
|
||||||
#
|
#
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
@ -42,72 +44,134 @@ ssh_deploy() {
|
|||||||
_debug _cfullchain "$_cfullchain"
|
_debug _cfullchain "$_cfullchain"
|
||||||
|
|
||||||
# USER is required to login by SSH to remote host.
|
# USER is required to login by SSH to remote host.
|
||||||
|
_migratedeployconf Le_Deploy_ssh_user DEPLOY_SSH_USER
|
||||||
_getdeployconf DEPLOY_SSH_USER
|
_getdeployconf DEPLOY_SSH_USER
|
||||||
_debug2 DEPLOY_SSH_USER "$DEPLOY_SSH_USER"
|
_debug2 DEPLOY_SSH_USER "$DEPLOY_SSH_USER"
|
||||||
if [ -z "$DEPLOY_SSH_USER" ]; then
|
if [ -z "$DEPLOY_SSH_USER" ]; then
|
||||||
if [ -z "$Le_Deploy_ssh_user" ]; then
|
|
||||||
_err "DEPLOY_SSH_USER not defined."
|
_err "DEPLOY_SSH_USER not defined."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
else
|
_savedeployconf DEPLOY_SSH_USER "$DEPLOY_SSH_USER"
|
||||||
Le_Deploy_ssh_user="$DEPLOY_SSH_USER"
|
|
||||||
_savedomainconf Le_Deploy_ssh_user "$Le_Deploy_ssh_user"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# SERVER is optional. If not provided then use _cdomain
|
# SERVER is optional. If not provided then use _cdomain
|
||||||
|
_migratedeployconf Le_Deploy_ssh_server DEPLOY_SSH_SERVER
|
||||||
_getdeployconf DEPLOY_SSH_SERVER
|
_getdeployconf DEPLOY_SSH_SERVER
|
||||||
_debug2 DEPLOY_SSH_SERVER "$DEPLOY_SSH_SERVER"
|
_debug2 DEPLOY_SSH_SERVER "$DEPLOY_SSH_SERVER"
|
||||||
if [ -n "$DEPLOY_SSH_SERVER" ]; then
|
if [ -z "$DEPLOY_SSH_SERVER" ]; then
|
||||||
Le_Deploy_ssh_server="$DEPLOY_SSH_SERVER"
|
DEPLOY_SSH_SERVER="$_cdomain"
|
||||||
_savedomainconf Le_Deploy_ssh_server "$Le_Deploy_ssh_server"
|
|
||||||
elif [ -z "$Le_Deploy_ssh_server" ]; then
|
|
||||||
Le_Deploy_ssh_server="$_cdomain"
|
|
||||||
fi
|
fi
|
||||||
|
_savedeployconf DEPLOY_SSH_SERVER "$DEPLOY_SSH_SERVER"
|
||||||
|
|
||||||
# CMD is optional. If not provided then use ssh
|
# CMD is optional. If not provided then use ssh
|
||||||
|
_migratedeployconf Le_Deploy_ssh_cmd DEPLOY_SSH_CMD
|
||||||
_getdeployconf DEPLOY_SSH_CMD
|
_getdeployconf DEPLOY_SSH_CMD
|
||||||
_debug2 DEPLOY_SSH_CMD "$DEPLOY_SSH_CMD"
|
_debug2 DEPLOY_SSH_CMD "$DEPLOY_SSH_CMD"
|
||||||
if [ -n "$DEPLOY_SSH_CMD" ]; then
|
if [ -z "$DEPLOY_SSH_CMD" ]; then
|
||||||
Le_Deploy_ssh_cmd="$DEPLOY_SSH_CMD"
|
DEPLOY_SSH_CMD="ssh -T"
|
||||||
_savedomainconf Le_Deploy_ssh_cmd "$Le_Deploy_ssh_cmd"
|
|
||||||
elif [ -z "$Le_Deploy_ssh_cmd" ]; then
|
|
||||||
Le_Deploy_ssh_cmd="ssh -T"
|
|
||||||
fi
|
fi
|
||||||
|
_savedeployconf DEPLOY_SSH_CMD "$DEPLOY_SSH_CMD"
|
||||||
|
|
||||||
# BACKUP is optional. If not provided then default to previously saved value or yes.
|
# BACKUP is optional. If not provided then default to previously saved value or yes.
|
||||||
|
_migratedeployconf Le_Deploy_ssh_backup DEPLOY_SSH_BACKUP
|
||||||
_getdeployconf DEPLOY_SSH_BACKUP
|
_getdeployconf DEPLOY_SSH_BACKUP
|
||||||
_debug2 DEPLOY_SSH_BACKUP "$DEPLOY_SSH_BACKUP"
|
_debug2 DEPLOY_SSH_BACKUP "$DEPLOY_SSH_BACKUP"
|
||||||
if [ "$DEPLOY_SSH_BACKUP" = "no" ]; then
|
if [ -z "$DEPLOY_SSH_BACKUP" ]; then
|
||||||
Le_Deploy_ssh_backup="no"
|
DEPLOY_SSH_BACKUP="yes"
|
||||||
elif [ -z "$Le_Deploy_ssh_backup" ] || [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
|
||||||
Le_Deploy_ssh_backup="yes"
|
|
||||||
fi
|
fi
|
||||||
_savedomainconf Le_Deploy_ssh_backup "$Le_Deploy_ssh_backup"
|
_savedeployconf DEPLOY_SSH_BACKUP "$DEPLOY_SSH_BACKUP"
|
||||||
|
|
||||||
# BACKUP_PATH is optional. If not provided then default to previously saved value or .acme_ssh_deploy
|
# BACKUP_PATH is optional. If not provided then default to previously saved value or .acme_ssh_deploy
|
||||||
|
_migratedeployconf Le_Deploy_ssh_backup_path DEPLOY_SSH_BACKUP_PATH
|
||||||
_getdeployconf DEPLOY_SSH_BACKUP_PATH
|
_getdeployconf DEPLOY_SSH_BACKUP_PATH
|
||||||
_debug2 DEPLOY_SSH_BACKUP_PATH "$DEPLOY_SSH_BACKUP_PATH"
|
_debug2 DEPLOY_SSH_BACKUP_PATH "$DEPLOY_SSH_BACKUP_PATH"
|
||||||
if [ -n "$DEPLOY_SSH_BACKUP_PATH" ]; then
|
if [ -z "$DEPLOY_SSH_BACKUP_PATH" ]; then
|
||||||
Le_Deploy_ssh_backup_path="$DEPLOY_SSH_BACKUP_PATH"
|
DEPLOY_SSH_BACKUP_PATH=".acme_ssh_deploy"
|
||||||
elif [ -z "$Le_Deploy_ssh_backup_path" ]; then
|
|
||||||
Le_Deploy_ssh_backup_path=".acme_ssh_deploy"
|
|
||||||
fi
|
fi
|
||||||
_savedomainconf Le_Deploy_ssh_backup_path "$Le_Deploy_ssh_backup_path"
|
_savedeployconf DEPLOY_SSH_BACKUP_PATH "$DEPLOY_SSH_BACKUP_PATH"
|
||||||
|
|
||||||
# MULTI_CALL is optional. If not provided then default to previously saved
|
# MULTI_CALL is optional. If not provided then default to previously saved
|
||||||
# value (which may be undefined... equivalent to "no").
|
# value (which may be undefined... equivalent to "no").
|
||||||
|
_migratedeployconf Le_Deploy_ssh_multi_call DEPLOY_SSH_MULTI_CALL
|
||||||
_getdeployconf DEPLOY_SSH_MULTI_CALL
|
_getdeployconf DEPLOY_SSH_MULTI_CALL
|
||||||
_debug2 DEPLOY_SSH_MULTI_CALL "$DEPLOY_SSH_MULTI_CALL"
|
_debug2 DEPLOY_SSH_MULTI_CALL "$DEPLOY_SSH_MULTI_CALL"
|
||||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
if [ -z "$DEPLOY_SSH_MULTI_CALL" ]; then
|
||||||
Le_Deploy_ssh_multi_call="yes"
|
DEPLOY_SSH_MULTI_CALL="no"
|
||||||
_savedomainconf Le_Deploy_ssh_multi_call "$Le_Deploy_ssh_multi_call"
|
fi
|
||||||
elif [ "$DEPLOY_SSH_MULTI_CALL" = "no" ]; then
|
_savedeployconf DEPLOY_SSH_MULTI_CALL "$DEPLOY_SSH_MULTI_CALL"
|
||||||
Le_Deploy_ssh_multi_call=""
|
|
||||||
_cleardomainconf Le_Deploy_ssh_multi_call
|
# KEYFILE is optional.
|
||||||
|
# If provided then private key will be copied to provided filename.
|
||||||
|
_migratedeployconf Le_Deploy_ssh_keyfile DEPLOY_SSH_KEYFILE
|
||||||
|
_getdeployconf DEPLOY_SSH_KEYFILE
|
||||||
|
_debug2 DEPLOY_SSH_KEYFILE "$DEPLOY_SSH_KEYFILE"
|
||||||
|
if [ -n "$DEPLOY_SSH_KEYFILE" ]; then
|
||||||
|
_savedeployconf DEPLOY_SSH_KEYFILE "$DEPLOY_SSH_KEYFILE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_deploy_ssh_servers=$Le_Deploy_ssh_server
|
# CERTFILE is optional.
|
||||||
for Le_Deploy_ssh_server in $_deploy_ssh_servers; do
|
# If provided then certificate will be copied or appended to provided filename.
|
||||||
|
_migratedeployconf Le_Deploy_ssh_certfile DEPLOY_SSH_CERTFILE
|
||||||
|
_getdeployconf DEPLOY_SSH_CERTFILE
|
||||||
|
_debug2 DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
|
||||||
|
if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
|
||||||
|
_savedeployconf DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# CAFILE is optional.
|
||||||
|
# If provided then CA intermediate certificate will be copied or appended to provided filename.
|
||||||
|
_migratedeployconf Le_Deploy_ssh_cafile DEPLOY_SSH_CAFILE
|
||||||
|
_getdeployconf DEPLOY_SSH_CAFILE
|
||||||
|
_debug2 DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
|
||||||
|
if [ -n "$DEPLOY_SSH_CAFILE" ]; then
|
||||||
|
_savedeployconf DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# FULLCHAIN is optional.
|
||||||
|
# If provided then fullchain certificate will be copied or appended to provided filename.
|
||||||
|
_migratedeployconf Le_Deploy_ssh_fullchain DEPLOY_SSH_FULLCHAIN
|
||||||
|
_getdeployconf DEPLOY_SSH_FULLCHAIN
|
||||||
|
_debug2 DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
|
||||||
|
if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then
|
||||||
|
_savedeployconf DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# REMOTE_CMD is optional.
|
||||||
|
# If provided then this command will be executed on remote host.
|
||||||
|
_migratedeployconf Le_Deploy_ssh_remote_cmd DEPLOY_SSH_REMOTE_CMD
|
||||||
|
_getdeployconf DEPLOY_SSH_REMOTE_CMD
|
||||||
|
_debug2 DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
|
||||||
|
if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
|
||||||
|
_savedeployconf DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# USE_SCP is optional. If not provided then default to previously saved
|
||||||
|
# value (which may be undefined... equivalent to "no").
|
||||||
|
_getdeployconf DEPLOY_SSH_USE_SCP
|
||||||
|
_debug2 DEPLOY_SSH_USE_SCP "$DEPLOY_SSH_USE_SCP"
|
||||||
|
if [ -z "$DEPLOY_SSH_USE_SCP" ]; then
|
||||||
|
DEPLOY_SSH_USE_SCP="no"
|
||||||
|
fi
|
||||||
|
_savedeployconf DEPLOY_SSH_USE_SCP "$DEPLOY_SSH_USE_SCP"
|
||||||
|
|
||||||
|
# SCP_CMD is optional. If not provided then use scp
|
||||||
|
_getdeployconf DEPLOY_SSH_SCP_CMD
|
||||||
|
_debug2 DEPLOY_SSH_SCP_CMD "$DEPLOY_SSH_SCP_CMD"
|
||||||
|
if [ -z "$DEPLOY_SSH_SCP_CMD" ]; then
|
||||||
|
DEPLOY_SSH_SCP_CMD="scp -q"
|
||||||
|
fi
|
||||||
|
_savedeployconf DEPLOY_SSH_SCP_CMD "$DEPLOY_SSH_SCP_CMD"
|
||||||
|
|
||||||
|
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||||
|
DEPLOY_SSH_MULTI_CALL="yes"
|
||||||
|
_info "Using scp as alternate method for copying files. Multicall Mode is implicit"
|
||||||
|
elif [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||||
|
_info "Using MULTI_CALL mode... Required commands sent in multiple calls to remote host"
|
||||||
|
else
|
||||||
|
_info "Required commands batched and sent in single call to remote host"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_deploy_ssh_servers="$DEPLOY_SSH_SERVER"
|
||||||
|
for DEPLOY_SSH_SERVER in $_deploy_ssh_servers; do
|
||||||
_ssh_deploy
|
_ssh_deploy
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
@ -117,16 +181,25 @@ _ssh_deploy() {
|
|||||||
_cmdstr=""
|
_cmdstr=""
|
||||||
_backupprefix=""
|
_backupprefix=""
|
||||||
_backupdir=""
|
_backupdir=""
|
||||||
|
_local_cert_file=""
|
||||||
|
_local_ca_file=""
|
||||||
|
_local_full_file=""
|
||||||
|
|
||||||
_info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server"
|
case $DEPLOY_SSH_SERVER in
|
||||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
*:*)
|
||||||
_info "Using MULTI_CALL mode... Required commands sent in multiple calls to remote host"
|
_host=${DEPLOY_SSH_SERVER%:*}
|
||||||
else
|
_port=${DEPLOY_SSH_SERVER##*:}
|
||||||
_info "Required commands batched and sent in single call to remote host"
|
;;
|
||||||
fi
|
*)
|
||||||
|
_host=$DEPLOY_SSH_SERVER
|
||||||
|
_port=
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
_info "Deploy certificates to remote server $DEPLOY_SSH_USER@$_host:$_port"
|
||||||
_backupprefix="$Le_Deploy_ssh_backup_path/$_cdomain-backup"
|
|
||||||
|
if [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||||
|
_backupprefix="$DEPLOY_SSH_BACKUP_PATH/$_cdomain-backup"
|
||||||
_backupdir="$_backupprefix-$(_utc_date | tr ' ' '-')"
|
_backupdir="$_backupprefix-$(_utc_date | tr ' ' '-')"
|
||||||
# run cleanup on the backup directory, erase all older
|
# run cleanup on the backup directory, erase all older
|
||||||
# than 180 days (15552000 seconds).
|
# than 180 days (15552000 seconds).
|
||||||
@ -138,7 +211,7 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
|||||||
_cmdstr="mkdir -p $_backupdir; $_cmdstr"
|
_cmdstr="mkdir -p $_backupdir; $_cmdstr"
|
||||||
_info "Backup of old certificate files will be placed in remote directory $_backupdir"
|
_info "Backup of old certificate files will be placed in remote directory $_backupdir"
|
||||||
_info "Backup directories erased after 180 days."
|
_info "Backup directories erased after 180 days."
|
||||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||||
return $_err_code
|
return $_err_code
|
||||||
fi
|
fi
|
||||||
@ -146,23 +219,11 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# KEYFILE is optional.
|
|
||||||
# If provided then private key will be copied to provided filename.
|
|
||||||
_getdeployconf DEPLOY_SSH_KEYFILE
|
|
||||||
_debug2 DEPLOY_SSH_KEYFILE "$DEPLOY_SSH_KEYFILE"
|
|
||||||
if [ -n "$DEPLOY_SSH_KEYFILE" ]; then
|
if [ -n "$DEPLOY_SSH_KEYFILE" ]; then
|
||||||
Le_Deploy_ssh_keyfile="$DEPLOY_SSH_KEYFILE"
|
if [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||||
_savedomainconf Le_Deploy_ssh_keyfile "$Le_Deploy_ssh_keyfile"
|
|
||||||
fi
|
|
||||||
if [ -n "$Le_Deploy_ssh_keyfile" ]; then
|
|
||||||
if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
|
||||||
# backup file we are about to overwrite.
|
# backup file we are about to overwrite.
|
||||||
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir >/dev/null;"
|
_cmdstr="$_cmdstr cp $DEPLOY_SSH_KEYFILE $_backupdir >/dev/null;"
|
||||||
fi
|
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||||
# copy new certificate into file.
|
|
||||||
_cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile;"
|
|
||||||
_info "will copy private key to remote file $Le_Deploy_ssh_keyfile"
|
|
||||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
|
||||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||||
return $_err_code
|
return $_err_code
|
||||||
fi
|
fi
|
||||||
@ -170,27 +231,34 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# CERTFILE is optional.
|
# copy new key into file.
|
||||||
# If provided then certificate will be copied or appended to provided filename.
|
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||||
_getdeployconf DEPLOY_SSH_CERTFILE
|
# scp the file
|
||||||
_debug2 DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
|
if ! _scp_remote_cmd "$_ckey" "$DEPLOY_SSH_KEYFILE"; then
|
||||||
|
return $_err_code
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# ssh echo to the file
|
||||||
|
_cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $DEPLOY_SSH_KEYFILE;"
|
||||||
|
_info "will copy private key to remote file $DEPLOY_SSH_KEYFILE"
|
||||||
|
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||||
|
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||||
|
return $_err_code
|
||||||
|
fi
|
||||||
|
_cmdstr=""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
|
if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
|
||||||
Le_Deploy_ssh_certfile="$DEPLOY_SSH_CERTFILE"
|
|
||||||
_savedomainconf Le_Deploy_ssh_certfile "$Le_Deploy_ssh_certfile"
|
|
||||||
fi
|
|
||||||
if [ -n "$Le_Deploy_ssh_certfile" ]; then
|
|
||||||
_pipe=">"
|
_pipe=">"
|
||||||
if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then
|
if [ "$DEPLOY_SSH_CERTFILE" = "$DEPLOY_SSH_KEYFILE" ]; then
|
||||||
# if filename is same as previous file then append.
|
# if filename is same as previous file then append.
|
||||||
_pipe=">>"
|
_pipe=">>"
|
||||||
elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
elif [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||||
# backup file we are about to overwrite.
|
# backup file we are about to overwrite.
|
||||||
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir >/dev/null;"
|
_cmdstr="$_cmdstr cp $DEPLOY_SSH_CERTFILE $_backupdir >/dev/null;"
|
||||||
fi
|
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||||
# copy new certificate into file.
|
|
||||||
_cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile;"
|
|
||||||
_info "will copy certificate to remote file $Le_Deploy_ssh_certfile"
|
|
||||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
|
||||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||||
return $_err_code
|
return $_err_code
|
||||||
fi
|
fi
|
||||||
@ -198,28 +266,40 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# CAFILE is optional.
|
# copy new certificate into file.
|
||||||
# If provided then CA intermediate certificate will be copied or appended to provided filename.
|
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||||
_getdeployconf DEPLOY_SSH_CAFILE
|
# scp the file
|
||||||
_debug2 DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
|
_local_cert_file=$(_mktemp)
|
||||||
|
if [ "$DEPLOY_SSH_CERTFILE" = "$DEPLOY_SSH_KEYFILE" ]; then
|
||||||
|
cat "$_ckey" >>"$_local_cert_file"
|
||||||
|
fi
|
||||||
|
cat "$_ccert" >>"$_local_cert_file"
|
||||||
|
if ! _scp_remote_cmd "$_local_cert_file" "$DEPLOY_SSH_CERTFILE"; then
|
||||||
|
return $_err_code
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# ssh echo to the file
|
||||||
|
_cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $DEPLOY_SSH_CERTFILE;"
|
||||||
|
_info "will copy certificate to remote file $DEPLOY_SSH_CERTFILE"
|
||||||
|
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||||
|
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||||
|
return $_err_code
|
||||||
|
fi
|
||||||
|
_cmdstr=""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -n "$DEPLOY_SSH_CAFILE" ]; then
|
if [ -n "$DEPLOY_SSH_CAFILE" ]; then
|
||||||
Le_Deploy_ssh_cafile="$DEPLOY_SSH_CAFILE"
|
|
||||||
_savedomainconf Le_Deploy_ssh_cafile "$Le_Deploy_ssh_cafile"
|
|
||||||
fi
|
|
||||||
if [ -n "$Le_Deploy_ssh_cafile" ]; then
|
|
||||||
_pipe=">"
|
_pipe=">"
|
||||||
if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] ||
|
if [ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_KEYFILE" ] ||
|
||||||
[ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then
|
[ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_CERTFILE" ]; then
|
||||||
# if filename is same as previous file then append.
|
# if filename is same as previous file then append.
|
||||||
_pipe=">>"
|
_pipe=">>"
|
||||||
elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
elif [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||||
# backup file we are about to overwrite.
|
# backup file we are about to overwrite.
|
||||||
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir >/dev/null;"
|
_cmdstr="$_cmdstr cp $DEPLOY_SSH_CAFILE $_backupdir >/dev/null;"
|
||||||
fi
|
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||||
# copy new certificate into file.
|
|
||||||
_cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile;"
|
|
||||||
_info "will copy CA file to remote file $Le_Deploy_ssh_cafile"
|
|
||||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
|
||||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||||
return $_err_code
|
return $_err_code
|
||||||
fi
|
fi
|
||||||
@ -227,29 +307,44 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# FULLCHAIN is optional.
|
# copy new certificate into file.
|
||||||
# If provided then fullchain certificate will be copied or appended to provided filename.
|
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||||
_getdeployconf DEPLOY_SSH_FULLCHAIN
|
# scp the file
|
||||||
_debug2 DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
|
_local_ca_file=$(_mktemp)
|
||||||
|
if [ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_KEYFILE" ]; then
|
||||||
|
cat "$_ckey" >>"$_local_ca_file"
|
||||||
|
fi
|
||||||
|
if [ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_CERTFILE" ]; then
|
||||||
|
cat "$_ccert" >>"$_local_ca_file"
|
||||||
|
fi
|
||||||
|
cat "$_cca" >>"$_local_ca_file"
|
||||||
|
if ! _scp_remote_cmd "$_local_ca_file" "$DEPLOY_SSH_CAFILE"; then
|
||||||
|
return $_err_code
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# ssh echo to the file
|
||||||
|
_cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $DEPLOY_SSH_CAFILE;"
|
||||||
|
_info "will copy CA file to remote file $DEPLOY_SSH_CAFILE"
|
||||||
|
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||||
|
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||||
|
return $_err_code
|
||||||
|
fi
|
||||||
|
_cmdstr=""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then
|
if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then
|
||||||
Le_Deploy_ssh_fullchain="$DEPLOY_SSH_FULLCHAIN"
|
|
||||||
_savedomainconf Le_Deploy_ssh_fullchain "$Le_Deploy_ssh_fullchain"
|
|
||||||
fi
|
|
||||||
if [ -n "$Le_Deploy_ssh_fullchain" ]; then
|
|
||||||
_pipe=">"
|
_pipe=">"
|
||||||
if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] ||
|
if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_KEYFILE" ] ||
|
||||||
[ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] ||
|
[ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CERTFILE" ] ||
|
||||||
[ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then
|
[ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CAFILE" ]; then
|
||||||
# if filename is same as previous file then append.
|
# if filename is same as previous file then append.
|
||||||
_pipe=">>"
|
_pipe=">>"
|
||||||
elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
elif [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||||
# backup file we are about to overwrite.
|
# backup file we are about to overwrite.
|
||||||
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir >/dev/null;"
|
_cmdstr="$_cmdstr cp $DEPLOY_SSH_FULLCHAIN $_backupdir >/dev/null;"
|
||||||
fi
|
if [ "$DEPLOY_SSH_FULLCHAIN" = "yes" ]; then
|
||||||
# copy new certificate into file.
|
|
||||||
_cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain;"
|
|
||||||
_info "will copy fullchain to remote file $Le_Deploy_ssh_fullchain"
|
|
||||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
|
||||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||||
return $_err_code
|
return $_err_code
|
||||||
fi
|
fi
|
||||||
@ -257,18 +352,51 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# REMOTE_CMD is optional.
|
# copy new certificate into file.
|
||||||
# If provided then this command will be executed on remote host.
|
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||||
_getdeployconf DEPLOY_SSH_REMOTE_CMD
|
# scp the file
|
||||||
_debug2 DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
|
_local_full_file=$(_mktemp)
|
||||||
if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
|
if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_KEYFILE" ]; then
|
||||||
Le_Deploy_ssh_remote_cmd="$DEPLOY_SSH_REMOTE_CMD"
|
cat "$_ckey" >>"$_local_full_file"
|
||||||
_savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd"
|
|
||||||
fi
|
fi
|
||||||
if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then
|
if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CERTFILE" ]; then
|
||||||
_cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd;"
|
cat "$_ccert" >>"$_local_full_file"
|
||||||
_info "Will execute remote command $Le_Deploy_ssh_remote_cmd"
|
fi
|
||||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CAFILE" ]; then
|
||||||
|
cat "$_cca" >>"$_local_full_file"
|
||||||
|
fi
|
||||||
|
cat "$_cfullchain" >>"$_local_full_file"
|
||||||
|
if ! _scp_remote_cmd "$_local_full_file" "$DEPLOY_SSH_FULLCHAIN"; then
|
||||||
|
return $_err_code
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# ssh echo to the file
|
||||||
|
_cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $DEPLOY_SSH_FULLCHAIN;"
|
||||||
|
_info "will copy fullchain to remote file $DEPLOY_SSH_FULLCHAIN"
|
||||||
|
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||||
|
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||||
|
return $_err_code
|
||||||
|
fi
|
||||||
|
_cmdstr=""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# cleanup local files if any
|
||||||
|
if [ -f "$_local_cert_file" ]; then
|
||||||
|
rm -f "$_local_cert_file"
|
||||||
|
fi
|
||||||
|
if [ -f "$_local_ca_file" ]; then
|
||||||
|
rm -f "$_local_ca_file"
|
||||||
|
fi
|
||||||
|
if [ -f "$_local_full_file" ]; then
|
||||||
|
rm -f "$_local_full_file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
|
||||||
|
_cmdstr="$_cmdstr $DEPLOY_SSH_REMOTE_CMD;"
|
||||||
|
_info "Will execute remote command $DEPLOY_SSH_REMOTE_CMD"
|
||||||
|
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||||
return $_err_code
|
return $_err_code
|
||||||
fi
|
fi
|
||||||
@ -282,17 +410,25 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
|||||||
return $_err_code
|
return $_err_code
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
# cleanup in case all is ok
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
#cmd
|
#cmd
|
||||||
_ssh_remote_cmd() {
|
_ssh_remote_cmd() {
|
||||||
_cmd="$1"
|
_cmd="$1"
|
||||||
|
|
||||||
|
_ssh_cmd="$DEPLOY_SSH_CMD"
|
||||||
|
if [ -n "$_port" ]; then
|
||||||
|
_ssh_cmd="$_ssh_cmd -p $_port"
|
||||||
|
fi
|
||||||
|
|
||||||
_secure_debug "Remote commands to execute: $_cmd"
|
_secure_debug "Remote commands to execute: $_cmd"
|
||||||
_info "Submitting sequence of commands to remote server by ssh"
|
_info "Submitting sequence of commands to remote server by $_ssh_cmd"
|
||||||
|
|
||||||
# quotations in bash cmd below intended. Squash travis spellcheck error
|
# quotations in bash cmd below intended. Squash travis spellcheck error
|
||||||
# shellcheck disable=SC2029
|
# shellcheck disable=SC2029
|
||||||
$Le_Deploy_ssh_cmd "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh -c "'$_cmd'"
|
$_ssh_cmd "$DEPLOY_SSH_USER@$_host" sh -c "'$_cmd'"
|
||||||
_err_code="$?"
|
_err_code="$?"
|
||||||
|
|
||||||
if [ "$_err_code" != "0" ]; then
|
if [ "$_err_code" != "0" ]; then
|
||||||
@ -301,3 +437,26 @@ _ssh_remote_cmd() {
|
|||||||
|
|
||||||
return $_err_code
|
return $_err_code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# cmd scp
|
||||||
|
_scp_remote_cmd() {
|
||||||
|
_src=$1
|
||||||
|
_dest=$2
|
||||||
|
|
||||||
|
_scp_cmd="$DEPLOY_SSH_SCP_CMD"
|
||||||
|
if [ -n "$_port" ]; then
|
||||||
|
_scp_cmd="$_scp_cmd -P $_port"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_secure_debug "Remote copy source $_src to destination $_dest"
|
||||||
|
_info "Submitting secure copy by $_scp_cmd"
|
||||||
|
|
||||||
|
$_scp_cmd "$_src" "$DEPLOY_SSH_USER"@"$_host":"$_dest"
|
||||||
|
_err_code="$?"
|
||||||
|
|
||||||
|
if [ "$_err_code" != "0" ]; then
|
||||||
|
_err "Error code $_err_code returned from scp"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $_err_code
|
||||||
|
}
|
||||||
|
@ -1,34 +1,53 @@
|
|||||||
#!/usr/bin/env sh
|
#!/bin/bash
|
||||||
|
|
||||||
# Here is a script to deploy cert to Synology DSM
|
################################################################################
|
||||||
#
|
# ACME.sh 3rd party deploy plugin for Synology DSM
|
||||||
# It requires following environment variables:
|
################################################################################
|
||||||
#
|
# Authors: Brian Hartvigsen (creator), https://github.com/tresni
|
||||||
# SYNO_Username - Synology Username to login (must be an administrator)
|
# Martin Arndt (contributor), https://troublezone.net/
|
||||||
# SYNO_Password - Synology Password to login
|
# Updated: 2023-07-03
|
||||||
# SYNO_Certificate - Certificate description to target for replacement
|
# Issues: https://github.com/acmesh-official/acme.sh/issues/2727
|
||||||
#
|
################################################################################
|
||||||
# The following environmental variables may be set if you don't like their
|
# Usage (shown values are the examples):
|
||||||
# default values:
|
# 1. Set required environment variables:
|
||||||
#
|
# - use automatically created temp admin user to authenticate
|
||||||
# SYNO_Scheme - defaults to http
|
# export SYNO_USE_TEMP_ADMIN=1
|
||||||
# SYNO_Hostname - defaults to localhost
|
# - or provide your own admin user credential to authenticate
|
||||||
# SYNO_Port - defaults to 5000
|
# 1. export SYNO_USERNAME="adminUser"
|
||||||
# SYNO_DID - device ID to skip OTP - defaults to empty
|
# 2. export SYNO_PASSWORD="adminPassword"
|
||||||
# SYNO_TOTP_SECRET - TOTP secret to generate OTP - defaults to empty
|
# 2. Set optional environment variables
|
||||||
#
|
# - common optional variables
|
||||||
|
# - export SYNO_SCHEME="http" - defaults to "http"
|
||||||
|
# - export SYNO_HOSTNAME="localhost" - defaults to "localhost"
|
||||||
|
# - export SYNO_PORT="5000" - defaults to "5000"
|
||||||
|
# - export SYNO_CREATE=1 - to allow creating the cert if it doesn't exist
|
||||||
|
# - export SYNO_CERTIFICATE="" - to replace a specific cert by its
|
||||||
|
# description
|
||||||
|
# - temp admin optional variables
|
||||||
|
# - export SYNO_LOCAL_HOSTNAME=1 - if set to 1, force to treat hostname is
|
||||||
|
# targeting current local machine (since
|
||||||
|
# this method only locally supported)
|
||||||
|
# - exsiting admin 2FA-OTP optional variables
|
||||||
|
# - export SYNO_OTP_CODE="XXXXXX" - if set, script won't require to
|
||||||
|
# interactive input the OTP code
|
||||||
|
# - export SYNO_DEVICE_NAME="CertRenewal" - if set, script won't require to
|
||||||
|
# interactive input the device name
|
||||||
|
# - export SYNO_DEVICE_ID="" - (deprecated, auth with OTP code instead)
|
||||||
|
# required for omitting 2FA-OTP
|
||||||
|
# 3. Run command:
|
||||||
|
# acme.sh --deploy --deploy-hook synology_dsm -d example.com
|
||||||
|
################################################################################
|
||||||
# Dependencies:
|
# Dependencies:
|
||||||
# -------------
|
# - curl
|
||||||
# - jq and curl
|
# - synouser & synogroup & synosetkeyvalue (Required for SYNO_USE_TEMP_ADMIN=1)
|
||||||
# - oathtool (When using 2 Factor Authentication and SYNO_TOTP_SECRET is set)
|
################################################################################
|
||||||
#
|
# Return value:
|
||||||
#returns 0 means success, otherwise error.
|
# 0 means success, otherwise error.
|
||||||
|
################################################################################
|
||||||
######## Public functions #####################
|
|
||||||
|
|
||||||
|
########## Public functions ####################################################
|
||||||
#domain keyfile certfile cafile fullchain
|
#domain keyfile certfile cafile fullchain
|
||||||
synology_dsm_deploy() {
|
synology_dsm_deploy() {
|
||||||
|
|
||||||
_cdomain="$1"
|
_cdomain="$1"
|
||||||
_ckey="$2"
|
_ckey="$2"
|
||||||
_ccert="$3"
|
_ccert="$3"
|
||||||
@ -36,143 +55,391 @@ synology_dsm_deploy() {
|
|||||||
|
|
||||||
_debug _cdomain "$_cdomain"
|
_debug _cdomain "$_cdomain"
|
||||||
|
|
||||||
# Get Username and Password, but don't save until we successfully authenticate
|
# Get username and password, but don't save until we authenticated successfully
|
||||||
_getdeployconf SYNO_Username
|
_migratedeployconf SYNO_Username SYNO_USERNAME
|
||||||
_getdeployconf SYNO_Password
|
_migratedeployconf SYNO_Password SYNO_PASSWORD
|
||||||
_getdeployconf SYNO_Create
|
_migratedeployconf SYNO_Device_ID SYNO_DEVICE_ID
|
||||||
_getdeployconf SYNO_DID
|
_migratedeployconf SYNO_Device_Name SYNO_DEVICE_NAME
|
||||||
_getdeployconf SYNO_TOTP_SECRET
|
_getdeployconf SYNO_USERNAME
|
||||||
if [ -z "${SYNO_Username:-}" ] || [ -z "${SYNO_Password:-}" ]; then
|
_getdeployconf SYNO_PASSWORD
|
||||||
_err "SYNO_Username & SYNO_Password must be set"
|
_getdeployconf SYNO_DEVICE_ID
|
||||||
|
_getdeployconf SYNO_DEVICE_NAME
|
||||||
|
|
||||||
|
# Prepare to use temp admin if SYNO_USE_TEMP_ADMIN is set
|
||||||
|
_getdeployconf SYNO_USE_TEMP_ADMIN
|
||||||
|
_check2cleardeployconfexp SYNO_USE_TEMP_ADMIN
|
||||||
|
_debug2 SYNO_USE_TEMP_ADMIN "$SYNO_USE_TEMP_ADMIN"
|
||||||
|
|
||||||
|
if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
|
||||||
|
if ! _exists synouser || ! _exists synogroup || ! _exists synosetkeyvalue; then
|
||||||
|
_err "Missing required tools to creat temp admin user, please set SYNO_USERNAME and SYNO_PASSWORD instead."
|
||||||
|
_err "Notice: temp admin user authorization method only supports local deployment on DSM."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if synouser --help 2>&1 | grep -q 'Permission denied'; then
|
||||||
|
_err "For creating temp admin user, the deploy script must be run as root."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_debug2 SYNO_Username "$SYNO_Username"
|
|
||||||
_secure_debug2 SYNO_Password "$SYNO_Password"
|
|
||||||
|
|
||||||
# Optional scheme, hostname, and port for Synology DSM
|
[ -n "$SYNO_USERNAME" ] || _savedeployconf SYNO_USERNAME ""
|
||||||
_getdeployconf SYNO_Scheme
|
[ -n "$SYNO_PASSWORD" ] || _savedeployconf SYNO_PASSWORD ""
|
||||||
_getdeployconf SYNO_Hostname
|
|
||||||
_getdeployconf SYNO_Port
|
|
||||||
|
|
||||||
# default vaules for scheme, hostname, and port
|
_debug "Setting temp admin user credential..."
|
||||||
# defaulting to localhost and http because it's localhost...
|
SYNO_USERNAME=sc-acmesh-tmp
|
||||||
[ -n "${SYNO_Scheme}" ] || SYNO_Scheme="http"
|
SYNO_PASSWORD=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 16)
|
||||||
[ -n "${SYNO_Hostname}" ] || SYNO_Hostname="localhost"
|
# Set 2FA-OTP settings to empty consider they won't be needed.
|
||||||
[ -n "${SYNO_Port}" ] || SYNO_Port="5000"
|
SYNO_DEVICE_ID=
|
||||||
|
SYNO_DEVICE_NAME=
|
||||||
|
SYNO_OTP_CODE=
|
||||||
|
else
|
||||||
|
_debug2 SYNO_USERNAME "$SYNO_USERNAME"
|
||||||
|
_secure_debug2 SYNO_PASSWORD "$SYNO_PASSWORD"
|
||||||
|
_debug2 SYNO_DEVICE_NAME "$SYNO_DEVICE_NAME"
|
||||||
|
_secure_debug2 SYNO_DEVICE_ID "$SYNO_DEVICE_ID"
|
||||||
|
fi
|
||||||
|
|
||||||
_savedeployconf SYNO_Scheme "$SYNO_Scheme"
|
if [ -z "$SYNO_USERNAME" ] || [ -z "$SYNO_PASSWORD" ]; then
|
||||||
_savedeployconf SYNO_Hostname "$SYNO_Hostname"
|
_err "You must set either SYNO_USE_TEMP_ADMIN, or set both SYNO_USERNAME and SYNO_PASSWORD."
|
||||||
_savedeployconf SYNO_Port "$SYNO_Port"
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
_debug2 SYNO_Scheme "$SYNO_Scheme"
|
# Optional scheme, hostname and port for Synology DSM
|
||||||
_debug2 SYNO_Hostname "$SYNO_Hostname"
|
_migratedeployconf SYNO_Scheme SYNO_SCHEME
|
||||||
_debug2 SYNO_Port "$SYNO_Port"
|
_migratedeployconf SYNO_Hostname SYNO_HOSTNAME
|
||||||
|
_migratedeployconf SYNO_Port SYNO_PORT
|
||||||
|
_getdeployconf SYNO_SCHEME
|
||||||
|
_getdeployconf SYNO_HOSTNAME
|
||||||
|
_getdeployconf SYNO_PORT
|
||||||
|
|
||||||
# Get the certificate description, but don't save it until we verfiy it's real
|
# Default values for scheme, hostname and port
|
||||||
_getdeployconf SYNO_Certificate
|
# Defaulting to localhost and http, because it's localhost…
|
||||||
_debug SYNO_Certificate "${SYNO_Certificate:-}"
|
[ -n "$SYNO_SCHEME" ] || SYNO_SCHEME="http"
|
||||||
|
[ -n "$SYNO_HOSTNAME" ] || SYNO_HOSTNAME="localhost"
|
||||||
|
[ -n "$SYNO_PORT" ] || SYNO_PORT="5000"
|
||||||
|
_savedeployconf SYNO_SCHEME "$SYNO_SCHEME"
|
||||||
|
_savedeployconf SYNO_HOSTNAME "$SYNO_HOSTNAME"
|
||||||
|
_savedeployconf SYNO_PORT "$SYNO_PORT"
|
||||||
|
_debug2 SYNO_SCHEME "$SYNO_SCHEME"
|
||||||
|
_debug2 SYNO_HOSTNAME "$SYNO_HOSTNAME"
|
||||||
|
_debug2 SYNO_PORT "$SYNO_PORT"
|
||||||
|
|
||||||
|
# Get the certificate description, but don't save it until we verify it's real
|
||||||
|
_migratedeployconf SYNO_Certificate SYNO_CERTIFICATE "base64"
|
||||||
|
_getdeployconf SYNO_CERTIFICATE
|
||||||
|
_check2cleardeployconfexp SYNO_CERTIFICATE
|
||||||
|
_debug SYNO_CERTIFICATE "${SYNO_CERTIFICATE:-}"
|
||||||
|
|
||||||
# shellcheck disable=SC1003 # We are not trying to escape a single quote
|
# shellcheck disable=SC1003 # We are not trying to escape a single quote
|
||||||
if printf "%s" "$SYNO_Certificate" | grep '\\'; then
|
if printf "%s" "$SYNO_CERTIFICATE" | grep '\\'; then
|
||||||
_err "Do not use a backslash (\) in your certificate description"
|
_err "Do not use a backslash (\) in your certificate description"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_base_url="$SYNO_Scheme://$SYNO_Hostname:$SYNO_Port"
|
_debug "Getting API version..."
|
||||||
|
_base_url="$SYNO_SCHEME://$SYNO_HOSTNAME:$SYNO_PORT"
|
||||||
_debug _base_url "$_base_url"
|
_debug _base_url "$_base_url"
|
||||||
|
|
||||||
_debug "Getting API version"
|
|
||||||
response=$(_get "$_base_url/webapi/query.cgi?api=SYNO.API.Info&version=1&method=query&query=SYNO.API.Auth")
|
response=$(_get "$_base_url/webapi/query.cgi?api=SYNO.API.Info&version=1&method=query&query=SYNO.API.Auth")
|
||||||
|
api_path=$(echo "$response" | grep "SYNO.API.Auth" | sed -n 's/.*"path" *: *"\([^"]*\)".*/\1/p')
|
||||||
api_version=$(echo "$response" | grep "SYNO.API.Auth" | sed -n 's/.*"maxVersion" *: *\([0-9]*\).*/\1/p')
|
api_version=$(echo "$response" | grep "SYNO.API.Auth" | sed -n 's/.*"maxVersion" *: *\([0-9]*\).*/\1/p')
|
||||||
_debug3 response "$response"
|
_debug3 response "$response"
|
||||||
|
_debug3 api_path "$api_path"
|
||||||
_debug3 api_version "$api_version"
|
_debug3 api_version "$api_version"
|
||||||
|
|
||||||
# Login, get the token from JSON and session id from cookie
|
# Login, get the session ID and SynoToken from JSON
|
||||||
_info "Logging into $SYNO_Hostname:$SYNO_Port"
|
_info "Logging into $SYNO_HOSTNAME:$SYNO_PORT..."
|
||||||
encoded_username="$(printf "%s" "$SYNO_Username" | _url_encode)"
|
encoded_username="$(printf "%s" "$SYNO_USERNAME" | _url_encode)"
|
||||||
encoded_password="$(printf "%s" "$SYNO_Password" | _url_encode)"
|
encoded_password="$(printf "%s" "$SYNO_PASSWORD" | _url_encode)"
|
||||||
|
|
||||||
|
# ## START ## - DEPRECATED, for backward compatibility
|
||||||
|
_getdeployconf SYNO_TOTP_SECRET
|
||||||
|
|
||||||
otp_code=""
|
|
||||||
if [ -n "$SYNO_TOTP_SECRET" ]; then
|
if [ -n "$SYNO_TOTP_SECRET" ]; then
|
||||||
otp_code="$(oathtool --base32 --totp "${SYNO_TOTP_SECRET}" 2>/dev/null)"
|
_info "WARNING: Usage of SYNO_TOTP_SECRET is deprecated!"
|
||||||
|
_info " See synology_dsm.sh script or ACME.sh Wiki page for details:"
|
||||||
|
_info " https://github.com/acmesh-official/acme.sh/wiki/Synology-NAS-Guide"
|
||||||
|
if ! _exists oathtool; then
|
||||||
|
_err "oathtool could not be found, install oathtool to use SYNO_TOTP_SECRET"
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
|
DEPRECATED_otp_code="$(oathtool --base32 --totp "$SYNO_TOTP_SECRET" 2>/dev/null)"
|
||||||
|
|
||||||
if [ -n "$SYNO_DID" ]; then
|
if [ -z "$SYNO_DEVICE_ID" ]; then
|
||||||
_H1="Cookie: did=$SYNO_DID"
|
_getdeployconf SYNO_DID
|
||||||
|
[ -n "$SYNO_DID" ] || SYNO_DEVICE_ID="$SYNO_DID"
|
||||||
|
fi
|
||||||
|
if [ -n "$SYNO_DEVICE_ID" ]; then
|
||||||
|
_H1="Cookie: did=$SYNO_DEVICE_ID"
|
||||||
export _H1
|
export _H1
|
||||||
_debug3 H1 "${_H1}"
|
_debug3 H1 "${_H1}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
response=$(_post "method=login&account=$encoded_username&passwd=$encoded_password&api=SYNO.API.Auth&version=$api_version&enable_syno_token=yes&otp_code=$otp_code" "$_base_url/webapi/auth.cgi?enable_syno_token=yes")
|
response=$(_post "method=login&account=$encoded_username&passwd=$encoded_password&api=SYNO.API.Auth&version=$api_version&enable_syno_token=yes&otp_code=$DEPRECATED_otp_code&device_name=certrenewal&device_id=$SYNO_DEVICE_ID" "$_base_url/webapi/$api_path?enable_syno_token=yes")
|
||||||
token=$(echo "$response" | grep "synotoken" | sed -n 's/.*"synotoken" *: *"\([^"]*\).*/\1/p')
|
|
||||||
_debug3 response "$response"
|
_debug3 response "$response"
|
||||||
_debug token "$token"
|
# ## END ## - DEPRECATED, for backward compatibility
|
||||||
|
# If SYNO_DEVICE_ID or SYNO_OTP_CODE is set, we treat current account enabled 2FA-OTP.
|
||||||
if [ -z "$token" ]; then
|
# Notice that if SYNO_USE_TEMP_ADMIN=1, both variables will be unset
|
||||||
_err "Unable to authenticate to $SYNO_Hostname:$SYNO_Port using $SYNO_Scheme."
|
else
|
||||||
_err "Check your username and password."
|
if [ -n "$SYNO_DEVICE_ID" ] || [ -n "$SYNO_OTP_CODE" ]; then
|
||||||
_err "If two-factor authentication is enabled for the user, set SYNO_TOTP_SECRET."
|
response='{"error":{"code":403}}'
|
||||||
|
# Assume the current account disabled 2FA-OTP, try to log in right away.
|
||||||
|
else
|
||||||
|
if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
|
||||||
|
_getdeployconf SYNO_LOCAL_HOSTNAME
|
||||||
|
_debug SYNO_LOCAL_HOSTNAME "${SYNO_LOCAL_HOSTNAME:-}"
|
||||||
|
if [ "$SYNO_LOCAL_HOSTNAME" != "1" ] && [ "$SYNO_LOCAL_HOSTNAME" == "$SYNO_HOSTNAME" ]; then
|
||||||
|
if [ "$SYNO_HOSTNAME" != "localhost" ] && [ "$SYNO_HOSTNAME" != "127.0.0.1" ]; then
|
||||||
|
_err "SYNO_USE_TEMP_ADMIN=1 only support local deployment, though if you are sure that the hostname $SYNO_HOSTNAME is targeting to your **current local machine**, execute 'export SYNO_LOCAL_HOSTNAME=1' then rerun."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
_debug "Creating temp admin user in Synology DSM..."
|
||||||
|
if synogroup --help | grep -q '\-\-memberadd '; then
|
||||||
|
_temp_admin_create "$SYNO_USERNAME" "$SYNO_PASSWORD"
|
||||||
|
synogroup --memberadd administrators "$SYNO_USERNAME" >/dev/null
|
||||||
|
elif synogroup --help | grep -q '\-\-member '; then
|
||||||
|
# For supporting DSM 6.x which only has `--member` parameter.
|
||||||
|
cur_admins=$(synogroup --get administrators | awk -F '[][]' '/Group Members/,0{if(NF>1)printf "%s ", $2}')
|
||||||
|
if [ -n "$cur_admins" ]; then
|
||||||
|
_temp_admin_create "$SYNO_USERNAME" "$SYNO_PASSWORD"
|
||||||
|
_secure_debug3 admin_users "$cur_admins$SYNO_USERNAME"
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
synogroup --member administrators $cur_admins $SYNO_USERNAME >/dev/null
|
||||||
|
else
|
||||||
|
_err "The tool synogroup may be broken, please set SYNO_USERNAME and SYNO_PASSWORD instead."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
_err "Unsupported synogroup tool detected, please set SYNO_USERNAME and SYNO_PASSWORD instead."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
# havig a workaround to temporary disable enforce 2FA-OTP, will restore
|
||||||
|
# it soon (after a single request), though if any accident occurs like
|
||||||
|
# unexpected interruption, this setting can be easily reverted manually.
|
||||||
|
otp_enforce_option=$(synogetkeyvalue /etc/synoinfo.conf otp_enforce_option)
|
||||||
|
if [ -n "$otp_enforce_option" ] && [ "${otp_enforce_option:-"none"}" != "none" ]; then
|
||||||
|
synosetkeyvalue /etc/synoinfo.conf otp_enforce_option none
|
||||||
|
_info "Enforcing 2FA-OTP has been disabled to complete temp admin authentication."
|
||||||
|
_info "Notice: it will be restored soon, if not, you can restore it manually via Control Panel."
|
||||||
|
_info "previous_otp_enforce_option" "$otp_enforce_option"
|
||||||
|
else
|
||||||
|
otp_enforce_option=""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes")
|
||||||
|
if [ -n "$SYNO_USE_TEMP_ADMIN" ] && [ -n "$otp_enforce_option" ]; then
|
||||||
|
synosetkeyvalue /etc/synoinfo.conf otp_enforce_option "$otp_enforce_option"
|
||||||
|
_info "Restored previous enforce 2FA-OTP option."
|
||||||
|
fi
|
||||||
|
_debug3 response "$response"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*')
|
||||||
|
_debug2 error_code "$error_code"
|
||||||
|
# Account has 2FA-OTP enabled, since error 403 reported.
|
||||||
|
# https://global.download.synology.com/download/Document/Software/DeveloperGuide/Os/DSM/All/enu/DSM_Login_Web_API_Guide_enu.pdf
|
||||||
|
if [ "$error_code" == "403" ]; then
|
||||||
|
if [ -z "$SYNO_DEVICE_NAME" ]; then
|
||||||
|
printf "Enter device name or leave empty for default (CertRenewal): "
|
||||||
|
read -r SYNO_DEVICE_NAME
|
||||||
|
[ -n "$SYNO_DEVICE_NAME" ] || SYNO_DEVICE_NAME="CertRenewal"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$SYNO_DEVICE_ID" ]; then
|
||||||
|
# Omit OTP code with SYNO_DEVICE_ID.
|
||||||
|
response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes&device_name=$SYNO_DEVICE_NAME&device_id=$SYNO_DEVICE_ID")
|
||||||
|
_secure_debug3 response "$response"
|
||||||
|
else
|
||||||
|
# Require the OTP code if still unset.
|
||||||
|
if [ -z "$SYNO_OTP_CODE" ]; then
|
||||||
|
printf "Enter OTP code for user '%s': " "$SYNO_USERNAME"
|
||||||
|
read -r SYNO_OTP_CODE
|
||||||
|
fi
|
||||||
|
_secure_debug SYNO_OTP_CODE "${SYNO_OTP_CODE:-}"
|
||||||
|
|
||||||
|
if [ -z "$SYNO_OTP_CODE" ]; then
|
||||||
|
response='{"error":{"code":404}}'
|
||||||
|
else
|
||||||
|
response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes&enable_device_token=yes&device_name=$SYNO_DEVICE_NAME&otp_code=$SYNO_OTP_CODE")
|
||||||
|
_secure_debug3 response "$response"
|
||||||
|
|
||||||
|
id_property='device_id'
|
||||||
|
[ "${api_version}" -gt '6' ] || id_property='did'
|
||||||
|
SYNO_DEVICE_ID=$(echo "$response" | grep "$id_property" | sed -n 's/.*"'$id_property'" *: *"\([^"]*\).*/\1/p')
|
||||||
|
_secure_debug2 SYNO_DEVICE_ID "$SYNO_DEVICE_ID"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*')
|
||||||
|
_debug2 error_code "$error_code"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$error_code" ]; then
|
||||||
|
if [ "$error_code" == "403" ] && [ -n "$SYNO_DEVICE_ID" ]; then
|
||||||
|
_cleardeployconf SYNO_DEVICE_ID
|
||||||
|
_err "Failed to authenticate with SYNO_DEVICE_ID (may expired or invalid), please try again in a new terminal window."
|
||||||
|
elif [ "$error_code" == "404" ]; then
|
||||||
|
_err "Failed to authenticate with provided 2FA-OTP code, please try again in a new terminal window."
|
||||||
|
elif [ "$error_code" == "406" ]; then
|
||||||
|
if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
|
||||||
|
_err "Failed with unexcepted error, please report this by providing full log with '--debug 3'."
|
||||||
|
else
|
||||||
|
_err "Enforce auth with 2FA-OTP enabled, please configure the user to enable 2FA-OTP to continue."
|
||||||
|
fi
|
||||||
|
elif [ "$error_code" == "400" ]; then
|
||||||
|
_err "Failed to authenticate, no such account or incorrect password."
|
||||||
|
elif [ "$error_code" == "401" ]; then
|
||||||
|
_err "Failed to authenticate with a non-existent account."
|
||||||
|
elif [ "$error_code" == "408" ] || [ "$error_code" == "409" ] || [ "$error_code" == "410" ]; then
|
||||||
|
_err "Failed to authenticate, the account password has expired or must be changed."
|
||||||
|
else
|
||||||
|
_err "Failed to authenticate with error: $error_code."
|
||||||
|
fi
|
||||||
|
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
sid=$(echo "$response" | grep "sid" | sed -n 's/.*"sid" *: *"\([^"]*\).*/\1/p')
|
sid=$(echo "$response" | grep "sid" | sed -n 's/.*"sid" *: *"\([^"]*\).*/\1/p')
|
||||||
|
token=$(echo "$response" | grep "synotoken" | sed -n 's/.*"synotoken" *: *"\([^"]*\).*/\1/p')
|
||||||
|
_debug "Session ID" "$sid"
|
||||||
|
_debug SynoToken "$token"
|
||||||
|
if [ -z "$sid" ] || [ -z "$token" ]; then
|
||||||
|
# Still can't get necessary info even got no errors, may Synology have API updated?
|
||||||
|
_err "Unable to authenticate to $_base_url, you may report this by providing full log with '--debug 3'."
|
||||||
|
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
_H1="X-SYNO-TOKEN: $token"
|
_H1="X-SYNO-TOKEN: $token"
|
||||||
export _H1
|
export _H1
|
||||||
_debug2 H1 "${_H1}"
|
_debug2 H1 "${_H1}"
|
||||||
|
|
||||||
# Now that we know the username and password are good, save them
|
# Now that we know the username and password are good, save them if not in temp admin mode.
|
||||||
_savedeployconf SYNO_Username "$SYNO_Username"
|
if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
|
||||||
_savedeployconf SYNO_Password "$SYNO_Password"
|
_cleardeployconf SYNO_USERNAME
|
||||||
_savedeployconf SYNO_DID "$SYNO_DID"
|
_cleardeployconf SYNO_PASSWORD
|
||||||
_savedeployconf SYNO_TOTP_SECRET "$SYNO_TOTP_SECRET"
|
_cleardeployconf SYNO_DEVICE_ID
|
||||||
|
_cleardeployconf SYNO_DEVICE_NAME
|
||||||
|
_savedeployconf SYNO_USE_TEMP_ADMIN "$SYNO_USE_TEMP_ADMIN"
|
||||||
|
_savedeployconf SYNO_LOCAL_HOSTNAME "$SYNO_HOSTNAME"
|
||||||
|
else
|
||||||
|
_savedeployconf SYNO_USERNAME "$SYNO_USERNAME"
|
||||||
|
_savedeployconf SYNO_PASSWORD "$SYNO_PASSWORD"
|
||||||
|
_savedeployconf SYNO_DEVICE_ID "$SYNO_DEVICE_ID"
|
||||||
|
_savedeployconf SYNO_DEVICE_NAME "$SYNO_DEVICE_NAME"
|
||||||
|
fi
|
||||||
|
|
||||||
_info "Getting certificates in Synology DSM"
|
_info "Getting certificates in Synology DSM..."
|
||||||
response=$(_post "api=SYNO.Core.Certificate.CRT&method=list&version=1&_sid=$sid" "$_base_url/webapi/entry.cgi")
|
response=$(_post "api=SYNO.Core.Certificate.CRT&method=list&version=1&_sid=$sid" "$_base_url/webapi/entry.cgi")
|
||||||
_debug3 response "$response"
|
_debug3 response "$response"
|
||||||
escaped_certificate="$(printf "%s" "$SYNO_Certificate" | sed 's/\([].*^$[]\)/\\\1/g;s/"/\\\\"/g')"
|
escaped_certificate="$(printf "%s" "$SYNO_CERTIFICATE" | sed 's/\([].*^$[]\)/\\\1/g;s/"/\\\\"/g')"
|
||||||
_debug escaped_certificate "$escaped_certificate"
|
_debug escaped_certificate "$escaped_certificate"
|
||||||
id=$(echo "$response" | sed -n "s/.*\"desc\":\"$escaped_certificate\",\"id\":\"\([^\"]*\).*/\1/p")
|
id=$(echo "$response" | sed -n "s/.*\"desc\":\"$escaped_certificate\",\"id\":\"\([^\"]*\).*/\1/p")
|
||||||
_debug2 id "$id"
|
_debug2 id "$id"
|
||||||
|
|
||||||
if [ -z "$id" ] && [ -z "${SYNO_Create:-}" ]; then
|
error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*')
|
||||||
_err "Unable to find certificate: $SYNO_Certificate and \$SYNO_Create is not set"
|
_debug2 error_code "$error_code"
|
||||||
|
if [ -n "$error_code" ]; then
|
||||||
|
if [ "$error_code" -eq 105 ]; then
|
||||||
|
_err "Current user is not administrator and does not have sufficient permission for deploying."
|
||||||
|
else
|
||||||
|
_err "Failed to fetch certificate info: $error_code, please try again or contact Synology to learn more."
|
||||||
|
fi
|
||||||
|
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# we've verified this certificate description is a thing, so save it
|
_migratedeployconf SYNO_Create SYNO_CREATE
|
||||||
_savedeployconf SYNO_Certificate "$SYNO_Certificate" "base64"
|
_getdeployconf SYNO_CREATE
|
||||||
|
_debug2 SYNO_CREATE "$SYNO_CREATE"
|
||||||
|
|
||||||
_info "Generate form POST request"
|
if [ -z "$id" ] && [ -z "$SYNO_CREATE" ]; then
|
||||||
|
_err "Unable to find certificate: $SYNO_CERTIFICATE and $SYNO_CREATE is not set."
|
||||||
|
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# We've verified this certificate description is a thing, so save it
|
||||||
|
_savedeployconf SYNO_CERTIFICATE "$SYNO_CERTIFICATE" "base64"
|
||||||
|
|
||||||
|
_info "Generating form POST request..."
|
||||||
nl="\0015\0012"
|
nl="\0015\0012"
|
||||||
delim="--------------------------$(_utc_date | tr -d -- '-: ')"
|
delim="--------------------------$(_utc_date | tr -d -- '-: ')"
|
||||||
content="--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")\0012"
|
content="--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")\0012"
|
||||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"cert\"; filename=\"$(basename "$_ccert")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ccert")\0012"
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"cert\"; filename=\"$(basename "$_ccert")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ccert")\0012"
|
||||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"inter_cert\"; filename=\"$(basename "$_cca")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cca")\0012"
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"inter_cert\"; filename=\"$(basename "$_cca")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_cca")\0012"
|
||||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"id\"${nl}${nl}$id"
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"id\"${nl}${nl}$id"
|
||||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"desc\"${nl}${nl}${SYNO_Certificate}"
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"desc\"${nl}${nl}${SYNO_CERTIFICATE}"
|
||||||
if echo "$response" | sed -n "s/.*\"desc\":\"$escaped_certificate\",\([^{]*\).*/\1/p" | grep -- 'is_default":true' >/dev/null; then
|
if echo "$response" | sed -n "s/.*\"desc\":\"$escaped_certificate\",\([^{]*\).*/\1/p" | grep -- 'is_default":true' >/dev/null; then
|
||||||
_debug2 default "this is the default certificate"
|
_debug2 default "This is the default certificate"
|
||||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"as_default\"${nl}${nl}true"
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"as_default\"${nl}${nl}true"
|
||||||
else
|
else
|
||||||
_debug2 default "this is NOT the default certificate"
|
_debug2 default "This is NOT the default certificate"
|
||||||
fi
|
fi
|
||||||
content="$content${nl}--$delim--${nl}"
|
content="$content${nl}--$delim--${nl}"
|
||||||
content="$(printf "%b_" "$content")"
|
content="$(printf "%b_" "$content")"
|
||||||
content="${content%_}" # protect trailing \n
|
content="${content%_}" # protect trailing \n
|
||||||
|
|
||||||
_info "Upload certificate to the Synology DSM"
|
_info "Upload certificate to the Synology DSM."
|
||||||
response=$(_post "$content" "$_base_url/webapi/entry.cgi?api=SYNO.Core.Certificate&method=import&version=1&SynoToken=$token&_sid=$sid" "" "POST" "multipart/form-data; boundary=${delim}")
|
response=$(_post "$content" "$_base_url/webapi/entry.cgi?api=SYNO.Core.Certificate&method=import&version=1&SynoToken=$token&_sid=$sid" "" "POST" "multipart/form-data; boundary=${delim}")
|
||||||
_debug3 response "$response"
|
_debug3 response "$response"
|
||||||
|
|
||||||
if ! echo "$response" | grep '"error":' >/dev/null; then
|
if ! echo "$response" | grep '"error":' >/dev/null; then
|
||||||
if echo "$response" | grep '"restart_httpd":true' >/dev/null; then
|
if echo "$response" | grep '"restart_httpd":true' >/dev/null; then
|
||||||
_info "http services were restarted"
|
_info "Restart HTTP services succeeded."
|
||||||
else
|
else
|
||||||
_info "http services were NOT restarted"
|
_info "Restart HTTP services failed."
|
||||||
fi
|
fi
|
||||||
|
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||||
|
_logout
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
_err "Unable to update certificate, error code $response"
|
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||||
|
_err "Unable to update certificate, got error response: $response."
|
||||||
|
_logout
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#################### Private functions below ##################################
|
||||||
|
_logout() {
|
||||||
|
# Logout CERT user only to not occupy a permanent session, e.g. in DSM's "Connected Users" widget (based on previous variables)
|
||||||
|
response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=logout&_sid=$sid")
|
||||||
|
_debug3 response "$response"
|
||||||
|
}
|
||||||
|
|
||||||
|
_temp_admin_create() {
|
||||||
|
_username="$1"
|
||||||
|
_password="$2"
|
||||||
|
synouser --del "$_username" >/dev/null 2>/dev/null
|
||||||
|
synouser --add "$_username" "$_password" "" 0 "scruelt@hotmail.com" 0 >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
_temp_admin_cleanup() {
|
||||||
|
_flag=$1
|
||||||
|
_username=$2
|
||||||
|
|
||||||
|
if [ -n "${_flag}" ]; then
|
||||||
|
_debug "Cleanuping temp admin info..."
|
||||||
|
synouser --del "$_username" >/dev/null
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
#_cleardeployconf key
|
||||||
|
_cleardeployconf() {
|
||||||
|
_cleardomainconf "SAVED_$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# key
|
||||||
|
_check2cleardeployconfexp() {
|
||||||
|
_key="$1"
|
||||||
|
_clear_key="CLEAR_$_key"
|
||||||
|
# Clear saved settings if explicitly requested
|
||||||
|
if [ -n "$(eval echo \$"$_clear_key")" ]; then
|
||||||
|
_debug2 "$_key: value cleared from config, exported value will be ignored."
|
||||||
|
_cleardeployconf "$_key"
|
||||||
|
eval "$_key"=
|
||||||
|
export "$_key"=
|
||||||
|
eval SAVED_"$_key"=
|
||||||
|
export SAVED_"$_key"=
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
@ -38,7 +38,7 @@ truenas_deploy() {
|
|||||||
_getdeployconf DEPLOY_TRUENAS_APIKEY
|
_getdeployconf DEPLOY_TRUENAS_APIKEY
|
||||||
|
|
||||||
if [ -z "$DEPLOY_TRUENAS_APIKEY" ]; then
|
if [ -z "$DEPLOY_TRUENAS_APIKEY" ]; then
|
||||||
_err "TrueNAS Api Key is not found, please define DEPLOY_TRUENAS_APIKEY."
|
_err "TrueNAS API key not found, please set the DEPLOY_TRUENAS_APIKEY environment variable."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_secure_debug2 DEPLOY_TRUENAS_APIKEY "$DEPLOY_TRUENAS_APIKEY"
|
_secure_debug2 DEPLOY_TRUENAS_APIKEY "$DEPLOY_TRUENAS_APIKEY"
|
||||||
@ -62,15 +62,14 @@ truenas_deploy() {
|
|||||||
|
|
||||||
_info "Testing Connection TrueNAS"
|
_info "Testing Connection TrueNAS"
|
||||||
_response=$(_get "$_api_url/system/state")
|
_response=$(_get "$_api_url/system/state")
|
||||||
_info "TrueNAS System State: $_response."
|
_info "TrueNAS system state: $_response."
|
||||||
|
|
||||||
if [ -z "$_response" ]; then
|
if [ -z "$_response" ]; then
|
||||||
_err "Unable to authenticate to $_api_url."
|
_err "Unable to authenticate to $_api_url."
|
||||||
_err 'Check your Connection and set DEPLOY_TRUENAS_HOSTNAME="192.168.178.x".'
|
_err 'Check your connection settings are correct, e.g.'
|
||||||
_err 'or'
|
_err 'DEPLOY_TRUENAS_HOSTNAME="192.168.x.y" or DEPLOY_TRUENAS_HOSTNAME="truenas.example.com".'
|
||||||
_err 'set DEPLOY_TRUENAS_HOSTNAME="<truenas_dnsname>".'
|
_err 'DEPLOY_TRUENAS_SCHEME="https" or DEPLOY_TRUENAS_SCHEME="http".'
|
||||||
_err 'Check your Connection and set DEPLOY_TRUENAS_SCHEME="https".'
|
_err "Verify your TrueNAS API key is valid and set correctly, e.g. DEPLOY_TRUENAS_APIKEY=xxxx...."
|
||||||
_err "Check your Api Key."
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -78,7 +77,7 @@ truenas_deploy() {
|
|||||||
_savedeployconf DEPLOY_TRUENAS_HOSTNAME "$DEPLOY_TRUENAS_HOSTNAME"
|
_savedeployconf DEPLOY_TRUENAS_HOSTNAME "$DEPLOY_TRUENAS_HOSTNAME"
|
||||||
_savedeployconf DEPLOY_TRUENAS_SCHEME "$DEPLOY_TRUENAS_SCHEME"
|
_savedeployconf DEPLOY_TRUENAS_SCHEME "$DEPLOY_TRUENAS_SCHEME"
|
||||||
|
|
||||||
_info "Getting active certificate from TrueNAS"
|
_info "Getting current active certificate from TrueNAS"
|
||||||
_response=$(_get "$_api_url/system/general")
|
_response=$(_get "$_api_url/system/general")
|
||||||
_active_cert_id=$(echo "$_response" | grep -B2 '"name":' | grep 'id' | tr -d -- '"id: ,')
|
_active_cert_id=$(echo "$_response" | grep -B2 '"name":' | grep 'id' | tr -d -- '"id: ,')
|
||||||
_active_cert_name=$(echo "$_response" | grep '"name":' | sed -n 's/.*: "\(.\{1,\}\)",$/\1/p')
|
_active_cert_name=$(echo "$_response" | grep '"name":' | sed -n 's/.*: "\(.\{1,\}\)",$/\1/p')
|
||||||
@ -88,14 +87,14 @@ truenas_deploy() {
|
|||||||
_debug Active_UI_http_redirect "$_param_httpsredirect"
|
_debug Active_UI_http_redirect "$_param_httpsredirect"
|
||||||
|
|
||||||
if [ "$DEPLOY_TRUENAS_SCHEME" = "http" ] && [ "$_param_httpsredirect" = "true" ]; then
|
if [ "$DEPLOY_TRUENAS_SCHEME" = "http" ] && [ "$_param_httpsredirect" = "true" ]; then
|
||||||
_info "http Redirect active"
|
_info "HTTP->HTTPS redirection is enabled"
|
||||||
_info "Setting DEPLOY_TRUENAS_SCHEME to 'https'"
|
_info "Setting DEPLOY_TRUENAS_SCHEME to 'https'"
|
||||||
DEPLOY_TRUENAS_SCHEME="https"
|
DEPLOY_TRUENAS_SCHEME="https"
|
||||||
_api_url="$DEPLOY_TRUENAS_SCHEME://$DEPLOY_TRUENAS_HOSTNAME/api/v2.0"
|
_api_url="$DEPLOY_TRUENAS_SCHEME://$DEPLOY_TRUENAS_HOSTNAME/api/v2.0"
|
||||||
_savedeployconf DEPLOY_TRUENAS_SCHEME "$DEPLOY_TRUENAS_SCHEME"
|
_savedeployconf DEPLOY_TRUENAS_SCHEME "$DEPLOY_TRUENAS_SCHEME"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_info "Upload new certifikate to TrueNAS"
|
_info "Uploading new certificate to TrueNAS"
|
||||||
_certname="Letsencrypt_$(_utc_date | tr ' ' '_' | tr -d -- ':')"
|
_certname="Letsencrypt_$(_utc_date | tr ' ' '_' | tr -d -- ':')"
|
||||||
_debug3 _certname "$_certname"
|
_debug3 _certname "$_certname"
|
||||||
|
|
||||||
@ -104,30 +103,30 @@ truenas_deploy() {
|
|||||||
|
|
||||||
_debug3 _add_cert_result "$_add_cert_result"
|
_debug3 _add_cert_result "$_add_cert_result"
|
||||||
|
|
||||||
_info "Getting Certificate list to get new Cert ID"
|
_info "Fetching list of installed certificates"
|
||||||
_cert_list=$(_get "$_api_url/system/general/ui_certificate_choices")
|
_cert_list=$(_get "$_api_url/system/general/ui_certificate_choices")
|
||||||
_cert_id=$(echo "$_cert_list" | grep "$_certname" | sed -n 's/.*"\([0-9]\{1,\}\)".*$/\1/p')
|
_cert_id=$(echo "$_cert_list" | grep "$_certname" | sed -n 's/.*"\([0-9]\{1,\}\)".*$/\1/p')
|
||||||
|
|
||||||
_debug3 _cert_id "$_cert_id"
|
_debug3 _cert_id "$_cert_id"
|
||||||
|
|
||||||
_info "Activate Certificate ID: $_cert_id"
|
_info "Current activate certificate ID: $_cert_id"
|
||||||
_activateData="{\"ui_certificate\": \"${_cert_id}\"}"
|
_activateData="{\"ui_certificate\": \"${_cert_id}\"}"
|
||||||
_activate_result="$(_post "$_activateData" "$_api_url/system/general" "" "PUT" "application/json")"
|
_activate_result="$(_post "$_activateData" "$_api_url/system/general" "" "PUT" "application/json")"
|
||||||
|
|
||||||
_debug3 _activate_result "$_activate_result"
|
_debug3 _activate_result "$_activate_result"
|
||||||
|
|
||||||
_info "Check if WebDAV certificate is the same as the WEB UI"
|
_info "Checking if WebDAV certificate is the same as the TrueNAS web UI"
|
||||||
_webdav_list=$(_get "$_api_url/webdav")
|
_webdav_list=$(_get "$_api_url/webdav")
|
||||||
_webdav_cert_id=$(echo "$_webdav_list" | grep '"certssl":' | tr -d -- '"certsl: ,')
|
_webdav_cert_id=$(echo "$_webdav_list" | grep '"certssl":' | tr -d -- '"certsl: ,')
|
||||||
|
|
||||||
if [ "$_webdav_cert_id" = "$_active_cert_id" ]; then
|
if [ "$_webdav_cert_id" = "$_active_cert_id" ]; then
|
||||||
_info "Update the WebDAV Certificate"
|
_info "Updating the WebDAV certificate"
|
||||||
_debug _webdav_cert_id "$_webdav_cert_id"
|
_debug _webdav_cert_id "$_webdav_cert_id"
|
||||||
_webdav_data="{\"certssl\": \"${_cert_id}\"}"
|
_webdav_data="{\"certssl\": \"${_cert_id}\"}"
|
||||||
_activate_webdav_cert="$(_post "$_webdav_data" "$_api_url/webdav" "" "PUT" "application/json")"
|
_activate_webdav_cert="$(_post "$_webdav_data" "$_api_url/webdav" "" "PUT" "application/json")"
|
||||||
_webdav_new_cert_id=$(echo "$_activate_webdav_cert" | _json_decode | sed -n 's/.*: \([0-9]\{1,\}\) }$/\1/p')
|
_webdav_new_cert_id=$(echo "$_activate_webdav_cert" | _json_decode | grep '"certssl":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
|
||||||
if [ "$_webdav_new_cert_id" -eq "$_cert_id" ]; then
|
if [ "$_webdav_new_cert_id" -eq "$_cert_id" ]; then
|
||||||
_info "WebDAV Certificate update successfully"
|
_info "WebDAV certificate updated successfully"
|
||||||
else
|
else
|
||||||
_err "Unable to set WebDAV certificate"
|
_err "Unable to set WebDAV certificate"
|
||||||
_debug3 _activate_webdav_cert "$_activate_webdav_cert"
|
_debug3 _activate_webdav_cert "$_activate_webdav_cert"
|
||||||
@ -136,21 +135,21 @@ truenas_deploy() {
|
|||||||
fi
|
fi
|
||||||
_debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
|
_debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
|
||||||
else
|
else
|
||||||
_info "WebDAV certificate not set or not the same as Web UI"
|
_info "WebDAV certificate is not configured or is not the same as TrueNAS web UI"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_info "Check if FTP certificate is the same as the WEB UI"
|
_info "Checking if FTP certificate is the same as the TrueNAS web UI"
|
||||||
_ftp_list=$(_get "$_api_url/ftp")
|
_ftp_list=$(_get "$_api_url/ftp")
|
||||||
_ftp_cert_id=$(echo "$_ftp_list" | grep '"ssltls_certificate":' | tr -d -- '"certislfa:_ ,')
|
_ftp_cert_id=$(echo "$_ftp_list" | grep '"ssltls_certificate":' | tr -d -- '"certislfa:_ ,')
|
||||||
|
|
||||||
if [ "$_ftp_cert_id" = "$_active_cert_id" ]; then
|
if [ "$_ftp_cert_id" = "$_active_cert_id" ]; then
|
||||||
_info "Update the FTP Certificate"
|
_info "Updating the FTP certificate"
|
||||||
_debug _ftp_cert_id "$_ftp_cert_id"
|
_debug _ftp_cert_id "$_ftp_cert_id"
|
||||||
_ftp_data="{\"ssltls_certificate\": \"${_cert_id}\"}"
|
_ftp_data="{\"ssltls_certificate\": \"${_cert_id}\"}"
|
||||||
_activate_ftp_cert="$(_post "$_ftp_data" "$_api_url/ftp" "" "PUT" "application/json")"
|
_activate_ftp_cert="$(_post "$_ftp_data" "$_api_url/ftp" "" "PUT" "application/json")"
|
||||||
_ftp_new_cert_id=$(echo "$_activate_ftp_cert" | _json_decode | sed -n 's/.*: \([0-9]\{1,\}\) }$/\1/p')
|
_ftp_new_cert_id=$(echo "$_activate_ftp_cert" | _json_decode | grep '"ssltls_certificate":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
|
||||||
if [ "$_ftp_new_cert_id" -eq "$_cert_id" ]; then
|
if [ "$_ftp_new_cert_id" -eq "$_cert_id" ]; then
|
||||||
_info "FTP Certificate update successfully"
|
_info "FTP certificate updated successfully"
|
||||||
else
|
else
|
||||||
_err "Unable to set FTP certificate"
|
_err "Unable to set FTP certificate"
|
||||||
_debug3 _activate_ftp_cert "$_activate_ftp_cert"
|
_debug3 _activate_ftp_cert "$_activate_ftp_cert"
|
||||||
@ -159,22 +158,66 @@ truenas_deploy() {
|
|||||||
fi
|
fi
|
||||||
_debug3 _activate_ftp_cert "$_activate_ftp_cert"
|
_debug3 _activate_ftp_cert "$_activate_ftp_cert"
|
||||||
else
|
else
|
||||||
_info "FTP certificate not set or not the same as Web UI"
|
_info "FTP certificate is not configured or is not the same as TrueNAS web UI"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_info "Delete old Certificate"
|
_info "Checking if S3 certificate is the same as the TrueNAS web UI"
|
||||||
|
_s3_list=$(_get "$_api_url/s3")
|
||||||
|
_s3_cert_id=$(echo "$_s3_list" | grep '"certificate":' | tr -d -- '"certifa:_ ,')
|
||||||
|
|
||||||
|
if [ "$_s3_cert_id" = "$_active_cert_id" ]; then
|
||||||
|
_info "Updating the S3 certificate"
|
||||||
|
_debug _s3_cert_id "$_s3_cert_id"
|
||||||
|
_s3_data="{\"certificate\": \"${_cert_id}\"}"
|
||||||
|
_activate_s3_cert="$(_post "$_s3_data" "$_api_url/s3" "" "PUT" "application/json")"
|
||||||
|
_s3_new_cert_id=$(echo "$_activate_s3_cert" | _json_decode | grep '"certificate":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
|
||||||
|
if [ "$_s3_new_cert_id" -eq "$_cert_id" ]; then
|
||||||
|
_info "S3 certificate updated successfully"
|
||||||
|
else
|
||||||
|
_err "Unable to set S3 certificate"
|
||||||
|
_debug3 _activate_s3_cert "$_activate_s3_cert"
|
||||||
|
_debug3 _s3_new_cert_id "$_s3_new_cert_id"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug3 _activate_s3_cert "$_activate_s3_cert"
|
||||||
|
else
|
||||||
|
_info "S3 certificate is not configured or is not the same as TrueNAS web UI"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info "Checking if any chart release Apps is using the same certificate as TrueNAS web UI. Tool 'jq' is required"
|
||||||
|
if _exists jq; then
|
||||||
|
_info "Query all chart release"
|
||||||
|
_release_list=$(_get "$_api_url/chart/release")
|
||||||
|
_related_name_list=$(printf "%s" "$_release_list" | jq -r "[.[] | {name,certId: .config.ingress?.main.tls[]?.scaleCert} | select(.certId==$_active_cert_id) | .name ] | unique")
|
||||||
|
_release_length=$(printf "%s" "$_related_name_list" | jq -r "length")
|
||||||
|
_info "Found $_release_length related chart release in list: $_related_name_list"
|
||||||
|
for i in $(seq 0 $((_release_length - 1))); do
|
||||||
|
_release_name=$(echo "$_related_name_list" | jq -r ".[$i]")
|
||||||
|
_info "Updating certificate from $_active_cert_id to $_cert_id for chart release: $_release_name"
|
||||||
|
#Read the chart release configuration
|
||||||
|
_chart_config=$(printf "%s" "$_release_list" | jq -r ".[] | select(.name==\"$_release_name\")")
|
||||||
|
#Replace the old certificate id with the new one in path .config.ingress.main.tls[].scaleCert. Then update .config.ingress
|
||||||
|
_updated_chart_config=$(printf "%s" "$_chart_config" | jq "(.config.ingress?.main.tls[]? | select(.scaleCert==$_active_cert_id) | .scaleCert ) |= $_cert_id | .config.ingress ")
|
||||||
|
_update_chart_result="$(_post "{\"values\" : { \"ingress\" : $_updated_chart_config } }" "$_api_url/chart/release/id/$_release_name" "" "PUT" "application/json")"
|
||||||
|
_debug3 _update_chart_result "$_update_chart_result"
|
||||||
|
done
|
||||||
|
else
|
||||||
|
_info "Tool 'jq' does not exists, skip chart release checking"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info "Deleting old certificate"
|
||||||
_delete_result="$(_post "" "$_api_url/certificate/id/$_active_cert_id" "" "DELETE" "application/json")"
|
_delete_result="$(_post "" "$_api_url/certificate/id/$_active_cert_id" "" "DELETE" "application/json")"
|
||||||
|
|
||||||
_debug3 _delete_result "$_delete_result"
|
_debug3 _delete_result "$_delete_result"
|
||||||
|
|
||||||
_info "Reload WebUI from TrueNAS"
|
_info "Reloading TrueNAS web UI"
|
||||||
_restart_UI=$(_get "$_api_url/system/general/ui_restart")
|
_restart_UI=$(_get "$_api_url/system/general/ui_restart")
|
||||||
_debug2 _restart_UI "$_restart_UI"
|
_debug2 _restart_UI "$_restart_UI"
|
||||||
|
|
||||||
if [ -n "$_add_cert_result" ] && [ -n "$_activate_result" ]; then
|
if [ -n "$_add_cert_result" ] && [ -n "$_activate_result" ]; then
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
_err "Certupdate was not succesfull, please use --debug"
|
_err "Certificate update was not succesful, please try again with --debug"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,9 @@
|
|||||||
#
|
#
|
||||||
# VAULT_PREFIX - this contains the prefix path in vault
|
# VAULT_PREFIX - this contains the prefix path in vault
|
||||||
# VAULT_ADDR - vault requires this to find your vault server
|
# VAULT_ADDR - vault requires this to find your vault server
|
||||||
|
# VAULT_SAVE_TOKEN - set to anything if you want to save the token
|
||||||
|
# VAULT_RENEW_TOKEN - set to anything if you want to renew the token to default TTL before deploying
|
||||||
|
# VAULT_KV_V2 - set to anything if you are using v2 of the kv engine
|
||||||
#
|
#
|
||||||
# additionally, you need to ensure that VAULT_TOKEN is avialable
|
# additionally, you need to ensure that VAULT_TOKEN is avialable
|
||||||
# to access the vault server
|
# to access the vault server
|
||||||
@ -45,33 +48,83 @@ vault_deploy() {
|
|||||||
fi
|
fi
|
||||||
_savedeployconf VAULT_ADDR "$VAULT_ADDR"
|
_savedeployconf VAULT_ADDR "$VAULT_ADDR"
|
||||||
|
|
||||||
|
_getdeployconf VAULT_SAVE_TOKEN
|
||||||
|
_savedeployconf VAULT_SAVE_TOKEN "$VAULT_SAVE_TOKEN"
|
||||||
|
|
||||||
|
_getdeployconf VAULT_RENEW_TOKEN
|
||||||
|
_savedeployconf VAULT_RENEW_TOKEN "$VAULT_RENEW_TOKEN"
|
||||||
|
|
||||||
|
_getdeployconf VAULT_KV_V2
|
||||||
|
_savedeployconf VAULT_KV_V2 "$VAULT_KV_V2"
|
||||||
|
|
||||||
|
_getdeployconf VAULT_TOKEN
|
||||||
|
if [ -z "$VAULT_TOKEN" ]; then
|
||||||
|
_err "VAULT_TOKEN needs to be defined"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [ -n "$VAULT_SAVE_TOKEN" ]; then
|
||||||
|
_savedeployconf VAULT_TOKEN "$VAULT_TOKEN"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_migratedeployconf FABIO VAULT_FABIO_MODE
|
||||||
|
|
||||||
# JSON does not allow multiline strings.
|
# JSON does not allow multiline strings.
|
||||||
# So replacing new-lines with "\n" here
|
# So replacing new-lines with "\n" here
|
||||||
_ckey=$(sed -z 's/\n/\\n/g' <"$2")
|
_ckey=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$2")
|
||||||
_ccert=$(sed -z 's/\n/\\n/g' <"$3")
|
_ccert=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$3")
|
||||||
_cca=$(sed -z 's/\n/\\n/g' <"$4")
|
_cca=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$4")
|
||||||
_cfullchain=$(sed -z 's/\n/\\n/g' <"$5")
|
_cfullchain=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$5")
|
||||||
|
|
||||||
URL="$VAULT_ADDR/v1/$VAULT_PREFIX/$_cdomain"
|
|
||||||
export _H1="X-Vault-Token: $VAULT_TOKEN"
|
export _H1="X-Vault-Token: $VAULT_TOKEN"
|
||||||
|
|
||||||
if [ -n "$FABIO" ]; then
|
if [ -n "$VAULT_RENEW_TOKEN" ]; then
|
||||||
|
URL="$VAULT_ADDR/v1/auth/token/renew-self"
|
||||||
|
_info "Renew the Vault token to default TTL"
|
||||||
|
if ! _post "" "$URL" >/dev/null; then
|
||||||
|
_err "Failed to renew the Vault token"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
URL="$VAULT_ADDR/v1/$VAULT_PREFIX/$_cdomain"
|
||||||
|
|
||||||
|
if [ -n "$VAULT_FABIO_MODE" ]; then
|
||||||
|
_info "Writing certificate and key to $URL in Fabio mode"
|
||||||
if [ -n "$VAULT_KV_V2" ]; then
|
if [ -n "$VAULT_KV_V2" ]; then
|
||||||
_post "{ \"data\": {\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"} }" "$URL"
|
_post "{ \"data\": {\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"} }" "$URL" >/dev/null || return 1
|
||||||
else
|
else
|
||||||
_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL"
|
_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL" >/dev/null || return 1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if [ -n "$VAULT_KV_V2" ]; then
|
if [ -n "$VAULT_KV_V2" ]; then
|
||||||
_post "{\"data\": {\"value\": \"$_ccert\"}}" "$URL/cert.pem"
|
_info "Writing certificate to $URL/cert.pem"
|
||||||
_post "{\"data\": {\"value\": \"$_ckey\"}}" "$URL/cert.key"
|
_post "{\"data\": {\"value\": \"$_ccert\"}}" "$URL/cert.pem" >/dev/null || return 1
|
||||||
_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/chain.pem"
|
_info "Writing key to $URL/cert.key"
|
||||||
_post "{\"data\": {\"value\": \"$_cfullchain\"}}" "$URL/fullchain.pem"
|
_post "{\"data\": {\"value\": \"$_ckey\"}}" "$URL/cert.key" >/dev/null || return 1
|
||||||
|
_info "Writing CA certificate to $URL/ca.pem"
|
||||||
|
_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/ca.pem" >/dev/null || return 1
|
||||||
|
_info "Writing full-chain certificate to $URL/fullchain.pem"
|
||||||
|
_post "{\"data\": {\"value\": \"$_cfullchain\"}}" "$URL/fullchain.pem" >/dev/null || return 1
|
||||||
else
|
else
|
||||||
_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem"
|
_info "Writing certificate to $URL/cert.pem"
|
||||||
_post "{\"value\": \"$_ckey\"}" "$URL/cert.key"
|
_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem" >/dev/null || return 1
|
||||||
_post "{\"value\": \"$_cca\"}" "$URL/chain.pem"
|
_info "Writing key to $URL/cert.key"
|
||||||
_post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem"
|
_post "{\"value\": \"$_ckey\"}" "$URL/cert.key" >/dev/null || return 1
|
||||||
|
_info "Writing CA certificate to $URL/ca.pem"
|
||||||
|
_post "{\"value\": \"$_cca\"}" "$URL/ca.pem" >/dev/null || return 1
|
||||||
|
_info "Writing full-chain certificate to $URL/fullchain.pem"
|
||||||
|
_post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem" >/dev/null || return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# To make it compatible with the wrong ca path `chain.pem` which was used in former versions
|
||||||
|
if _contains "$(_get "$URL/chain.pem")" "-----BEGIN CERTIFICATE-----"; then
|
||||||
|
_err "The CA certificate has moved from chain.pem to ca.pem, if you don't depend on chain.pem anymore, you can delete it to avoid this warning"
|
||||||
|
_info "Updating CA certificate to $URL/chain.pem for backward compatibility"
|
||||||
|
if [ -n "$VAULT_KV_V2" ]; then
|
||||||
|
_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/chain.pem" >/dev/null || return 1
|
||||||
|
else
|
||||||
|
_post "{\"value\": \"$_cca\"}" "$URL/chain.pem" >/dev/null || return 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
#
|
#
|
||||||
# VAULT_PREFIX - this contains the prefix path in vault
|
# VAULT_PREFIX - this contains the prefix path in vault
|
||||||
# VAULT_ADDR - vault requires this to find your vault server
|
# VAULT_ADDR - vault requires this to find your vault server
|
||||||
|
# VAULT_SAVE_TOKEN - set to anything if you want to save the token
|
||||||
|
# VAULT_RENEW_TOKEN - set to anything if you want to renew the token to default TTL before deploying
|
||||||
#
|
#
|
||||||
# additionally, you need to ensure that VAULT_TOKEN is avialable or
|
# additionally, you need to ensure that VAULT_TOKEN is avialable or
|
||||||
# `vault auth` has applied the appropriate authorization for the vault binary
|
# `vault auth` has applied the appropriate authorization for the vault binary
|
||||||
@ -33,15 +35,36 @@ vault_cli_deploy() {
|
|||||||
_debug _cfullchain "$_cfullchain"
|
_debug _cfullchain "$_cfullchain"
|
||||||
|
|
||||||
# validate required env vars
|
# validate required env vars
|
||||||
|
_getdeployconf VAULT_PREFIX
|
||||||
if [ -z "$VAULT_PREFIX" ]; then
|
if [ -z "$VAULT_PREFIX" ]; then
|
||||||
_err "VAULT_PREFIX needs to be defined (contains prefix path in vault)"
|
_err "VAULT_PREFIX needs to be defined (contains prefix path in vault)"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
_savedeployconf VAULT_PREFIX "$VAULT_PREFIX"
|
||||||
|
|
||||||
|
_getdeployconf VAULT_ADDR
|
||||||
if [ -z "$VAULT_ADDR" ]; then
|
if [ -z "$VAULT_ADDR" ]; then
|
||||||
_err "VAULT_ADDR needs to be defined (contains vault connection address)"
|
_err "VAULT_ADDR needs to be defined (contains vault connection address)"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
_savedeployconf VAULT_ADDR "$VAULT_ADDR"
|
||||||
|
|
||||||
|
_getdeployconf VAULT_SAVE_TOKEN
|
||||||
|
_savedeployconf VAULT_SAVE_TOKEN "$VAULT_SAVE_TOKEN"
|
||||||
|
|
||||||
|
_getdeployconf VAULT_RENEW_TOKEN
|
||||||
|
_savedeployconf VAULT_RENEW_TOKEN "$VAULT_RENEW_TOKEN"
|
||||||
|
|
||||||
|
_getdeployconf VAULT_TOKEN
|
||||||
|
if [ -z "$VAULT_TOKEN" ]; then
|
||||||
|
_err "VAULT_TOKEN needs to be defined"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
if [ -n "$VAULT_SAVE_TOKEN" ]; then
|
||||||
|
_savedeployconf VAULT_TOKEN "$VAULT_TOKEN"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_migratedeployconf FABIO VAULT_FABIO_MODE
|
||||||
|
|
||||||
VAULT_CMD=$(command -v vault)
|
VAULT_CMD=$(command -v vault)
|
||||||
if [ ! $? ]; then
|
if [ ! $? ]; then
|
||||||
@ -49,13 +72,33 @@ vault_cli_deploy() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$FABIO" ]; then
|
if [ -n "$VAULT_RENEW_TOKEN" ]; then
|
||||||
|
_info "Renew the Vault token to default TTL"
|
||||||
|
if ! $VAULT_CMD token renew; then
|
||||||
|
_err "Failed to renew the Vault token"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$VAULT_FABIO_MODE" ]; then
|
||||||
|
_info "Writing certificate and key to ${VAULT_PREFIX}/${_cdomain} in Fabio mode"
|
||||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}" cert=@"$_cfullchain" key=@"$_ckey" || return 1
|
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}" cert=@"$_cfullchain" key=@"$_ckey" || return 1
|
||||||
else
|
else
|
||||||
|
_info "Writing certificate to ${VAULT_PREFIX}/${_cdomain}/cert.pem"
|
||||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1
|
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1
|
||||||
|
_info "Writing key to ${VAULT_PREFIX}/${_cdomain}/cert.key"
|
||||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1
|
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1
|
||||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1
|
_info "Writing CA certificate to ${VAULT_PREFIX}/${_cdomain}/ca.pem"
|
||||||
|
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/ca.pem" value=@"$_cca" || return 1
|
||||||
|
_info "Writing full-chain certificate to ${VAULT_PREFIX}/${_cdomain}/fullchain.pem"
|
||||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1
|
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1
|
||||||
|
|
||||||
|
# To make it compatible with the wrong ca path `chain.pem` which was used in former versions
|
||||||
|
if $VAULT_CMD kv get "${VAULT_PREFIX}/${_cdomain}/chain.pem" >/dev/null; then
|
||||||
|
_err "The CA certificate has moved from chain.pem to ca.pem, if you don't depend on chain.pem anymore, you can delete it to avoid this warning"
|
||||||
|
_info "Updating CA certificate to ${VAULT_PREFIX}/${_cdomain}/chain.pem for backward compatibility"
|
||||||
|
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,48 +1,44 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
#This file name is "dns_1984hosting.sh"
|
# shellcheck disable=SC2034
|
||||||
#So, here must be a method dns_1984hosting_add()
|
dns_1984hosting_info='1984.hosting
|
||||||
#Which will be called by acme.sh to add the txt record to your api system.
|
Domains: 1984.is
|
||||||
#returns 0 means success, otherwise error.
|
Site: 1984.hosting
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_1984hosting
|
||||||
|
Options:
|
||||||
|
One984HOSTING_Username Username
|
||||||
|
One984HOSTING_Password Password
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/2851
|
||||||
|
Author: Adrian Fedoreanu
|
||||||
|
'
|
||||||
|
|
||||||
#Author: Adrian Fedoreanu
|
|
||||||
#Report Bugs here: https://github.com/acmesh-official/acme.sh
|
|
||||||
# or here... https://github.com/acmesh-official/acme.sh/issues/2851
|
|
||||||
#
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
# Export 1984HOSTING username and password in following variables
|
# Usage: dns_1984hosting_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
#
|
# Add a text record.
|
||||||
# One984HOSTING_Username=username
|
|
||||||
# One984HOSTING_Password=password
|
|
||||||
#
|
|
||||||
# sessionid cookie is saved in ~/.acme.sh/account.conf
|
|
||||||
# username/password need to be set only when changed.
|
|
||||||
|
|
||||||
#Usage: dns_1984hosting_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
|
||||||
dns_1984hosting_add() {
|
dns_1984hosting_add() {
|
||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
txtvalue=$2
|
txtvalue=$2
|
||||||
|
|
||||||
_info "Add TXT record using 1984Hosting"
|
_info "Add TXT record using 1984Hosting."
|
||||||
_debug fulldomain "$fulldomain"
|
_debug fulldomain "$fulldomain"
|
||||||
_debug txtvalue "$txtvalue"
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
if ! _1984hosting_login; then
|
if ! _1984hosting_login; then
|
||||||
_err "1984Hosting login failed for user $One984HOSTING_Username. Check $HTTP_HEADER file"
|
_err "1984Hosting login failed for user $One984HOSTING_Username. Check $HTTP_HEADER file."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_debug "First detect the root zone"
|
_debug "First detect the root zone."
|
||||||
if ! _get_root "$fulldomain"; then
|
if ! _get_root "$fulldomain"; then
|
||||||
_err "invalid domain" "$fulldomain"
|
_err "Invalid domain '$fulldomain'."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_debug _sub_domain "$_sub_domain"
|
_debug _sub_domain "$_sub_domain"
|
||||||
_debug _domain "$_domain"
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
_debug "Add TXT record $fulldomain with value '$txtvalue'"
|
_debug "Add TXT record $fulldomain with value '$txtvalue'."
|
||||||
value="$(printf '%s' "$txtvalue" | _url_encode)"
|
value="$(printf '%s' "$txtvalue" | _url_encode)"
|
||||||
url="https://management.1984hosting.com/domains/entry/"
|
url="https://1984.hosting/domains/entry/"
|
||||||
|
|
||||||
postdata="entry=new"
|
postdata="entry=new"
|
||||||
postdata="$postdata&type=TXT"
|
postdata="$postdata&type=TXT"
|
||||||
@ -53,92 +49,96 @@ dns_1984hosting_add() {
|
|||||||
_debug2 postdata "$postdata"
|
_debug2 postdata "$postdata"
|
||||||
|
|
||||||
_authpost "$postdata" "$url"
|
_authpost "$postdata" "$url"
|
||||||
response="$(echo "$_response" | _normalizeJson)"
|
if _contains "$_response" '"haserrors": true'; then
|
||||||
_debug2 response "$response"
|
_err "1984Hosting failed to add TXT record for $_sub_domain bad RC from _post."
|
||||||
|
|
||||||
if _contains "$response" '"haserrors": true'; then
|
|
||||||
_err "1984Hosting failed to add TXT record for $_sub_domain bad RC from _post"
|
|
||||||
return 1
|
return 1
|
||||||
elif _contains "$response" "html>"; then
|
elif _contains "$_response" "html>"; then
|
||||||
_err "1984Hosting failed to add TXT record for $_sub_domain. Check $HTTP_HEADER file"
|
_err "1984Hosting failed to add TXT record for $_sub_domain. Check $HTTP_HEADER file."
|
||||||
return 1
|
return 1
|
||||||
elif _contains "$response" '"auth": false'; then
|
elif _contains "$_response" '"auth": false'; then
|
||||||
_err "1984Hosting failed to add TXT record for $_sub_domain. Invalid or expired cookie"
|
_err "1984Hosting failed to add TXT record for $_sub_domain. Invalid or expired cookie."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_info "Added acme challenge TXT record for $fulldomain at 1984Hosting"
|
_info "Added acme challenge TXT record for $fulldomain at 1984Hosting."
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
#Usage: fulldomain txtvalue
|
# Usage: fulldomain txtvalue
|
||||||
#Remove the txt record after validation.
|
# Remove the txt record after validation.
|
||||||
dns_1984hosting_rm() {
|
dns_1984hosting_rm() {
|
||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
txtvalue=$2
|
txtvalue=$2
|
||||||
|
|
||||||
_info "Delete TXT record using 1984Hosting"
|
_info "Delete TXT record using 1984Hosting."
|
||||||
_debug fulldomain "$fulldomain"
|
_debug fulldomain "$fulldomain"
|
||||||
_debug txtvalue "$txtvalue"
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
if ! _1984hosting_login; then
|
if ! _1984hosting_login; then
|
||||||
_err "1984Hosting login failed for user $One984HOSTING_Username. Check $HTTP_HEADER file"
|
_err "1984Hosting login failed for user $One984HOSTING_Username. Check $HTTP_HEADER file."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_debug "First detect the root zone"
|
_debug "First detect the root zone."
|
||||||
if ! _get_root "$fulldomain"; then
|
if ! _get_root "$fulldomain"; then
|
||||||
_err "invalid domain" "$fulldomain"
|
_err "Invalid domain '$fulldomain'."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_debug _sub_domain "$_sub_domain"
|
_debug _sub_domain "$_sub_domain"
|
||||||
_debug _domain "$_domain"
|
_debug _domain "$_domain"
|
||||||
_debug "Delete $fulldomain TXT record"
|
_debug "Delete $fulldomain TXT record."
|
||||||
|
|
||||||
url="https://management.1984hosting.com/domains"
|
url="https://1984.hosting/domains"
|
||||||
if ! _get_zone_id "$url" "$_domain"; then
|
if ! _get_zone_id "$url" "$_domain"; then
|
||||||
_err "invalid zone" "$_domain"
|
_err "Invalid zone '$_domain'."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_htmlget "$url/$_zone_id" "$txtvalue"
|
_htmlget "$url/$_zone_id" "$txtvalue"
|
||||||
_debug2 _response "$_response"
|
|
||||||
entry_id="$(echo "$_response" | _egrep_o 'entry_[0-9]+' | sed 's/entry_//')"
|
entry_id="$(echo "$_response" | _egrep_o 'entry_[0-9]+' | sed 's/entry_//')"
|
||||||
_debug2 entry_id "$entry_id"
|
_debug2 entry_id "$entry_id"
|
||||||
if [ -z "$entry_id" ]; then
|
if [ -z "$entry_id" ]; then
|
||||||
_err "Error getting TXT entry_id for $1"
|
_err "Error getting TXT entry_id for $1."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_authpost "entry=$entry_id" "$url/delentry/"
|
_authpost "entry=$entry_id" "$url/delentry/"
|
||||||
response="$(echo "$_response" | _normalizeJson)"
|
if ! _contains "$_response" '"ok": true'; then
|
||||||
_debug2 response "$response"
|
_err "1984Hosting failed to delete TXT record for $entry_id bad RC from _post."
|
||||||
|
|
||||||
if ! _contains "$response" '"ok": true'; then
|
|
||||||
_err "1984Hosting failed to delete TXT record for $entry_id bad RC from _post"
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_info "Deleted acme challenge TXT record for $fulldomain at 1984Hosting"
|
_info "Deleted acme challenge TXT record for $fulldomain at 1984Hosting."
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
#################### Private functions below ##################################
|
||||||
|
|
||||||
# usage: _1984hosting_login username password
|
|
||||||
# returns 0 success
|
|
||||||
_1984hosting_login() {
|
_1984hosting_login() {
|
||||||
if ! _check_credentials; then return 1; fi
|
if ! _check_credentials; then return 1; fi
|
||||||
|
|
||||||
if _check_cookies; then
|
if _check_cookies; then
|
||||||
_debug "Already logged in"
|
_debug "Already logged in."
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_debug "Login to 1984Hosting as user $One984HOSTING_Username"
|
_debug "Login to 1984Hosting as user $One984HOSTING_Username."
|
||||||
username=$(printf '%s' "$One984HOSTING_Username" | _url_encode)
|
username=$(printf '%s' "$One984HOSTING_Username" | _url_encode)
|
||||||
password=$(printf '%s' "$One984HOSTING_Password" | _url_encode)
|
password=$(printf '%s' "$One984HOSTING_Password" | _url_encode)
|
||||||
url="https://management.1984hosting.com/accounts/checkuserauth/"
|
url="https://1984.hosting/api/auth/"
|
||||||
|
|
||||||
|
_get "https://1984.hosting/accounts/login/" | grep "csrfmiddlewaretoken"
|
||||||
|
csrftoken="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'csrftoken=[^;]*;' | tr -d ';')"
|
||||||
|
sessionid="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'sessionid=[^;]*;' | tr -d ';')"
|
||||||
|
|
||||||
|
if [ -z "$csrftoken" ] || [ -z "$sessionid" ]; then
|
||||||
|
_err "One or more cookies are empty: '$csrftoken', '$sessionid'."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
export _H1="Cookie: $csrftoken; $sessionid"
|
||||||
|
export _H2="Referer: https://1984.hosting/accounts/login/"
|
||||||
|
csrf_header=$(echo "$csrftoken" | sed 's/csrftoken=//' | _head_n 1)
|
||||||
|
export _H3="X-CSRFToken: $csrf_header"
|
||||||
|
|
||||||
response="$(_post "username=$username&password=$password&otpkey=" $url)"
|
response="$(_post "username=$username&password=$password&otpkey=" $url)"
|
||||||
response="$(echo "$response" | _normalizeJson)"
|
response="$(echo "$response" | _normalizeJson)"
|
||||||
@ -149,6 +149,8 @@ _1984hosting_login() {
|
|||||||
One984HOSTING_CSRFTOKEN_COOKIE="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'csrftoken=[^;]*;' | tr -d ';')"
|
One984HOSTING_CSRFTOKEN_COOKIE="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'csrftoken=[^;]*;' | tr -d ';')"
|
||||||
export One984HOSTING_SESSIONID_COOKIE
|
export One984HOSTING_SESSIONID_COOKIE
|
||||||
export One984HOSTING_CSRFTOKEN_COOKIE
|
export One984HOSTING_CSRFTOKEN_COOKIE
|
||||||
|
_saveaccountconf_mutable One984HOSTING_Username "$One984HOSTING_Username"
|
||||||
|
_saveaccountconf_mutable One984HOSTING_Password "$One984HOSTING_Password"
|
||||||
_saveaccountconf_mutable One984HOSTING_SESSIONID_COOKIE "$One984HOSTING_SESSIONID_COOKIE"
|
_saveaccountconf_mutable One984HOSTING_SESSIONID_COOKIE "$One984HOSTING_SESSIONID_COOKIE"
|
||||||
_saveaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE "$One984HOSTING_CSRFTOKEN_COOKIE"
|
_saveaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE "$One984HOSTING_CSRFTOKEN_COOKIE"
|
||||||
return 0
|
return 0
|
||||||
@ -157,9 +159,13 @@ _1984hosting_login() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_check_credentials() {
|
_check_credentials() {
|
||||||
|
One984HOSTING_Username="${One984HOSTING_Username:-$(_readaccountconf_mutable One984HOSTING_Username)}"
|
||||||
|
One984HOSTING_Password="${One984HOSTING_Password:-$(_readaccountconf_mutable One984HOSTING_Password)}"
|
||||||
if [ -z "$One984HOSTING_Username" ] || [ -z "$One984HOSTING_Password" ]; then
|
if [ -z "$One984HOSTING_Username" ] || [ -z "$One984HOSTING_Password" ]; then
|
||||||
One984HOSTING_Username=""
|
One984HOSTING_Username=""
|
||||||
One984HOSTING_Password=""
|
One984HOSTING_Password=""
|
||||||
|
_clearaccountconf_mutable One984HOSTING_Username
|
||||||
|
_clearaccountconf_mutable One984HOSTING_Password
|
||||||
_err "You haven't specified 1984Hosting username or password yet."
|
_err "You haven't specified 1984Hosting username or password yet."
|
||||||
_err "Please export as One984HOSTING_Username / One984HOSTING_Password and try again."
|
_err "Please export as One984HOSTING_Username / One984HOSTING_Password and try again."
|
||||||
return 1
|
return 1
|
||||||
@ -171,25 +177,26 @@ _check_cookies() {
|
|||||||
One984HOSTING_SESSIONID_COOKIE="${One984HOSTING_SESSIONID_COOKIE:-$(_readaccountconf_mutable One984HOSTING_SESSIONID_COOKIE)}"
|
One984HOSTING_SESSIONID_COOKIE="${One984HOSTING_SESSIONID_COOKIE:-$(_readaccountconf_mutable One984HOSTING_SESSIONID_COOKIE)}"
|
||||||
One984HOSTING_CSRFTOKEN_COOKIE="${One984HOSTING_CSRFTOKEN_COOKIE:-$(_readaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE)}"
|
One984HOSTING_CSRFTOKEN_COOKIE="${One984HOSTING_CSRFTOKEN_COOKIE:-$(_readaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE)}"
|
||||||
if [ -z "$One984HOSTING_SESSIONID_COOKIE" ] || [ -z "$One984HOSTING_CSRFTOKEN_COOKIE" ]; then
|
if [ -z "$One984HOSTING_SESSIONID_COOKIE" ] || [ -z "$One984HOSTING_CSRFTOKEN_COOKIE" ]; then
|
||||||
_debug "No cached cookie(s) found"
|
_debug "No cached cookie(s) found."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_authget "https://management.1984hosting.com/accounts/loginstatus/"
|
_authget "https://1984.hosting/api/auth/"
|
||||||
if _contains "$response" '"ok": true'; then
|
if _contains "$_response" '"ok": true'; then
|
||||||
_debug "Cached cookies still valid"
|
_debug "Cached cookies still valid."
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
_debug "Cached cookies no longer valid"
|
|
||||||
|
_debug "Cached cookies no longer valid. Clearing cookies."
|
||||||
One984HOSTING_SESSIONID_COOKIE=""
|
One984HOSTING_SESSIONID_COOKIE=""
|
||||||
One984HOSTING_CSRFTOKEN_COOKIE=""
|
One984HOSTING_CSRFTOKEN_COOKIE=""
|
||||||
_saveaccountconf_mutable One984HOSTING_SESSIONID_COOKIE "$One984HOSTING_SESSIONID_COOKIE"
|
_clearaccountconf_mutable One984HOSTING_SESSIONID_COOKIE
|
||||||
_saveaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE "$One984HOSTING_CSRFTOKEN_COOKIE"
|
_clearaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
#_acme-challenge.www.domain.com
|
# _acme-challenge.www.domain.com
|
||||||
#returns
|
# Returns
|
||||||
# _sub_domain=_acme-challenge.www
|
# _sub_domain=_acme-challenge.www
|
||||||
# _domain=domain.com
|
# _domain=domain.com
|
||||||
_get_root() {
|
_get_root() {
|
||||||
@ -197,16 +204,16 @@ _get_root() {
|
|||||||
i=1
|
i=1
|
||||||
p=1
|
p=1
|
||||||
while true; do
|
while true; do
|
||||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||||
|
|
||||||
|
# not valid
|
||||||
if [ -z "$h" ]; then
|
if [ -z "$h" ]; then
|
||||||
#not valid
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_authget "https://management.1984hosting.com/domains/soacheck/?zone=$h&nameserver=ns0.1984.is."
|
_authget "https://1984.hosting/domains/zonestatus/$h/?cached=no"
|
||||||
if _contains "$_response" "serial" && ! _contains "$_response" "null"; then
|
if _contains "$_response" '"ok": true'; then
|
||||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||||
_domain="$h"
|
_domain="$h"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@ -216,46 +223,46 @@ _get_root() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
#usage: _get_zone_id url domain.com
|
# Usage: _get_zone_id url domain.com
|
||||||
#returns zone id for domain.com
|
# Returns zone id for domain.com
|
||||||
_get_zone_id() {
|
_get_zone_id() {
|
||||||
url=$1
|
url=$1
|
||||||
domain=$2
|
domain=$2
|
||||||
_htmlget "$url" "$domain"
|
_htmlget "$url" "$domain"
|
||||||
_debug2 _response "$_response"
|
|
||||||
_zone_id="$(echo "$_response" | _egrep_o 'zone\/[0-9]+' | _head_n 1)"
|
_zone_id="$(echo "$_response" | _egrep_o 'zone\/[0-9]+' | _head_n 1)"
|
||||||
_debug2 _zone_id "$_zone_id"
|
_debug2 _zone_id "$_zone_id"
|
||||||
if [ -z "$_zone_id" ]; then
|
if [ -z "$_zone_id" ]; then
|
||||||
_err "Error getting _zone_id for $2"
|
_err "Error getting _zone_id for $2."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# add extra headers to request
|
# Add extra headers to request
|
||||||
_authget() {
|
_authget() {
|
||||||
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE;$One984HOSTING_SESSIONID_COOKIE"
|
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE; $One984HOSTING_SESSIONID_COOKIE"
|
||||||
_response=$(_get "$1" | _normalizeJson)
|
_response=$(_get "$1" | _normalizeJson)
|
||||||
_debug2 _response "$_response"
|
_debug2 _response "$_response"
|
||||||
}
|
}
|
||||||
|
|
||||||
# truncate huge HTML response
|
# Truncate huge HTML response
|
||||||
# echo: Argument list too long
|
|
||||||
_htmlget() {
|
_htmlget() {
|
||||||
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE;$One984HOSTING_SESSIONID_COOKIE"
|
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE; $One984HOSTING_SESSIONID_COOKIE"
|
||||||
_response=$(_get "$1" | grep "$2")
|
_response=$(_get "$1" | grep "$2")
|
||||||
if _contains "$_response" "@$2"; then
|
if _contains "$_response" "@$2"; then
|
||||||
_response=$(echo "$_response" | grep -v "[@]" | _head_n 1)
|
_response=$(echo "$_response" | grep -v "[@]" | _head_n 1)
|
||||||
fi
|
fi
|
||||||
|
_debug2 _response "$_response"
|
||||||
}
|
}
|
||||||
|
|
||||||
# add extra headers to request
|
# Add extra headers to request
|
||||||
_authpost() {
|
_authpost() {
|
||||||
url="https://management.1984hosting.com/domains"
|
url="https://1984.hosting/domains"
|
||||||
_get_zone_id "$url" "$_domain"
|
_get_zone_id "$url" "$_domain"
|
||||||
csrf_header="$(echo "$One984HOSTING_CSRFTOKEN_COOKIE" | _egrep_o "=[^=][0-9a-zA-Z]*" | tr -d "=")"
|
csrf_header="$(echo "$One984HOSTING_CSRFTOKEN_COOKIE" | _egrep_o "=[^=][0-9a-zA-Z]*" | tr -d "=")"
|
||||||
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE;$One984HOSTING_SESSIONID_COOKIE"
|
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE; $One984HOSTING_SESSIONID_COOKIE"
|
||||||
export _H2="Referer: https://management.1984hosting.com/domains/$_zone_id"
|
export _H2="Referer: https://1984.hosting/domains/$_zone_id"
|
||||||
export _H3="X-CSRFToken: $csrf_header"
|
export _H3="X-CSRFToken: $csrf_header"
|
||||||
_response=$(_post "$1" "$2")
|
_response="$(_post "$1" "$2" | _normalizeJson)"
|
||||||
|
_debug2 _response "$_response"
|
||||||
}
|
}
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
#
|
# shellcheck disable=SC2034
|
||||||
#Author: Wolfgang Ebner
|
dns_acmedns_info='acme-dns Server API
|
||||||
#Author: Sven Neubuaer
|
The acme-dns is a limited DNS server with RESTful API to handle ACME DNS challenges.
|
||||||
#Report Bugs here: https://github.com/dampfklon/acme.sh
|
Site: github.com/joohoi/acme-dns
|
||||||
#
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_acmedns
|
||||||
# Usage:
|
Options:
|
||||||
# export ACMEDNS_BASE_URL="https://auth.acme-dns.io"
|
ACMEDNS_USERNAME Username. Optional.
|
||||||
#
|
ACMEDNS_PASSWORD Password. Optional.
|
||||||
# You can optionally define an already existing account:
|
ACMEDNS_SUBDOMAIN Subdomain. Optional.
|
||||||
#
|
ACMEDNS_BASE_URL API endpoint. Default: "https://auth.acme-dns.io".
|
||||||
# export ACMEDNS_USERNAME="<username>"
|
Issues: github.com/dampfklon/acme.sh
|
||||||
# export ACMEDNS_PASSWORD="<password>"
|
Author: Wolfgang Ebner, Sven Neubuaer
|
||||||
# export ACMEDNS_SUBDOMAIN="<subdomain>"
|
'
|
||||||
#
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
#Usage: dns_acmedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
#Usage: dns_acmedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
18
dnsapi/dns_acmeproxy.sh
Normal file → Executable file
18
dnsapi/dns_acmeproxy.sh
Normal file → Executable file
@ -1,9 +1,17 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
## Acmeproxy DNS provider to be used with acmeproxy (http://github.com/mdbraber/acmeproxy)
|
dns_acmeproxy_info='AcmeProxy Server API
|
||||||
## API integration by Maarten den Braber
|
AcmeProxy can be used to as a single host in your network to request certificates through a DNS API.
|
||||||
##
|
Clients can connect with the one AcmeProxy host so you do not need to store DNS API credentials on every single host.
|
||||||
## Report any bugs via https://github.com/mdbraber/acme.sh
|
Site: github.com/mdbraber/acmeproxy
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_acmeproxy
|
||||||
|
Options:
|
||||||
|
ACMEPROXY_ENDPOINT API Endpoint
|
||||||
|
ACMEPROXY_USERNAME Username
|
||||||
|
ACMEPROXY_PASSWORD Password
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/2251
|
||||||
|
Author: Maarten den Braber
|
||||||
|
'
|
||||||
|
|
||||||
dns_acmeproxy_add() {
|
dns_acmeproxy_add() {
|
||||||
fulldomain="${1}"
|
fulldomain="${1}"
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
#ACTIVE24_Token="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
dns_active24_info='Active24.com
|
||||||
|
Site: Active24.com
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_active24
|
||||||
|
Options:
|
||||||
|
ACTIVE24_Token API Token
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/2059
|
||||||
|
Author: Milan Pála
|
||||||
|
'
|
||||||
|
|
||||||
ACTIVE24_Api="https://api.active24.com"
|
ACTIVE24_Api="https://api.active24.com"
|
||||||
|
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
#
|
dns_ad_info='AlwaysData.com
|
||||||
#AD_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
Site: AlwaysData.com
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_ad
|
||||||
#This is the Alwaysdata api wrapper for acme.sh
|
Options:
|
||||||
#
|
AD_API_KEY API Key
|
||||||
#Author: Paul Koppen
|
Issues: github.com/acmesh-official/acme.sh/pull/503
|
||||||
#Report Bugs here: https://github.com/wpk-/acme.sh
|
Author: Paul Koppen
|
||||||
|
'
|
||||||
|
|
||||||
AD_API_URL="https://$AD_API_KEY:@api.alwaysdata.com/v1"
|
AD_API_URL="https://$AD_API_KEY:@api.alwaysdata.com/v1"
|
||||||
|
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_ali_info='AlibabaCloud.com
|
||||||
|
Domains: Aliyun.com
|
||||||
|
Site: AlibabaCloud.com
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_ali
|
||||||
|
Options:
|
||||||
|
Ali_Key API Key
|
||||||
|
Ali_Secret API Secret
|
||||||
|
'
|
||||||
|
|
||||||
Ali_API="https://alidns.aliyuncs.com/"
|
Ali_API="https://alidns.aliyuncs.com/"
|
||||||
|
|
||||||
#Ali_Key="LTqIA87hOKdjevsf5"
|
|
||||||
#Ali_Secret="0p5EYueFNq501xnCPzKNbx6K51qPH2"
|
|
||||||
|
|
||||||
#Usage: dns_ali_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
#Usage: dns_ali_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
dns_ali_add() {
|
dns_ali_add() {
|
||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
@ -117,7 +123,7 @@ _ali_urlencode() {
|
|||||||
_ali_nonce() {
|
_ali_nonce() {
|
||||||
#_head_n 1 </dev/urandom | _digest "sha256" hex | cut -c 1-31
|
#_head_n 1 </dev/urandom | _digest "sha256" hex | cut -c 1-31
|
||||||
#Not so good...
|
#Not so good...
|
||||||
date +"%s%N"
|
date +"%s%N" | sed 's/%N//g'
|
||||||
}
|
}
|
||||||
|
|
||||||
_check_exist_query() {
|
_check_exist_query() {
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
# Anexia CloudDNS acme.sh hook
|
dns_anx_info='Anexia.com CloudDNS
|
||||||
# Author: MA
|
Site: Anexia.com
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_anx
|
||||||
#ANX_Token="xxxx"
|
Options:
|
||||||
|
ANX_Token API Token
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/3238
|
||||||
|
'
|
||||||
|
|
||||||
ANX_API='https://engine.anexia-it.com/api/clouddns/v1'
|
ANX_API='https://engine.anexia-it.com/api/clouddns/v1'
|
||||||
|
|
||||||
|
177
dnsapi/dns_artfiles.sh
Normal file
177
dnsapi/dns_artfiles.sh
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_artfiles_info='ArtFiles.de
|
||||||
|
Site: ArtFiles.de
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_artfiles
|
||||||
|
Options:
|
||||||
|
AF_API_USERNAME API Username
|
||||||
|
AF_API_PASSWORD API Password
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/4718
|
||||||
|
Author: Martin Arndt <https://troublezone.net/>
|
||||||
|
'
|
||||||
|
|
||||||
|
########## API configuration ###################################################
|
||||||
|
|
||||||
|
AF_API_SUCCESS='status":"OK'
|
||||||
|
AF_URL_DCP='https://dcp.c.artfiles.de/api/'
|
||||||
|
AF_URL_DNS=${AF_URL_DCP}'dns/{*}_dns.html?domain='
|
||||||
|
AF_URL_DOMAINS=${AF_URL_DCP}'domain/get_domains.html'
|
||||||
|
|
||||||
|
########## Public functions ####################################################
|
||||||
|
|
||||||
|
# Adds a new TXT record for given ACME challenge value & domain.
|
||||||
|
# Usage: dns_artfiles_add _acme-challenge.www.example.com "ACME challenge value"
|
||||||
|
dns_artfiles_add() {
|
||||||
|
domain="$1"
|
||||||
|
txtValue="$2"
|
||||||
|
_info 'Using ArtFiles.de DNS addition API…'
|
||||||
|
_debug 'Domain' "$domain"
|
||||||
|
_debug 'txtValue' "$txtValue"
|
||||||
|
|
||||||
|
_set_credentials
|
||||||
|
_saveaccountconf_mutable 'AF_API_USERNAME' "$AF_API_USERNAME"
|
||||||
|
_saveaccountconf_mutable 'AF_API_PASSWORD' "$AF_API_PASSWORD"
|
||||||
|
|
||||||
|
_set_headers
|
||||||
|
_get_zone "$domain"
|
||||||
|
_dns 'GET'
|
||||||
|
if ! _contains "$response" 'TXT'; then
|
||||||
|
_err 'Retrieving TXT records failed.'
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_clean_records
|
||||||
|
_dns 'SET' "$(printf -- '%s\n_acme-challenge "%s"' "$response" "$txtValue")"
|
||||||
|
if ! _contains "$response" "$AF_API_SUCCESS"; then
|
||||||
|
_err 'Adding ACME challenge value failed.'
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Removes the existing TXT record for given ACME challenge value & domain.
|
||||||
|
# Usage: dns_artfiles_rm _acme-challenge.www.example.com "ACME challenge value"
|
||||||
|
dns_artfiles_rm() {
|
||||||
|
domain="$1"
|
||||||
|
txtValue="$2"
|
||||||
|
_info 'Using ArtFiles.de DNS removal API…'
|
||||||
|
_debug 'Domain' "$domain"
|
||||||
|
_debug 'txtValue' "$txtValue"
|
||||||
|
|
||||||
|
_set_credentials
|
||||||
|
_set_headers
|
||||||
|
_get_zone "$domain"
|
||||||
|
if ! _dns 'GET'; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _contains "$response" "$txtValue"; then
|
||||||
|
_err 'Retrieved TXT records are missing given ACME challenge value.'
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_clean_records
|
||||||
|
response="$(printf -- '%s' "$response" | sed '/_acme-challenge "'"$txtValue"'"/d')"
|
||||||
|
_dns 'SET' "$response"
|
||||||
|
if ! _contains "$response" "$AF_API_SUCCESS"; then
|
||||||
|
_err 'Removing ACME challenge value failed.'
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
########## Private functions ###################################################
|
||||||
|
|
||||||
|
# Cleans awful TXT records response of ArtFiles's API & pretty prints it.
|
||||||
|
# Usage: _clean_records
|
||||||
|
_clean_records() {
|
||||||
|
_info 'Cleaning TXT records…'
|
||||||
|
# Extract TXT part, strip trailing quote sign (ACME.sh API guidelines forbid
|
||||||
|
# usage of SED's GNU extensions, hence couldn't omit it via regex), strip '\'
|
||||||
|
# from '\"' & turn '\n' into real LF characters.
|
||||||
|
# Yup, awful API to use - but that's all we got to get this working, so… ;)
|
||||||
|
_debug2 'Raw ' "$response"
|
||||||
|
response="$(printf -- '%s' "$response" | sed 's/^.*TXT":"\([^}]*\).*$/\1/;s/,".*$//;s/.$//;s/\\"/"/g;s/\\n/\n/g')"
|
||||||
|
_debug2 'Clean' "$response"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Executes an HTTP GET or POST request for getting or setting DNS records,
|
||||||
|
# containing given payload upon POST.
|
||||||
|
# Usage: _dns [GET | SET] [payload]
|
||||||
|
_dns() {
|
||||||
|
_info 'Executing HTTP request…'
|
||||||
|
action="$1"
|
||||||
|
payload="$(printf -- '%s' "$2" | _url_encode)"
|
||||||
|
url="$(printf -- '%s%s' "$AF_URL_DNS" "$domain" | sed 's/{\*}/'"$(printf -- '%s' "$action" | _lower_case)"'/')"
|
||||||
|
|
||||||
|
if [ "$action" = 'SET' ]; then
|
||||||
|
_debug2 'Payload' "$payload"
|
||||||
|
response="$(_post '' "$url&TXT=$payload" '' 'POST' 'application/x-www-form-urlencoded')"
|
||||||
|
else
|
||||||
|
response="$(_get "$url" '' 10)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _contains "$response" "$AF_API_SUCCESS"; then
|
||||||
|
_err "DNS API error: $response"
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug 'Response' "$response"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Gets the root domain zone for given domain.
|
||||||
|
# Usage: _get_zone _acme-challenge.www.example.com
|
||||||
|
_get_zone() {
|
||||||
|
fqdn="$1"
|
||||||
|
domains="$(_get "$AF_URL_DOMAINS" '' 10)"
|
||||||
|
_info 'Getting domain zone…'
|
||||||
|
_debug2 'FQDN' "$fqdn"
|
||||||
|
_debug2 'Domains' "$domains"
|
||||||
|
|
||||||
|
while _contains "$fqdn" "."; do
|
||||||
|
if _contains "$domains" "$fqdn"; then
|
||||||
|
domain="$fqdn"
|
||||||
|
_info "Found root domain zone: $domain"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
fqdn="${fqdn#*.}"
|
||||||
|
_debug2 'FQDN' "$fqdn"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$domain" = "$fqdn" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
_err 'Couldn'\''t find root domain zone.'
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Sets the credentials for accessing ArtFiles's API
|
||||||
|
# Usage: _set_credentials
|
||||||
|
_set_credentials() {
|
||||||
|
_info 'Setting credentials…'
|
||||||
|
AF_API_USERNAME="${AF_API_USERNAME:-$(_readaccountconf_mutable AF_API_USERNAME)}"
|
||||||
|
AF_API_PASSWORD="${AF_API_PASSWORD:-$(_readaccountconf_mutable AF_API_PASSWORD)}"
|
||||||
|
if [ -z "$AF_API_USERNAME" ] || [ -z "$AF_API_PASSWORD" ]; then
|
||||||
|
_err 'Missing ArtFiles.de username and/or password.'
|
||||||
|
_err 'Please ensure both are set via export command & try again.'
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Adds the HTTP Authorization & Content-Type headers to a follow-up request.
|
||||||
|
# Usage: _set_headers
|
||||||
|
_set_headers() {
|
||||||
|
_info 'Setting headers…'
|
||||||
|
encoded="$(printf -- '%s:%s' "$AF_API_USERNAME" "$AF_API_PASSWORD" | _base64)"
|
||||||
|
export _H1="Authorization: Basic $encoded"
|
||||||
|
export _H2='Content-Type: application/json'
|
||||||
|
}
|
@ -1,11 +1,16 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_arvan_info='ArvanCloud.ir
|
||||||
|
Site: ArvanCloud.ir
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_arvan
|
||||||
|
Options:
|
||||||
|
Arvan_Token API Token
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/2796
|
||||||
|
Author: Vahid Fardi
|
||||||
|
'
|
||||||
|
|
||||||
#Arvan_Token="Apikey xxxx"
|
ARVAN_API_URL="https://napi.arvancloud.ir/cdn/4.0/domains"
|
||||||
|
|
||||||
ARVAN_API_URL="https://napi.arvancloud.com/cdn/4.0/domains"
|
|
||||||
#Author: Vahid Fardi
|
|
||||||
#Report Bugs here: https://github.com/Neilpang/acme.sh
|
|
||||||
#
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
#Usage: dns_arvan_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
#Usage: dns_arvan_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
@ -18,7 +23,7 @@ dns_arvan_add() {
|
|||||||
|
|
||||||
if [ -z "$Arvan_Token" ]; then
|
if [ -z "$Arvan_Token" ]; then
|
||||||
_err "You didn't specify \"Arvan_Token\" token yet."
|
_err "You didn't specify \"Arvan_Token\" token yet."
|
||||||
_err "You can get yours from here https://npanel.arvancloud.com/profile/api-keys"
|
_err "You can get yours from here https://npanel.arvancloud.ir/profile/api-keys"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
#save the api token to the account conf file.
|
#save the api token to the account conf file.
|
||||||
@ -40,7 +45,7 @@ dns_arvan_add() {
|
|||||||
_info "response id is $response"
|
_info "response id is $response"
|
||||||
_info "Added, OK"
|
_info "Added, OK"
|
||||||
return 0
|
return 0
|
||||||
elif _contains "$response" "Record Data is Duplicated"; then
|
elif _contains "$response" "Record Data is duplicate"; then
|
||||||
_info "Already exists, OK"
|
_info "Already exists, OK"
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
@ -141,6 +146,7 @@ _arvan_rest() {
|
|||||||
response="$(_post "$data" "$ARVAN_API_URL/$ep" "" "$mtd")"
|
response="$(_post "$data" "$ARVAN_API_URL/$ep" "" "$mtd")"
|
||||||
elif [ "$mtd" = "POST" ]; then
|
elif [ "$mtd" = "POST" ]; then
|
||||||
export _H2="Content-Type: application/json"
|
export _H2="Content-Type: application/json"
|
||||||
|
export _H3="Accept: application/json"
|
||||||
_debug data "$data"
|
_debug data "$data"
|
||||||
response="$(_post "$data" "$ARVAN_API_URL/$ep" "" "$mtd")"
|
response="$(_post "$data" "$ARVAN_API_URL/$ep" "" "$mtd")"
|
||||||
else
|
else
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
#
|
dns_aurora_info='versio.nl AuroraDNS
|
||||||
#AURORA_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
Domains: pcextreme.nl
|
||||||
#
|
Site: versio.nl
|
||||||
#AURORA_Secret="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_aurora
|
||||||
|
Options:
|
||||||
|
AURORA_Key API Key
|
||||||
|
AURORA_Secret API Secret
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/3459
|
||||||
|
Author: Jasper Zonneveld
|
||||||
|
'
|
||||||
|
|
||||||
AURORA_Api="https://api.auroradns.eu"
|
AURORA_Api="https://api.auroradns.eu"
|
||||||
|
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*-
|
# shellcheck disable=SC2034
|
||||||
|
dns_autodns_info='InternetX autoDNS
|
||||||
# This is the InternetX autoDNS xml api wrapper for acme.sh
|
InternetX autoDNS XML API
|
||||||
# Author: auerswald@gmail.com
|
Site: InternetX.com/autodns/
|
||||||
# Created: 2018-01-14
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_autodns
|
||||||
#
|
Options:
|
||||||
# export AUTODNS_USER="username"
|
AUTODNS_USER Username
|
||||||
# export AUTODNS_PASSWORD="password"
|
AUTODNS_PASSWORD Password
|
||||||
# export AUTODNS_CONTEXT="context"
|
AUTODNS_CONTEXT Context
|
||||||
#
|
Author: <auerswald@gmail.com>
|
||||||
# Usage:
|
'
|
||||||
# acme.sh --issue --dns dns_autodns -d example.com
|
|
||||||
|
|
||||||
AUTODNS_API="https://gateway.autodns.com"
|
AUTODNS_API="https://gateway.autodns.com"
|
||||||
|
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_aws_info='Amazon AWS Route53 domain API
|
||||||
|
Site: docs.aws.amazon.com/route53/
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_aws
|
||||||
|
Options:
|
||||||
|
AWS_ACCESS_KEY_ID API Key ID
|
||||||
|
AWS_SECRET_ACCESS_KEY API Secret
|
||||||
|
'
|
||||||
|
|
||||||
#
|
# All `_sleep` commands are included to avoid Route53 throttling, see
|
||||||
#AWS_ACCESS_KEY_ID="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
# https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/DNSLimitations.html#limits-api-requests
|
||||||
#
|
|
||||||
#AWS_SECRET_ACCESS_KEY="xxxxxxx"
|
|
||||||
|
|
||||||
#This is the Amazon Route53 api wrapper for acme.sh
|
|
||||||
#All `_sleep` commands are included to avoid Route53 throttling, see
|
|
||||||
#https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/DNSLimitations.html#limits-api-requests
|
|
||||||
|
|
||||||
AWS_HOST="route53.amazonaws.com"
|
AWS_HOST="route53.amazonaws.com"
|
||||||
AWS_URL="https://$AWS_HOST"
|
AWS_URL="https://$AWS_HOST"
|
||||||
@ -145,41 +147,29 @@ dns_aws_rm() {
|
|||||||
fi
|
fi
|
||||||
_sleep 1
|
_sleep 1
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
#################### Private functions below ##################################
|
||||||
|
|
||||||
_get_root() {
|
_get_root() {
|
||||||
domain=$1
|
domain=$1
|
||||||
i=2
|
i=1
|
||||||
p=1
|
p=1
|
||||||
|
|
||||||
if aws_rest GET "2013-04-01/hostedzone"; then
|
# iterate over names (a.b.c.d -> b.c.d -> c.d -> d)
|
||||||
while true; do
|
while true; do
|
||||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
h=$(printf "%s" "$domain" | cut -d . -f $i-100 | sed 's/\./\\./g')
|
||||||
_debug2 "Checking domain: $h"
|
_debug "Checking domain: $h"
|
||||||
if [ -z "$h" ]; then
|
if [ -z "$h" ]; then
|
||||||
if _contains "$response" "<IsTruncated>true</IsTruncated>" && _contains "$response" "<NextMarker>"; then
|
_error "invalid domain"
|
||||||
_debug "IsTruncated"
|
|
||||||
_nextMarker="$(echo "$response" | _egrep_o "<NextMarker>.*</NextMarker>" | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
|
||||||
_debug "NextMarker" "$_nextMarker"
|
|
||||||
if aws_rest GET "2013-04-01/hostedzone" "marker=$_nextMarker"; then
|
|
||||||
_debug "Truncated request OK"
|
|
||||||
i=2
|
|
||||||
p=1
|
|
||||||
continue
|
|
||||||
else
|
|
||||||
_err "Truncated request error."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
#not valid
|
|
||||||
_err "Invalid domain"
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# iterate over paginated result for list_hosted_zones
|
||||||
|
aws_rest GET "2013-04-01/hostedzone"
|
||||||
|
while true; do
|
||||||
if _contains "$response" "<Name>$h.</Name>"; then
|
if _contains "$response" "<Name>$h.</Name>"; then
|
||||||
hostedzone="$(echo "$response" | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<PrivateZone>false<.PrivateZone>.*<.HostedZone>")"
|
hostedzone="$(echo "$response" | tr -d '\n' | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<PrivateZone>false<.PrivateZone>.*<.HostedZone>")"
|
||||||
_debug hostedzone "$hostedzone"
|
_debug hostedzone "$hostedzone"
|
||||||
if [ "$hostedzone" ]; then
|
if [ "$hostedzone" ]; then
|
||||||
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "<Id>.*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>")
|
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "<Id>.*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>")
|
||||||
@ -192,10 +182,19 @@ _get_root() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
if _contains "$response" "<IsTruncated>true</IsTruncated>" && _contains "$response" "<NextMarker>"; then
|
||||||
|
_debug "IsTruncated"
|
||||||
|
_nextMarker="$(echo "$response" | _egrep_o "<NextMarker>.*</NextMarker>" | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||||
|
_debug "NextMarker" "$_nextMarker"
|
||||||
|
else
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
_debug "Checking domain: $h - Next Page "
|
||||||
|
aws_rest GET "2013-04-01/hostedzone" "marker=$_nextMarker"
|
||||||
|
done
|
||||||
p=$i
|
p=$i
|
||||||
i=$(_math "$i" + 1)
|
i=$(_math "$i" + 1)
|
||||||
done
|
done
|
||||||
fi
|
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,24 +208,40 @@ _use_container_role() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_use_instance_role() {
|
_use_instance_role() {
|
||||||
_url="http://169.254.169.254/latest/meta-data/iam/security-credentials/"
|
_instance_role_name_url="http://169.254.169.254/latest/meta-data/iam/security-credentials/"
|
||||||
_debug "_url" "$_url"
|
|
||||||
if ! _get "$_url" true 1 | _head_n 1 | grep -Fq 200; then
|
if _get "$_instance_role_name_url" true 1 | _head_n 1 | grep -Fq 401; then
|
||||||
|
_debug "Using IMDSv2"
|
||||||
|
_token_url="http://169.254.169.254/latest/api/token"
|
||||||
|
export _H1="X-aws-ec2-metadata-token-ttl-seconds: 21600"
|
||||||
|
_token="$(_post "" "$_token_url" "" "PUT")"
|
||||||
|
_secure_debug3 "_token" "$_token"
|
||||||
|
if [ -z "$_token" ]; then
|
||||||
|
_debug "Unable to fetch IMDSv2 token from instance metadata"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
export _H1="X-aws-ec2-metadata-token: $_token"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _get "$_instance_role_name_url" true 1 | _head_n 1 | grep -Fq 200; then
|
||||||
_debug "Unable to fetch IAM role from instance metadata"
|
_debug "Unable to fetch IAM role from instance metadata"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_aws_role=$(_get "$_url" "" 1)
|
|
||||||
_debug "_aws_role" "$_aws_role"
|
_instance_role_name=$(_get "$_instance_role_name_url" "" 1)
|
||||||
_use_metadata "$_url$_aws_role"
|
_debug "_instance_role_name" "$_instance_role_name"
|
||||||
|
_use_metadata "$_instance_role_name_url$_instance_role_name" "$_token"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_use_metadata() {
|
_use_metadata() {
|
||||||
|
export _H1="X-aws-ec2-metadata-token: $2"
|
||||||
_aws_creds="$(
|
_aws_creds="$(
|
||||||
_get "$1" "" 1 |
|
_get "$1" "" 1 |
|
||||||
_normalizeJson |
|
_normalizeJson |
|
||||||
tr '{,}' '\n' |
|
tr '{,}' '\n' |
|
||||||
while read -r _line; do
|
while read -r _line; do
|
||||||
_key="$(echo "${_line%%:*}" | tr -d '"')"
|
_key="$(echo "${_line%%:*}" | tr -d '\"')"
|
||||||
_value="${_line#*:}"
|
_value="${_line#*:}"
|
||||||
_debug3 "_key" "$_key"
|
_debug3 "_key" "$_key"
|
||||||
_secure_debug3 "_value" "$_value"
|
_secure_debug3 "_value" "$_value"
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
#
|
dns_azion_info='Azion.om
|
||||||
#AZION_Email=""
|
Site: Azion.com
|
||||||
#AZION_Password=""
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_azion
|
||||||
#
|
Options:
|
||||||
|
AZION_Email Email
|
||||||
|
AZION_Password Password
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/3555
|
||||||
|
'
|
||||||
|
|
||||||
AZION_Api="https://api.azionapi.net"
|
AZION_Api="https://api.azionapi.net"
|
||||||
|
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
WIKI="https://github.com/acmesh-official/acme.sh/wiki/How-to-use-Azure-DNS"
|
dns_azure_info='Azure
|
||||||
|
Site: Azure.microsoft.com
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_azure
|
||||||
|
Options:
|
||||||
|
AZUREDNS_SUBSCRIPTIONID Subscription ID
|
||||||
|
AZUREDNS_TENANTID Tenant ID
|
||||||
|
AZUREDNS_APPID App ID. App ID of the service principal
|
||||||
|
AZUREDNS_CLIENTSECRET Client Secret. Secret from creating the service principal
|
||||||
|
AZUREDNS_MANAGEDIDENTITY Use Managed Identity. Use Managed Identity assigned to a resource instead of a service principal. "true"/"false"
|
||||||
|
'
|
||||||
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
@ -9,23 +18,36 @@ WIKI="https://github.com/acmesh-official/acme.sh/wiki/How-to-use-Azure-DNS"
|
|||||||
#
|
#
|
||||||
# Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/createorupdate
|
# Ref: https://docs.microsoft.com/en-us/rest/api/dns/recordsets/createorupdate
|
||||||
#
|
#
|
||||||
|
|
||||||
dns_azure_add() {
|
dns_azure_add() {
|
||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
txtvalue=$2
|
txtvalue=$2
|
||||||
|
|
||||||
AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}"
|
AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}"
|
||||||
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
|
|
||||||
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
|
|
||||||
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
|
|
||||||
|
|
||||||
if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then
|
if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then
|
||||||
AZUREDNS_SUBSCRIPTIONID=""
|
AZUREDNS_SUBSCRIPTIONID=""
|
||||||
AZUREDNS_TENANTID=""
|
AZUREDNS_TENANTID=""
|
||||||
AZUREDNS_APPID=""
|
AZUREDNS_APPID=""
|
||||||
AZUREDNS_CLIENTSECRET=""
|
AZUREDNS_CLIENTSECRET=""
|
||||||
_err "You didn't specify the Azure Subscription ID "
|
_err "You didn't specify the Azure Subscription ID"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
#save subscription id to account conf file.
|
||||||
|
_saveaccountconf_mutable AZUREDNS_SUBSCRIPTIONID "$AZUREDNS_SUBSCRIPTIONID"
|
||||||
|
|
||||||
|
AZUREDNS_MANAGEDIDENTITY="${AZUREDNS_MANAGEDIDENTITY:-$(_readaccountconf_mutable AZUREDNS_MANAGEDIDENTITY)}"
|
||||||
|
if [ "$AZUREDNS_MANAGEDIDENTITY" = true ]; then
|
||||||
|
_info "Using Azure managed identity"
|
||||||
|
#save managed identity as preferred authentication method, clear service principal credentials from conf file.
|
||||||
|
_saveaccountconf_mutable AZUREDNS_MANAGEDIDENTITY "$AZUREDNS_MANAGEDIDENTITY"
|
||||||
|
_saveaccountconf_mutable AZUREDNS_TENANTID ""
|
||||||
|
_saveaccountconf_mutable AZUREDNS_APPID ""
|
||||||
|
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET ""
|
||||||
|
else
|
||||||
|
_info "You didn't ask to use Azure managed identity, checking service principal credentials"
|
||||||
|
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
|
||||||
|
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
|
||||||
|
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
|
||||||
|
|
||||||
if [ -z "$AZUREDNS_TENANTID" ]; then
|
if [ -z "$AZUREDNS_TENANTID" ]; then
|
||||||
AZUREDNS_SUBSCRIPTIONID=""
|
AZUREDNS_SUBSCRIPTIONID=""
|
||||||
@ -53,13 +75,15 @@ dns_azure_add() {
|
|||||||
_err "You didn't specify the Azure Client Secret"
|
_err "You didn't specify the Azure Client Secret"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
#save account details to account conf file.
|
|
||||||
_saveaccountconf_mutable AZUREDNS_SUBSCRIPTIONID "$AZUREDNS_SUBSCRIPTIONID"
|
#save account details to account conf file, don't opt in for azure manages identity check.
|
||||||
|
_saveaccountconf_mutable AZUREDNS_MANAGEDIDENTITY "false"
|
||||||
_saveaccountconf_mutable AZUREDNS_TENANTID "$AZUREDNS_TENANTID"
|
_saveaccountconf_mutable AZUREDNS_TENANTID "$AZUREDNS_TENANTID"
|
||||||
_saveaccountconf_mutable AZUREDNS_APPID "$AZUREDNS_APPID"
|
_saveaccountconf_mutable AZUREDNS_APPID "$AZUREDNS_APPID"
|
||||||
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET"
|
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET"
|
||||||
|
fi
|
||||||
|
|
||||||
accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
|
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
|
||||||
|
|
||||||
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
|
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
|
||||||
_err "invalid domain"
|
_err "invalid domain"
|
||||||
@ -116,10 +140,6 @@ dns_azure_rm() {
|
|||||||
txtvalue=$2
|
txtvalue=$2
|
||||||
|
|
||||||
AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}"
|
AZUREDNS_SUBSCRIPTIONID="${AZUREDNS_SUBSCRIPTIONID:-$(_readaccountconf_mutable AZUREDNS_SUBSCRIPTIONID)}"
|
||||||
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
|
|
||||||
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
|
|
||||||
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
|
|
||||||
|
|
||||||
if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then
|
if [ -z "$AZUREDNS_SUBSCRIPTIONID" ]; then
|
||||||
AZUREDNS_SUBSCRIPTIONID=""
|
AZUREDNS_SUBSCRIPTIONID=""
|
||||||
AZUREDNS_TENANTID=""
|
AZUREDNS_TENANTID=""
|
||||||
@ -129,6 +149,15 @@ dns_azure_rm() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
AZUREDNS_MANAGEDIDENTITY="${AZUREDNS_MANAGEDIDENTITY:-$(_readaccountconf_mutable AZUREDNS_MANAGEDIDENTITY)}"
|
||||||
|
if [ "$AZUREDNS_MANAGEDIDENTITY" = true ]; then
|
||||||
|
_info "Using Azure managed identity"
|
||||||
|
else
|
||||||
|
_info "You didn't ask to use Azure managed identity, checking service principal credentials"
|
||||||
|
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
|
||||||
|
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
|
||||||
|
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
|
||||||
|
|
||||||
if [ -z "$AZUREDNS_TENANTID" ]; then
|
if [ -z "$AZUREDNS_TENANTID" ]; then
|
||||||
AZUREDNS_SUBSCRIPTIONID=""
|
AZUREDNS_SUBSCRIPTIONID=""
|
||||||
AZUREDNS_TENANTID=""
|
AZUREDNS_TENANTID=""
|
||||||
@ -155,8 +184,9 @@ dns_azure_rm() {
|
|||||||
_err "You didn't specify the Azure Client Secret"
|
_err "You didn't specify the Azure Client Secret"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
accesstoken=$(_azure_getaccess_token "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
|
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
|
||||||
|
|
||||||
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
|
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
|
||||||
_err "invalid domain"
|
_err "invalid domain"
|
||||||
@ -258,9 +288,10 @@ _azure_rest() {
|
|||||||
|
|
||||||
## Ref: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service#request-an-access-token
|
## Ref: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service#request-an-access-token
|
||||||
_azure_getaccess_token() {
|
_azure_getaccess_token() {
|
||||||
tenantID=$1
|
managedIdentity=$1
|
||||||
clientID=$2
|
tenantID=$2
|
||||||
clientSecret=$3
|
clientID=$3
|
||||||
|
clientSecret=$4
|
||||||
|
|
||||||
accesstoken="${AZUREDNS_BEARERTOKEN:-$(_readaccountconf_mutable AZUREDNS_BEARERTOKEN)}"
|
accesstoken="${AZUREDNS_BEARERTOKEN:-$(_readaccountconf_mutable AZUREDNS_BEARERTOKEN)}"
|
||||||
expires_on="${AZUREDNS_TOKENVALIDTO:-$(_readaccountconf_mutable AZUREDNS_TOKENVALIDTO)}"
|
expires_on="${AZUREDNS_TOKENVALIDTO:-$(_readaccountconf_mutable AZUREDNS_TOKENVALIDTO)}"
|
||||||
@ -278,9 +309,16 @@ _azure_getaccess_token() {
|
|||||||
fi
|
fi
|
||||||
_debug "getting new bearer token"
|
_debug "getting new bearer token"
|
||||||
|
|
||||||
|
if [ "$managedIdentity" = true ]; then
|
||||||
|
# https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http
|
||||||
|
export _H1="Metadata: true"
|
||||||
|
response="$(_get http://169.254.169.254/metadata/identity/oauth2/token\?api-version=2018-02-01\&resource=https://management.azure.com/)"
|
||||||
|
response="$(echo "$response" | _normalizeJson)"
|
||||||
|
accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||||
|
expires_on=$(echo "$response" | _egrep_o "\"expires_on\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||||
|
else
|
||||||
export _H1="accept: application/json"
|
export _H1="accept: application/json"
|
||||||
export _H2="Content-Type: application/x-www-form-urlencoded"
|
export _H2="Content-Type: application/x-www-form-urlencoded"
|
||||||
|
|
||||||
body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials"
|
body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials"
|
||||||
_secure_debug2 "data $body"
|
_secure_debug2 "data $body"
|
||||||
response="$(_post "$body" "https://login.microsoftonline.com/$tenantID/oauth2/token" "" "POST")"
|
response="$(_post "$body" "https://login.microsoftonline.com/$tenantID/oauth2/token" "" "POST")"
|
||||||
@ -289,6 +327,7 @@ _azure_getaccess_token() {
|
|||||||
response="$(echo "$response" | _normalizeJson)"
|
response="$(echo "$response" | _normalizeJson)"
|
||||||
accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||||
expires_on=$(echo "$response" | _egrep_o "\"expires_on\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
expires_on=$(echo "$response" | _egrep_o "\"expires_on\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||||
|
fi
|
||||||
|
|
||||||
if [ -z "$accesstoken" ]; then
|
if [ -z "$accesstoken" ]; then
|
||||||
_err "no acccess token received. Check your Azure settings see $WIKI"
|
_err "no acccess token received. Check your Azure settings see $WIKI"
|
||||||
|
88
dnsapi/dns_bookmyname.sh
Normal file
88
dnsapi/dns_bookmyname.sh
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_bookmyname_info='BookMyName.com
|
||||||
|
Site: BookMyName.com
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_bookmyname
|
||||||
|
Options:
|
||||||
|
BOOKMYNAME_USERNAME Username
|
||||||
|
BOOKMYNAME_PASSWORD Password
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/3209
|
||||||
|
Author: Neilpang
|
||||||
|
'
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
|
||||||
|
# BookMyName urls:
|
||||||
|
# https://BOOKMYNAME_USERNAME:BOOKMYNAME_PASSWORD@www.bookmyname.com/dyndns/?hostname=_acme-challenge.domain.tld&type=txt&ttl=300&do=add&value="XXXXXXXX"'
|
||||||
|
# https://BOOKMYNAME_USERNAME:BOOKMYNAME_PASSWORD@www.bookmyname.com/dyndns/?hostname=_acme-challenge.domain.tld&type=txt&ttl=300&do=remove&value="XXXXXXXX"'
|
||||||
|
|
||||||
|
# Output:
|
||||||
|
#good: update done, cid 123456, domain id 456789, type txt, ip XXXXXXXX
|
||||||
|
#good: remove done 1, cid 123456, domain id 456789, ttl 300, type txt, ip XXXXXXXX
|
||||||
|
|
||||||
|
# Be careful, BMN DNS servers can be slow to pick up changes; using dnssleep is thus advised.
|
||||||
|
|
||||||
|
# Usage:
|
||||||
|
# export BOOKMYNAME_USERNAME="ABCDE-FREE"
|
||||||
|
# export BOOKMYNAME_PASSWORD="MyPassword"
|
||||||
|
# /usr/local/ssl/acme.sh/acme.sh --dns dns_bookmyname --dnssleep 600 --issue -d domain.tld
|
||||||
|
|
||||||
|
#Usage: dns_bookmyname_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
dns_bookmyname_add() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
_info "Using bookmyname"
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
|
BOOKMYNAME_USERNAME="${BOOKMYNAME_USERNAME:-$(_readaccountconf_mutable BOOKMYNAME_USERNAME)}"
|
||||||
|
BOOKMYNAME_PASSWORD="${BOOKMYNAME_PASSWORD:-$(_readaccountconf_mutable BOOKMYNAME_PASSWORD)}"
|
||||||
|
|
||||||
|
if [ -z "$BOOKMYNAME_USERNAME" ] || [ -z "$BOOKMYNAME_PASSWORD" ]; then
|
||||||
|
BOOKMYNAME_USERNAME=""
|
||||||
|
BOOKMYNAME_PASSWORD=""
|
||||||
|
_err "You didn't specify BookMyName username and password yet."
|
||||||
|
_err "Please specify them and try again."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#save the credentials to the account conf file.
|
||||||
|
_saveaccountconf_mutable BOOKMYNAME_USERNAME "$BOOKMYNAME_USERNAME"
|
||||||
|
_saveaccountconf_mutable BOOKMYNAME_PASSWORD "$BOOKMYNAME_PASSWORD"
|
||||||
|
|
||||||
|
uri="https://${BOOKMYNAME_USERNAME}:${BOOKMYNAME_PASSWORD}@www.bookmyname.com/dyndns/"
|
||||||
|
data="?hostname=${fulldomain}&type=TXT&ttl=300&do=add&value=${txtvalue}"
|
||||||
|
result="$(_get "${uri}${data}")"
|
||||||
|
_debug "Result: $result"
|
||||||
|
|
||||||
|
if ! _startswith "$result" 'good: update done, cid '; then
|
||||||
|
_err "Can't add $fulldomain"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#Usage: fulldomain txtvalue
|
||||||
|
#Remove the txt record after validation.
|
||||||
|
dns_bookmyname_rm() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
_info "Using bookmyname"
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
|
BOOKMYNAME_USERNAME="${BOOKMYNAME_USERNAME:-$(_readaccountconf_mutable BOOKMYNAME_USERNAME)}"
|
||||||
|
BOOKMYNAME_PASSWORD="${BOOKMYNAME_PASSWORD:-$(_readaccountconf_mutable BOOKMYNAME_PASSWORD)}"
|
||||||
|
|
||||||
|
uri="https://${BOOKMYNAME_USERNAME}:${BOOKMYNAME_PASSWORD}@www.bookmyname.com/dyndns/"
|
||||||
|
data="?hostname=${fulldomain}&type=TXT&ttl=300&do=remove&value=${txtvalue}"
|
||||||
|
result="$(_get "${uri}${data}")"
|
||||||
|
_debug "Result: $result"
|
||||||
|
|
||||||
|
if ! _startswith "$result" 'good: remove done 1, cid '; then
|
||||||
|
_info "Can't remove $fulldomain"
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#################### Private functions below ##################################
|
245
dnsapi/dns_bunny.sh
Normal file
245
dnsapi/dns_bunny.sh
Normal file
@ -0,0 +1,245 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_bunny_info='Bunny.net
|
||||||
|
Site: Bunny.net/dns/
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_bunny
|
||||||
|
Options:
|
||||||
|
BUNNY_API_KEY API Key
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/4296
|
||||||
|
Author: <nosilver4u@ewww.io>
|
||||||
|
'
|
||||||
|
|
||||||
|
##################### Public functions #####################
|
||||||
|
|
||||||
|
## Create the text record for validation.
|
||||||
|
## Usage: fulldomain txtvalue
|
||||||
|
## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
|
||||||
|
dns_bunny_add() {
|
||||||
|
fulldomain="$(echo "$1" | _lower_case)"
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
BUNNY_API_KEY="${BUNNY_API_KEY:-$(_readaccountconf_mutable BUNNY_API_KEY)}"
|
||||||
|
# Check if API Key is set
|
||||||
|
if [ -z "$BUNNY_API_KEY" ]; then
|
||||||
|
BUNNY_API_KEY=""
|
||||||
|
_err "You did not specify Bunny.net API key."
|
||||||
|
_err "Please export BUNNY_API_KEY and try again."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info "Using Bunny.net dns validation - add record"
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
|
## save the env vars (key and domain split location) for later automated use
|
||||||
|
_saveaccountconf_mutable BUNNY_API_KEY "$BUNNY_API_KEY"
|
||||||
|
|
||||||
|
## split the domain for Bunny API
|
||||||
|
if ! _get_base_domain "$fulldomain"; then
|
||||||
|
_err "domain not found in your account for addition"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
_debug _domain_id "$_domain_id"
|
||||||
|
|
||||||
|
## Set the header with our post type and auth key
|
||||||
|
export _H1="Accept: application/json"
|
||||||
|
export _H2="AccessKey: $BUNNY_API_KEY"
|
||||||
|
export _H3="Content-Type: application/json"
|
||||||
|
PURL="https://api.bunny.net/dnszone/$_domain_id/records"
|
||||||
|
PBODY='{"Id":'$_domain_id',"Type":3,"Name":"'$_sub_domain'","Value":"'$txtvalue'","ttl":120}'
|
||||||
|
|
||||||
|
_debug PURL "$PURL"
|
||||||
|
_debug PBODY "$PBODY"
|
||||||
|
|
||||||
|
## the create request - POST
|
||||||
|
## args: BODY, URL, [need64, httpmethod]
|
||||||
|
response="$(_post "$PBODY" "$PURL" "" "PUT")"
|
||||||
|
|
||||||
|
## check response
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "error in response: $response"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 response "$response"
|
||||||
|
|
||||||
|
## finished correctly
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
## Remove the txt record after validation.
|
||||||
|
## Usage: fulldomain txtvalue
|
||||||
|
## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
|
||||||
|
dns_bunny_rm() {
|
||||||
|
fulldomain="$(echo "$1" | _lower_case)"
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
BUNNY_API_KEY="${BUNNY_API_KEY:-$(_readaccountconf_mutable BUNNY_API_KEY)}"
|
||||||
|
# Check if API Key Exists
|
||||||
|
if [ -z "$BUNNY_API_KEY" ]; then
|
||||||
|
BUNNY_API_KEY=""
|
||||||
|
_err "You did not specify Bunny.net API key."
|
||||||
|
_err "Please export BUNNY_API_KEY and try again."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info "Using Bunny.net dns validation - remove record"
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
|
## split the domain for Bunny API
|
||||||
|
if ! _get_base_domain "$fulldomain"; then
|
||||||
|
_err "Domain not found in your account for TXT record removal"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
_debug _domain_id "$_domain_id"
|
||||||
|
|
||||||
|
## Set the header with our post type and key auth key
|
||||||
|
export _H1="Accept: application/json"
|
||||||
|
export _H2="AccessKey: $BUNNY_API_KEY"
|
||||||
|
## get URL for the list of DNS records
|
||||||
|
GURL="https://api.bunny.net/dnszone/$_domain_id"
|
||||||
|
|
||||||
|
## 1) Get the domain/zone records
|
||||||
|
## the fetch request - GET
|
||||||
|
## args: URL, [onlyheader, timeout]
|
||||||
|
domain_list="$(_get "$GURL")"
|
||||||
|
|
||||||
|
## check response
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "error in domain_list response: $domain_list"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 domain_list "$domain_list"
|
||||||
|
|
||||||
|
## 2) search through records
|
||||||
|
## check for what we are looking for: "Type":3,"Value":"$txtvalue","Name":"$_sub_domain"
|
||||||
|
record="$(echo "$domain_list" | _egrep_o "\"Id\"\s*\:\s*\"*[0-9]+\"*,\s*\"Type\"[^}]*\"Value\"\s*\:\s*\"$txtvalue\"[^}]*\"Name\"\s*\:\s*\"$_sub_domain\"")"
|
||||||
|
|
||||||
|
if [ -n "$record" ]; then
|
||||||
|
|
||||||
|
## We found records
|
||||||
|
rec_ids="$(echo "$record" | _egrep_o "Id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
|
||||||
|
_debug rec_ids "$rec_ids"
|
||||||
|
if [ -n "$rec_ids" ]; then
|
||||||
|
echo "$rec_ids" | while IFS= read -r rec_id; do
|
||||||
|
## delete the record
|
||||||
|
## delete URL for removing the one we dont want
|
||||||
|
DURL="https://api.bunny.net/dnszone/$_domain_id/records/$rec_id"
|
||||||
|
|
||||||
|
## the removal request - DELETE
|
||||||
|
## args: BODY, URL, [need64, httpmethod]
|
||||||
|
response="$(_post "" "$DURL" "" "DELETE")"
|
||||||
|
|
||||||
|
## check response (sort of)
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "error in remove response: $response"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 response "$response"
|
||||||
|
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
## finished correctly
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
##################### Private functions below #####################
|
||||||
|
|
||||||
|
## Split the domain provided into the "base domain" and the "start prefix".
|
||||||
|
## This function searches for the longest subdomain in your account
|
||||||
|
## for the full domain given and splits it into the base domain (zone)
|
||||||
|
## and the prefix/record to be added/removed
|
||||||
|
## USAGE: fulldomain
|
||||||
|
## EG: "_acme-challenge.two.three.four.domain.com"
|
||||||
|
## returns
|
||||||
|
## _sub_domain="_acme-challenge.two"
|
||||||
|
## _domain="three.four.domain.com" *IF* zone "three.four.domain.com" exists
|
||||||
|
## _domain_id=234
|
||||||
|
## if only "domain.com" exists it will return
|
||||||
|
## _sub_domain="_acme-challenge.two.three.four"
|
||||||
|
## _domain="domain.com"
|
||||||
|
## _domain_id=234
|
||||||
|
_get_base_domain() {
|
||||||
|
# args
|
||||||
|
fulldomain="$(echo "$1" | _lower_case)"
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
|
||||||
|
# domain max legal length = 253
|
||||||
|
MAX_DOM=255
|
||||||
|
page=1
|
||||||
|
|
||||||
|
## get a list of domains for the account to check thru
|
||||||
|
## Set the headers
|
||||||
|
export _H1="Accept: application/json"
|
||||||
|
export _H2="AccessKey: $BUNNY_API_KEY"
|
||||||
|
_debug BUNNY_API_KEY "$BUNNY_API_KEY"
|
||||||
|
## get URL for the list of domains
|
||||||
|
## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
|
||||||
|
DOMURL="https://api.bunny.net/dnszone"
|
||||||
|
|
||||||
|
## while we dont have a matching domain we keep going
|
||||||
|
while [ -z "$found" ]; do
|
||||||
|
## get the domain list (current page)
|
||||||
|
domain_list="$(_get "$DOMURL")"
|
||||||
|
|
||||||
|
## check response
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "error in domain_list response: $domain_list"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 domain_list "$domain_list"
|
||||||
|
|
||||||
|
i=1
|
||||||
|
while [ $i -gt 0 ]; do
|
||||||
|
## get next longest domain
|
||||||
|
_domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
|
||||||
|
## check we got something back from our cut (or are we at the end)
|
||||||
|
if [ -z "$_domain" ]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
## we got part of a domain back - grep it out
|
||||||
|
found="$(echo "$domain_list" | _egrep_o "\"Id\"\s*:\s*\"*[0-9]+\"*,\s*\"Domain\"\s*\:\s*\"$_domain\"")"
|
||||||
|
## check if it exists
|
||||||
|
if [ -n "$found" ]; then
|
||||||
|
## exists - exit loop returning the parts
|
||||||
|
sub_point=$(_math $i - 1)
|
||||||
|
_sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point")
|
||||||
|
_domain_id="$(echo "$found" | _egrep_o "Id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
|
||||||
|
_debug _domain_id "$_domain_id"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
found=""
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
## increment cut point $i
|
||||||
|
i=$(_math $i + 1)
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$found" ]; then
|
||||||
|
page=$(_math $page + 1)
|
||||||
|
nextpage="https://api.bunny.net/dnszone?page=$page"
|
||||||
|
## Find the next page if we don't have a match.
|
||||||
|
hasnextpage="$(echo "$domain_list" | _egrep_o "\"HasMoreItems\"\s*:\s*true")"
|
||||||
|
if [ -z "$hasnextpage" ]; then
|
||||||
|
_err "No record and no nextpage in Bunny.net domain search."
|
||||||
|
found=""
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 nextpage "$nextpage"
|
||||||
|
DOMURL="$nextpage"
|
||||||
|
fi
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
## We went through the entire domain zone list and didn't find one that matched.
|
||||||
|
## If we ever get here, something is broken in the code...
|
||||||
|
_err "Domain not found in Bunny.net account, but we should never get here!"
|
||||||
|
found=""
|
||||||
|
return 1
|
||||||
|
}
|
@ -1,13 +1,16 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
#
|
dns_cf_info='CloudFlare
|
||||||
#CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
Site: CloudFlare.com
|
||||||
#
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cf
|
||||||
#CF_Email="xxxx@sss.com"
|
Options:
|
||||||
|
CF_Key API Key
|
||||||
#CF_Token="xxxx"
|
CF_Email Your account email
|
||||||
#CF_Account_ID="xxxx"
|
OptionsAlt:
|
||||||
#CF_Zone_ID="xxxx"
|
CF_Token API Token
|
||||||
|
CF_Account_ID Account ID
|
||||||
|
CF_Zone_ID Zone ID. Optional.
|
||||||
|
'
|
||||||
|
|
||||||
CF_Api="https://api.cloudflare.com/client/v4"
|
CF_Api="https://api.cloudflare.com/client/v4"
|
||||||
|
|
||||||
@ -25,9 +28,16 @@ dns_cf_add() {
|
|||||||
CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}"
|
CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}"
|
||||||
|
|
||||||
if [ "$CF_Token" ]; then
|
if [ "$CF_Token" ]; then
|
||||||
|
if [ "$CF_Zone_ID" ]; then
|
||||||
|
_savedomainconf CF_Token "$CF_Token"
|
||||||
|
_savedomainconf CF_Account_ID "$CF_Account_ID"
|
||||||
|
_savedomainconf CF_Zone_ID "$CF_Zone_ID"
|
||||||
|
else
|
||||||
_saveaccountconf_mutable CF_Token "$CF_Token"
|
_saveaccountconf_mutable CF_Token "$CF_Token"
|
||||||
_saveaccountconf_mutable CF_Account_ID "$CF_Account_ID"
|
_saveaccountconf_mutable CF_Account_ID "$CF_Account_ID"
|
||||||
_saveaccountconf_mutable CF_Zone_ID "$CF_Zone_ID"
|
_clearaccountconf_mutable CF_Zone_ID
|
||||||
|
_clearaccountconf CF_Zone_ID
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
|
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
|
||||||
CF_Key=""
|
CF_Key=""
|
||||||
@ -45,6 +55,14 @@ dns_cf_add() {
|
|||||||
#save the api key and email to the account conf file.
|
#save the api key and email to the account conf file.
|
||||||
_saveaccountconf_mutable CF_Key "$CF_Key"
|
_saveaccountconf_mutable CF_Key "$CF_Key"
|
||||||
_saveaccountconf_mutable CF_Email "$CF_Email"
|
_saveaccountconf_mutable CF_Email "$CF_Email"
|
||||||
|
|
||||||
|
_clearaccountconf_mutable CF_Token
|
||||||
|
_clearaccountconf_mutable CF_Account_ID
|
||||||
|
_clearaccountconf_mutable CF_Zone_ID
|
||||||
|
_clearaccountconf CF_Token
|
||||||
|
_clearaccountconf CF_Account_ID
|
||||||
|
_clearaccountconf CF_Zone_ID
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_debug "First detect the root zone"
|
_debug "First detect the root zone"
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
# Author: Radek Sprta <sprta@vshosting.cz>
|
dns_clouddns_info='vshosting.cz CloudDNS
|
||||||
|
Site: github.com/vshosting/clouddns
|
||||||
#CLOUDDNS_EMAIL=XXXXX
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_clouddns
|
||||||
#CLOUDDNS_PASSWORD="YYYYYYYYY"
|
Options:
|
||||||
#CLOUDDNS_CLIENT_ID=XXXXX
|
CLOUDDNS_EMAIL Email
|
||||||
|
CLOUDDNS_PASSWORD Password
|
||||||
|
CLOUDDNS_CLIENT_ID Client ID
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/2699
|
||||||
|
Author: Radek Sprta <sprta@vshosting.cz>
|
||||||
|
'
|
||||||
|
|
||||||
CLOUDDNS_API='https://admin.vshosting.cloud/clouddns'
|
CLOUDDNS_API='https://admin.vshosting.cloud/clouddns'
|
||||||
CLOUDDNS_LOGIN_API='https://admin.vshosting.cloud/api/public/auth/login'
|
CLOUDDNS_LOGIN_API='https://admin.vshosting.cloud/api/public/auth/login'
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_cloudns_info='ClouDNS.net
|
||||||
|
Site: ClouDNS.net
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cloudns
|
||||||
|
Options:
|
||||||
|
CLOUDNS_AUTH_ID Regular auth ID
|
||||||
|
CLOUDNS_SUB_AUTH_ID Sub auth ID
|
||||||
|
CLOUDNS_AUTH_PASSWORD Auth Password
|
||||||
|
Author: Boyan Peychev <boyan@cloudns.net>
|
||||||
|
'
|
||||||
|
|
||||||
# Author: Boyan Peychev <boyan at cloudns dot net>
|
|
||||||
# Repository: https://github.com/ClouDNS/acme.sh/
|
|
||||||
# Editor: I Komang Suryadana
|
|
||||||
|
|
||||||
#CLOUDNS_AUTH_ID=XXXXX
|
|
||||||
#CLOUDNS_SUB_AUTH_ID=XXXXX
|
|
||||||
#CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"
|
|
||||||
CLOUDNS_API="https://api.cloudns.net"
|
CLOUDNS_API="https://api.cloudns.net"
|
||||||
DOMAIN_TYPE=
|
DOMAIN_TYPE=
|
||||||
DOMAIN_MASTER=
|
DOMAIN_MASTER=
|
||||||
@ -78,7 +81,7 @@ dns_cloudns_rm() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for i in $(echo "$response" | tr '{' "\n" | grep "$record"); do
|
for i in $(echo "$response" | tr '{' "\n" | grep -- "$record"); do
|
||||||
record_id=$(echo "$i" | tr ',' "\n" | grep -E '^"id"' | sed -re 's/^\"id\"\:\"([0-9]+)\"$/\1/g')
|
record_id=$(echo "$i" | tr ',' "\n" | grep -E '^"id"' | sed -re 's/^\"id\"\:\"([0-9]+)\"$/\1/g')
|
||||||
|
|
||||||
if [ -n "$record_id" ]; then
|
if [ -n "$record_id" ]; then
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
# DNS API for acme.sh for Core-Networks (https://beta.api.core-networks.de/doc/).
|
dns_cn_info='Core-Networks.de
|
||||||
# created by 5ll and francis
|
Site: beta.api.Core-Networks.de/doc/
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cn
|
||||||
|
Options:
|
||||||
|
CN_User User
|
||||||
|
CN_Password Password
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/2142
|
||||||
|
Author: 5ll, francis
|
||||||
|
'
|
||||||
|
|
||||||
CN_API="https://beta.api.core-networks.de"
|
CN_API="https://beta.api.core-networks.de"
|
||||||
|
|
||||||
|
@ -1,4 +1,15 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_conoha_info='ConoHa.jp
|
||||||
|
Domains: ConoHa.io
|
||||||
|
Site: ConoHa.jp
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_conoha
|
||||||
|
Options:
|
||||||
|
CONOHA_Username Username
|
||||||
|
CONOHA_Password Password
|
||||||
|
CONOHA_TenantId TenantId
|
||||||
|
CONOHA_IdentityServiceApi Identity Service API. E.g. "https://identity.xxxx.conoha.io/v2.0"
|
||||||
|
'
|
||||||
|
|
||||||
CONOHA_DNS_EP_PREFIX_REGEXP="https://dns-service\."
|
CONOHA_DNS_EP_PREFIX_REGEXP="https://dns-service\."
|
||||||
|
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
# Author: Wout Decre <wout@canodus.be>
|
dns_constellix_info='Constellix.com
|
||||||
|
Site: Constellix.com
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_constellix
|
||||||
|
Options:
|
||||||
|
CONSTELLIX_Key API Key
|
||||||
|
CONSTELLIX_Secret API Secret
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/2724
|
||||||
|
Author: Wout Decre <wout@canodus.be>
|
||||||
|
'
|
||||||
|
|
||||||
CONSTELLIX_Api="https://api.dns.constellix.com/v1"
|
CONSTELLIX_Api="https://api.dns.constellix.com/v1"
|
||||||
#CONSTELLIX_Key="XXX"
|
|
||||||
#CONSTELLIX_Secret="XXX"
|
|
||||||
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
#
|
# shellcheck disable=SC2034
|
||||||
#Author: Bjarne Saltbaek
|
dns_cpanel_info='cPanel Server API
|
||||||
#Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/3732
|
Manage DNS via cPanel Dashboard.
|
||||||
#
|
Site: cPanel.net
|
||||||
#
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_cpanel
|
||||||
|
Options:
|
||||||
|
cPanel_Username Username
|
||||||
|
cPanel_Apitoken API Token
|
||||||
|
cPanel_Hostname Server URL. E.g. "https://hostname:port"
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/3732
|
||||||
|
Author: Bjarne Saltbaek
|
||||||
|
'
|
||||||
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
#
|
|
||||||
# Export CPANEL username,api token and hostname in the following variables
|
|
||||||
#
|
|
||||||
# cPanel_Username=username
|
|
||||||
# cPanel_Apitoken=apitoken
|
|
||||||
# cPanel_Hostname=hostname
|
|
||||||
#
|
|
||||||
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
|
||||||
# Used to add txt record
|
# Used to add txt record
|
||||||
dns_cpanel_add() {
|
dns_cpanel_add() {
|
||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
@ -120,7 +121,7 @@ _myget() {
|
|||||||
|
|
||||||
_get_root() {
|
_get_root() {
|
||||||
_myget 'json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=fetchzones'
|
_myget 'json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=fetchzones'
|
||||||
_domains=$(echo "$_result" | sed 's/.*\(zones.*\[\).*/\1/' | cut -d':' -f2 | sed 's/"//g' | sed 's/{//g')
|
_domains=$(echo "$_result" | _egrep_o '"[a-z0-9\.\-]*":\["; cPanel first' | cut -d':' -f1 | sed 's/"//g' | sed 's/{//g')
|
||||||
_debug "_result is: $_result"
|
_debug "_result is: $_result"
|
||||||
_debug "_domains is: $_domains"
|
_debug "_domains is: $_domains"
|
||||||
if [ -z "$_domains" ]; then
|
if [ -z "$_domains" ]; then
|
||||||
@ -138,15 +139,15 @@ _get_root() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_successful_update() {
|
_successful_update() {
|
||||||
if (echo "$_result" | grep -q 'newserial'); then return 0; fi
|
if (echo "$_result" | _egrep_o 'data":\[[^]]*]' | grep -q '"newserial":null'); then return 1; fi
|
||||||
return 1
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
_findentry() {
|
_findentry() {
|
||||||
_debug "In _findentry"
|
_debug "In _findentry"
|
||||||
#returns id of dns entry, if it exists
|
#returns id of dns entry, if it exists
|
||||||
_myget "json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=fetchzone_records&domain=$_domain"
|
_myget "json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=fetchzone_records&domain=$_domain"
|
||||||
_id=$(echo "$_result" | sed "s/.*\(line.*$fulldomain.*$txtvalue\).*/\1/" | cut -d ':' -f 2 | cut -d ',' -f 1)
|
_id=$(echo "$_result" | sed -e "s/},{/},\n{/g" | grep "$fulldomain" | grep "$txtvalue" | _egrep_o 'line":[0-9]+' | cut -d ':' -f 2)
|
||||||
_debug "_result is: $_result"
|
_debug "_result is: $_result"
|
||||||
_debug "fulldomain. is $fulldomain."
|
_debug "fulldomain. is $fulldomain."
|
||||||
_debug "txtvalue is $txtvalue"
|
_debug "txtvalue is $txtvalue"
|
||||||
|
165
dnsapi/dns_curanet.sh
Normal file
165
dnsapi/dns_curanet.sh
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_curanet_info='Curanet.dk
|
||||||
|
Domains: scannet.dk wannafind.dk dandomain.dk
|
||||||
|
Site: Curanet.dk
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_curanet
|
||||||
|
Options:
|
||||||
|
CURANET_AUTHCLIENTID Auth ClientID. Requires scope dns
|
||||||
|
CURANET_AUTHSECRET Auth Secret
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/3933
|
||||||
|
Author: Peter L. Hansen <peter@r12.dk>
|
||||||
|
'
|
||||||
|
|
||||||
|
CURANET_REST_URL="https://api.curanet.dk/dns/v1/Domains"
|
||||||
|
CURANET_AUTH_URL="https://apiauth.dk.team.blue/auth/realms/Curanet/protocol/openid-connect/token"
|
||||||
|
CURANET_ACCESS_TOKEN=""
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
|
||||||
|
#Usage: dns_curanet_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
dns_curanet_add() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
_info "Using curanet"
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
|
CURANET_AUTHCLIENTID="${CURANET_AUTHCLIENTID:-$(_readaccountconf_mutable CURANET_AUTHCLIENTID)}"
|
||||||
|
CURANET_AUTHSECRET="${CURANET_AUTHSECRET:-$(_readaccountconf_mutable CURANET_AUTHSECRET)}"
|
||||||
|
if [ -z "$CURANET_AUTHCLIENTID" ] || [ -z "$CURANET_AUTHSECRET" ]; then
|
||||||
|
CURANET_AUTHCLIENTID=""
|
||||||
|
CURANET_AUTHSECRET=""
|
||||||
|
_err "You don't specify curanet api client and secret."
|
||||||
|
_err "Please create your auth info and try again."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#save the credentials to the account conf file.
|
||||||
|
_saveaccountconf_mutable CURANET_AUTHCLIENTID "$CURANET_AUTHCLIENTID"
|
||||||
|
_saveaccountconf_mutable CURANET_AUTHSECRET "$CURANET_AUTHSECRET"
|
||||||
|
|
||||||
|
if ! _get_token; then
|
||||||
|
_err "Unable to get token"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _get_root "$fulldomain"; then
|
||||||
|
_err "Invalid domain"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
export _H1="Content-Type: application/json-patch+json"
|
||||||
|
export _H2="Accept: application/json"
|
||||||
|
export _H3="Authorization: Bearer $CURANET_ACCESS_TOKEN"
|
||||||
|
data="{\"name\": \"$fulldomain\",\"type\": \"TXT\",\"ttl\": 60,\"priority\": 0,\"data\": \"$txtvalue\"}"
|
||||||
|
response="$(_post "$data" "$CURANET_REST_URL/${_domain}/Records" "" "")"
|
||||||
|
|
||||||
|
if _contains "$response" "$txtvalue"; then
|
||||||
|
_debug "TXT record added OK"
|
||||||
|
else
|
||||||
|
_err "Unable to add TXT record"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#Usage: fulldomain txtvalue
|
||||||
|
#Remove the txt record after validation.
|
||||||
|
dns_curanet_rm() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
_info "Using curanet"
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
|
CURANET_AUTHCLIENTID="${CURANET_AUTHCLIENTID:-$(_readaccountconf_mutable CURANET_AUTHCLIENTID)}"
|
||||||
|
CURANET_AUTHSECRET="${CURANET_AUTHSECRET:-$(_readaccountconf_mutable CURANET_AUTHSECRET)}"
|
||||||
|
|
||||||
|
if ! _get_token; then
|
||||||
|
_err "Unable to get token"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _get_root "$fulldomain"; then
|
||||||
|
_err "Invalid domain"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug "Getting current record list to identify TXT to delete"
|
||||||
|
|
||||||
|
export _H1="Content-Type: application/json"
|
||||||
|
export _H2="Accept: application/json"
|
||||||
|
export _H3="Authorization: Bearer $CURANET_ACCESS_TOKEN"
|
||||||
|
|
||||||
|
response="$(_get "$CURANET_REST_URL/${_domain}/Records" "" "")"
|
||||||
|
|
||||||
|
if ! _contains "$response" "$txtvalue"; then
|
||||||
|
_err "Unable to delete record (does not contain $txtvalue )"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
recordid=$(echo "$response" | _egrep_o "{\"id\":[0-9]+,\"name\":\"$fulldomain\",\"type\":\"TXT\",\"ttl\":60,\"priority\":0,\"data\":\"..$txtvalue" | _egrep_o "id\":[0-9]+" | cut -c 5-)
|
||||||
|
|
||||||
|
if [ -z "$recordid" ]; then
|
||||||
|
_err "Unable to get recordid"
|
||||||
|
_debug "regex {\"id\":[0-9]+,\"name\":\"$fulldomain\",\"type\":\"TXT\",\"ttl\":60,\"priority\":0,\"data\":\"..$txtvalue"
|
||||||
|
_debug "response $response"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug "Deleting recordID $recordid"
|
||||||
|
response="$(_post "" "$CURANET_REST_URL/${_domain}/Records/$recordid" "" "DELETE")"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#################### Private functions below ##################################
|
||||||
|
|
||||||
|
_get_token() {
|
||||||
|
response="$(_post "grant_type=client_credentials&client_id=$CURANET_AUTHCLIENTID&client_secret=$CURANET_AUTHSECRET&scope=dns" "$CURANET_AUTH_URL" "" "")"
|
||||||
|
if ! _contains "$response" "access_token"; then
|
||||||
|
_err "Unable get access token"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
CURANET_ACCESS_TOKEN=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]+" | cut -c 17-)
|
||||||
|
|
||||||
|
if [ -z "$CURANET_ACCESS_TOKEN" ]; then
|
||||||
|
_err "Unable to get token"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#_acme-challenge.www.domain.com
|
||||||
|
#returns
|
||||||
|
# _domain=domain.com
|
||||||
|
# _domain_id=sdjkglgdfewsdfg
|
||||||
|
_get_root() {
|
||||||
|
domain=$1
|
||||||
|
i=1
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||||
|
_debug h "$h"
|
||||||
|
if [ -z "$h" ]; then
|
||||||
|
#not valid
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
export _H1="Content-Type: application/json"
|
||||||
|
export _H2="Accept: application/json"
|
||||||
|
export _H3="Authorization: Bearer $CURANET_ACCESS_TOKEN"
|
||||||
|
response="$(_get "$CURANET_REST_URL/$h/Records" "" "")"
|
||||||
|
|
||||||
|
if [ ! "$(echo "$response" | _egrep_o "Entity not found")" ]; then
|
||||||
|
_domain=$h
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
i=$(_math "$i" + 1)
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
185
dnsapi/dns_cx.sh
185
dnsapi/dns_cx.sh
@ -1,185 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
# CloudXNS Domain api
|
|
||||||
#
|
|
||||||
#CX_Key="1234"
|
|
||||||
#
|
|
||||||
#CX_Secret="sADDsdasdgdsf"
|
|
||||||
|
|
||||||
CX_Api="https://www.cloudxns.net/api2"
|
|
||||||
|
|
||||||
#REST_API
|
|
||||||
######## Public functions #####################
|
|
||||||
|
|
||||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
|
||||||
dns_cx_add() {
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
|
|
||||||
CX_Key="${CX_Key:-$(_readaccountconf_mutable CX_Key)}"
|
|
||||||
CX_Secret="${CX_Secret:-$(_readaccountconf_mutable CX_Secret)}"
|
|
||||||
if [ -z "$CX_Key" ] || [ -z "$CX_Secret" ]; then
|
|
||||||
CX_Key=""
|
|
||||||
CX_Secret=""
|
|
||||||
_err "You don't specify cloudxns.net api key or secret yet."
|
|
||||||
_err "Please create you key and try again."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
REST_API="$CX_Api"
|
|
||||||
|
|
||||||
#save the api key and email to the account conf file.
|
|
||||||
_saveaccountconf_mutable CX_Key "$CX_Key"
|
|
||||||
_saveaccountconf_mutable CX_Secret "$CX_Secret"
|
|
||||||
|
|
||||||
_debug "First detect the root zone"
|
|
||||||
if ! _get_root "$fulldomain"; then
|
|
||||||
_err "invalid domain"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
add_record "$_domain" "$_sub_domain" "$txtvalue"
|
|
||||||
}
|
|
||||||
|
|
||||||
#fulldomain txtvalue
|
|
||||||
dns_cx_rm() {
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
CX_Key="${CX_Key:-$(_readaccountconf_mutable CX_Key)}"
|
|
||||||
CX_Secret="${CX_Secret:-$(_readaccountconf_mutable CX_Secret)}"
|
|
||||||
REST_API="$CX_Api"
|
|
||||||
if _get_root "$fulldomain"; then
|
|
||||||
record_id=""
|
|
||||||
existing_records "$_domain" "$_sub_domain" "$txtvalue"
|
|
||||||
if [ "$record_id" ]; then
|
|
||||||
_rest DELETE "record/$record_id/$_domain_id" "{}"
|
|
||||||
_info "Deleted record ${fulldomain}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
#usage: root sub
|
|
||||||
#return if the sub record already exists.
|
|
||||||
#echos the existing records count.
|
|
||||||
# '0' means doesn't exist
|
|
||||||
existing_records() {
|
|
||||||
_debug "Getting txt records"
|
|
||||||
root=$1
|
|
||||||
sub=$2
|
|
||||||
if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100"; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
seg=$(printf "%s\n" "$response" | _egrep_o '"record_id":[^{]*host":"'"$_sub_domain"'"[^}]*\}')
|
|
||||||
_debug seg "$seg"
|
|
||||||
if [ -z "$seg" ]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then
|
|
||||||
record_id=$(printf "%s\n" "$seg" | _egrep_o '"record_id":"[^"]*"' | cut -d : -f 2 | tr -d \" | _head_n 1)
|
|
||||||
_debug record_id "$record_id"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#add the txt record.
|
|
||||||
#usage: root sub txtvalue
|
|
||||||
add_record() {
|
|
||||||
root=$1
|
|
||||||
sub=$2
|
|
||||||
txtvalue=$3
|
|
||||||
fulldomain="$sub.$root"
|
|
||||||
|
|
||||||
_info "Adding record"
|
|
||||||
|
|
||||||
if ! _rest POST "record" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}"; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
|
||||||
#_acme-challenge.www.domain.com
|
|
||||||
#returns
|
|
||||||
# _sub_domain=_acme-challenge.www
|
|
||||||
# _domain=domain.com
|
|
||||||
# _domain_id=sdjkglgdfewsdfg
|
|
||||||
_get_root() {
|
|
||||||
domain=$1
|
|
||||||
i=2
|
|
||||||
p=1
|
|
||||||
|
|
||||||
if ! _rest GET "domain"; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
|
||||||
_debug h "$h"
|
|
||||||
if [ -z "$h" ]; then
|
|
||||||
#not valid
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if _contains "$response" "$h."; then
|
|
||||||
seg=$(printf "%s\n" "$response" | _egrep_o '"id":[^{]*"'"$h"'."[^}]*}')
|
|
||||||
_debug seg "$seg"
|
|
||||||
_domain_id=$(printf "%s\n" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")
|
|
||||||
_debug _domain_id "$_domain_id"
|
|
||||||
if [ "$_domain_id" ]; then
|
|
||||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
|
||||||
_debug _sub_domain "$_sub_domain"
|
|
||||||
_domain="$h"
|
|
||||||
_debug _domain "$_domain"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
p="$i"
|
|
||||||
i=$(_math "$i" + 1)
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#Usage: method URI data
|
|
||||||
_rest() {
|
|
||||||
m=$1
|
|
||||||
ep="$2"
|
|
||||||
_debug ep "$ep"
|
|
||||||
url="$REST_API/$ep"
|
|
||||||
_debug url "$url"
|
|
||||||
|
|
||||||
cdate=$(date -u "+%Y-%m-%d %H:%M:%S UTC")
|
|
||||||
_debug cdate "$cdate"
|
|
||||||
|
|
||||||
data="$3"
|
|
||||||
_debug data "$data"
|
|
||||||
|
|
||||||
sec="$CX_Key$url$data$cdate$CX_Secret"
|
|
||||||
_debug sec "$sec"
|
|
||||||
hmac=$(printf "%s" "$sec" | _digest md5 hex)
|
|
||||||
_debug hmac "$hmac"
|
|
||||||
|
|
||||||
export _H1="API-KEY: $CX_Key"
|
|
||||||
export _H2="API-REQUEST-DATE: $cdate"
|
|
||||||
export _H3="API-HMAC: $hmac"
|
|
||||||
export _H4="Content-Type: application/json"
|
|
||||||
|
|
||||||
if [ "$data" ]; then
|
|
||||||
response="$(_post "$data" "$url" "" "$m")"
|
|
||||||
else
|
|
||||||
response="$(_get "$url")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$?" != "0" ]; then
|
|
||||||
_err "error $ep"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_debug2 response "$response"
|
|
||||||
|
|
||||||
_contains "$response" '"code":1'
|
|
||||||
|
|
||||||
}
|
|
@ -1,21 +1,15 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
########
|
dns_cyon_info='cyon.ch
|
||||||
# Custom cyon.ch DNS API for use with [acme.sh](https://github.com/acmesh-official/acme.sh)
|
Site: cyon.ch
|
||||||
#
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cyon
|
||||||
# Usage: acme.sh --issue --dns dns_cyon -d www.domain.com
|
Options:
|
||||||
#
|
CY_Username Username
|
||||||
# Dependencies:
|
CY_Password API Token
|
||||||
# -------------
|
CY_OTP_Secret OTP token. Only required if using 2FA
|
||||||
# - oathtool (When using 2 Factor Authentication)
|
Issues: github.com/noplanman/cyon-api/issues
|
||||||
#
|
Author: Armando Lüscher <armando@noplanman.ch>
|
||||||
# Issues:
|
'
|
||||||
# -------
|
|
||||||
# Any issues / questions / suggestions can be posted here:
|
|
||||||
# https://github.com/noplanman/cyon-api/issues
|
|
||||||
#
|
|
||||||
# Author: Armando Lüscher <armando@noplanman.ch>
|
|
||||||
########
|
|
||||||
|
|
||||||
dns_cyon_add() {
|
dns_cyon_add() {
|
||||||
_cyon_load_credentials &&
|
_cyon_load_credentials &&
|
||||||
@ -44,7 +38,7 @@ dns_cyon_rm() {
|
|||||||
_cyon_load_credentials() {
|
_cyon_load_credentials() {
|
||||||
# Convert loaded password to/from base64 as needed.
|
# Convert loaded password to/from base64 as needed.
|
||||||
if [ "${CY_Password_B64}" ]; then
|
if [ "${CY_Password_B64}" ]; then
|
||||||
CY_Password="$(printf "%s" "${CY_Password_B64}" | _dbase64 "multiline")"
|
CY_Password="$(printf "%s" "${CY_Password_B64}" | _dbase64)"
|
||||||
elif [ "${CY_Password}" ]; then
|
elif [ "${CY_Password}" ]; then
|
||||||
CY_Password_B64="$(printf "%s" "${CY_Password}" | _base64)"
|
CY_Password_B64="$(printf "%s" "${CY_Password}" | _base64)"
|
||||||
fi
|
fi
|
||||||
|
@ -1,31 +1,14 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*-
|
# shellcheck disable=SC2034
|
||||||
# vim: et ts=2 sw=2
|
dns_da_info='DirectAdmin Server API
|
||||||
#
|
Site: DirectAdmin.com/api.php
|
||||||
# DirectAdmin 1.41.0 API
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_da
|
||||||
# The DirectAdmin interface has it's own Let's encrypt functionality, but this
|
Options:
|
||||||
# script can be used to generate certificates for names which are not hosted on
|
DA_Api API Server URL. E.g. "https://remoteUser:remotePassword@da.domain.tld:8443"
|
||||||
# DirectAdmin
|
DA_Api_Insecure Insecure TLS. 0: check for cert validity, 1: always accept
|
||||||
#
|
Issues: github.com/TigerP/acme.sh/issues
|
||||||
# User must provide login data and URL to DirectAdmin incl. port.
|
'
|
||||||
# You can create login key, by using the Login Keys function
|
|
||||||
# ( https://da.example.com:8443/CMD_LOGIN_KEYS ), which only has access to
|
|
||||||
# - CMD_API_DNS_CONTROL
|
|
||||||
# - CMD_API_SHOW_DOMAINS
|
|
||||||
#
|
|
||||||
# See also https://www.directadmin.com/api.php and
|
|
||||||
# https://www.directadmin.com/features.php?id=1298
|
|
||||||
#
|
|
||||||
# Report bugs to https://github.com/TigerP/acme.sh/issues
|
|
||||||
#
|
|
||||||
# Values to export:
|
|
||||||
# export DA_Api="https://remoteUser:remotePassword@da.example.com:8443"
|
|
||||||
# export DA_Api_Insecure=1
|
|
||||||
#
|
|
||||||
# Set DA_Api_Insecure to 1 for insecure and 0 for secure -> difference is
|
|
||||||
# whether ssl cert is checked for validity (0) or whether it is just accepted
|
|
||||||
# (1)
|
|
||||||
#
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
# Usage: dns_myapi_add _acme-challenge.www.example.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
# Usage: dns_myapi_add _acme-challenge.www.example.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_ddnss_info='DDNSS.de
|
||||||
|
Site: DDNSS.de
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_ddnss
|
||||||
|
Options:
|
||||||
|
DDNSS_Token API Token
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/2230
|
||||||
|
Author: RaidenII, helbgd, mod242
|
||||||
|
'
|
||||||
|
|
||||||
#Created by RaidenII, to use DuckDNS's API to add/remove text records
|
DDNSS_DNS_API="https://ddnss.de/upd.php"
|
||||||
#modified by helbgd @ 03/13/2018 to support ddnss.de
|
|
||||||
#modified by mod242 @ 04/24/2018 to support different ddnss domains
|
|
||||||
#Please note: the Wildcard Feature must be turned on for the Host record
|
|
||||||
#and the checkbox for TXT needs to be enabled
|
|
||||||
|
|
||||||
# Pass credentials before "acme.sh --issue --dns dns_ddnss ..."
|
|
||||||
# --
|
|
||||||
# export DDNSS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
|
||||||
# --
|
|
||||||
#
|
|
||||||
|
|
||||||
DDNSS_DNS_API="https://ip4.ddnss.de/upd.php"
|
|
||||||
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
@ -77,7 +74,7 @@ dns_ddnss_rm() {
|
|||||||
|
|
||||||
# Now remove the TXT record from DDNS DNS
|
# Now remove the TXT record from DDNS DNS
|
||||||
_info "Trying to remove TXT record"
|
_info "Trying to remove TXT record"
|
||||||
if _ddnss_rest GET "key=$DDNSS_Token&host=$_ddnss_domain&txtm=1&txt=."; then
|
if _ddnss_rest GET "key=$DDNSS_Token&host=$_ddnss_domain&txtm=2"; then
|
||||||
if [ "$response" = "Updated 1 hostname." ]; then
|
if [ "$response" = "Updated 1 hostname." ]; then
|
||||||
_info "TXT record has been successfully removed from your DDNSS domain."
|
_info "TXT record has been successfully removed from your DDNSS domain."
|
||||||
return 0
|
return 0
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
#
|
# shellcheck disable=SC2034
|
||||||
# deSEC.io Domain API
|
dns_desec_info='deSEC.io
|
||||||
#
|
Site: desec.readthedocs.io/en/latest/
|
||||||
# Author: Zheng Qian
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_desec
|
||||||
#
|
Options:
|
||||||
# deSEC API doc
|
DDNSS_Token API Token
|
||||||
# https://desec.readthedocs.io/en/latest/
|
Issues: github.com/acmesh-official/acme.sh/issues/2180
|
||||||
|
Author: Zheng Qian
|
||||||
|
'
|
||||||
|
|
||||||
REST_API="https://desec.io/api/v1/domains"
|
REST_API="https://desec.io/api/v1/domains"
|
||||||
|
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
########################################################################
|
dns_df_info='DynDnsFree.de
|
||||||
# https://dyndnsfree.de hook script for acme.sh
|
Domains: dynup.de
|
||||||
#
|
Site: DynDnsFree.de
|
||||||
# Environment variables:
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_df
|
||||||
#
|
Options:
|
||||||
# - $DF_user (your dyndnsfree.de username)
|
DF_user Username
|
||||||
# - $DF_password (your dyndnsfree.de password)
|
DF_password Password
|
||||||
#
|
Issues: github.com/acmesh-official/acme.sh/issues/2897
|
||||||
# Author: Thilo Gass <thilo.gass@gmail.com>
|
Author: Thilo Gass <thilo.gass@gmail.com>
|
||||||
# Git repo: https://github.com/ThiloGa/acme.sh
|
'
|
||||||
|
|
||||||
#-- dns_df_add() - Add TXT record --------------------------------------
|
|
||||||
# Usage: dns_df_add _acme-challenge.subdomain.domain.com "XyZ123..."
|
|
||||||
|
|
||||||
dyndnsfree_api="https://dynup.de/acme.php"
|
dyndnsfree_api="https://dynup.de/acme.php"
|
||||||
|
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
## Will be called by acme.sh to add the txt record to your api system.
|
dns_dgon_info='DigitalOcean.com
|
||||||
## returns 0 means success, otherwise error.
|
Site: DigitalOcean.com/help/api/
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dgon
|
||||||
## Author: thewer <github at thewer.com>
|
Options:
|
||||||
## GitHub: https://github.com/gitwer/acme.sh
|
DO_API_KEY API Key
|
||||||
|
Author: <github@thewer.com>
|
||||||
##
|
'
|
||||||
## Environment Variables Required:
|
|
||||||
##
|
|
||||||
## DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc"
|
|
||||||
##
|
|
||||||
|
|
||||||
##################### Public functions #####################
|
##################### Public functions #####################
|
||||||
|
|
||||||
@ -192,6 +188,7 @@ _get_base_domain() {
|
|||||||
## get URL for the list of domains
|
## get URL for the list of domains
|
||||||
## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
|
## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
|
||||||
DOMURL="https://api.digitalocean.com/v2/domains"
|
DOMURL="https://api.digitalocean.com/v2/domains"
|
||||||
|
found=""
|
||||||
|
|
||||||
## while we dont have a matching domain we keep going
|
## while we dont have a matching domain we keep going
|
||||||
while [ -z "$found" ]; do
|
while [ -z "$found" ]; do
|
||||||
@ -205,9 +202,7 @@ _get_base_domain() {
|
|||||||
fi
|
fi
|
||||||
_debug2 domain_list "$domain_list"
|
_debug2 domain_list "$domain_list"
|
||||||
|
|
||||||
## for each shortening of our $fulldomain, check if it exists in the $domain_list
|
i=1
|
||||||
## can never start on 1 (aka whole $fulldomain) as $fulldomain starts with "_acme-challenge"
|
|
||||||
i=2
|
|
||||||
while [ $i -gt 0 ]; do
|
while [ $i -gt 0 ]; do
|
||||||
## get next longest domain
|
## get next longest domain
|
||||||
_domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
|
_domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
|
||||||
|
188
dnsapi/dns_dnsexit.sh
Normal file
188
dnsapi/dns_dnsexit.sh
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_dnsexit_info='DNSExit.com
|
||||||
|
Site: DNSExit.com
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dnsexit
|
||||||
|
Options:
|
||||||
|
DNSEXIT_API_KEY API Key
|
||||||
|
DNSEXIT_AUTH_USER Username
|
||||||
|
DNSEXIT_AUTH_PASS Password
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/4719
|
||||||
|
Author: Samuel Jimenez
|
||||||
|
'
|
||||||
|
|
||||||
|
DNSEXIT_API_URL="https://api.dnsexit.com/dns/"
|
||||||
|
DNSEXIT_HOSTS_URL="https://update.dnsexit.com/ipupdate/hosts.jsp"
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
#Usage: dns_dnsexit_add _acme-challenge.*.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
dns_dnsexit_add() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
_info "Using DNSExit.com"
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
|
_debug 'Load account auth'
|
||||||
|
if ! get_account_info; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug 'First detect the root zone'
|
||||||
|
if ! _get_root "$fulldomain"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
|
if ! _dnsexit_rest "{\"domain\":\"$_domain\",\"add\":{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":0,\"overwrite\":false}}"; then
|
||||||
|
_err "$response"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug2 _response "$response"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#Usage: fulldomain txtvalue
|
||||||
|
#Remove the txt record after validation.
|
||||||
|
dns_dnsexit_rm() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
_info "Using DNSExit.com"
|
||||||
|
_debug fulldomain "$fulldomain"
|
||||||
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
|
_debug 'Load account auth'
|
||||||
|
if ! get_account_info; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug 'First detect the root zone'
|
||||||
|
if ! _get_root "$fulldomain"; then
|
||||||
|
_err "$response"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
|
if ! _dnsexit_rest "{\"domain\":\"$_domain\",\"delete\":{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\"}}"; then
|
||||||
|
_err "$response"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug2 _response "$response"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#################### Private functions below ##################################
|
||||||
|
#_acme-challenge.www.domain.com
|
||||||
|
#returns
|
||||||
|
# _sub_domain=_acme-challenge.www
|
||||||
|
# _domain=domain.com
|
||||||
|
_get_root() {
|
||||||
|
domain=$1
|
||||||
|
i=1
|
||||||
|
while true; do
|
||||||
|
_domain=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||||
|
_debug h "$_domain"
|
||||||
|
if [ -z "$_domain" ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug login "$DNSEXIT_AUTH_USER"
|
||||||
|
_debug password "$DNSEXIT_AUTH_PASS"
|
||||||
|
_debug domain "$_domain"
|
||||||
|
|
||||||
|
_dnsexit_http "login=$DNSEXIT_AUTH_USER&password=$DNSEXIT_AUTH_PASS&domain=$_domain"
|
||||||
|
|
||||||
|
if _contains "$response" "0=$_domain"; then
|
||||||
|
_sub_domain="$(echo "$fulldomain" | sed "s/\\.$_domain\$//")"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
_debug "Go to next level of $_domain"
|
||||||
|
fi
|
||||||
|
i=$(_math "$i" + 1)
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_dnsexit_rest() {
|
||||||
|
m=POST
|
||||||
|
ep=""
|
||||||
|
data="$1"
|
||||||
|
_debug _dnsexit_rest "$ep"
|
||||||
|
_debug data "$data"
|
||||||
|
|
||||||
|
api_key_trimmed=$(echo "$DNSEXIT_API_KEY" | tr -d '"')
|
||||||
|
|
||||||
|
export _H1="apikey: $api_key_trimmed"
|
||||||
|
export _H2='Content-Type: application/json'
|
||||||
|
|
||||||
|
if [ "$m" != "GET" ]; then
|
||||||
|
_debug data "$data"
|
||||||
|
response="$(_post "$data" "$DNSEXIT_API_URL/$ep" "" "$m")"
|
||||||
|
else
|
||||||
|
response="$(_get "$DNSEXIT_API_URL/$ep")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "Error $ep"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug2 response "$response"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_dnsexit_http() {
|
||||||
|
m=GET
|
||||||
|
param="$1"
|
||||||
|
_debug param "$param"
|
||||||
|
_debug get "$DNSEXIT_HOSTS_URL?$param"
|
||||||
|
|
||||||
|
response="$(_get "$DNSEXIT_HOSTS_URL?$param")"
|
||||||
|
|
||||||
|
_debug response "$response"
|
||||||
|
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "Error $param"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug2 response "$response"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
get_account_info() {
|
||||||
|
|
||||||
|
DNSEXIT_API_KEY="${DNSEXIT_API_KEY:-$(_readaccountconf_mutable DNSEXIT_API_KEY)}"
|
||||||
|
if test -z "$DNSEXIT_API_KEY"; then
|
||||||
|
DNSEXIT_API_KEY=''
|
||||||
|
_err 'DNSEXIT_API_KEY was not exported'
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_saveaccountconf_mutable DNSEXIT_API_KEY "$DNSEXIT_API_KEY"
|
||||||
|
|
||||||
|
DNSEXIT_AUTH_USER="${DNSEXIT_AUTH_USER:-$(_readaccountconf_mutable DNSEXIT_AUTH_USER)}"
|
||||||
|
if test -z "$DNSEXIT_AUTH_USER"; then
|
||||||
|
DNSEXIT_AUTH_USER=""
|
||||||
|
_err 'DNSEXIT_AUTH_USER was not exported'
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_saveaccountconf_mutable DNSEXIT_AUTH_USER "$DNSEXIT_AUTH_USER"
|
||||||
|
|
||||||
|
DNSEXIT_AUTH_PASS="${DNSEXIT_AUTH_PASS:-$(_readaccountconf_mutable DNSEXIT_AUTH_PASS)}"
|
||||||
|
if test -z "$DNSEXIT_AUTH_PASS"; then
|
||||||
|
DNSEXIT_AUTH_PASS=""
|
||||||
|
_err 'DNSEXIT_AUTH_PASS was not exported'
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_saveaccountconf_mutable DNSEXIT_AUTH_PASS "$DNSEXIT_AUTH_PASS"
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
@ -1,15 +1,14 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
# dnsHome.de API for acme.sh
|
dns_dnshome_info='dnsHome.de
|
||||||
#
|
Site: dnsHome.de
|
||||||
# This Script adds the necessary TXT record to a Subdomain
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dnshome
|
||||||
#
|
Options:
|
||||||
# Author dnsHome.de (https://github.com/dnsHome-de)
|
DNSHOME_Subdomain Subdomain
|
||||||
#
|
DNSHOME_SubdomainPassword Subdomain Password
|
||||||
# Report Bugs to https://github.com/acmesh-official/acme.sh/issues/3819
|
Issues: github.com/acmesh-official/acme.sh/issues/3819
|
||||||
#
|
Author: dnsHome.de https://github.com/dnsHome-de
|
||||||
# export DNSHOME_Subdomain=""
|
'
|
||||||
# export DNSHOME_SubdomainPassword=""
|
|
||||||
|
|
||||||
# Usage: add subdomain.ddnsdomain.tld "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
# Usage: add subdomain.ddnsdomain.tld "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
# Used to add txt record
|
# Used to add txt record
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
# DNSimple domain api
|
dns_dnsimple_info='DNSimple.com
|
||||||
# https://github.com/pho3nixf1re/acme.sh/issues
|
Site: DNSimple.com
|
||||||
#
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dnsimple
|
||||||
# This is your oauth token which can be acquired on the account page. Please
|
Options:
|
||||||
# note that this must be an _account_ token and not a _user_ token.
|
DNSimple_OAUTH_TOKEN OAuth Token
|
||||||
# https://dnsimple.com/a/<your account id>/account/access_tokens
|
Issues: github.com/pho3nixf1re/acme.sh/issues
|
||||||
# DNSimple_OAUTH_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
'
|
||||||
|
|
||||||
DNSimple_API="https://api.dnsimple.com/v2"
|
DNSimple_API="https://api.dnsimple.com/v2"
|
||||||
|
|
||||||
|
251
dnsapi/dns_dnsservices.sh
Executable file
251
dnsapi/dns_dnsservices.sh
Executable file
@ -0,0 +1,251 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_dnsservices_info='DNS.Services
|
||||||
|
Site: DNS.Services
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dnsservices
|
||||||
|
Options:
|
||||||
|
DnsServices_Username Username
|
||||||
|
DnsServices_Password Password
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/4152
|
||||||
|
Author: Bjarke Bruun <bbruun@gmail.com>
|
||||||
|
'
|
||||||
|
|
||||||
|
DNSServices_API=https://dns.services/api
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
|
||||||
|
#Usage: dns_dnsservices_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
dns_dnsservices_add() {
|
||||||
|
fulldomain="$1"
|
||||||
|
txtvalue="$2"
|
||||||
|
|
||||||
|
_info "Using dns.services to create ACME DNS challenge"
|
||||||
|
_debug2 add_fulldomain "$fulldomain"
|
||||||
|
_debug2 add_txtvalue "$txtvalue"
|
||||||
|
|
||||||
|
# Read username/password from environment or .acme.sh/accounts.conf
|
||||||
|
DnsServices_Username="${DnsServices_Username:-$(_readaccountconf_mutable DnsServices_Username)}"
|
||||||
|
DnsServices_Password="${DnsServices_Password:-$(_readaccountconf_mutable DnsServices_Password)}"
|
||||||
|
if [ -z "$DnsServices_Username" ] || [ -z "$DnsServices_Password" ]; then
|
||||||
|
DnsServices_Username=""
|
||||||
|
DnsServices_Password=""
|
||||||
|
_err "You didn't specify dns.services api username and password yet."
|
||||||
|
_err "Set environment variables DnsServices_Username and DnsServices_Password"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Setup GET/POST/DELETE headers
|
||||||
|
_setup_headers
|
||||||
|
|
||||||
|
#save the credentials to the account conf file.
|
||||||
|
_saveaccountconf_mutable DnsServices_Username "$DnsServices_Username"
|
||||||
|
_saveaccountconf_mutable DnsServices_Password "$DnsServices_Password"
|
||||||
|
|
||||||
|
if ! _contains "$DnsServices_Username" "@"; then
|
||||||
|
_err "It seems that the username variable DnsServices_Username has not been set/left blank"
|
||||||
|
_err "or is not a valid email. Please correct and try again."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _get_root "${fulldomain}"; then
|
||||||
|
_err "Invalid domain ${fulldomain}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! createRecord "$fulldomain" "${txtvalue}"; then
|
||||||
|
_err "Error creating TXT record in domain $fulldomain in $rootZoneName"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug2 challenge-created "Created $fulldomain"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#Usage: fulldomain txtvalue
|
||||||
|
#Description: Remove the txt record after validation.
|
||||||
|
dns_dnsservices_rm() {
|
||||||
|
fulldomain="$1"
|
||||||
|
txtvalue="$2"
|
||||||
|
|
||||||
|
_info "Using dns.services to remove DNS record $fulldomain TXT $txtvalue"
|
||||||
|
_debug rm_fulldomain "$fulldomain"
|
||||||
|
_debug rm_txtvalue "$txtvalue"
|
||||||
|
|
||||||
|
# Read username/password from environment or .acme.sh/accounts.conf
|
||||||
|
DnsServices_Username="${DnsServices_Username:-$(_readaccountconf_mutable DnsServices_Username)}"
|
||||||
|
DnsServices_Password="${DnsServices_Password:-$(_readaccountconf_mutable DnsServices_Password)}"
|
||||||
|
if [ -z "$DnsServices_Username" ] || [ -z "$DnsServices_Password" ]; then
|
||||||
|
DnsServices_Username=""
|
||||||
|
DnsServices_Password=""
|
||||||
|
_err "You didn't specify dns.services api username and password yet."
|
||||||
|
_err "Set environment variables DnsServices_Username and DnsServices_Password"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Setup GET/POST/DELETE headers
|
||||||
|
_setup_headers
|
||||||
|
|
||||||
|
if ! _get_root "${fulldomain}"; then
|
||||||
|
_err "Invalid domain ${fulldomain}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug2 rm_rootDomainInfo "found root domain $rootZoneName for $fulldomain"
|
||||||
|
|
||||||
|
if ! deleteRecord "${fulldomain}" "${txtvalue}"; then
|
||||||
|
_err "Error removing record: $fulldomain TXT ${txtvalue}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#################### Private functions below ##################################
|
||||||
|
|
||||||
|
_setup_headers() {
|
||||||
|
# Set up API Headers for _get() and _post()
|
||||||
|
# The <function>_add or <function>_rm must have been called before to work
|
||||||
|
|
||||||
|
if [ -z "$DnsServices_Username" ] || [ -z "$DnsServices_Password" ]; then
|
||||||
|
_err "Could not setup BASIC authentication headers, they are missing"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
DnsServiceCredentials="$(printf "%s" "$DnsServices_Username:$DnsServices_Password" | _base64)"
|
||||||
|
export _H1="Authorization: Basic $DnsServiceCredentials"
|
||||||
|
export _H2="Content-Type: application/json"
|
||||||
|
|
||||||
|
# Just return if headers are set
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_get_root() {
|
||||||
|
domain="$1"
|
||||||
|
_debug2 _get_root "Get the root domain of ${domain} for DNS API"
|
||||||
|
|
||||||
|
# Setup _get() and _post() headers
|
||||||
|
#_setup_headers
|
||||||
|
|
||||||
|
result=$(_H1="$_H1" _H2="$_H2" _get "$DNSServices_API/dns")
|
||||||
|
result2="$(printf "%s\n" "$result" | tr '[' '\n' | grep '"name"')"
|
||||||
|
result3="$(printf "%s\n" "$result2" | tr '}' '\n' | grep '"name"' | sed "s,^\,,,g" | sed "s,$,},g")"
|
||||||
|
useResult=""
|
||||||
|
_debug2 _get_root "Got the following root domain(s) $result"
|
||||||
|
_debug2 _get_root "- JSON: $result"
|
||||||
|
|
||||||
|
if [ "$(printf "%s\n" "$result" | tr '}' '\n' | grep -c '"name"')" -gt "1" ]; then
|
||||||
|
checkMultiZones="true"
|
||||||
|
_debug2 _get_root "- multiple zones found"
|
||||||
|
else
|
||||||
|
checkMultiZones="false"
|
||||||
|
_debug2 _get_root "- single zone found"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Find/isolate the root zone to work with in createRecord() and deleteRecord()
|
||||||
|
rootZone=""
|
||||||
|
if [ "$checkMultiZones" = "true" ]; then
|
||||||
|
#rootZone=$(for x in $(printf "%s" "${result3}" | tr ',' '\n' | sed -n 's/.*"name":"\(.*\)",.*/\1/p'); do if [ "$(echo "$domain" | grep "$x")" != "" ]; then echo "$x"; fi; done)
|
||||||
|
rootZone=$(for x in $(printf "%s\n" "${result3}" | tr ',' '\n' | grep name | cut -d'"' -f4); do if [ "$(echo "$domain" | grep "$x")" != "" ]; then echo "$x"; fi; done)
|
||||||
|
if [ "$rootZone" != "" ]; then
|
||||||
|
_debug2 _rootZone "- root zone for $domain is $rootZone"
|
||||||
|
else
|
||||||
|
_err "Could not find root zone for $domain, is it correctly typed?"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
rootZone=$(echo "$result" | tr '}' '\n' | _egrep_o '"name":"[^"]*' | cut -d'"' -f4)
|
||||||
|
_debug2 _get_root "- only found 1 domain in API: $rootZone"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$rootZone" ]; then
|
||||||
|
_err "Could not find root domain for $domain - is it correctly typed?"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Make sure we use the correct API zone data
|
||||||
|
useResult="$(printf "%s\n" "${result3}" tr ',' '\n' | grep "$rootZone")"
|
||||||
|
_debug2 _useResult "useResult=$useResult"
|
||||||
|
|
||||||
|
# Setup variables used by other functions to communicate with DNS.Services API
|
||||||
|
#zoneInfo=$(printf "%s\n" "$useResult" | sed -E 's,.*(zones)(.*),\1\2,g' | sed -E 's,^(.*"name":")([^"]*)"(.*)$,\2,g')
|
||||||
|
zoneInfo=$(printf "%s\n" "$useResult" | tr ',' '\n' | grep '"name"' | cut -d'"' -f4)
|
||||||
|
rootZoneName="$rootZone"
|
||||||
|
subDomainName="$(printf "%s\n" "$domain" | sed "s,\.$rootZone,,g")"
|
||||||
|
subDomainNameClean="$(printf "%s\n" "$domain" | sed "s,_acme-challenge.,,g")"
|
||||||
|
rootZoneDomainID=$(printf "%s\n" "$useResult" | tr ',' '\n' | grep domain_id | cut -d'"' -f4)
|
||||||
|
rootZoneServiceID=$(printf "%s\n" "$useResult" | tr ',' '\n' | grep service_id | cut -d'"' -f4)
|
||||||
|
|
||||||
|
_debug2 _zoneInfo "Zone info from API : $zoneInfo"
|
||||||
|
_debug2 _get_root "Root zone name : $rootZoneName"
|
||||||
|
_debug2 _get_root "Root zone domain ID : $rootZoneDomainID"
|
||||||
|
_debug2 _get_root "Root zone service ID: $rootZoneServiceID"
|
||||||
|
_debug2 _get_root "Sub domain : $subDomainName"
|
||||||
|
|
||||||
|
_debug _get_root "Found valid root domain $rootZone for $subDomainNameClean"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
createRecord() {
|
||||||
|
fulldomain="$1"
|
||||||
|
txtvalue="$2"
|
||||||
|
|
||||||
|
# Get root domain information - needed for DNS.Services API communication
|
||||||
|
if [ -z "$rootZoneName" ] || [ -z "$rootZoneDomainID" ] || [ -z "$rootZoneServiceID" ]; then
|
||||||
|
_get_root "$fulldomain"
|
||||||
|
fi
|
||||||
|
if [ -z "$rootZoneName" ] || [ -z "$rootZoneDomainID" ] || [ -z "$rootZoneServiceID" ]; then
|
||||||
|
_err "Something happend - could not get the API zone information"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug2 createRecord "CNAME TXT value is: $txtvalue"
|
||||||
|
|
||||||
|
# Prepare data to send to API
|
||||||
|
data="{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"${txtvalue}\", \"ttl\":\"10\"}"
|
||||||
|
|
||||||
|
_debug2 createRecord "data to API: $data"
|
||||||
|
result=$(_post "$data" "$DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID/records" "" "POST")
|
||||||
|
_debug2 createRecord "result from API: $result"
|
||||||
|
|
||||||
|
if [ "$(echo "$result" | _egrep_o "\"success\":true")" = "" ]; then
|
||||||
|
_err "Failed to create TXT record $fulldomain with content $txtvalue in zone $rootZoneName"
|
||||||
|
_err "$result"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info "Record \"$fulldomain TXT $txtvalue\" has been created"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteRecord() {
|
||||||
|
fulldomain="$1"
|
||||||
|
txtvalue="$2"
|
||||||
|
|
||||||
|
_log deleteRecord "Deleting $fulldomain TXT $txtvalue record"
|
||||||
|
|
||||||
|
if [ -z "$rootZoneName" ] || [ -z "$rootZoneDomainID" ] || [ -z "$rootZoneServiceID" ]; then
|
||||||
|
_get_root "$fulldomain"
|
||||||
|
fi
|
||||||
|
|
||||||
|
result="$(_H1="$_H1" _H2="$_H2" _get "$DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID")"
|
||||||
|
#recordInfo="$(echo "$result" | sed -e 's/:{/:{\n/g' -e 's/},/\n},\n/g' | grep "${txtvalue}")"
|
||||||
|
#recordID="$(echo "$recordInfo" | sed -e 's/:{/:{\n/g' -e 's/},/\n},\n/g' | grep "${txtvalue}" | sed -E 's,.*(zones)(.*),\1\2,g' | sed -E 's,^(.*"id":")([^"]*)"(.*)$,\2,g')"
|
||||||
|
recordID="$(printf "%s\n" "$result" | tr '}' '\n' | grep -- "$txtvalue" | tr ',' '\n' | grep '"id"' | cut -d'"' -f4)"
|
||||||
|
_debug2 _recordID "recordID used for deletion of record: $recordID"
|
||||||
|
|
||||||
|
if [ -z "$recordID" ]; then
|
||||||
|
_info "Record $fulldomain TXT $txtvalue not found or already deleted"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
_debug2 deleteRecord "Found recordID=$recordID"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug2 deleteRecord "DELETE request $DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID/records/$recordID"
|
||||||
|
_log "curl DELETE request $DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID/records/$recordID"
|
||||||
|
result="$(_H1="$_H1" _H2="$_H2" _post "" "$DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID/records/$recordID" "" "DELETE")"
|
||||||
|
_debug2 deleteRecord "API Delete result \"$result\""
|
||||||
|
_log "curl API Delete result \"$result\""
|
||||||
|
|
||||||
|
# Return OK regardless
|
||||||
|
return 0
|
||||||
|
}
|
148
dnsapi/dns_do.sh
148
dnsapi/dns_do.sh
@ -1,148 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
# DNS API for Domain-Offensive / Resellerinterface / Domainrobot
|
|
||||||
|
|
||||||
# Report bugs at https://github.com/seidler2547/acme.sh/issues
|
|
||||||
|
|
||||||
# set these environment variables to match your customer ID and password:
|
|
||||||
# DO_PID="KD-1234567"
|
|
||||||
# DO_PW="cdfkjl3n2"
|
|
||||||
|
|
||||||
DO_URL="https://soap.resellerinterface.de/"
|
|
||||||
|
|
||||||
######## Public functions #####################
|
|
||||||
|
|
||||||
#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
|
||||||
dns_do_add() {
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
if _dns_do_authenticate; then
|
|
||||||
_info "Adding TXT record to ${_domain} as ${fulldomain}"
|
|
||||||
_dns_do_soap createRR origin "${_domain}" name "${fulldomain}" type TXT data "${txtvalue}" ttl 300
|
|
||||||
if _contains "${response}" '>success<'; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
_err "Could not create resource record, check logs"
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#fulldomain
|
|
||||||
dns_do_rm() {
|
|
||||||
fulldomain=$1
|
|
||||||
if _dns_do_authenticate; then
|
|
||||||
if _dns_do_list_rrs; then
|
|
||||||
_dns_do_had_error=0
|
|
||||||
for _rrid in ${_rr_list}; do
|
|
||||||
_info "Deleting resource record $_rrid for $_domain"
|
|
||||||
_dns_do_soap deleteRR origin "${_domain}" rrid "${_rrid}"
|
|
||||||
if ! _contains "${response}" '>success<'; then
|
|
||||||
_dns_do_had_error=1
|
|
||||||
_err "Could not delete resource record for ${_domain}, id ${_rrid}"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
return $_dns_do_had_error
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
|
||||||
_dns_do_authenticate() {
|
|
||||||
_info "Authenticating as ${DO_PID}"
|
|
||||||
_dns_do_soap authPartner partner "${DO_PID}" password "${DO_PW}"
|
|
||||||
if _contains "${response}" '>success<'; then
|
|
||||||
_get_root "$fulldomain"
|
|
||||||
_debug "_domain $_domain"
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
_err "Authentication failed, are DO_PID and DO_PW set correctly?"
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
_dns_do_list_rrs() {
|
|
||||||
_dns_do_soap getRRList origin "${_domain}"
|
|
||||||
if ! _contains "${response}" 'SOAP-ENC:Array'; then
|
|
||||||
_err "getRRList origin ${_domain} failed"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_rr_list="$(echo "${response}" |
|
|
||||||
tr -d "\n\r\t" |
|
|
||||||
sed -e 's/<item xsi:type="ns2:Map">/\n/g' |
|
|
||||||
grep ">$(_regexcape "$fulldomain")</value>" |
|
|
||||||
sed -e 's/<\/item>/\n/g' |
|
|
||||||
grep '>id</key><value' |
|
|
||||||
_egrep_o '>[0-9]{1,16}<' |
|
|
||||||
tr -d '><')"
|
|
||||||
[ "${_rr_list}" ]
|
|
||||||
}
|
|
||||||
|
|
||||||
_dns_do_soap() {
|
|
||||||
func="$1"
|
|
||||||
shift
|
|
||||||
# put the parameters to xml
|
|
||||||
body="<tns:${func} xmlns:tns=\"${DO_URL}\">"
|
|
||||||
while [ "$1" ]; do
|
|
||||||
_k="$1"
|
|
||||||
shift
|
|
||||||
_v="$1"
|
|
||||||
shift
|
|
||||||
body="$body<$_k>$_v</$_k>"
|
|
||||||
done
|
|
||||||
body="$body</tns:${func}>"
|
|
||||||
_debug2 "SOAP request ${body}"
|
|
||||||
|
|
||||||
# build SOAP XML
|
|
||||||
_xml='<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
|
|
||||||
<env:Body>'"$body"'</env:Body>
|
|
||||||
</env:Envelope>'
|
|
||||||
|
|
||||||
# set SOAP headers
|
|
||||||
export _H1="SOAPAction: ${DO_URL}#${func}"
|
|
||||||
|
|
||||||
if ! response="$(_post "${_xml}" "${DO_URL}")"; then
|
|
||||||
_err "Error <$1>"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_debug2 "SOAP response $response"
|
|
||||||
|
|
||||||
# retrieve cookie header
|
|
||||||
_H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)"
|
|
||||||
export _H2
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_root() {
|
|
||||||
domain=$1
|
|
||||||
i=1
|
|
||||||
|
|
||||||
_dns_do_soap getDomainList
|
|
||||||
_all_domains="$(echo "${response}" |
|
|
||||||
tr -d "\n\r\t " |
|
|
||||||
_egrep_o 'domain</key><value[^>]+>[^<]+' |
|
|
||||||
sed -e 's/^domain<\/key><value[^>]*>//g')"
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
|
||||||
if [ -z "$h" ]; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if _contains "${_all_domains}" "^$(_regexcape "$h")\$"; then
|
|
||||||
_domain="$h"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
i=$(_math $i + 1)
|
|
||||||
done
|
|
||||||
_debug "$domain not found"
|
|
||||||
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
_regexcape() {
|
|
||||||
echo "$1" | sed -e 's/\([]\.$*^[]\)/\\\1/g'
|
|
||||||
}
|
|
@ -1,12 +1,15 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
# Official Let's Encrypt API for do.de / Domain-Offensive
|
dns_doapi_info='Domain-Offensive do.de
|
||||||
#
|
Official LetsEncrypt API for do.de / Domain-Offensive.
|
||||||
# This is different from the dns_do adapter, because dns_do is only usable for enterprise customers
|
This is different from the dns_do adapter, because dns_do is only usable for enterprise customers.
|
||||||
# This API is also available to private customers/individuals
|
This API is also available to private customers/individuals.
|
||||||
#
|
Site: do.de
|
||||||
# Provide the required LetsEncrypt token like this:
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_doapi
|
||||||
# DO_LETOKEN="FmD408PdqT1E269gUK57"
|
Options:
|
||||||
|
DO_LETOKEN LetsEncrypt Token
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/2057
|
||||||
|
'
|
||||||
|
|
||||||
DO_API="https://www.do.de/api/letsencrypt"
|
DO_API="https://www.do.de/api/letsencrypt"
|
||||||
|
|
||||||
|
@ -1,4 +1,13 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_domeneshop_info='DomeneShop.no
|
||||||
|
Site: DomeneShop.no
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_domeneshop
|
||||||
|
Options:
|
||||||
|
DOMENESHOP_Token Token
|
||||||
|
DOMENESHOP_Secret Secret
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/2457
|
||||||
|
'
|
||||||
|
|
||||||
DOMENESHOP_Api_Endpoint="https://api.domeneshop.no/v0"
|
DOMENESHOP_Api_Endpoint="https://api.domeneshop.no/v0"
|
||||||
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
# Dnspod.cn Domain api
|
dns_dp_info='DNSPod.cn
|
||||||
#
|
Site: DNSPod.cn
|
||||||
#DP_Id="1234"
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dp
|
||||||
#
|
Options:
|
||||||
#DP_Key="sADDsdasdgdsf"
|
DP_Id Id
|
||||||
|
DP_Key Key
|
||||||
|
'
|
||||||
|
|
||||||
REST_API="https://dnsapi.cn"
|
REST_API="https://dnsapi.cn"
|
||||||
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
# Dnspod.com Domain api
|
dns_dpi_info='DNSPod.com
|
||||||
#
|
Site: DNSPod.com
|
||||||
#DPI_Id="1234"
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dpi
|
||||||
#
|
Options:
|
||||||
#DPI_Key="sADDsdasdgdsf"
|
DPI_Id Id
|
||||||
|
DPI_Key Key
|
||||||
|
'
|
||||||
|
|
||||||
REST_API="https://api.dnspod.com"
|
REST_API="https://api.dnspod.com"
|
||||||
|
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_dreamhost_info='DreamHost.com
|
||||||
|
Site: DreamHost.com
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dreamhost
|
||||||
|
Options:
|
||||||
|
DH_API_KEY API Key
|
||||||
|
Issues: github.com/RhinoLance/acme.sh
|
||||||
|
Author: RhinoLance
|
||||||
|
'
|
||||||
|
|
||||||
#Author: RhinoLance
|
|
||||||
#Report Bugs here: https://github.com/RhinoLance/acme.sh
|
|
||||||
#
|
|
||||||
|
|
||||||
#define the api endpoint
|
|
||||||
DH_API_ENDPOINT="https://api.dreamhost.com/"
|
DH_API_ENDPOINT="https://api.dreamhost.com/"
|
||||||
querystring=""
|
querystring=""
|
||||||
|
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
#Created by RaidenII, to use DuckDNS's API to add/remove text records
|
dns_duckdns_info='DuckDNS.org
|
||||||
#06/27/2017
|
Site: www.DuckDNS.org
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_duckdns
|
||||||
# Pass credentials before "acme.sh --issue --dns dns_duckdns ..."
|
Options:
|
||||||
# --
|
DuckDNS_Token API Token
|
||||||
# export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
Author: RaidenII
|
||||||
# --
|
'
|
||||||
#
|
|
||||||
# Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure may need to be used with acme.sh
|
|
||||||
|
|
||||||
DuckDNS_API="https://www.duckdns.org/update"
|
DuckDNS_API="https://www.duckdns.org/update"
|
||||||
|
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
#DD_API_User="xxxxx"
|
dns_durabledns_info='DurableDNS.com
|
||||||
#DD_API_Key="xxxxxx"
|
Site: DurableDNS.com
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_durabledns
|
||||||
|
Options:
|
||||||
|
DD_API_User API User
|
||||||
|
DD_API_Key API Key
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/2281
|
||||||
|
'
|
||||||
|
|
||||||
_DD_BASE="https://durabledns.com/services/dns"
|
_DD_BASE="https://durabledns.com/services/dns"
|
||||||
|
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
#
|
# shellcheck disable=SC2034
|
||||||
# Dyn.com Domain API
|
dns_dyn_info='Dyn.com
|
||||||
#
|
Domains: dynect.net
|
||||||
# Author: Gerd Naschenweng
|
Site: Dyn.com
|
||||||
# https://github.com/magicdude4eva
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dyn
|
||||||
#
|
Options:
|
||||||
|
DYN_Customer Customer
|
||||||
|
DYN_Username API Username
|
||||||
|
DYN_Password Secret
|
||||||
|
Author: Gerd Naschenweng <https://github.com/magicdude4eva>
|
||||||
|
'
|
||||||
|
|
||||||
# Dyn Managed DNS API
|
# Dyn Managed DNS API
|
||||||
# https://help.dyn.com/dns-api-knowledge-base/
|
# https://help.dyn.com/dns-api-knowledge-base/
|
||||||
#
|
#
|
||||||
@ -20,13 +26,6 @@
|
|||||||
# ZoneRemoveNode
|
# ZoneRemoveNode
|
||||||
# ZonePublish
|
# ZonePublish
|
||||||
# --
|
# --
|
||||||
#
|
|
||||||
# Pass credentials before "acme.sh --issue --dns dns_dyn ..."
|
|
||||||
# --
|
|
||||||
# export DYN_Customer="customer"
|
|
||||||
# export DYN_Username="apiuser"
|
|
||||||
# export DYN_Password="secret"
|
|
||||||
# --
|
|
||||||
|
|
||||||
DYN_API="https://api.dynect.net/REST"
|
DYN_API="https://api.dynect.net/REST"
|
||||||
|
|
||||||
|
@ -1,20 +1,21 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_dynu_info='Dynu.com
|
||||||
|
Site: Dynu.com
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dynu
|
||||||
|
Options:
|
||||||
|
Dynu_ClientId Client ID
|
||||||
|
Dynu_Secret Secret
|
||||||
|
Issues: github.com/shar0119/acme.sh
|
||||||
|
Author: Dynu Systems Inc
|
||||||
|
'
|
||||||
|
|
||||||
#Client ID
|
|
||||||
#Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d"
|
|
||||||
#
|
|
||||||
#Secret
|
|
||||||
#Dynu_Secret="aCUEY4BDCV45KI8CSIC3sp2LKQ9"
|
|
||||||
#
|
|
||||||
#Token
|
#Token
|
||||||
Dynu_Token=""
|
Dynu_Token=""
|
||||||
#
|
#
|
||||||
#Endpoint
|
#Endpoint
|
||||||
Dynu_EndPoint="https://api.dynu.com/v2"
|
Dynu_EndPoint="https://api.dynu.com/v2"
|
||||||
#
|
|
||||||
#Author: Dynu Systems, Inc.
|
|
||||||
#Report Bugs here: https://github.com/shar0119/acme.sh
|
|
||||||
#
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
@ -1,8 +1,15 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
#Author StefanAbl
|
# shellcheck disable=SC2034
|
||||||
#Usage specify a private keyfile to use with dynv6 'export KEY="path/to/keyfile"'
|
dns_dynv6_info='DynV6.com
|
||||||
#or use the HTTP REST API by by specifying a token 'export DYNV6_TOKEN="value"
|
Site: DynV6.com
|
||||||
#if no keyfile is specified, you will be asked if you want to create one in /home/$USER/.ssh/dynv6 and /home/$USER/.ssh/dynv6.pub
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dynv6
|
||||||
|
Options:
|
||||||
|
DYNV6_TOKEN REST API token. Get from https://DynV6.com/keys
|
||||||
|
OptionsAlt:
|
||||||
|
KEY Path to SSH private key file. E.g. "/root/.ssh/dynv6"
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/2702
|
||||||
|
Author: StefanAbl
|
||||||
|
'
|
||||||
|
|
||||||
dynv6_api="https://dynv6.com/api/v2"
|
dynv6_api="https://dynv6.com/api/v2"
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
@ -94,8 +101,8 @@ _get_domain() {
|
|||||||
_your_hosts="$(echo "$_your_hosts" | awk '/\./ {print $1}')"
|
_your_hosts="$(echo "$_your_hosts" | awk '/\./ {print $1}')"
|
||||||
for l in $_your_hosts; do
|
for l in $_your_hosts; do
|
||||||
#echo "host: $l"
|
#echo "host: $l"
|
||||||
if test "${_full_domain#*$l}" != "$_full_domain"; then
|
if test "${_full_domain#*"$l"}" != "$_full_domain"; then
|
||||||
_record="${_full_domain%.$l}"
|
_record=${_full_domain%."$l"}
|
||||||
_host=$l
|
_host=$l
|
||||||
_debug "The host is $_host and the record $_record"
|
_debug "The host is $_host and the record $_record"
|
||||||
return 0
|
return 0
|
||||||
@ -143,7 +150,7 @@ _dns_dynv6_add_http() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_get_zone_name "$_zone_id"
|
_get_zone_name "$_zone_id"
|
||||||
record="${fulldomain%%.$_zone_name}"
|
record=${fulldomain%%."$_zone_name"}
|
||||||
_set_record TXT "$record" "$txtvalue"
|
_set_record TXT "$record" "$txtvalue"
|
||||||
if _contains "$response" "$txtvalue"; then
|
if _contains "$response" "$txtvalue"; then
|
||||||
_info "Successfully added record"
|
_info "Successfully added record"
|
||||||
@ -161,7 +168,7 @@ _dns_dynv6_rm_http() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_get_zone_name "$_zone_id"
|
_get_zone_name "$_zone_id"
|
||||||
record="${fulldomain%%.$_zone_name}"
|
record=${fulldomain%%."$_zone_name"}
|
||||||
_get_record_id "$_zone_id" "$record" "$txtvalue"
|
_get_record_id "$_zone_id" "$record" "$txtvalue"
|
||||||
_del_record "$_zone_id" "$_record_id"
|
_del_record "$_zone_id" "$_record_id"
|
||||||
if [ -z "$response" ]; then
|
if [ -z "$response" ]; then
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_easydns_info='easyDNS.net
|
||||||
|
Site: easyDNS.net
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_easydns
|
||||||
|
Options:
|
||||||
|
EASYDNS_Token API Token
|
||||||
|
EASYDNS_Key API Key
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/2647
|
||||||
|
Author: Neilpang, wurzelpanzer <wurzelpanzer@maximolider.net>
|
||||||
|
'
|
||||||
|
|
||||||
#######################################################
|
|
||||||
#
|
|
||||||
# easyDNS REST API for acme.sh by Neilpang based on dns_cf.sh
|
|
||||||
#
|
|
||||||
# API Documentation: https://sandbox.rest.easydns.net:3001/
|
# API Documentation: https://sandbox.rest.easydns.net:3001/
|
||||||
#
|
|
||||||
# Author: wurzelpanzer [wurzelpanzer@maximolider.net]
|
|
||||||
# Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/2647
|
|
||||||
#
|
|
||||||
#################### Public functions #################
|
#################### Public functions #################
|
||||||
|
|
||||||
#EASYDNS_Key="xxxxxxxxxxxxxxxxxxxxxxxx"
|
#EASYDNS_Key="xxxxxxxxxxxxxxxxxxxxxxxx"
|
||||||
|
@ -1,4 +1,15 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_edgedns_info='Akamai.com Edge DNS
|
||||||
|
Site: techdocs.Akamai.com/edge-dns/reference/edge-dns-api
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_edgedns
|
||||||
|
Options: Specify individual credentials
|
||||||
|
AKAMAI_HOST Host
|
||||||
|
AKAMAI_ACCESS_TOKEN Access token
|
||||||
|
AKAMAI_CLIENT_TOKEN Client token
|
||||||
|
AKAMAI_CLIENT_SECRET Client secret
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/3157
|
||||||
|
'
|
||||||
|
|
||||||
# Akamai Edge DNS v2 API
|
# Akamai Edge DNS v2 API
|
||||||
# User must provide Open Edgegrid API credentials to the EdgeDNS installation. The remote user in EdgeDNS must have CRUD access to
|
# User must provide Open Edgegrid API credentials to the EdgeDNS installation. The remote user in EdgeDNS must have CRUD access to
|
||||||
@ -6,18 +17,10 @@
|
|||||||
|
|
||||||
# Report bugs to https://control.akamai.com/apps/support-ui/#/contact-support
|
# Report bugs to https://control.akamai.com/apps/support-ui/#/contact-support
|
||||||
|
|
||||||
# Values to export:
|
|
||||||
# --EITHER--
|
|
||||||
# *** TBD. NOT IMPLEMENTED YET ***
|
# *** TBD. NOT IMPLEMENTED YET ***
|
||||||
# specify Edgegrid credentials file and section
|
# Specify Edgegrid credentials file and section.
|
||||||
# AKAMAI_EDGERC=<full file path>
|
# AKAMAI_EDGERC Edge RC. Full file path
|
||||||
# AKAMAI_EDGERC_SECTION="default"
|
# AKAMAI_EDGERC_SECTION Edge RC Section. E.g. "default"
|
||||||
## --OR--
|
|
||||||
# specify indiviual credentials
|
|
||||||
# export AKAMAI_HOST = <host>
|
|
||||||
# export AKAMAI_ACCESS_TOKEN = <access token>
|
|
||||||
# export AKAMAI_CLIENT_TOKEN = <client token>
|
|
||||||
# export AKAMAI_CLIENT_SECRET = <client secret>
|
|
||||||
|
|
||||||
ACME_EDGEDNS_VERSION="0.1.0"
|
ACME_EDGEDNS_VERSION="0.1.0"
|
||||||
|
|
||||||
@ -176,6 +179,7 @@ _EDGEDNS_credentials() {
|
|||||||
_debug "GettingEdge DNS credentials"
|
_debug "GettingEdge DNS credentials"
|
||||||
_log "$(printf "ACME DNSAPI Edge DNS version %s" ${ACME_EDGEDNS_VERSION})"
|
_log "$(printf "ACME DNSAPI Edge DNS version %s" ${ACME_EDGEDNS_VERSION})"
|
||||||
args_missing=0
|
args_missing=0
|
||||||
|
AKAMAI_ACCESS_TOKEN="${AKAMAI_ACCESS_TOKEN:-$(_readaccountconf_mutable AKAMAI_ACCESS_TOKEN)}"
|
||||||
if [ -z "$AKAMAI_ACCESS_TOKEN" ]; then
|
if [ -z "$AKAMAI_ACCESS_TOKEN" ]; then
|
||||||
AKAMAI_ACCESS_TOKEN=""
|
AKAMAI_ACCESS_TOKEN=""
|
||||||
AKAMAI_CLIENT_TOKEN=""
|
AKAMAI_CLIENT_TOKEN=""
|
||||||
@ -184,6 +188,7 @@ _EDGEDNS_credentials() {
|
|||||||
_err "AKAMAI_ACCESS_TOKEN is missing"
|
_err "AKAMAI_ACCESS_TOKEN is missing"
|
||||||
args_missing=1
|
args_missing=1
|
||||||
fi
|
fi
|
||||||
|
AKAMAI_CLIENT_TOKEN="${AKAMAI_CLIENT_TOKEN:-$(_readaccountconf_mutable AKAMAI_CLIENT_TOKEN)}"
|
||||||
if [ -z "$AKAMAI_CLIENT_TOKEN" ]; then
|
if [ -z "$AKAMAI_CLIENT_TOKEN" ]; then
|
||||||
AKAMAI_ACCESS_TOKEN=""
|
AKAMAI_ACCESS_TOKEN=""
|
||||||
AKAMAI_CLIENT_TOKEN=""
|
AKAMAI_CLIENT_TOKEN=""
|
||||||
@ -192,6 +197,7 @@ _EDGEDNS_credentials() {
|
|||||||
_err "AKAMAI_CLIENT_TOKEN is missing"
|
_err "AKAMAI_CLIENT_TOKEN is missing"
|
||||||
args_missing=1
|
args_missing=1
|
||||||
fi
|
fi
|
||||||
|
AKAMAI_HOST="${AKAMAI_HOST:-$(_readaccountconf_mutable AKAMAI_HOST)}"
|
||||||
if [ -z "$AKAMAI_HOST" ]; then
|
if [ -z "$AKAMAI_HOST" ]; then
|
||||||
AKAMAI_ACCESS_TOKEN=""
|
AKAMAI_ACCESS_TOKEN=""
|
||||||
AKAMAI_CLIENT_TOKEN=""
|
AKAMAI_CLIENT_TOKEN=""
|
||||||
@ -200,6 +206,7 @@ _EDGEDNS_credentials() {
|
|||||||
_err "AKAMAI_HOST is missing"
|
_err "AKAMAI_HOST is missing"
|
||||||
args_missing=1
|
args_missing=1
|
||||||
fi
|
fi
|
||||||
|
AKAMAI_CLIENT_SECRET="${AKAMAI_CLIENT_SECRET:-$(_readaccountconf_mutable AKAMAI_CLIENT_SECRET)}"
|
||||||
if [ -z "$AKAMAI_CLIENT_SECRET" ]; then
|
if [ -z "$AKAMAI_CLIENT_SECRET" ]; then
|
||||||
AKAMAI_ACCESS_TOKEN=""
|
AKAMAI_ACCESS_TOKEN=""
|
||||||
AKAMAI_CLIENT_TOKEN=""
|
AKAMAI_CLIENT_TOKEN=""
|
||||||
@ -414,7 +421,7 @@ _edgedns_make_data_to_sign() {
|
|||||||
_secure_debug2 "hdr" "$hdr"
|
_secure_debug2 "hdr" "$hdr"
|
||||||
_edgedns_make_content_hash
|
_edgedns_make_content_hash
|
||||||
path="$(echo "$_request_url_path" | tr -d "\n\r" | sed 's/https\?:\/\///')"
|
path="$(echo "$_request_url_path" | tr -d "\n\r" | sed 's/https\?:\/\///')"
|
||||||
path="${path#*$AKAMAI_HOST}"
|
path=${path#*"$AKAMAI_HOST"}
|
||||||
_debug "hier path" "$path"
|
_debug "hier path" "$path"
|
||||||
# dont expose headers to sign so use MT string
|
# dont expose headers to sign so use MT string
|
||||||
_mdata="$(printf "%s\thttps\t%s\t%s\t%s\t%s\t%s" "$_request_method" "$AKAMAI_HOST" "$path" "" "$_hash" "$hdr")"
|
_mdata="$(printf "%s\thttps\t%s\t%s\t%s\t%s\t%s" "$_request_method" "$AKAMAI_HOST" "$path" "" "$_hash" "$hdr")"
|
||||||
|
@ -1,18 +1,14 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
#This is the euserv.eu api wrapper for acme.sh
|
dns_euserv_info='EUserv.com
|
||||||
#
|
Domains: EUserv.eu
|
||||||
#Author: Michael Brueckner
|
Site: EUserv.com
|
||||||
#Report Bugs: https://www.github.com/initit/acme.sh or mbr@initit.de
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_euserv
|
||||||
|
Options:
|
||||||
#
|
EUSERV_Username Username
|
||||||
#EUSERV_Username="username"
|
EUSERV_Password Password
|
||||||
#
|
Author: Michael Brueckner
|
||||||
#EUSERV_Password="password"
|
'
|
||||||
#
|
|
||||||
# Dependencies:
|
|
||||||
# -------------
|
|
||||||
# - none -
|
|
||||||
|
|
||||||
EUSERV_Api="https://api.euserv.net"
|
EUSERV_Api="https://api.euserv.net"
|
||||||
|
|
||||||
|
@ -1,4 +1,12 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_exoscale_info='Exoscale.com
|
||||||
|
Site: Exoscale.com
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_exoscale
|
||||||
|
Options:
|
||||||
|
EXOSCALE_API_KEY API Key
|
||||||
|
EXOSCALE_SECRET_KEY API Secret key
|
||||||
|
'
|
||||||
|
|
||||||
EXOSCALE_API=https://api.exoscale.com/dns/v1
|
EXOSCALE_API=https://api.exoscale.com/dns/v1
|
||||||
|
|
||||||
|
153
dnsapi/dns_fornex.sh
Normal file
153
dnsapi/dns_fornex.sh
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_fornex_info='Fornex.com
|
||||||
|
Site: Fornex.com
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_fornex
|
||||||
|
Options:
|
||||||
|
FORNEX_API_KEY API Key
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/3998
|
||||||
|
Author: Timur Umarov <inbox@tumarov.com>
|
||||||
|
'
|
||||||
|
|
||||||
|
FORNEX_API_URL="https://fornex.com/api/dns/v0.1"
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
|
||||||
|
#Usage: dns_fornex_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
dns_fornex_add() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
if ! _Fornex_API; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _get_root "$fulldomain"; then
|
||||||
|
_err "Unable to determine root domain"
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info "Adding record"
|
||||||
|
if _rest POST "$_domain/entry_set/add/" "host=$fulldomain&type=TXT&value=$txtvalue&apikey=$FORNEX_API_KEY"; then
|
||||||
|
_debug _response "$response"
|
||||||
|
if _contains "$response" '"ok": true' || _contains "$response" 'Такая запись уже существует.'; then
|
||||||
|
_info "Added, OK"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
_err "Add txt record error."
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#Usage: dns_fornex_rm _acme-challenge.www.domain.com
|
||||||
|
dns_fornex_rm() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
if ! _Fornex_API; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _get_root "$fulldomain"; then
|
||||||
|
_err "Unable to determine root domain"
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug "Getting txt records"
|
||||||
|
_rest GET "$_domain/entry_set.json?apikey=$FORNEX_API_KEY"
|
||||||
|
|
||||||
|
if ! _contains "$response" "$txtvalue"; then
|
||||||
|
_err "Txt record not found"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_record_id="$(echo "$response" | _egrep_o "{[^{]*\"value\"*:*\"$txtvalue\"[^}]*}" | sed -n -e 's#.*"id": \([0-9]*\).*#\1#p')"
|
||||||
|
_debug "_record_id" "$_record_id"
|
||||||
|
if [ -z "$_record_id" ]; then
|
||||||
|
_err "can not find _record_id"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _rest POST "$_domain/entry_set/$_record_id/delete/" "apikey=$FORNEX_API_KEY"; then
|
||||||
|
_err "Delete record error."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
#################### Private functions below ##################################
|
||||||
|
|
||||||
|
#_acme-challenge.www.domain.com
|
||||||
|
#returns
|
||||||
|
# _sub_domain=_acme-challenge.www
|
||||||
|
# _domain=domain.com
|
||||||
|
_get_root() {
|
||||||
|
domain=$1
|
||||||
|
|
||||||
|
i=1
|
||||||
|
while true; do
|
||||||
|
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||||
|
_debug h "$h"
|
||||||
|
if [ -z "$h" ]; then
|
||||||
|
#not valid
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _rest GET "domain_list.json?q=$h&apikey=$FORNEX_API_KEY"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if _contains "$response" "\"$h\"" >/dev/null; then
|
||||||
|
_domain=$h
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
_debug "$h not found"
|
||||||
|
fi
|
||||||
|
i=$(_math "$i" + 1)
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_Fornex_API() {
|
||||||
|
FORNEX_API_KEY="${FORNEX_API_KEY:-$(_readaccountconf_mutable FORNEX_API_KEY)}"
|
||||||
|
if [ -z "$FORNEX_API_KEY" ]; then
|
||||||
|
FORNEX_API_KEY=""
|
||||||
|
|
||||||
|
_err "You didn't specify the Fornex API key yet."
|
||||||
|
_err "Please create your key and try again."
|
||||||
|
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_saveaccountconf_mutable FORNEX_API_KEY "$FORNEX_API_KEY"
|
||||||
|
}
|
||||||
|
|
||||||
|
#method method action data
|
||||||
|
_rest() {
|
||||||
|
m=$1
|
||||||
|
ep="$2"
|
||||||
|
data="$3"
|
||||||
|
_debug "$ep"
|
||||||
|
|
||||||
|
export _H1="Accept: application/json"
|
||||||
|
|
||||||
|
if [ "$m" != "GET" ]; then
|
||||||
|
_debug data "$data"
|
||||||
|
response="$(_post "$data" "$FORNEX_API_URL/$ep" "" "$m")"
|
||||||
|
else
|
||||||
|
response="$(_get "$FORNEX_API_URL/$ep" | _normalizeJson)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_ret="$?"
|
||||||
|
if [ "$_ret" != "0" ]; then
|
||||||
|
_err "error $ep"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 response "$response"
|
||||||
|
return 0
|
||||||
|
}
|
@ -1,14 +1,15 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_freedns_info='FreeDNS
|
||||||
|
Site: FreeDNS.afraid.org
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_freedns
|
||||||
|
Options:
|
||||||
|
FREEDNS_User Username
|
||||||
|
FREEDNS_Password Password
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/2305
|
||||||
|
Author: David Kerr <https://github.com/dkerr64>
|
||||||
|
'
|
||||||
|
|
||||||
#This file name is "dns_freedns.sh"
|
|
||||||
#So, here must be a method dns_freedns_add()
|
|
||||||
#Which will be called by acme.sh to add the txt record to your api system.
|
|
||||||
#returns 0 means success, otherwise error.
|
|
||||||
#
|
|
||||||
#Author: David Kerr
|
|
||||||
#Report Bugs here: https://github.com/dkerr64/acme.sh
|
|
||||||
#or here... https://github.com/acmesh-official/acme.sh/issues/2305
|
|
||||||
#
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
# Export FreeDNS userid and password in following variables...
|
# Export FreeDNS userid and password in following variables...
|
||||||
|
@ -1,31 +1,42 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_gandi_livedns_info='Gandi.net LiveDNS
|
||||||
|
Site: Gandi.net/domain/dns
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gandi_livedns
|
||||||
|
Options:
|
||||||
|
GANDI_LIVEDNS_KEY API Key
|
||||||
|
Issues: github.com/fcrozat/acme.sh
|
||||||
|
Author: Frédéric Crozat <fcrozat@suse.com>, Dominik Röttsches <drott@google.com>
|
||||||
|
'
|
||||||
|
|
||||||
# Gandi LiveDNS v5 API
|
# Gandi LiveDNS v5 API
|
||||||
# http://doc.livedns.gandi.net/
|
# https://api.gandi.net/docs/livedns/
|
||||||
|
# https://api.gandi.net/docs/authentication/ for token + apikey (deprecated) authentication
|
||||||
# currently under beta
|
# currently under beta
|
||||||
#
|
|
||||||
# Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable
|
|
||||||
#
|
|
||||||
#Author: Frédéric Crozat <fcrozat@suse.com>
|
|
||||||
# Dominik Röttsches <drott@google.com>
|
|
||||||
#Report Bugs here: https://github.com/fcrozat/acme.sh
|
|
||||||
#
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
GANDI_LIVEDNS_API="https://dns.api.gandi.net/api/v5"
|
GANDI_LIVEDNS_API="https://api.gandi.net/v5/livedns"
|
||||||
|
|
||||||
#Usage: dns_gandi_livedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
#Usage: dns_gandi_livedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
dns_gandi_livedns_add() {
|
dns_gandi_livedns_add() {
|
||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
txtvalue=$2
|
txtvalue=$2
|
||||||
|
|
||||||
if [ -z "$GANDI_LIVEDNS_KEY" ]; then
|
if [ -z "$GANDI_LIVEDNS_KEY" ] && [ -z "$GANDI_LIVEDNS_TOKEN" ]; then
|
||||||
_err "No API key specified for Gandi LiveDNS."
|
_err "No Token or API key (deprecated) specified for Gandi LiveDNS."
|
||||||
_err "Create your key and export it as GANDI_LIVEDNS_KEY"
|
_err "Create your token or key and export it as GANDI_LIVEDNS_KEY or GANDI_LIVEDNS_TOKEN respectively"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Keep only one secret in configuration
|
||||||
|
if [ -n "$GANDI_LIVEDNS_TOKEN" ]; then
|
||||||
|
_saveaccountconf GANDI_LIVEDNS_TOKEN "$GANDI_LIVEDNS_TOKEN"
|
||||||
|
_clearaccountconf GANDI_LIVEDNS_KEY
|
||||||
|
elif [ -n "$GANDI_LIVEDNS_KEY" ]; then
|
||||||
_saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY"
|
_saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY"
|
||||||
|
_clearaccountconf GANDI_LIVEDNS_TOKEN
|
||||||
|
fi
|
||||||
|
|
||||||
_debug "First detect the root zone"
|
_debug "First detect the root zone"
|
||||||
if ! _get_root "$fulldomain"; then
|
if ! _get_root "$fulldomain"; then
|
||||||
@ -70,7 +81,7 @@ dns_gandi_livedns_rm() {
|
|||||||
_gandi_livedns_rest PUT \
|
_gandi_livedns_rest PUT \
|
||||||
"domains/$_domain/records/$_sub_domain/TXT" \
|
"domains/$_domain/records/$_sub_domain/TXT" \
|
||||||
"{\"rrset_ttl\": 300, \"rrset_values\": $_new_rrset_values}" &&
|
"{\"rrset_ttl\": 300, \"rrset_values\": $_new_rrset_values}" &&
|
||||||
_contains "$response" '{"message": "DNS Record Created"}' &&
|
_contains "$response" '{"message":"DNS Record Created"}' &&
|
||||||
_info "Removing record $(__green "success")"
|
_info "Removing record $(__green "success")"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +137,7 @@ _dns_gandi_append_record() {
|
|||||||
_debug new_rrset_values "$_rrset_values"
|
_debug new_rrset_values "$_rrset_values"
|
||||||
_gandi_livedns_rest PUT "domains/$_domain/records/$sub_domain/TXT" \
|
_gandi_livedns_rest PUT "domains/$_domain/records/$sub_domain/TXT" \
|
||||||
"{\"rrset_ttl\": 300, \"rrset_values\": $_rrset_values}" &&
|
"{\"rrset_ttl\": 300, \"rrset_values\": $_rrset_values}" &&
|
||||||
_contains "$response" '{"message": "DNS Record Created"}' &&
|
_contains "$response" '{"message":"DNS Record Created"}' &&
|
||||||
_info "Adding record $(__green "success")"
|
_info "Adding record $(__green "success")"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,11 +147,11 @@ _dns_gandi_existing_rrset_values() {
|
|||||||
if ! _gandi_livedns_rest GET "domains/$domain/records/$sub_domain"; then
|
if ! _gandi_livedns_rest GET "domains/$domain/records/$sub_domain"; then
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
if ! _contains "$response" '"rrset_type": "TXT"'; then
|
if ! _contains "$response" '"rrset_type":"TXT"'; then
|
||||||
_debug "Does not have a _acme-challenge TXT record yet."
|
_debug "Does not have a _acme-challenge TXT record yet."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
if _contains "$response" '"rrset_values": \[\]'; then
|
if _contains "$response" '"rrset_values":\[\]'; then
|
||||||
_debug "Empty rrset_values for TXT record, no previous TXT record."
|
_debug "Empty rrset_values for TXT record, no previous TXT record."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
@ -157,7 +168,12 @@ _gandi_livedns_rest() {
|
|||||||
_debug "$ep"
|
_debug "$ep"
|
||||||
|
|
||||||
export _H1="Content-Type: application/json"
|
export _H1="Content-Type: application/json"
|
||||||
export _H2="X-Api-Key: $GANDI_LIVEDNS_KEY"
|
|
||||||
|
if [ -n "$GANDI_LIVEDNS_TOKEN" ]; then
|
||||||
|
export _H2="Authorization: Bearer $GANDI_LIVEDNS_TOKEN"
|
||||||
|
else
|
||||||
|
export _H2="Authorization: Apikey $GANDI_LIVEDNS_KEY"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$m" = "GET" ]; then
|
if [ "$m" = "GET" ]; then
|
||||||
response="$(_get "$GANDI_LIVEDNS_API/$ep")"
|
response="$(_get "$GANDI_LIVEDNS_API/$ep")"
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
# Author: Janos Lenart <janos@lenart.io>
|
dns_gcloud_info='Google Cloud DNS
|
||||||
|
Site: Cloud.Google.com/dns
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gcloud
|
||||||
|
Options:
|
||||||
|
CLOUDSDK_ACTIVE_CONFIG_NAME Active config name. E.g. "default"
|
||||||
|
Author: Janos Lenart <janos@lenart.io>
|
||||||
|
'
|
||||||
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
@ -39,10 +45,10 @@ dns_gcloud_rm() {
|
|||||||
_dns_gcloud_start_tr || return $?
|
_dns_gcloud_start_tr || return $?
|
||||||
_dns_gcloud_get_rrdatas || return $?
|
_dns_gcloud_get_rrdatas || return $?
|
||||||
echo "$rrdatas" | _dns_gcloud_remove_rrs || return $?
|
echo "$rrdatas" | _dns_gcloud_remove_rrs || return $?
|
||||||
echo "$rrdatas" | grep -F -v "\"$txtvalue\"" | _dns_gcloud_add_rrs || return $?
|
echo "$rrdatas" | grep -F -v -- "\"$txtvalue\"" | _dns_gcloud_add_rrs || return $?
|
||||||
_dns_gcloud_execute_tr || return $?
|
_dns_gcloud_execute_tr || return $?
|
||||||
|
|
||||||
_info "$fulldomain record added"
|
_info "$fulldomain record removed"
|
||||||
}
|
}
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
#################### Private functions below ##################################
|
||||||
@ -98,7 +104,7 @@ _dns_gcloud_remove_rrs() {
|
|||||||
--ttl="$ttl" \
|
--ttl="$ttl" \
|
||||||
--type=TXT \
|
--type=TXT \
|
||||||
--zone="$managedZone" \
|
--zone="$managedZone" \
|
||||||
--transaction-file="$tr"; then
|
--transaction-file="$tr" --; then
|
||||||
_debug tr "$(cat "$tr")"
|
_debug tr "$(cat "$tr")"
|
||||||
rm -r "$trd"
|
rm -r "$trd"
|
||||||
_err "_dns_gcloud_remove_rrs: failed to remove RRs"
|
_err "_dns_gcloud_remove_rrs: failed to remove RRs"
|
||||||
@ -113,7 +119,7 @@ _dns_gcloud_add_rrs() {
|
|||||||
--ttl="$ttl" \
|
--ttl="$ttl" \
|
||||||
--type=TXT \
|
--type=TXT \
|
||||||
--zone="$managedZone" \
|
--zone="$managedZone" \
|
||||||
--transaction-file="$tr"; then
|
--transaction-file="$tr" --; then
|
||||||
_debug tr "$(cat "$tr")"
|
_debug tr "$(cat "$tr")"
|
||||||
rm -r "$trd"
|
rm -r "$trd"
|
||||||
_err "_dns_gcloud_add_rrs: failed to add RRs"
|
_err "_dns_gcloud_add_rrs: failed to add RRs"
|
||||||
|
191
dnsapi/dns_gcore.sh
Executable file
191
dnsapi/dns_gcore.sh
Executable file
@ -0,0 +1,191 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_gcore_info='Gcore.com
|
||||||
|
Site: Gcore.com
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gcore
|
||||||
|
Options:
|
||||||
|
GCORE_Key API Key
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/4460
|
||||||
|
'
|
||||||
|
|
||||||
|
GCORE_Api="https://api.gcore.com/dns/v2"
|
||||||
|
GCORE_Doc="https://api.gcore.com/docs/dns"
|
||||||
|
|
||||||
|
######## Public functions #####################
|
||||||
|
|
||||||
|
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
dns_gcore_add() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
GCORE_Key="${GCORE_Key:-$(_readaccountconf_mutable GCORE_Key)}"
|
||||||
|
|
||||||
|
if [ -z "$GCORE_Key" ]; then
|
||||||
|
GCORE_Key=""
|
||||||
|
_err "You didn't specify a Gcore api key yet."
|
||||||
|
_err "You can get yours from here $GCORE_Doc"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
#save the api key to the account conf file.
|
||||||
|
_saveaccountconf_mutable GCORE_Key "$GCORE_Key"
|
||||||
|
|
||||||
|
_debug "First detect the zone name"
|
||||||
|
if ! _get_root "$fulldomain"; then
|
||||||
|
_err "invalid domain"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug _zone_name "$_zone_name"
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
|
_debug "Getting txt records"
|
||||||
|
_gcore_rest GET "zones/$_zone_name/$fulldomain/TXT"
|
||||||
|
payload=""
|
||||||
|
|
||||||
|
if echo "$response" | grep "record is not found" >/dev/null; then
|
||||||
|
_info "Record doesn't exists"
|
||||||
|
payload="{\"resource_records\":[{\"content\":[\"$txtvalue\"],\"enabled\":true}],\"ttl\":120}"
|
||||||
|
elif echo "$response" | grep "$txtvalue" >/dev/null; then
|
||||||
|
_info "Already exists, OK"
|
||||||
|
return 0
|
||||||
|
elif echo "$response" | tr -d " " | grep \"name\":\""$fulldomain"\",\"type\":\"TXT\" >/dev/null; then
|
||||||
|
_info "Record with mismatch txtvalue, try update it"
|
||||||
|
payload=$(echo "$response" | tr -d " " | sed 's/"updated_at":[0-9]\+,//g' | sed 's/"meta":{}}]}/"meta":{}},{"content":['\""$txtvalue"\"'],"enabled":true}]}/')
|
||||||
|
fi
|
||||||
|
|
||||||
|
# For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so
|
||||||
|
# we can not use updating anymore.
|
||||||
|
# count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2)
|
||||||
|
# _debug count "$count"
|
||||||
|
# if [ "$count" = "0" ]; then
|
||||||
|
_info "Adding record"
|
||||||
|
if _gcore_rest PUT "zones/$_zone_name/$fulldomain/TXT" "$payload"; then
|
||||||
|
if _contains "$response" "$txtvalue"; then
|
||||||
|
_info "Added, OK"
|
||||||
|
return 0
|
||||||
|
elif _contains "$response" "rrset is already exists"; then
|
||||||
|
_info "Already exists, OK"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
_err "Add txt record error."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
_err "Add txt record error."
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#fulldomain txtvalue
|
||||||
|
dns_gcore_rm() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
GCORE_Key="${GCORE_Key:-$(_readaccountconf_mutable GCORE_Key)}"
|
||||||
|
|
||||||
|
_debug "First detect the root zone"
|
||||||
|
if ! _get_root "$fulldomain"; then
|
||||||
|
_err "invalid domain"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug _zone_name "$_zone_name"
|
||||||
|
_debug _sub_domain "$_sub_domain"
|
||||||
|
_debug _domain "$_domain"
|
||||||
|
|
||||||
|
_debug "Getting txt records"
|
||||||
|
_gcore_rest GET "zones/$_zone_name/$fulldomain/TXT"
|
||||||
|
|
||||||
|
if echo "$response" | grep "record is not found" >/dev/null; then
|
||||||
|
_info "No such txt recrod"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! echo "$response" | tr -d " " | grep \"name\":\""$fulldomain"\",\"type\":\"TXT\" >/dev/null; then
|
||||||
|
_err "Error: $response"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! echo "$response" | tr -d " " | grep \""$txtvalue"\" >/dev/null; then
|
||||||
|
_info "No such txt recrod"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
count="$(echo "$response" | grep -o "content" | wc -l)"
|
||||||
|
|
||||||
|
if [ "$count" = "1" ]; then
|
||||||
|
if ! _gcore_rest DELETE "zones/$_zone_name/$fulldomain/TXT"; then
|
||||||
|
_err "Delete record error. $response"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
payload="$(echo "$response" | tr -d " " | sed 's/"updated_at":[0-9]\+,//g' | sed 's/{"id":[0-9]\+,"content":\["'"$txtvalue"'"\],"enabled":true,"meta":{}}//' | sed 's/\[,/\[/' | sed 's/,,/,/' | sed 's/,\]/\]/')"
|
||||||
|
if ! _gcore_rest PUT "zones/$_zone_name/$fulldomain/TXT" "$payload"; then
|
||||||
|
_err "Delete record error. $response"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
#################### Private functions below ##################################
|
||||||
|
#_acme-challenge.sub.domain.com
|
||||||
|
#returns
|
||||||
|
# _sub_domain=_acme-challenge.sub or _acme-challenge
|
||||||
|
# _domain=domain.com
|
||||||
|
# _zone_name=domain.com or sub.domain.com
|
||||||
|
_get_root() {
|
||||||
|
domain=$1
|
||||||
|
i=1
|
||||||
|
p=1
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||||
|
_debug h "$h"
|
||||||
|
if [ -z "$h" ]; then
|
||||||
|
#not valid
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _gcore_rest GET "zones/$h"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if _contains "$response" "\"name\":\"$h\""; then
|
||||||
|
_zone_name=$h
|
||||||
|
if [ "$_zone_name" ]; then
|
||||||
|
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||||
|
_domain=$h
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
p=$i
|
||||||
|
i=$(_math "$i" + 1)
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_gcore_rest() {
|
||||||
|
m=$1
|
||||||
|
ep="$2"
|
||||||
|
data="$3"
|
||||||
|
_debug "$ep"
|
||||||
|
|
||||||
|
key_trimmed=$(echo "$GCORE_Key" | tr -d '"')
|
||||||
|
|
||||||
|
export _H1="Content-Type: application/json"
|
||||||
|
export _H2="Authorization: APIKey $key_trimmed"
|
||||||
|
|
||||||
|
if [ "$m" != "GET" ]; then
|
||||||
|
_debug data "$data"
|
||||||
|
response="$(_post "$data" "$GCORE_Api/$ep" "" "$m")"
|
||||||
|
else
|
||||||
|
response="$(_get "$GCORE_Api/$ep")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "error $ep"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug2 response "$response"
|
||||||
|
return 0
|
||||||
|
}
|
@ -1,10 +1,12 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
#Godaddy domain api
|
dns_gd_info='GoDaddy.com
|
||||||
#
|
Site: GoDaddy.com
|
||||||
#GD_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gd
|
||||||
#
|
Options:
|
||||||
#GD_Secret="asdfsdfsfsdfsdfdfsdf"
|
GD_Key API Key
|
||||||
|
GD_Secret API Secret
|
||||||
|
'
|
||||||
|
|
||||||
GD_Api="https://api.godaddy.com/v1"
|
GD_Api="https://api.godaddy.com/v1"
|
||||||
|
|
||||||
@ -20,8 +22,8 @@ dns_gd_add() {
|
|||||||
if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ]; then
|
if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ]; then
|
||||||
GD_Key=""
|
GD_Key=""
|
||||||
GD_Secret=""
|
GD_Secret=""
|
||||||
_err "You don't specify godaddy api key and secret yet."
|
_err "You didn't specify godaddy api key and secret yet."
|
||||||
_err "Please create you key and try again."
|
_err "Please create your key and try again."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -44,14 +46,15 @@ dns_gd_add() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if _contains "$response" "$txtvalue"; then
|
if _contains "$response" "$txtvalue"; then
|
||||||
_info "The record is existing, skip"
|
_info "This record already exists, skipping"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_add_data="{\"data\":\"$txtvalue\"}"
|
_add_data="{\"data\":\"$txtvalue\"}"
|
||||||
for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do
|
for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do
|
||||||
_debug2 t "$t"
|
_debug2 t "$t"
|
||||||
if [ "$t" ]; then
|
# ignore empty (previously removed) records, to prevent useless _acme-challenge TXT entries
|
||||||
|
if [ "$t" ] && [ "$t" != '""' ]; then
|
||||||
_add_data="$_add_data,{\"data\":$t}"
|
_add_data="$_add_data,{\"data\":$t}"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@ -59,13 +62,25 @@ dns_gd_add() {
|
|||||||
|
|
||||||
_info "Adding record"
|
_info "Adding record"
|
||||||
if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then
|
if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then
|
||||||
_info "Added, sleeping 10 seconds"
|
_debug "Checking updated records of '${fulldomain}'"
|
||||||
_sleep 10
|
|
||||||
#todo: check if the record takes effect
|
if ! _gd_rest GET "domains/$_domain/records/TXT/$_sub_domain"; then
|
||||||
return 0
|
_err "Validating TXT record for '${fulldomain}' with rest error [$?]." "$response"
|
||||||
fi
|
|
||||||
_err "Add txt record error."
|
|
||||||
return 1
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! _contains "$response" "$txtvalue"; then
|
||||||
|
_err "TXT record '${txtvalue}' for '${fulldomain}', value wasn't set!"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
_err "Add txt record error, value '${txtvalue}' for '${fulldomain}' was not set."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_sleep 10
|
||||||
|
_info "Added TXT record '${txtvalue}' for '${fulldomain}'."
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
#fulldomain
|
#fulldomain
|
||||||
@ -107,11 +122,20 @@ dns_gd_rm() {
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if [ -z "$_add_data" ]; then
|
if [ -z "$_add_data" ]; then
|
||||||
_add_data="{\"data\":\"\"}"
|
# delete empty record
|
||||||
|
_debug "Delete last record for '${fulldomain}'"
|
||||||
|
if ! _gd_rest DELETE "domains/$_domain/records/TXT/$_sub_domain"; then
|
||||||
|
_err "Cannot delete empty TXT record for '$fulldomain'"
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
|
# remove specific TXT value, keeping other entries
|
||||||
_debug2 _add_data "$_add_data"
|
_debug2 _add_data "$_add_data"
|
||||||
|
if ! _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then
|
||||||
_gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"
|
_err "Cannot update TXT record for '$fulldomain'"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
#################### Private functions below ##################################
|
||||||
@ -156,15 +180,15 @@ _gd_rest() {
|
|||||||
export _H1="Authorization: sso-key $GD_Key:$GD_Secret"
|
export _H1="Authorization: sso-key $GD_Key:$GD_Secret"
|
||||||
export _H2="Content-Type: application/json"
|
export _H2="Content-Type: application/json"
|
||||||
|
|
||||||
if [ "$data" ]; then
|
if [ "$data" ] || [ "$m" = "DELETE" ]; then
|
||||||
_debug data "$data"
|
_debug "data ($m): " "$data"
|
||||||
response="$(_post "$data" "$GD_Api/$ep" "" "$m")"
|
response="$(_post "$data" "$GD_Api/$ep" "" "$m")"
|
||||||
else
|
else
|
||||||
response="$(_get "$GD_Api/$ep")"
|
response="$(_get "$GD_Api/$ep")"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$?" != "0" ]; then
|
if [ "$?" != "0" ]; then
|
||||||
_err "error $ep"
|
_err "error on rest call ($m): $ep"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_debug2 response "$response"
|
_debug2 response "$response"
|
||||||
|
@ -1,177 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
#Author: Herman Sletteng
|
|
||||||
#Report Bugs here: https://github.com/loial/acme.sh
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# Note, gratisdns requires a login first, so the script needs to handle
|
|
||||||
# temporary cookies. Since acme.sh _get/_post currently don't directly support
|
|
||||||
# cookies, I've defined wrapper functions _myget/_mypost to set the headers
|
|
||||||
|
|
||||||
GDNSDK_API="https://admin.gratisdns.com"
|
|
||||||
######## Public functions #####################
|
|
||||||
#Usage: dns_gdnsdk_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
|
||||||
dns_gdnsdk_add() {
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
_info "Using gratisdns.dk"
|
|
||||||
_debug fulldomain "$fulldomain"
|
|
||||||
_debug txtvalue "$txtvalue"
|
|
||||||
if ! _gratisdns_login; then
|
|
||||||
_err "Login failed!"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
#finding domain zone
|
|
||||||
if ! _get_domain; then
|
|
||||||
_err "No matching root domain for $fulldomain found"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
# adding entry
|
|
||||||
_info "Adding the entry"
|
|
||||||
_mypost "action=dns_primary_record_added_txt&user_domain=$_domain&name=$fulldomain&txtdata=$txtvalue&ttl=1"
|
|
||||||
if _successful_update; then return 0; fi
|
|
||||||
_err "Couldn't create entry!"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#Usage: fulldomain txtvalue
|
|
||||||
#Remove the txt record after validation.
|
|
||||||
dns_gdnsdk_rm() {
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
_info "Using gratisdns.dk"
|
|
||||||
_debug fulldomain "$fulldomain"
|
|
||||||
_debug txtvalue "$txtvalue"
|
|
||||||
if ! _gratisdns_login; then
|
|
||||||
_err "Login failed!"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
if ! _get_domain; then
|
|
||||||
_err "No matching root domain for $fulldomain found"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_findentry "$fulldomain" "$txtvalue"
|
|
||||||
if [ -z "$_id" ]; then
|
|
||||||
_info "Entry doesn't exist, nothing to delete"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
_debug "Deleting record..."
|
|
||||||
_mypost "action=dns_primary_delete_txt&user_domain=$_domain&id=$_id"
|
|
||||||
# removing entry
|
|
||||||
|
|
||||||
if _successful_update; then return 0; fi
|
|
||||||
_err "Couldn't delete entry!"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
|
||||||
|
|
||||||
_checkcredentials() {
|
|
||||||
GDNSDK_Username="${GDNSDK_Username:-$(_readaccountconf_mutable GDNSDK_Username)}"
|
|
||||||
GDNSDK_Password="${GDNSDK_Password:-$(_readaccountconf_mutable GDNSDK_Password)}"
|
|
||||||
|
|
||||||
if [ -z "$GDNSDK_Username" ] || [ -z "$GDNSDK_Password" ]; then
|
|
||||||
GDNSDK_Username=""
|
|
||||||
GDNSDK_Password=""
|
|
||||||
_err "You haven't specified gratisdns.dk username and password yet."
|
|
||||||
_err "Please add credentials and try again."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
#save the credentials to the account conf file.
|
|
||||||
_saveaccountconf_mutable GDNSDK_Username "$GDNSDK_Username"
|
|
||||||
_saveaccountconf_mutable GDNSDK_Password "$GDNSDK_Password"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
_checkcookie() {
|
|
||||||
GDNSDK_Cookie="${GDNSDK_Cookie:-$(_readaccountconf_mutable GDNSDK_Cookie)}"
|
|
||||||
if [ -z "$GDNSDK_Cookie" ]; then
|
|
||||||
_debug "No cached cookie found"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_myget "action="
|
|
||||||
if (echo "$_result" | grep -q "logmeout"); then
|
|
||||||
_debug "Cached cookie still valid"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
_debug "Cached cookie no longer valid"
|
|
||||||
GDNSDK_Cookie=""
|
|
||||||
_saveaccountconf_mutable GDNSDK_Cookie "$GDNSDK_Cookie"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
_gratisdns_login() {
|
|
||||||
if ! _checkcredentials; then return 1; fi
|
|
||||||
|
|
||||||
if _checkcookie; then
|
|
||||||
_debug "Already logged in"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
_debug "Logging into GratisDNS with user $GDNSDK_Username"
|
|
||||||
|
|
||||||
if ! _mypost "login=$GDNSDK_Username&password=$GDNSDK_Password&action=logmein"; then
|
|
||||||
_err "GratisDNS login failed for user $GDNSDK_Username bad RC from _post"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
GDNSDK_Cookie="$(grep -A 15 '302 Found' "$HTTP_HEADER" | _egrep_o 'Cookie: [^;]*' | _head_n 1 | cut -d ' ' -f2)"
|
|
||||||
|
|
||||||
if [ -z "$GDNSDK_Cookie" ]; then
|
|
||||||
_err "GratisDNS login failed for user $GDNSDK_Username. Check $HTTP_HEADER file"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
export GDNSDK_Cookie
|
|
||||||
_saveaccountconf_mutable GDNSDK_Cookie "$GDNSDK_Cookie"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
_myget() {
|
|
||||||
#Adds cookie to request
|
|
||||||
export _H1="Cookie: $GDNSDK_Cookie"
|
|
||||||
_result=$(_get "$GDNSDK_API?$1")
|
|
||||||
}
|
|
||||||
_mypost() {
|
|
||||||
#Adds cookie to request
|
|
||||||
export _H1="Cookie: $GDNSDK_Cookie"
|
|
||||||
_result=$(_post "$1" "$GDNSDK_API")
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_domain() {
|
|
||||||
_myget 'action=dns_primarydns'
|
|
||||||
_domains=$(echo "$_result" | _egrep_o ' domain="[[:alnum:]._-]+' | sed 's/^.*"//')
|
|
||||||
if [ -z "$_domains" ]; then
|
|
||||||
_err "Primary domain list not found!"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
for _domain in $_domains; do
|
|
||||||
if (_endswith "$fulldomain" "$_domain"); then
|
|
||||||
_debug "Root domain: $_domain"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
_successful_update() {
|
|
||||||
if (echo "$_result" | grep -q 'table-success'); then return 0; fi
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
_findentry() {
|
|
||||||
#args $1: fulldomain, $2: txtvalue
|
|
||||||
#returns id of dns entry, if it exists
|
|
||||||
_myget "action=dns_primary_changeDNSsetup&user_domain=$_domain"
|
|
||||||
_debug3 "_result: $_result"
|
|
||||||
|
|
||||||
_tmp_result=$(echo "$_result" | tr -d '\n\r' | _egrep_o "<td>$1</td>\s*<td>$2</td>[^?]*[^&]*&id=[^&]*")
|
|
||||||
_debug _tmp_result "$_tmp_result"
|
|
||||||
if [ -z "${_tmp_result:-}" ]; then
|
|
||||||
_debug "The variable is _tmp_result is not supposed to be empty, there may be something wrong with the script"
|
|
||||||
fi
|
|
||||||
|
|
||||||
_id=$(echo "$_tmp_result" | sed 's/^.*=//')
|
|
||||||
if [ -n "$_id" ]; then
|
|
||||||
_debug "Entry found with _id=$_id"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
|
232
dnsapi/dns_geoscaling.sh
Executable file
232
dnsapi/dns_geoscaling.sh
Executable file
@ -0,0 +1,232 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_geoscaling_info='GeoScaling.com
|
||||||
|
Site: GeoScaling.com
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_geoscaling
|
||||||
|
Options:
|
||||||
|
GEOSCALING_Username Username. This is usually NOT an email address
|
||||||
|
GEOSCALING_Password Password
|
||||||
|
'
|
||||||
|
|
||||||
|
#-- dns_geoscaling_add() - Add TXT record --------------------------------------
|
||||||
|
# Usage: dns_geoscaling_add _acme-challenge.subdomain.domain.com "XyZ123..."
|
||||||
|
|
||||||
|
dns_geoscaling_add() {
|
||||||
|
full_domain=$1
|
||||||
|
txt_value=$2
|
||||||
|
_info "Using DNS-01 Geoscaling DNS2 hook"
|
||||||
|
|
||||||
|
GEOSCALING_Username="${GEOSCALING_Username:-$(_readaccountconf_mutable GEOSCALING_Username)}"
|
||||||
|
GEOSCALING_Password="${GEOSCALING_Password:-$(_readaccountconf_mutable GEOSCALING_Password)}"
|
||||||
|
if [ -z "$GEOSCALING_Username" ] || [ -z "$GEOSCALING_Password" ]; then
|
||||||
|
GEOSCALING_Username=
|
||||||
|
GEOSCALING_Password=
|
||||||
|
_err "No auth details provided. Please set user credentials using the \$GEOSCALING_Username and \$GEOSCALING_Password environment variables."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_saveaccountconf_mutable GEOSCALING_Username "${GEOSCALING_Username}"
|
||||||
|
_saveaccountconf_mutable GEOSCALING_Password "${GEOSCALING_Password}"
|
||||||
|
|
||||||
|
# Fills in the $zone_id and $zone_name
|
||||||
|
find_zone "${full_domain}" || return 1
|
||||||
|
_debug "Zone id '${zone_id}' will be used."
|
||||||
|
|
||||||
|
# We're logged in here
|
||||||
|
|
||||||
|
# we should add ${full_domain} minus the trailing ${zone_name}
|
||||||
|
|
||||||
|
prefix=$(echo "${full_domain}" | sed "s|\\.${zone_name}\$||")
|
||||||
|
|
||||||
|
body="id=${zone_id}&name=${prefix}&type=TXT&content=${txt_value}&ttl=300&prio=0"
|
||||||
|
|
||||||
|
do_post "$body" "https://www.geoscaling.com/dns2/ajax/add_record.php"
|
||||||
|
exit_code="$?"
|
||||||
|
if [ "${exit_code}" -eq 0 ]; then
|
||||||
|
_info "TXT record added successfully."
|
||||||
|
else
|
||||||
|
_err "Couldn't add the TXT record."
|
||||||
|
fi
|
||||||
|
do_logout
|
||||||
|
return "${exit_code}"
|
||||||
|
}
|
||||||
|
|
||||||
|
#-- dns_geoscaling_rm() - Remove TXT record ------------------------------------
|
||||||
|
# Usage: dns_geoscaling_rm _acme-challenge.subdomain.domain.com "XyZ123..."
|
||||||
|
|
||||||
|
dns_geoscaling_rm() {
|
||||||
|
full_domain=$1
|
||||||
|
txt_value=$2
|
||||||
|
_info "Cleaning up after DNS-01 Geoscaling DNS2 hook"
|
||||||
|
|
||||||
|
GEOSCALING_Username="${GEOSCALING_Username:-$(_readaccountconf_mutable GEOSCALING_Username)}"
|
||||||
|
GEOSCALING_Password="${GEOSCALING_Password:-$(_readaccountconf_mutable GEOSCALING_Password)}"
|
||||||
|
if [ -z "$GEOSCALING_Username" ] || [ -z "$GEOSCALING_Password" ]; then
|
||||||
|
GEOSCALING_Username=
|
||||||
|
GEOSCALING_Password=
|
||||||
|
_err "No auth details provided. Please set user credentials using the \$GEOSCALING_Username and \$GEOSCALING_Password environment variables."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_saveaccountconf_mutable GEOSCALING_Username "${GEOSCALING_Username}"
|
||||||
|
_saveaccountconf_mutable GEOSCALING_Password "${GEOSCALING_Password}"
|
||||||
|
|
||||||
|
# fills in the $zone_id
|
||||||
|
find_zone "${full_domain}" || return 1
|
||||||
|
_debug "Zone id '${zone_id}' will be used."
|
||||||
|
|
||||||
|
# Here we're logged in
|
||||||
|
# Find the record id to clean
|
||||||
|
|
||||||
|
# get the domain
|
||||||
|
response=$(do_get "https://www.geoscaling.com/dns2/index.php?module=domain&id=${zone_id}")
|
||||||
|
_debug2 "response" "$response"
|
||||||
|
|
||||||
|
table="$(echo "${response}" | tr -d '\n' | sed 's|.*<div class="box"><div class="boxtitle">Basic Records</div><div class="boxtext"><table|<table|; s|</table>.*|</table>|')"
|
||||||
|
_debug2 table "${table}"
|
||||||
|
names=$(echo "${table}" | _egrep_o 'id="[0-9]+\.name">[^<]*</td>' | sed 's|</td>||; s|.*>||')
|
||||||
|
ids=$(echo "${table}" | _egrep_o 'id="[0-9]+\.name">[^<]*</td>' | sed 's|\.name">.*||; s|id="||')
|
||||||
|
types=$(echo "${table}" | _egrep_o 'id="[0-9]+\.type">[^<]*</td>' | sed 's|</td>||; s|.*>||')
|
||||||
|
values=$(echo "${table}" | _egrep_o 'id="[0-9]+\.content">[^<]*</td>' | sed 's|</td>||; s|.*>||')
|
||||||
|
|
||||||
|
_debug2 names "${names}"
|
||||||
|
_debug2 ids "${ids}"
|
||||||
|
_debug2 types "${types}"
|
||||||
|
_debug2 values "${values}"
|
||||||
|
|
||||||
|
# look for line whose name is ${full_domain}, whose type is TXT, and whose value is ${txt_value}
|
||||||
|
line_num="$(echo "${values}" | grep -F -n -- "${txt_value}" | _head_n 1 | cut -d ':' -f 1)"
|
||||||
|
_debug2 line_num "${line_num}"
|
||||||
|
found_id=
|
||||||
|
if [ -n "$line_num" ]; then
|
||||||
|
type=$(echo "${types}" | sed -n "${line_num}p")
|
||||||
|
name=$(echo "${names}" | sed -n "${line_num}p")
|
||||||
|
id=$(echo "${ids}" | sed -n "${line_num}p")
|
||||||
|
|
||||||
|
_debug2 type "$type"
|
||||||
|
_debug2 name "$name"
|
||||||
|
_debug2 id "$id"
|
||||||
|
_debug2 full_domain "$full_domain"
|
||||||
|
|
||||||
|
if [ "${type}" = "TXT" ] && [ "${name}" = "${full_domain}" ]; then
|
||||||
|
found_id=${id}
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "${found_id}" = "" ]; then
|
||||||
|
_err "Can not find record id."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Remove the record
|
||||||
|
body="id=${zone_id}&record_id=${found_id}"
|
||||||
|
response=$(do_post "$body" "https://www.geoscaling.com/dns2/ajax/delete_record.php")
|
||||||
|
exit_code="$?"
|
||||||
|
if [ "$exit_code" -eq 0 ]; then
|
||||||
|
_info "Record removed successfully."
|
||||||
|
else
|
||||||
|
_err "Could not clean (remove) up the record. Please go to Geoscaling administration interface and clean it by hand."
|
||||||
|
fi
|
||||||
|
do_logout
|
||||||
|
return "${exit_code}"
|
||||||
|
}
|
||||||
|
|
||||||
|
########################## PRIVATE FUNCTIONS ###########################
|
||||||
|
|
||||||
|
do_get() {
|
||||||
|
_url=$1
|
||||||
|
export _H1="Cookie: $geoscaling_phpsessid_cookie"
|
||||||
|
_get "${_url}"
|
||||||
|
}
|
||||||
|
|
||||||
|
do_post() {
|
||||||
|
_body=$1
|
||||||
|
_url=$2
|
||||||
|
export _H1="Cookie: $geoscaling_phpsessid_cookie"
|
||||||
|
_post "${_body}" "${_url}"
|
||||||
|
}
|
||||||
|
|
||||||
|
do_login() {
|
||||||
|
|
||||||
|
_info "Logging in..."
|
||||||
|
|
||||||
|
username_encoded="$(printf "%s" "${GEOSCALING_Username}" | _url_encode)"
|
||||||
|
password_encoded="$(printf "%s" "${GEOSCALING_Password}" | _url_encode)"
|
||||||
|
body="username=${username_encoded}&password=${password_encoded}"
|
||||||
|
|
||||||
|
response=$(_post "$body" "https://www.geoscaling.com/dns2/index.php?module=auth")
|
||||||
|
_debug2 response "${response}"
|
||||||
|
|
||||||
|
#retcode=$(grep '^HTTP[^ ]*' "${HTTP_HEADER}" | _head_n 1 | _egrep_o '[0-9]+$')
|
||||||
|
retcode=$(grep '^HTTP[^ ]*' "${HTTP_HEADER}" | _head_n 1 | cut -d ' ' -f 2)
|
||||||
|
|
||||||
|
if [ "$retcode" != "302" ]; then
|
||||||
|
_err "Geoscaling login failed for user ${GEOSCALING_Username}. Check ${HTTP_HEADER} file"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
geoscaling_phpsessid_cookie="$(grep -i '^set-cookie:' "${HTTP_HEADER}" | _egrep_o 'PHPSESSID=[^;]*;' | tr -d ';')"
|
||||||
|
return 0
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
do_logout() {
|
||||||
|
_info "Logging out."
|
||||||
|
response="$(do_get "https://www.geoscaling.com/dns2/index.php?module=auth")"
|
||||||
|
_debug2 response "$response"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
find_zone() {
|
||||||
|
domain="$1"
|
||||||
|
|
||||||
|
# do login
|
||||||
|
do_login || return 1
|
||||||
|
|
||||||
|
# get zones
|
||||||
|
response="$(do_get "https://www.geoscaling.com/dns2/index.php?module=domains")"
|
||||||
|
|
||||||
|
table="$(echo "${response}" | tr -d '\n' | sed 's|.*<div class="box"><div class="boxtitle">Your domains</div><div class="boxtext"><table|<table|; s|</table>.*|</table>|')"
|
||||||
|
_debug2 table "${table}"
|
||||||
|
zone_names="$(echo "${table}" | _egrep_o '<b>[^<]*</b>' | sed 's|<b>||;s|</b>||')"
|
||||||
|
_debug2 _matches "${zone_names}"
|
||||||
|
# Zone names and zone IDs are in same order
|
||||||
|
zone_ids=$(echo "${table}" | _egrep_o '<a href=.index\.php\?module=domain&id=[0-9]+. onclick="javascript:show_loader\(\);">' | sed 's|.*id=||;s|. .*||')
|
||||||
|
|
||||||
|
_debug2 "These are the zones on this Geoscaling account:"
|
||||||
|
_debug2 "zone_names" "${zone_names}"
|
||||||
|
_debug2 "And these are their respective IDs:"
|
||||||
|
_debug2 "zone_ids" "${zone_ids}"
|
||||||
|
if [ -z "${zone_names}" ] || [ -z "${zone_ids}" ]; then
|
||||||
|
_err "Can not get zone names or IDs."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
# Walk through all possible zone names
|
||||||
|
strip_counter=1
|
||||||
|
while true; do
|
||||||
|
attempted_zone=$(echo "${domain}" | cut -d . -f ${strip_counter}-)
|
||||||
|
|
||||||
|
# All possible zone names have been tried
|
||||||
|
if [ -z "${attempted_zone}" ]; then
|
||||||
|
_err "No zone for domain '${domain}' found."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug "Looking for zone '${attempted_zone}'"
|
||||||
|
|
||||||
|
line_num="$(echo "${zone_names}" | grep -n "^${attempted_zone}\$" | _head_n 1 | cut -d : -f 1)"
|
||||||
|
_debug2 line_num "${line_num}"
|
||||||
|
if [ "$line_num" ]; then
|
||||||
|
zone_id=$(echo "${zone_ids}" | sed -n "${line_num}p")
|
||||||
|
zone_name=$(echo "${zone_names}" | sed -n "${line_num}p")
|
||||||
|
if [ -z "${zone_id}" ]; then
|
||||||
|
_err "Can not find zone id."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
_debug "Found relevant zone '${attempted_zone}' with id '${zone_id}' - will be used for domain '${domain}'."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug "Zone '${attempted_zone}' doesn't exist, let's try a less specific zone."
|
||||||
|
strip_counter=$(_math "${strip_counter}" + 1)
|
||||||
|
done
|
||||||
|
}
|
||||||
|
# vim: et:ts=2:sw=2:
|
178
dnsapi/dns_googledomains.sh
Executable file
178
dnsapi/dns_googledomains.sh
Executable file
@ -0,0 +1,178 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
dns_googledomains_info='Google Domains
|
||||||
|
Site: Domains.Google.com
|
||||||
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_googledomains
|
||||||
|
Options:
|
||||||
|
GOOGLEDOMAINS_ACCESS_TOKEN API Access Token
|
||||||
|
GOOGLEDOMAINS_ZONE Zone
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/4545
|
||||||
|
Author: Alex Leigh <leigh@alexleigh.me>
|
||||||
|
'
|
||||||
|
|
||||||
|
GOOGLEDOMAINS_API="https://acmedns.googleapis.com/v1/acmeChallengeSets"
|
||||||
|
|
||||||
|
######## Public functions ########
|
||||||
|
|
||||||
|
#Usage: dns_googledomains_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
dns_googledomains_add() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
_info "Invoking Google Domains ACME DNS API."
|
||||||
|
|
||||||
|
if ! _dns_googledomains_setup; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
zone="$(_dns_googledomains_get_zone "$fulldomain")"
|
||||||
|
if [ -z "$zone" ]; then
|
||||||
|
_err "Could not find a Google Domains-managed zone containing the requested domain."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug zone "$zone"
|
||||||
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
|
_info "Adding TXT record for $fulldomain."
|
||||||
|
if _dns_googledomains_api "$zone" ":rotateChallenges" "{\"accessToken\":\"$GOOGLEDOMAINS_ACCESS_TOKEN\",\"recordsToAdd\":[{\"fqdn\":\"$fulldomain\",\"digest\":\"$txtvalue\"}],\"keepExpiredRecords\":true}"; then
|
||||||
|
if _contains "$response" "$txtvalue"; then
|
||||||
|
_info "TXT record added."
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
_err "Error adding TXT record."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
_err "Error adding TXT record."
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#Usage: dns_googledomains_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
|
dns_googledomains_rm() {
|
||||||
|
fulldomain=$1
|
||||||
|
txtvalue=$2
|
||||||
|
|
||||||
|
_info "Invoking Google Domains ACME DNS API."
|
||||||
|
|
||||||
|
if ! _dns_googledomains_setup; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
zone="$(_dns_googledomains_get_zone "$fulldomain")"
|
||||||
|
if [ -z "$zone" ]; then
|
||||||
|
_err "Could not find a Google Domains-managed domain based on request."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug zone "$zone"
|
||||||
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
|
_info "Removing TXT record for $fulldomain."
|
||||||
|
if _dns_googledomains_api "$zone" ":rotateChallenges" "{\"accessToken\":\"$GOOGLEDOMAINS_ACCESS_TOKEN\",\"recordsToRemove\":[{\"fqdn\":\"$fulldomain\",\"digest\":\"$txtvalue\"}],\"keepExpiredRecords\":true}"; then
|
||||||
|
if _contains "$response" "$txtvalue"; then
|
||||||
|
_err "Error removing TXT record."
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
_info "TXT record removed."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
_err "Error removing TXT record."
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
######## Private functions ########
|
||||||
|
|
||||||
|
_dns_googledomains_setup() {
|
||||||
|
if [ -n "$GOOGLEDOMAINS_SETUP_COMPLETED" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
GOOGLEDOMAINS_ACCESS_TOKEN="${GOOGLEDOMAINS_ACCESS_TOKEN:-$(_readaccountconf_mutable GOOGLEDOMAINS_ACCESS_TOKEN)}"
|
||||||
|
GOOGLEDOMAINS_ZONE="${GOOGLEDOMAINS_ZONE:-$(_readaccountconf_mutable GOOGLEDOMAINS_ZONE)}"
|
||||||
|
|
||||||
|
if [ -z "$GOOGLEDOMAINS_ACCESS_TOKEN" ]; then
|
||||||
|
GOOGLEDOMAINS_ACCESS_TOKEN=""
|
||||||
|
_err "Google Domains access token was not specified."
|
||||||
|
_err "Please visit Google Domains Security settings to provision an ACME DNS API access token."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$GOOGLEDOMAINS_ZONE" ]; then
|
||||||
|
_savedomainconf GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
|
||||||
|
_savedomainconf GOOGLEDOMAINS_ZONE "$GOOGLEDOMAINS_ZONE"
|
||||||
|
else
|
||||||
|
_saveaccountconf_mutable GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
|
||||||
|
_clearaccountconf_mutable GOOGLEDOMAINS_ZONE
|
||||||
|
_clearaccountconf GOOGLEDOMAINS_ZONE
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
|
||||||
|
_debug GOOGLEDOMAINS_ZONE "$GOOGLEDOMAINS_ZONE"
|
||||||
|
|
||||||
|
GOOGLEDOMAINS_SETUP_COMPLETED=1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_dns_googledomains_get_zone() {
|
||||||
|
domain=$1
|
||||||
|
|
||||||
|
# Use zone directly if provided
|
||||||
|
if [ "$GOOGLEDOMAINS_ZONE" ]; then
|
||||||
|
if ! _dns_googledomains_api "$GOOGLEDOMAINS_ZONE"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$GOOGLEDOMAINS_ZONE"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
i=2
|
||||||
|
while true; do
|
||||||
|
curr=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||||
|
_debug curr "$curr"
|
||||||
|
|
||||||
|
if [ -z "$curr" ]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if _dns_googledomains_api "$curr"; then
|
||||||
|
echo "$curr"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
i=$(_math "$i" + 1)
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
_dns_googledomains_api() {
|
||||||
|
zone=$1
|
||||||
|
apimethod=$2
|
||||||
|
data="$3"
|
||||||
|
|
||||||
|
if [ -z "$data" ]; then
|
||||||
|
response="$(_get "$GOOGLEDOMAINS_API/$zone$apimethod")"
|
||||||
|
else
|
||||||
|
_debug data "$data"
|
||||||
|
export _H1="Content-Type: application/json"
|
||||||
|
response="$(_post "$data" "$GOOGLEDOMAINS_API/$zone$apimethod")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
_debug response "$response"
|
||||||
|
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "Error"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if _contains "$response" "\"error\": {"; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
@ -1,15 +1,14 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
########################################################################
|
dns_he_info='Hurricane Electric HE.net
|
||||||
# Hurricane Electric hook script for acme.sh
|
Site: dns.he.net
|
||||||
#
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_he
|
||||||
# Environment variables:
|
Options:
|
||||||
#
|
HE_Username Username
|
||||||
# - $HE_Username (your dns.he.net username)
|
HE_Password Password
|
||||||
# - $HE_Password (your dns.he.net password)
|
Issues: github.com/angel333/acme.sh/issues/
|
||||||
#
|
Author: Ondrej Simek <me@ondrejsimek.com>
|
||||||
# Author: Ondrej Simek <me@ondrejsimek.com>
|
'
|
||||||
# Git repo: https://github.com/angel333/acme.sh
|
|
||||||
|
|
||||||
#-- dns_he_add() - Add TXT record --------------------------------------
|
#-- dns_he_add() - Add TXT record --------------------------------------
|
||||||
# Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..."
|
# Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..."
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
#
|
dns_hetzner_info='Hetzner.com
|
||||||
#HETZNER_Token="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
Site: Hetzner.com
|
||||||
#
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_hetzner
|
||||||
|
Options:
|
||||||
|
HETZNER_Token API Token
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/2943
|
||||||
|
'
|
||||||
|
|
||||||
HETZNER_Api="https://dns.hetzner.com/api/v1"
|
HETZNER_Api="https://dns.hetzner.com/api/v1"
|
||||||
|
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
#
|
dns_hexonet_info='Hexonet.com
|
||||||
# Hexonet_Login="username!roleId"
|
Site: Hexonet.com
|
||||||
#
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_hexonet
|
||||||
# Hexonet_Password="rolePassword"
|
Options:
|
||||||
|
Hexonet_Login Login. E.g. "username!roleId"
|
||||||
|
Hexonet_Password Role Password
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/2389
|
||||||
|
'
|
||||||
|
|
||||||
Hexonet_Api="https://coreapi.1api.net/api/call.cgi"
|
Hexonet_Api="https://coreapi.1api.net/api/call.cgi"
|
||||||
|
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
# shellcheck disable=SC2034
|
||||||
# hosting.de API
|
dns_hostingde_info='Hosting.de
|
||||||
|
Site: Hosting.de
|
||||||
# Values to export:
|
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_hostingde
|
||||||
# export HOSTINGDE_ENDPOINT='https://secure.hosting.de'
|
Options:
|
||||||
# export HOSTINGDE_APIKEY='xxxxx'
|
HOSTINGDE_ENDPOINT Endpoint. E.g. "https://secure.hosting.de"
|
||||||
|
HOSTINGDE_APIKEY API Key
|
||||||
|
Issues: github.com/acmesh-official/acme.sh/issues/2058
|
||||||
|
'
|
||||||
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user