Compare commits
No commits in common. "master" and "2.9.0" have entirely different histories.
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: neilpang
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
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
|
||||||
|
|||||||
40
.github/auto-comment.yml
vendored
Normal file
40
.github/auto-comment.yml
vendored
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# Comment to a new issue.
|
||||||
|
issuesOpened: >
|
||||||
|
If this is a bug report, please upgrade to the latest code and try again:
|
||||||
|
|
||||||
|
如果有 bug, 请先更新到最新版试试:
|
||||||
|
|
||||||
|
```
|
||||||
|
acme.sh --upgrade
|
||||||
|
```
|
||||||
|
|
||||||
|
please also provide the log with `--debug 2`.
|
||||||
|
|
||||||
|
同时请提供调试输出 `--debug 2`
|
||||||
|
|
||||||
|
see: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh
|
||||||
|
|
||||||
|
Without `--debug 2` log, your issue will NEVER get replied.
|
||||||
|
|
||||||
|
没有调试输出, 你的 issue 不会得到任何解答.
|
||||||
|
|
||||||
|
|
||||||
|
pullRequestOpened: >
|
||||||
|
First, NEVER send a PR to `master` branch, it will NEVER be accepted. Please send to the `dev` branch instead.
|
||||||
|
|
||||||
|
If this is a PR to support new DNS API or new notification API, please read this guide first:
|
||||||
|
https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide
|
||||||
|
|
||||||
|
Please check the guide items one by one.
|
||||||
|
|
||||||
|
Then add your usage here:
|
||||||
|
https://github.com/acmesh-official/acme.sh/wiki/dnsapi
|
||||||
|
|
||||||
|
Or some other wiki pages:
|
||||||
|
|
||||||
|
https://github.com/acmesh-official/acme.sh/wiki/deployhooks
|
||||||
|
|
||||||
|
https://github.com/acmesh-official/acme.sh/wiki/notify
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
369
.github/workflows/DNS.yml
vendored
369
.github/workflows/DNS.yml
vendored
@ -11,9 +11,6 @@ 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:
|
||||||
@ -40,7 +37,7 @@ jobs:
|
|||||||
- name: "Read this: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Test"
|
- name: "Read this: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Test"
|
||||||
run: |
|
run: |
|
||||||
echo "Read this: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Test"
|
echo "Read this: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Test"
|
||||||
if [ "${{github.repository_owner}}" != "acmesh-official" ]; then
|
if [ "${{github.actor}}" != "Neilpang" ]; then
|
||||||
false
|
false
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -52,47 +49,37 @@ jobs:
|
|||||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||||
TestingDomain: ${{ secrets.TestingDomain }}
|
TestingDomain: ${{ secrets.TestingDomain }}
|
||||||
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
|
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 }}
|
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||||
CASE: le_test_dnsapi
|
CASE: le_test_dnsapi
|
||||||
TEST_LOCAL: 1
|
TEST_LOCAL: 1
|
||||||
DEBUG: ${{ secrets.DEBUG }}
|
DEBUG: 1
|
||||||
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@v4
|
- uses: actions/checkout@v2
|
||||||
- name: Clone acmetest
|
- name: Clone acmetest
|
||||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
run: cd .. && git clone 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
|
||||||
if [ "${{ secrets.TokenName1}}" ] ; then
|
if [ "${{ secrets.TokenName1}}" ] ; then
|
||||||
echo "${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}" >> docker.env
|
echo "${{ secrets.TokenName1}}=${{ secrets.TokenValue1}}" >> env.list
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName2}}" ] ; then
|
if [ "${{ secrets.TokenName2}}" ] ; then
|
||||||
echo "${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}" >> docker.env
|
echo "${{ secrets.TokenName2}}=${{ secrets.TokenValue2}}" >> env.list
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName3}}" ] ; then
|
if [ "${{ secrets.TokenName3}}" ] ; then
|
||||||
echo "${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}" >> docker.env
|
echo "${{ secrets.TokenName3}}=${{ secrets.TokenValue3}}" >> env.list
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName4}}" ] ; then
|
if [ "${{ secrets.TokenName4}}" ] ; then
|
||||||
echo "${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}" >> docker.env
|
echo "${{ secrets.TokenName4}}=${{ secrets.TokenValue4}}" >> env.list
|
||||||
fi
|
fi
|
||||||
if [ "${{ secrets.TokenName5}}" ] ; then
|
if [ "${{ secrets.TokenName5}}" ] ; then
|
||||||
echo "${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}" >> docker.env
|
echo "${{ secrets.TokenName5}}=${{ secrets.TokenValue5}}" >> env.list
|
||||||
fi
|
fi
|
||||||
|
echo "TEST_DNS_NO_WILDCARD" >> env.list
|
||||||
|
echo "TEST_DNS_SLEEP" >> env.list
|
||||||
- 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
|
||||||
@ -100,47 +87,36 @@ jobs:
|
|||||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||||
TestingDomain: ${{ secrets.TestingDomain }}
|
TestingDomain: ${{ secrets.TestingDomain }}
|
||||||
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
|
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 }}
|
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||||
CASE: le_test_dnsapi
|
CASE: le_test_dnsapi
|
||||||
TEST_LOCAL: 1
|
TEST_LOCAL: 1
|
||||||
DEBUG: ${{ secrets.DEBUG }}
|
DEBUG: 1
|
||||||
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@v4
|
- uses: actions/checkout@v2
|
||||||
- name: Install tools
|
- name: Install tools
|
||||||
run: brew install socat
|
run: brew install socat
|
||||||
- name: Clone acmetest
|
- name: Clone acmetest
|
||||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
run: cd .. && git clone 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
|
||||||
@ -148,23 +124,15 @@ jobs:
|
|||||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||||
TestingDomain: ${{ secrets.TestingDomain }}
|
TestingDomain: ${{ secrets.TestingDomain }}
|
||||||
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
|
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 }}
|
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||||
CASE: le_test_dnsapi
|
CASE: le_test_dnsapi
|
||||||
TEST_LOCAL: 1
|
TEST_LOCAL: 1
|
||||||
DEBUG: ${{ secrets.DEBUG }}
|
DEBUG: 1
|
||||||
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@v4
|
- uses: actions/checkout@v2
|
||||||
- name: Install cygwin base packages with chocolatey
|
- name: Install cygwin base packages with chocolatey
|
||||||
run: |
|
run: |
|
||||||
choco config get cacheLocation
|
choco config get cacheLocation
|
||||||
@ -172,341 +140,108 @@ 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 https://mirrors.kernel.org/sourceware/cygwin/ -P socat,curl,cron,unzip,git
|
C:\tools\cygwin\cygwinsetup.exe -qgnNdO -R C:/tools/cygwin -s http://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 --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
run: cd .. && git clone 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: ubuntu-latest
|
runs-on: macos-latest
|
||||||
needs: Windows
|
needs: Windows
|
||||||
env:
|
env:
|
||||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||||
TestingDomain: ${{ secrets.TestingDomain }}
|
TestingDomain: ${{ secrets.TestingDomain }}
|
||||||
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
|
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 }}
|
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||||
CASE: le_test_dnsapi
|
CASE: le_test_dnsapi
|
||||||
TEST_LOCAL: 1
|
TEST_LOCAL: 1
|
||||||
DEBUG: ${{ secrets.DEBUG }}
|
DEBUG: 1
|
||||||
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@v4
|
- uses: actions/checkout@v2
|
||||||
- name: Clone acmetest
|
- name: Clone acmetest
|
||||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||||
- uses: vmactions/freebsd-vm@v1
|
- uses: vmactions/freebsd-vm@v0.1.4
|
||||||
with:
|
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}}'
|
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG ${{ 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-latest
|
||||||
|
|
||||||
OpenBSD:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: FreeBSD
|
needs: FreeBSD
|
||||||
env:
|
env:
|
||||||
TEST_DNS : ${{ secrets.TEST_DNS }}
|
TEST_DNS : ${{ secrets.TEST_DNS }}
|
||||||
TestingDomain: ${{ secrets.TestingDomain }}
|
TestingDomain: ${{ secrets.TestingDomain }}
|
||||||
TEST_DNS_NO_WILDCARD: ${{ secrets.TEST_DNS_NO_WILDCARD }}
|
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 }}
|
TEST_DNS_SLEEP: ${{ secrets.TEST_DNS_SLEEP }}
|
||||||
CASE: le_test_dnsapi
|
CASE: le_test_dnsapi
|
||||||
TEST_LOCAL: 1
|
TEST_LOCAL: 1
|
||||||
DEBUG: ${{ secrets.DEBUG }}
|
DEBUG: 1
|
||||||
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@v4
|
- uses: actions/checkout@v2
|
||||||
- name: Clone acmetest
|
- name: Clone acmetest
|
||||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||||
- uses: vmactions/openbsd-vm@v1
|
- uses: vmactions/solaris-vm@v0.0.3
|
||||||
with:
|
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}}'
|
envs: 'TEST_DNS TestingDomain TEST_DNS_NO_WILDCARD TEST_DNS_SLEEP CASE TEST_LOCAL DEBUG ${{ secrets.TokenName1}} ${{ secrets.TokenName2}} ${{ secrets.TokenName3}} ${{ secrets.TokenName4}} ${{ secrets.TokenName5}}'
|
||||||
prepare: pkg_add socat curl
|
prepare: pkgutil -y -i socat curl
|
||||||
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
|
|
||||||
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
|
|
||||||
run: |
|
|
||||||
pkg set-mediator -v -I default@1.1 openssl
|
|
||||||
export PATH=/usr/gnu/bin:$PATH
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
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
|
fi
|
||||||
cd ../acmetest
|
cd ../acmetest
|
||||||
./letest.sh
|
./letest.sh
|
||||||
|
|||||||
71
.github/workflows/DragonFlyBSD.yml
vendored
71
.github/workflows/DragonFlyBSD.yml
vendored
@ -1,71 +0,0 @@
|
|||||||
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) Pretend Pear X1
|
|
||||||
#- 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
|
|
||||||
|
|
||||||
|
|
||||||
76
.github/workflows/FreeBSD.yml
vendored
76
.github/workflows/FreeBSD.yml
vendored
@ -1,76 +0,0 @@
|
|||||||
name: FreeBSD
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- '*'
|
|
||||||
paths:
|
|
||||||
- '*.sh'
|
|
||||||
- '.github/workflows/FreeBSD.yml'
|
|
||||||
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- dev
|
|
||||||
paths:
|
|
||||||
- '*.sh'
|
|
||||||
- '.github/workflows/FreeBSD.yml'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
FreeBSD:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
|
||||||
CA_ECDSA: ""
|
|
||||||
CA: ""
|
|
||||||
CA_EMAIL: ""
|
|
||||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
|
||||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
|
||||||
CA_ECDSA: ""
|
|
||||||
CA: ""
|
|
||||||
CA_EMAIL: ""
|
|
||||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
|
||||||
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/freebsd-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 socat curl wget
|
|
||||||
usesh: true
|
|
||||||
copyback: false
|
|
||||||
run: |
|
|
||||||
cd ../acmetest \
|
|
||||||
&& ./letest.sh
|
|
||||||
|
|
||||||
|
|
||||||
127
.github/workflows/LetsEncrypt.yml
vendored
Normal file
127
.github/workflows/LetsEncrypt.yml
vendored
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
name: LetsEncrypt
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- '*'
|
||||||
|
paths:
|
||||||
|
- '**.sh'
|
||||||
|
- '**.yml'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- dev
|
||||||
|
paths:
|
||||||
|
- '**.sh'
|
||||||
|
- '**.yml'
|
||||||
|
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
Ubuntu:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
TEST_LOCAL: 1
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install tools
|
||||||
|
run: sudo apt-get install -y socat
|
||||||
|
- name: Clone acmetest
|
||||||
|
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||||
|
- name: Run acmetest
|
||||||
|
run: cd ../acmetest && sudo --preserve-env ./letest.sh
|
||||||
|
|
||||||
|
MacOS:
|
||||||
|
runs-on: macos-latest
|
||||||
|
env:
|
||||||
|
TEST_LOCAL: 1
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install tools
|
||||||
|
run: brew install socat
|
||||||
|
- name: Clone acmetest
|
||||||
|
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||||
|
- name: Run acmetest
|
||||||
|
run: cd ../acmetest && sudo --preserve-env ./letest.sh
|
||||||
|
|
||||||
|
Windows:
|
||||||
|
runs-on: windows-latest
|
||||||
|
env:
|
||||||
|
TEST_LOCAL: 1
|
||||||
|
#The 80 port is used by Windows server, we have to use a custom port, tunnel will also use this port.
|
||||||
|
Le_HTTPPort: 8888
|
||||||
|
steps:
|
||||||
|
- name: Set git to use LF
|
||||||
|
run: |
|
||||||
|
git config --global core.autocrlf false
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install cygwin base packages with chocolatey
|
||||||
|
run: |
|
||||||
|
choco config get cacheLocation
|
||||||
|
choco install --no-progress cygwin
|
||||||
|
shell: cmd
|
||||||
|
- name: Install cygwin additional packages
|
||||||
|
run: |
|
||||||
|
C:\tools\cygwin\cygwinsetup.exe -qgnNdO -R C:/tools/cygwin -s http://mirrors.kernel.org/sourceware/cygwin/ -P socat,curl,cron,unzip,git
|
||||||
|
shell: cmd
|
||||||
|
- name: Set ENV
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
echo PATH=C:\tools\cygwin\bin;C:\tools\cygwin\usr\bin >> %GITHUB_ENV%
|
||||||
|
- name: Check ENV
|
||||||
|
shell: cmd
|
||||||
|
run: |
|
||||||
|
echo "PATH=%PATH%"
|
||||||
|
- name: Clone acmetest
|
||||||
|
shell: cmd
|
||||||
|
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||||
|
- name: Run acmetest
|
||||||
|
shell: cmd
|
||||||
|
run: cd ../acmetest && bash.exe -c ./letest.sh
|
||||||
|
|
||||||
|
FreeBSD:
|
||||||
|
runs-on: macos-latest
|
||||||
|
env:
|
||||||
|
TEST_LOCAL: 1
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: vmactions/cf-tunnel@v0.0.2
|
||||||
|
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 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||||
|
- uses: vmactions/freebsd-vm@v0.1.4
|
||||||
|
with:
|
||||||
|
envs: 'TEST_LOCAL TestingDomain'
|
||||||
|
nat: |
|
||||||
|
"8080": "80"
|
||||||
|
prepare: pkg install -y socat curl
|
||||||
|
usesh: true
|
||||||
|
run: |
|
||||||
|
cd ../acmetest && ./letest.sh
|
||||||
|
|
||||||
|
Solaris:
|
||||||
|
runs-on: macos-latest
|
||||||
|
env:
|
||||||
|
TEST_LOCAL: 1
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: vmactions/cf-tunnel@v0.0.2
|
||||||
|
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 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||||
|
- uses: vmactions/solaris-vm@v0.0.3
|
||||||
|
with:
|
||||||
|
envs: 'TEST_LOCAL TestingDomain'
|
||||||
|
nat: |
|
||||||
|
"8080": "80"
|
||||||
|
prepare: pkgutil -y -i socat curl
|
||||||
|
run: |
|
||||||
|
cd ../acmetest && ./letest.sh
|
||||||
|
|
||||||
48
.github/workflows/Linux.yml
vendored
48
.github/workflows/Linux.yml
vendored
@ -1,48 +0,0 @@
|
|||||||
name: Linux
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- '*'
|
|
||||||
paths:
|
|
||||||
- '*.sh'
|
|
||||||
- '.github/workflows/Linux.yml'
|
|
||||||
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- dev
|
|
||||||
paths:
|
|
||||||
- '*.sh'
|
|
||||||
- '.github/workflows/Linux.yml'
|
|
||||||
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
Linux:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
os: ["ubuntu:latest", "debian:latest", "almalinux:latest", "fedora:latest", "centos:7", "opensuse/leap:latest", "alpine:latest", "oraclelinux:8", "kalilinux/kali", "archlinux:latest", "mageia", "gentoo/stage3"]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
env:
|
|
||||||
TEST_LOCAL: 1
|
|
||||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
|
||||||
TEST_ACME_Server: "LetsEncrypt.org_test"
|
|
||||||
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/
|
|
||||||
- name: Run acmetest
|
|
||||||
run: |
|
|
||||||
cd ../acmetest \
|
|
||||||
&& ./rundocker.sh testplat ${{ matrix.os }}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
60
.github/workflows/MacOS.yml
vendored
60
.github/workflows/MacOS.yml
vendored
@ -1,60 +0,0 @@
|
|||||||
name: MacOS
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- '*'
|
|
||||||
paths:
|
|
||||||
- '*.sh'
|
|
||||||
- '.github/workflows/MacOS.yml'
|
|
||||||
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- dev
|
|
||||||
paths:
|
|
||||||
- '*.sh'
|
|
||||||
- '.github/workflows/MacOS.yml'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
MacOS:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
|
||||||
CA_ECDSA: ""
|
|
||||||
CA: ""
|
|
||||||
CA_EMAIL: ""
|
|
||||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
|
||||||
#- 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: macos-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 }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Install tools
|
|
||||||
run: brew install socat
|
|
||||||
- name: Clone acmetest
|
|
||||||
run: |
|
|
||||||
cd .. \
|
|
||||||
&& git clone --depth=1 https://github.com/acmesh-official/acmetest.git \
|
|
||||||
&& cp -r acme.sh acmetest/
|
|
||||||
- name: Run acmetest
|
|
||||||
run: |
|
|
||||||
cd ../acmetest \
|
|
||||||
&& sudo --preserve-env ./letest.sh
|
|
||||||
|
|
||||||
|
|
||||||
71
.github/workflows/NetBSD.yml
vendored
71
.github/workflows/NetBSD.yml
vendored
@ -1,71 +0,0 @@
|
|||||||
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) Pretend Pear X1
|
|
||||||
#- 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
75
.github/workflows/Omnios.yml
vendored
@ -1,75 +0,0 @@
|
|||||||
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) Pretend Pear X1
|
|
||||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
|
||||||
CA_ECDSA: ""
|
|
||||||
CA: ""
|
|
||||||
CA_EMAIL: ""
|
|
||||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
|
||||||
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
76
.github/workflows/OpenBSD.yml
vendored
@ -1,76 +0,0 @@
|
|||||||
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) Pretend Pear X1
|
|
||||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
|
||||||
CA_ECDSA: ""
|
|
||||||
CA: ""
|
|
||||||
CA_EMAIL: ""
|
|
||||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
47
.github/workflows/PebbleStrict.yml
vendored
47
.github/workflows/PebbleStrict.yml
vendored
@ -4,21 +4,14 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- '*'
|
- '*'
|
||||||
paths:
|
paths:
|
||||||
- '*.sh'
|
- '**.sh'
|
||||||
- '.github/workflows/PebbleStrict.yml'
|
- '**.yml'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- dev
|
- dev
|
||||||
paths:
|
paths:
|
||||||
- '*.sh'
|
- '**.sh'
|
||||||
- '.github/workflows/PebbleStrict.yml'
|
- '**.yml'
|
||||||
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
PebbleStrict:
|
PebbleStrict:
|
||||||
@ -26,14 +19,14 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
TestingDomain: example.com
|
TestingDomain: example.com
|
||||||
TestingAltDomains: www.example.com
|
TestingAltDomains: www.example.com
|
||||||
TEST_ACME_Server: https://localhost:14000/dir
|
ACME_DIRECTORY: https://localhost:14000/dir
|
||||||
HTTPS_INSECURE: 1
|
HTTPS_INSECURE: 1
|
||||||
Le_HTTPPort: 5002
|
Le_HTTPPort: 5002
|
||||||
TEST_LOCAL: 1
|
TEST_LOCAL: 1
|
||||||
TEST_CA: "Pebble Intermediate CA"
|
TEST_CA: "Pebble Intermediate CA"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v2
|
||||||
- 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
|
||||||
@ -41,32 +34,6 @@ jobs:
|
|||||||
- 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 --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
run: cd .. && git clone https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
||||||
- name: Run acmetest
|
|
||||||
run: cd ../acmetest && ./letest.sh
|
|
||||||
|
|
||||||
PebbleStrict_IPCert:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
env:
|
|
||||||
TestingDomain: 1.23.45.67
|
|
||||||
TEST_ACME_Server: https://localhost:14000/dir
|
|
||||||
HTTPS_INSECURE: 1
|
|
||||||
Le_HTTPPort: 5002
|
|
||||||
Le_TLSPort: 5001
|
|
||||||
TEST_LOCAL: 1
|
|
||||||
TEST_CA: "Pebble Intermediate CA"
|
|
||||||
TEST_IPCERT: 1
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Install tools
|
|
||||||
run: sudo apt-get install -y socat
|
|
||||||
- name: Run Pebble
|
|
||||||
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
|
|
||||||
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
|
||||||
75
.github/workflows/Solaris.yml
vendored
75
.github/workflows/Solaris.yml
vendored
@ -1,75 +0,0 @@
|
|||||||
name: Solaris
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- '*'
|
|
||||||
paths:
|
|
||||||
- '*.sh'
|
|
||||||
- '.github/workflows/Solaris.yml'
|
|
||||||
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- dev
|
|
||||||
paths:
|
|
||||||
- '*.sh'
|
|
||||||
- '.github/workflows/Solaris.yml'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
Solaris:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
|
||||||
CA_ECDSA: ""
|
|
||||||
CA: ""
|
|
||||||
CA_EMAIL: ""
|
|
||||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
|
||||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
|
||||||
CA_ECDSA: ""
|
|
||||||
CA: ""
|
|
||||||
CA_EMAIL: ""
|
|
||||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
|
||||||
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/solaris-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: pkgutil -y -i socat curl wget
|
|
||||||
copyback: false
|
|
||||||
run: |
|
|
||||||
cd ../acmetest \
|
|
||||||
&& ./letest.sh
|
|
||||||
|
|
||||||
|
|
||||||
103
.github/workflows/Ubuntu.yml
vendored
103
.github/workflows/Ubuntu.yml
vendored
@ -1,103 +0,0 @@
|
|||||||
name: Ubuntu
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- '*'
|
|
||||||
paths:
|
|
||||||
- '*.sh'
|
|
||||||
- '.github/workflows/Ubuntu.yml'
|
|
||||||
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- dev
|
|
||||||
paths:
|
|
||||||
- '*.sh'
|
|
||||||
- '.github/workflows/Ubuntu.yml'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
Ubuntu:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
|
||||||
CA_ECDSA: ""
|
|
||||||
CA: ""
|
|
||||||
CA_EMAIL: ""
|
|
||||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
|
||||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
|
||||||
CA_ECDSA: ""
|
|
||||||
CA: ""
|
|
||||||
CA_EMAIL: ""
|
|
||||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
|
||||||
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: ""
|
|
||||||
- TEST_ACME_Server: "https://localhost:9000/acme/acme/directory"
|
|
||||||
CA_ECDSA: "Smallstep Intermediate CA"
|
|
||||||
CA: "Smallstep Intermediate CA"
|
|
||||||
CA_EMAIL: ""
|
|
||||||
TEST_PREFERRED_CHAIN: ""
|
|
||||||
NO_REVOKE: 1
|
|
||||||
- TEST_ACME_Server: "https://localhost:9000/acme/acme/directory"
|
|
||||||
CA_ECDSA: "Smallstep Intermediate CA"
|
|
||||||
CA: "Smallstep Intermediate CA"
|
|
||||||
CA_EMAIL: ""
|
|
||||||
TEST_PREFERRED_CHAIN: ""
|
|
||||||
NO_REVOKE: 1
|
|
||||||
TEST_IPCERT: 1
|
|
||||||
TestingDomain: "172.17.0.1"
|
|
||||||
|
|
||||||
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 }}
|
|
||||||
NO_ECC_384: ${{ matrix.NO_ECC_384 }}
|
|
||||||
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
|
|
||||||
NO_REVOKE: ${{ matrix.NO_REVOKE }}
|
|
||||||
TEST_IPCERT: ${{ matrix.TEST_IPCERT }}
|
|
||||||
TestingDomain: ${{ matrix.TestingDomain }}
|
|
||||||
ACME_USE_WGET: ${{ matrix.ACME_USE_WGET }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Install tools
|
|
||||||
run: sudo apt-get install -y socat wget
|
|
||||||
- name: Start StepCA
|
|
||||||
if: ${{ matrix.TEST_ACME_Server=='https://localhost:9000/acme/acme/directory' }}
|
|
||||||
run: |
|
|
||||||
docker run --rm -d \
|
|
||||||
-p 9000:9000 \
|
|
||||||
-e "DOCKER_STEPCA_INIT_NAME=Smallstep" \
|
|
||||||
-e "DOCKER_STEPCA_INIT_DNS_NAMES=localhost,$(hostname -f)" \
|
|
||||||
-e "DOCKER_STEPCA_INIT_REMOTE_MANAGEMENT=true" \
|
|
||||||
-e "DOCKER_STEPCA_INIT_PASSWORD=test" \
|
|
||||||
--name stepca \
|
|
||||||
smallstep/step-ca:0.23.1
|
|
||||||
|
|
||||||
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 cat /home/step/certs/root_ca.crt | sudo bash -c "cat - >>/etc/ssl/certs/ca-certificates.crt"
|
|
||||||
- name: Clone acmetest
|
|
||||||
run: |
|
|
||||||
cd .. \
|
|
||||||
&& git clone --depth=1 https://github.com/acmesh-official/acmetest.git \
|
|
||||||
&& cp -r acme.sh acmetest/
|
|
||||||
- name: Run acmetest
|
|
||||||
run: |
|
|
||||||
cd ../acmetest \
|
|
||||||
&& sudo --preserve-env ./letest.sh
|
|
||||||
|
|
||||||
|
|
||||||
78
.github/workflows/Windows.yml
vendored
78
.github/workflows/Windows.yml
vendored
@ -1,78 +0,0 @@
|
|||||||
name: Windows
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- '*'
|
|
||||||
paths:
|
|
||||||
- '*.sh'
|
|
||||||
- '.github/workflows/Windows.yml'
|
|
||||||
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- dev
|
|
||||||
paths:
|
|
||||||
- '*.sh'
|
|
||||||
- '.github/workflows/Windows.yml'
|
|
||||||
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
Windows:
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- TEST_ACME_Server: "LetsEncrypt.org_test"
|
|
||||||
CA_ECDSA: ""
|
|
||||||
CA: ""
|
|
||||||
CA_EMAIL: ""
|
|
||||||
TEST_PREFERRED_CHAIN: (STAGING) Pretend Pear X1
|
|
||||||
#- 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: windows-latest
|
|
||||||
env:
|
|
||||||
TEST_ACME_Server: ${{ matrix.TEST_ACME_Server }}
|
|
||||||
CA_ECDSA: ${{ matrix.CA_ECDSA }}
|
|
||||||
CA: ${{ matrix.CA }}
|
|
||||||
CA_EMAIL: ${{ matrix.CA_EMAIL }}
|
|
||||||
TEST_LOCAL: 1
|
|
||||||
#The 80 port is used by Windows server, we have to use a custom port, tunnel will also use this port.
|
|
||||||
Le_HTTPPort: 8888
|
|
||||||
TEST_PREFERRED_CHAIN: ${{ matrix.TEST_PREFERRED_CHAIN }}
|
|
||||||
steps:
|
|
||||||
- name: Set git to use LF
|
|
||||||
run: |
|
|
||||||
git config --global core.autocrlf false
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Install cygwin base packages with chocolatey
|
|
||||||
run: |
|
|
||||||
choco config get cacheLocation
|
|
||||||
choco install --no-progress cygwin
|
|
||||||
shell: cmd
|
|
||||||
- name: Install cygwin additional packages
|
|
||||||
run: |
|
|
||||||
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
|
|
||||||
- name: Set ENV
|
|
||||||
shell: cmd
|
|
||||||
run: |
|
|
||||||
echo PATH=C:\tools\cygwin\bin;C:\tools\cygwin\usr\bin;%PATH% >> %GITHUB_ENV%
|
|
||||||
- name: Check ENV
|
|
||||||
shell: cmd
|
|
||||||
run: |
|
|
||||||
echo "PATH=%PATH%"
|
|
||||||
- name: Clone acmetest
|
|
||||||
shell: cmd
|
|
||||||
run: cd .. && git clone --depth=1 https://github.com/acmesh-official/acmetest.git && cp -r acme.sh acmetest/
|
|
||||||
- name: Run acmetest
|
|
||||||
shell: cmd
|
|
||||||
run: cd ../acmetest && bash.exe -c ./letest.sh
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
19
.github/workflows/dockerhub.yml
vendored
19
.github/workflows/dockerhub.yml
vendored
@ -6,15 +6,6 @@ on:
|
|||||||
- '*'
|
- '*'
|
||||||
tags:
|
tags:
|
||||||
- '*'
|
- '*'
|
||||||
paths:
|
|
||||||
- '**.sh'
|
|
||||||
- "Dockerfile"
|
|
||||||
- '.github/workflows/dockerhub.yml'
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
CheckToken:
|
CheckToken:
|
||||||
@ -28,9 +19,9 @@ jobs:
|
|||||||
id: step_one
|
id: step_one
|
||||||
run: |
|
run: |
|
||||||
if [ "$DOCKER_PASSWORD" ] ; then
|
if [ "$DOCKER_PASSWORD" ] ; then
|
||||||
echo "hasToken=true" >>$GITHUB_OUTPUT
|
echo "::set-output name=hasToken::true"
|
||||||
else
|
else
|
||||||
echo "hasToken=false" >>$GITHUB_OUTPUT
|
echo "::set-output name=hasToken::false"
|
||||||
fi
|
fi
|
||||||
- name: Check the value
|
- name: Check the value
|
||||||
run: echo ${{ steps.step_one.outputs.hasToken }}
|
run: echo ${{ steps.step_one.outputs.hasToken }}
|
||||||
@ -41,11 +32,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@v4
|
uses: actions/checkout@v2
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v1
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v1
|
||||||
- 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
19
.github/workflows/issue.yml
vendored
@ -1,19 +0,0 @@
|
|||||||
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
30
.github/workflows/pr_dns.yml
vendored
@ -1,30 +0,0 @@
|
|||||||
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
30
.github/workflows/pr_notify.yml
vendored
@ -1,30 +0,0 @@
|
|||||||
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 ✨
|
|
||||||
`
|
|
||||||
})
|
|
||||||
|
|
||||||
15
.github/workflows/shellcheck.yml
vendored
15
.github/workflows/shellcheck.yml
vendored
@ -5,33 +5,28 @@ on:
|
|||||||
- '*'
|
- '*'
|
||||||
paths:
|
paths:
|
||||||
- '**.sh'
|
- '**.sh'
|
||||||
- '.github/workflows/shellcheck.yml'
|
- '**.yml'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- dev
|
- dev
|
||||||
paths:
|
paths:
|
||||||
- '**.sh'
|
- '**.sh'
|
||||||
- '.github/workflows/shellcheck.yml'
|
- '**.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@v4
|
- uses: actions/checkout@v2
|
||||||
- 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 -e SC2089 **/*.sh && echo "shellcheck OK"
|
run: shellcheck -V && shellcheck -e SC2181 **/*.sh && echo "shellcheck OK"
|
||||||
|
|
||||||
shfmt:
|
shfmt:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v2
|
||||||
- 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
|
||||||
|
|||||||
19
Dockerfile
19
Dockerfile
@ -1,6 +1,7 @@
|
|||||||
FROM alpine:3.17
|
FROM alpine:3.12
|
||||||
|
|
||||||
RUN apk --no-cache add -f \
|
RUN apk update -f \
|
||||||
|
&& apk --no-cache add -f \
|
||||||
openssl \
|
openssl \
|
||||||
openssh-client \
|
openssh-client \
|
||||||
coreutils \
|
coreutils \
|
||||||
@ -12,8 +13,7 @@ RUN apk --no-cache add -f \
|
|||||||
oath-toolkit-oathtool \
|
oath-toolkit-oathtool \
|
||||||
tar \
|
tar \
|
||||||
libidn \
|
libidn \
|
||||||
jq \
|
&& rm -rf /var/cache/apk/*
|
||||||
cronie
|
|
||||||
|
|
||||||
ENV LE_CONFIG_HOME /acme.sh
|
ENV LE_CONFIG_HOME /acme.sh
|
||||||
|
|
||||||
@ -22,11 +22,11 @@ ARG AUTO_UPGRADE=1
|
|||||||
ENV AUTO_UPGRADE $AUTO_UPGRADE
|
ENV AUTO_UPGRADE $AUTO_UPGRADE
|
||||||
|
|
||||||
#Install
|
#Install
|
||||||
COPY ./ /install_acme.sh/
|
ADD ./ /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#> /proc/1/fd/1 2>/proc/1/fd/2#' | crontab -
|
RUN ln -s /root/.acme.sh/acme.sh /usr/local/bin/acme.sh && crontab -l | grep acme.sh | sed 's#> /dev/null##' | crontab -
|
||||||
|
|
||||||
RUN for verb in help \
|
RUN for verb in help \
|
||||||
version \
|
version \
|
||||||
@ -42,7 +42,6 @@ RUN for verb in help \
|
|||||||
revoke \
|
revoke \
|
||||||
remove \
|
remove \
|
||||||
list \
|
list \
|
||||||
info \
|
|
||||||
showcsr \
|
showcsr \
|
||||||
install-cronjob \
|
install-cronjob \
|
||||||
uninstall-cronjob \
|
uninstall-cronjob \
|
||||||
@ -58,17 +57,17 @@ RUN for verb in help \
|
|||||||
deactivate-account \
|
deactivate-account \
|
||||||
set-notify \
|
set-notify \
|
||||||
set-default-ca \
|
set-default-ca \
|
||||||
set-default-chain \
|
|
||||||
; do \
|
; do \
|
||||||
printf -- "%b" "#!/usr/bin/env sh\n/root/.acme.sh/acme.sh --${verb} --config-home /acme.sh \"\$@\"" >/usr/local/bin/--${verb} && chmod +x /usr/local/bin/--${verb} \
|
printf -- "%b" "#!/usr/bin/env sh\n/root/.acme.sh/acme.sh --${verb} --config-home /acme.sh \"\$@\"" >/usr/local/bin/--${verb} && chmod +x /usr/local/bin/--${verb} \
|
||||||
; done
|
; done
|
||||||
|
|
||||||
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 \
|
||||||
exec crond -n -s -m off \n \
|
trap \"echo stop && killall crond && exit 0\" SIGTERM SIGINT \n \
|
||||||
|
crond && while true; do sleep 1; done;\n \
|
||||||
else \n \
|
else \n \
|
||||||
exec -- \"\$@\"\n \
|
exec -- \"\$@\"\n \
|
||||||
fi\n" >/entry.sh && chmod +x /entry.sh
|
fi" >/entry.sh && chmod +x /entry.sh
|
||||||
|
|
||||||
VOLUME /acme.sh
|
VOLUME /acme.sh
|
||||||
|
|
||||||
|
|||||||
95
README.md
95
README.md
@ -1,15 +1,6 @@
|
|||||||
# 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/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/Ubuntu.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/DragonFlyBSD.yml)
|
|
||||||
[](https://github.com/acmesh-official/acme.sh/actions/workflows/Omnios.yml)
|
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
@ -24,18 +15,18 @@
|
|||||||
|
|
||||||
- An ACME protocol client written purely in Shell (Unix shell) language.
|
- An ACME protocol client written purely in Shell (Unix shell) language.
|
||||||
- Full ACME protocol implementation.
|
- Full ACME protocol implementation.
|
||||||
- Support ECDSA certs
|
- Support ACME v1 and ACME v2
|
||||||
- Support SAN and wildcard certs
|
- Support ACME v2 wildcard certs
|
||||||
- Simple, powerful and very easy to use. You only need 3 minutes to learn it.
|
- Simple, powerful and very easy to use. You only need 3 minutes to learn it.
|
||||||
- Bash, dash and sh compatible.
|
- Bash, dash and sh compatible.
|
||||||
- Purely written in Shell with no dependencies on python.
|
- Purely written in Shell with no dependencies on python or the official Let's Encrypt client.
|
||||||
- Just one script to issue, renew and install your certificates automatically.
|
- Just one script to issue, renew and install your certificates automatically.
|
||||||
- DOES NOT require `root/sudoer` access.
|
- DOES NOT require `root/sudoer` access.
|
||||||
- Docker ready
|
- Docker friendly
|
||||||
- IPv6 ready
|
- IPv6 support
|
||||||
- Cron job notifications for renewal or error etc.
|
- Cron job notifications for renewal or error etc.
|
||||||
|
|
||||||
It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates.
|
It's probably the `easiest & smartest` shell script to automatically issue & renew the free certificates from Let's Encrypt.
|
||||||
|
|
||||||
Wiki: https://github.com/acmesh-official/acme.sh/wiki
|
Wiki: https://github.com/acmesh-official/acme.sh/wiki
|
||||||
|
|
||||||
@ -51,12 +42,14 @@ 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](https://control-webpanel.com)
|
- [CentOS Web Panel](http://centos-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)
|
||||||
|
|
||||||
@ -64,43 +57,37 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
|
|||||||
|
|
||||||
| NO | Status| Platform|
|
| NO | Status| Platform|
|
||||||
|----|-------|---------|
|
|----|-------|---------|
|
||||||
|1|[](https://github.com/acmesh-official/acme.sh/actions/workflows/MacOS.yml)|Mac OSX
|
|1|[](https://github.com/acmesh-official/acme.sh/actions?query=workflow%3ALetsEncrypt)|Mac OSX
|
||||||
|2|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Windows.yml)|Windows (cygwin with curl, openssl and crontab included)
|
|2|[](https://github.com/acmesh-official/acme.sh/actions?query=workflow%3ALetsEncrypt)|Windows (cygwin with curl, openssl and crontab included)
|
||||||
|3|[](https://github.com/acmesh-official/acme.sh/actions/workflows/FreeBSD.yml)|FreeBSD
|
|3|[](https://github.com/acmesh-official/acme.sh/actions?query=workflow%3ALetsEncrypt)|FreeBSD
|
||||||
|4|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Solaris.yml)|Solaris
|
|4|[](https://github.com/acmesh-official/acme.sh/actions?query=workflow%3ALetsEncrypt)|Solaris
|
||||||
|5|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Ubuntu.yml)| Ubuntu
|
|5|[](https://github.com/acmesh-official/acme.sh/actions?query=workflow%3ALetsEncrypt)| Ubuntu
|
||||||
|6|NA|pfsense
|
|6|[](https://github.com/acmesh-official/acmetest#here-are-the-latest-status)|pfsense
|
||||||
|7|[](https://github.com/acmesh-official/acme.sh/actions/workflows/OpenBSD.yml)|OpenBSD
|
|7|[](https://github.com/acmesh-official/acmetest#here-are-the-latest-status)|OpenBSD
|
||||||
|8|[](https://github.com/acmesh-official/acme.sh/actions/workflows/NetBSD.yml)|NetBSD
|
|8|[](https://github.com/acmesh-official/acmetest#here-are-the-latest-status)| Debian
|
||||||
|9|[](https://github.com/acmesh-official/acme.sh/actions/workflows/DragonFlyBSD.yml)|DragonFlyBSD
|
|9|[](https://github.com/acmesh-official/acmetest#here-are-the-latest-status)|CentOS
|
||||||
|10|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Omnios.yml)|Omnios
|
|10|[](https://github.com/acmesh-official/acmetest#here-are-the-latest-status)|openSUSE
|
||||||
|11|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)| Debian
|
|11|[](https://github.com/acmesh-official/acmetest#here-are-the-latest-status)|Alpine Linux (with curl)
|
||||||
|12|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|CentOS
|
|12|[](https://github.com/acmesh-official/acmetest#here-are-the-latest-status)|Archlinux
|
||||||
|13|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|openSUSE
|
|13|[](https://github.com/acmesh-official/acmetest#here-are-the-latest-status)|fedora
|
||||||
|14|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Alpine Linux (with curl)
|
|14|[](https://github.com/acmesh-official/acmetest#here-are-the-latest-status)|Kali Linux
|
||||||
|15|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Archlinux
|
|15|[](https://github.com/acmesh-official/acmetest#here-are-the-latest-status)|Oracle Linux
|
||||||
|16|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|fedora
|
|16|[](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)
|
||||||
|17|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Kali Linux
|
|17|-----| Cloud Linux https://github.com/acmesh-official/acme.sh/issues/111
|
||||||
|18|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Oracle Linux
|
|18|[](https://github.com/acmesh-official/acmetest#here-are-the-latest-status)|Mageia
|
||||||
|19|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Mageia
|
|19|-----| 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
|
|20|[](https://github.com/acmesh-official/acmetest#here-are-the-latest-status)|Gentoo Linux
|
||||||
|11|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|ClearLinux
|
|21|[](https://github.com/acmesh-official/acmetest#here-are-the-latest-status)|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)
|
|
||||||
|
|
||||||
|
For all build statuses, check our [weekly build project](https://github.com/acmesh-official/acmetest):
|
||||||
Check our [testing project](https://github.com/acmesh-official/acmetest):
|
|
||||||
|
|
||||||
https://github.com/acmesh-official/acmetest
|
https://github.com/acmesh-official/acmetest
|
||||||
|
|
||||||
# Supported CA
|
# Supported CA
|
||||||
|
|
||||||
- [ZeroSSL.com CA](https://github.com/acmesh-official/acme.sh/wiki/ZeroSSL.com-CA)(default)
|
- Letsencrypt.org CA(default)
|
||||||
- Letsencrypt.org CA
|
- [ZeroSSL.com CA](https://github.com/acmesh-official/acme.sh/wiki/ZeroSSL.com-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)
|
|
||||||
- [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
|
||||||
|
|
||||||
@ -360,6 +347,10 @@ 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:
|
||||||
@ -380,12 +371,10 @@ Please look at the `keylength` parameter above.
|
|||||||
|
|
||||||
Valid values are:
|
Valid values are:
|
||||||
|
|
||||||
1. **ec-256 (prime256v1, "ECDSA P-256", which is the default key type)**
|
1. **ec-256 (prime256v1, "ECDSA P-256")**
|
||||||
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
|
||||||
@ -480,7 +469,7 @@ TODO:
|
|||||||
|
|
||||||
### Code Contributors
|
### Code Contributors
|
||||||
|
|
||||||
This project exists thanks to all the people who contribute.
|
This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)].
|
||||||
<a href="https://github.com/acmesh-official/acme.sh/graphs/contributors"><img src="https://opencollective.com/acmesh/contributors.svg?width=890&button=false" /></a>
|
<a href="https://github.com/acmesh-official/acme.sh/graphs/contributors"><img src="https://opencollective.com/acmesh/contributors.svg?width=890&button=false" /></a>
|
||||||
|
|
||||||
### Financial Contributors
|
### Financial Contributors
|
||||||
@ -506,8 +495,6 @@ 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
|
||||||
|
|||||||
@ -1,98 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
# Here is a script to deploy cert to hashicorp consul using curl
|
|
||||||
# (https://www.consul.io/)
|
|
||||||
#
|
|
||||||
# it requires following environment variables:
|
|
||||||
#
|
|
||||||
# CONSUL_PREFIX - this contains the prefix path in consul
|
|
||||||
# CONSUL_HTTP_ADDR - consul requires this to find your consul server
|
|
||||||
#
|
|
||||||
# additionally, you need to ensure that CONSUL_HTTP_TOKEN is available
|
|
||||||
# to access the consul server
|
|
||||||
|
|
||||||
#returns 0 means success, otherwise error.
|
|
||||||
|
|
||||||
######## Public functions #####################
|
|
||||||
|
|
||||||
#domain keyfile certfile cafile fullchain
|
|
||||||
consul_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"
|
|
||||||
|
|
||||||
# validate required env vars
|
|
||||||
_getdeployconf CONSUL_PREFIX
|
|
||||||
if [ -z "$CONSUL_PREFIX" ]; then
|
|
||||||
_err "CONSUL_PREFIX needs to be defined (contains prefix path in vault)"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_savedeployconf CONSUL_PREFIX "$CONSUL_PREFIX"
|
|
||||||
|
|
||||||
_getdeployconf CONSUL_HTTP_ADDR
|
|
||||||
if [ -z "$CONSUL_HTTP_ADDR" ]; then
|
|
||||||
_err "CONSUL_HTTP_ADDR needs to be defined (contains consul connection address)"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_savedeployconf CONSUL_HTTP_ADDR "$CONSUL_HTTP_ADDR"
|
|
||||||
|
|
||||||
CONSUL_CMD=$(command -v consul)
|
|
||||||
|
|
||||||
# force CLI, but the binary does not exist => error
|
|
||||||
if [ -n "$USE_CLI" ] && [ -z "$CONSUL_CMD" ]; then
|
|
||||||
_err "Cannot find the consul binary!"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# use the CLI first
|
|
||||||
if [ -n "$USE_CLI" ] || [ -n "$CONSUL_CMD" ]; then
|
|
||||||
_info "Found consul binary, deploying with CLI"
|
|
||||||
consul_deploy_cli "$CONSUL_CMD" "$CONSUL_PREFIX"
|
|
||||||
else
|
|
||||||
_info "Did not find consul binary, deploying with API"
|
|
||||||
consul_deploy_api "$CONSUL_HTTP_ADDR" "$CONSUL_PREFIX" "$CONSUL_HTTP_TOKEN"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
consul_deploy_api() {
|
|
||||||
CONSUL_HTTP_ADDR="$1"
|
|
||||||
CONSUL_PREFIX="$2"
|
|
||||||
CONSUL_HTTP_TOKEN="$3"
|
|
||||||
|
|
||||||
URL="$CONSUL_HTTP_ADDR/v1/kv/$CONSUL_PREFIX"
|
|
||||||
export _H1="X-Consul-Token: $CONSUL_HTTP_TOKEN"
|
|
||||||
|
|
||||||
if [ -n "$FABIO" ]; then
|
|
||||||
_post "$(cat "$_cfullchain")" "$URL/${_cdomain}-cert.pem" '' "PUT" || return 1
|
|
||||||
_post "$(cat "$_ckey")" "$URL/${_cdomain}-key.pem" '' "PUT" || return 1
|
|
||||||
else
|
|
||||||
_post "$(cat "$_ccert")" "$URL/${_cdomain}/cert.pem" '' "PUT" || return 1
|
|
||||||
_post "$(cat "$_ckey")" "$URL/${_cdomain}/cert.key" '' "PUT" || return 1
|
|
||||||
_post "$(cat "$_cca")" "$URL/${_cdomain}/chain.pem" '' "PUT" || return 1
|
|
||||||
_post "$(cat "$_cfullchain")" "$URL/${_cdomain}/fullchain.pem" '' "PUT" || return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
consul_deploy_cli() {
|
|
||||||
CONSUL_CMD="$1"
|
|
||||||
CONSUL_PREFIX="$2"
|
|
||||||
|
|
||||||
if [ -n "$FABIO" ]; then
|
|
||||||
$CONSUL_CMD kv put "${CONSUL_PREFIX}/${_cdomain}-cert.pem" @"$_cfullchain" || return 1
|
|
||||||
$CONSUL_CMD kv put "${CONSUL_PREFIX}/${_cdomain}-key.pem" @"$_ckey" || return 1
|
|
||||||
else
|
|
||||||
$CONSUL_CMD kv put "${CONSUL_PREFIX}/${_cdomain}/cert.pem" value=@"$_ccert" || return 1
|
|
||||||
$CONSUL_CMD kv put "${CONSUL_PREFIX}/${_cdomain}/cert.key" value=@"$_ckey" || return 1
|
|
||||||
$CONSUL_CMD kv put "${CONSUL_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1
|
|
||||||
$CONSUL_CMD kv put "${CONSUL_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
@ -3,29 +3,18 @@
|
|||||||
# 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"
|
||||||
@ -33,9 +22,6 @@ 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"
|
||||||
@ -46,166 +32,31 @@ 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")
|
||||||
|
|
||||||
_debug2 _cert "$_cert"
|
_debug _cert "$_cert"
|
||||||
_debug2 _key "$_key"
|
_debug _key "$_key"
|
||||||
|
|
||||||
if [ "$(id -u)" = 0 ]; then
|
if [ "$(id -u)" = 0 ]; then
|
||||||
_getdeployconf DEPLOY_CPANEL_USER
|
if [ -z "$DEPLOY_CPANEL_USER" ]; then
|
||||||
# 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
|
||||||
_debug DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER"
|
_savedomainconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER"
|
||||||
_savedeployconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER"
|
_response=$(uapi --user="$DEPLOY_CPANEL_USER" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
||||||
|
|
||||||
_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
|
else
|
||||||
# "classic" mode - will only try to deploy to the primary domain; will not check UAPI first
|
_response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
||||||
if [ -n "$_uapi_user" ]; then
|
|
||||||
_response=$(uapi --user="$_uapi_user" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
|
||||||
else
|
|
||||||
_response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "${_response#*"$uapi_error_response"}" != "$_response" ]; then
|
|
||||||
_err "Error in deploying certificate:"
|
|
||||||
_err "$_response"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
_debug response "$_response"
|
|
||||||
_info "Certificate successfully deployed"
|
|
||||||
return 0
|
|
||||||
fi
|
fi
|
||||||
}
|
error_response="status: 0"
|
||||||
|
if test "${_response#*$error_response}" != "$_response"; then
|
||||||
######## Private functions #####################
|
_err "Error in deploying certificate:"
|
||||||
|
_err "$_response"
|
||||||
# Internal utility to process YML from UAPI - looks at main_domain, sub_domains, addon domains and parked domains
|
return 1
|
||||||
#[response]
|
fi
|
||||||
__cpanel_parse_response() {
|
|
||||||
if [ $# -gt 0 ]; then resp="$*"; else resp="$(cat)"; fi
|
_debug response "$_response"
|
||||||
|
_info "Certificate successfully deployed"
|
||||||
echo "$resp" |
|
return 0
|
||||||
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,27 +273,16 @@ _check_curl_version() {
|
|||||||
_minor="$(_getfield "$_cversion" 2 '.')"
|
_minor="$(_getfield "$_cversion" 2 '.')"
|
||||||
_debug2 "_minor" "$_minor"
|
_debug2 "_minor" "$_minor"
|
||||||
|
|
||||||
if [ "$_major" -ge "8" ]; then
|
if [ "$_major$_minor" -lt "740" ]; then
|
||||||
#ok
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
if [ "$_major" = "7" ]; then
|
|
||||||
if [ "$_minor" -lt "40" ]; then
|
|
||||||
_err "curl v$_cversion doesn't support unit socket"
|
|
||||||
_err "Please upgrade to curl 7.40 or later."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
if [ "$_minor" -lt "50" ]; then
|
|
||||||
_debug "Use short host name"
|
|
||||||
export _CURL_NO_HOST=1
|
|
||||||
else
|
|
||||||
export _CURL_NO_HOST=
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
_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
|
||||||
|
_debug "Use short host name"
|
||||||
|
export _CURL_NO_HOST=1
|
||||||
|
else
|
||||||
|
export _CURL_NO_HOST=
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,51 +36,43 @@ fritzbox_deploy() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Clear traces of incorrectly stored values
|
_fritzbox_username="${DEPLOY_FRITZBOX_USERNAME}"
|
||||||
_clearaccountconf DEPLOY_FRITZBOX_USERNAME
|
_fritzbox_password="${DEPLOY_FRITZBOX_PASSWORD}"
|
||||||
_clearaccountconf DEPLOY_FRITZBOX_PASSWORD
|
_fritzbox_url="${DEPLOY_FRITZBOX_URL}"
|
||||||
_clearaccountconf DEPLOY_FRITZBOX_URL
|
|
||||||
|
|
||||||
# Read config from saved values or env
|
_debug _fritzbox_url "$_fritzbox_url"
|
||||||
_getdeployconf DEPLOY_FRITZBOX_USERNAME
|
_debug _fritzbox_username "$_fritzbox_username"
|
||||||
_getdeployconf DEPLOY_FRITZBOX_PASSWORD
|
_secure_debug _fritzbox_password "$_fritzbox_password"
|
||||||
_getdeployconf DEPLOY_FRITZBOX_URL
|
if [ -z "$_fritzbox_username" ]; then
|
||||||
|
|
||||||
_debug DEPLOY_FRITZBOX_URL "$DEPLOY_FRITZBOX_URL"
|
|
||||||
_debug DEPLOY_FRITZBOX_USERNAME "$DEPLOY_FRITZBOX_USERNAME"
|
|
||||||
_secure_debug DEPLOY_FRITZBOX_PASSWORD "$DEPLOY_FRITZBOX_PASSWORD"
|
|
||||||
|
|
||||||
if [ -z "$DEPLOY_FRITZBOX_USERNAME" ]; then
|
|
||||||
_err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME."
|
_err "FRITZ!Box username is not found, please define DEPLOY_FRITZBOX_USERNAME."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
if [ -z "$DEPLOY_FRITZBOX_PASSWORD" ]; then
|
if [ -z "$_fritzbox_password" ]; then
|
||||||
_err "FRITZ!Box password is not found, please define DEPLOY_FRITZBOX_PASSWORD."
|
_err "FRITZ!Box password is not found, please define DEPLOY_FRITZBOX_PASSWORD."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
if [ -z "$DEPLOY_FRITZBOX_URL" ]; then
|
if [ -z "$_fritzbox_url" ]; then
|
||||||
_err "FRITZ!Box url is not found, please define DEPLOY_FRITZBOX_URL."
|
_err "FRITZ!Box url is not found, please define DEPLOY_FRITZBOX_URL."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Save current values
|
_saveaccountconf DEPLOY_FRITZBOX_USERNAME "${_fritzbox_username}"
|
||||||
_savedeployconf DEPLOY_FRITZBOX_USERNAME "$DEPLOY_FRITZBOX_USERNAME"
|
_saveaccountconf DEPLOY_FRITZBOX_PASSWORD "${_fritzbox_password}"
|
||||||
_savedeployconf DEPLOY_FRITZBOX_PASSWORD "$DEPLOY_FRITZBOX_PASSWORD"
|
_saveaccountconf DEPLOY_FRITZBOX_URL "${_fritzbox_url}"
|
||||||
_savedeployconf DEPLOY_FRITZBOX_URL "$DEPLOY_FRITZBOX_URL"
|
|
||||||
|
|
||||||
# Do not check for a valid SSL certificate, because initially the cert is not valid, so it could not install the LE generated certificate
|
# Do not check for a valid SSL certificate, because initially the cert is not valid, so it could not install the LE generated certificate
|
||||||
export HTTPS_INSECURE=1
|
export HTTPS_INSECURE=1
|
||||||
|
|
||||||
_info "Log in to the FRITZ!Box"
|
_info "Log in to the FRITZ!Box"
|
||||||
_fritzbox_challenge="$(_get "${DEPLOY_FRITZBOX_URL}/login_sid.lua" | sed -e 's/^.*<Challenge>//' -e 's/<\/Challenge>.*$//')"
|
_fritzbox_challenge="$(_get "${_fritzbox_url}/login_sid.lua" | sed -e 's/^.*<Challenge>//' -e 's/<\/Challenge>.*$//')"
|
||||||
if _exists iconv; then
|
if _exists iconv; then
|
||||||
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${DEPLOY_FRITZBOX_PASSWORD}" | iconv -f ASCII -t UTF16LE | _digest md5 hex)"
|
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | iconv -f ASCII -t UTF16LE | _digest md5 hex)"
|
||||||
elif _exists uconv; then
|
elif _exists uconv; then
|
||||||
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${DEPLOY_FRITZBOX_PASSWORD}" | uconv -f ASCII -t UTF16LE | _digest md5 hex)"
|
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | uconv -f ASCII -t UTF16LE | _digest md5 hex)"
|
||||||
else
|
else
|
||||||
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${DEPLOY_FRITZBOX_PASSWORD}" | perl -p -e 'use Encode qw/encode/; print encode("UTF-16LE","$_"); $_="";' | _digest md5 hex)"
|
_fritzbox_hash="$(printf "%s-%s" "${_fritzbox_challenge}" "${_fritzbox_password}" | perl -p -e 'use Encode qw/encode/; print encode("UTF-16LE","$_"); $_="";' | _digest md5 hex)"
|
||||||
fi
|
fi
|
||||||
_fritzbox_sid="$(_get "${DEPLOY_FRITZBOX_URL}/login_sid.lua?sid=0000000000000000&username=${DEPLOY_FRITZBOX_USERNAME}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*<SID>//' -e 's/<\/SID>.*$//')"
|
_fritzbox_sid="$(_get "${_fritzbox_url}/login_sid.lua?sid=0000000000000000&username=${_fritzbox_username}&response=${_fritzbox_challenge}-${_fritzbox_hash}" | sed -e 's/^.*<SID>//' -e 's/<\/SID>.*$//')"
|
||||||
|
|
||||||
if [ -z "${_fritzbox_sid}" ] || [ "${_fritzbox_sid}" = "0000000000000000" ]; then
|
if [ -z "${_fritzbox_sid}" ] || [ "${_fritzbox_sid}" = "0000000000000000" ]; then
|
||||||
_err "Logging in to the FRITZ!Box failed. Please check username, password and URL."
|
_err "Logging in to the FRITZ!Box failed. Please check username, password and URL."
|
||||||
@ -112,7 +104,7 @@ fritzbox_deploy() {
|
|||||||
_info "Upload certificate to the FRITZ!Box"
|
_info "Upload certificate to the FRITZ!Box"
|
||||||
|
|
||||||
export _H1="Content-type: multipart/form-data boundary=${_post_boundary}"
|
export _H1="Content-type: multipart/form-data boundary=${_post_boundary}"
|
||||||
_post "$(cat "${_post_request}")" "${DEPLOY_FRITZBOX_URL}/cgi-bin/firmwarecfg" | grep SSL
|
_post "$(cat "${_post_request}")" "${_fritzbox_url}/cgi-bin/firmwarecfg" | grep SSL
|
||||||
|
|
||||||
retval=$?
|
retval=$?
|
||||||
if [ $retval = 0 ]; then
|
if [ $retval = 0 ]; then
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
# 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).
|
# 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/).
|
||||||
# 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
|
||||||
@ -57,7 +56,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.gcore.com/auth/jwt/login")
|
_response=$(_post "$_request" "https://api.gcdn.co/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"
|
||||||
@ -70,8 +69,8 @@ gcore_cdn_deploy() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
_info "Find CDN resource with cname $_cdomain"
|
_info "Find CDN resource with cname $_cdomain"
|
||||||
export _H2="Authorization:Bearer $_token"
|
export _H2="Authorization:Token $_token"
|
||||||
_response=$(_get "https://api.gcore.com/cdn/resources")
|
_response=$(_get "https://api.gcdn.co/resources")
|
||||||
_debug _response "$_response"
|
_debug _response "$_response"
|
||||||
_regex="\"primary_resource\":null},"
|
_regex="\"primary_resource\":null},"
|
||||||
_debug _regex "$_regex"
|
_debug _regex "$_regex"
|
||||||
@ -103,7 +102,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.gcore.com/cdn/sslData")
|
_response=$(_post "$_request" "https://api.gcdn.co/sslData")
|
||||||
_debug _response "$_response"
|
_debug _response "$_response"
|
||||||
_regex=".*\"id\":\([0-9]*\).*$"
|
_regex=".*\"id\":\([0-9]*\).*$"
|
||||||
_debug _regex "$_regex"
|
_debug _regex "$_regex"
|
||||||
@ -118,7 +117,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.gcore.com/cdn/resources/$_resourceId" '' "PUT")
|
_response=$(_post "$_request" "https://api.gcdn.co/resources/$_resourceId" '' "PUT")
|
||||||
_debug _response "$_response"
|
_debug _response "$_response"
|
||||||
_regex=".*\"sslData\":\([0-9]*\).*$"
|
_regex=".*\"sslData\":\([0-9]*\).*$"
|
||||||
_debug _regex "$_regex"
|
_debug _regex "$_regex"
|
||||||
@ -134,7 +133,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.gcore.com/cdn/sslData/$_sslDataOld" '' "DELETE")
|
_response=$(_post '' "https://api.gcdn.co/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,19 +36,6 @@
|
|||||||
# 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 #####################
|
||||||
|
|
||||||
@ -59,7 +46,6 @@ 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"
|
||||||
@ -67,8 +53,11 @@ 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"
|
if [ -f "${DOMAIN_CONF}" ]; then
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
. "${DOMAIN_CONF}"
|
||||||
|
fi
|
||||||
|
|
||||||
_debug _cdomain "${_cdomain}"
|
_debug _cdomain "${_cdomain}"
|
||||||
_debug _ckey "${_ckey}"
|
_debug _ckey "${_ckey}"
|
||||||
@ -77,8 +66,6 @@ haproxy_deploy() {
|
|||||||
_debug _cfullchain "${_cfullchain}"
|
_debug _cfullchain "${_cfullchain}"
|
||||||
|
|
||||||
# PEM_PATH is optional. If not provided then assume "${DEPLOY_HAPROXY_PEM_PATH_DEFAULT}"
|
# PEM_PATH is optional. If not provided then assume "${DEPLOY_HAPROXY_PEM_PATH_DEFAULT}"
|
||||||
_getdeployconf DEPLOY_HAPROXY_PEM_PATH
|
|
||||||
_debug2 DEPLOY_HAPROXY_PEM_PATH "${DEPLOY_HAPROXY_PEM_PATH}"
|
|
||||||
if [ -n "${DEPLOY_HAPROXY_PEM_PATH}" ]; then
|
if [ -n "${DEPLOY_HAPROXY_PEM_PATH}" ]; then
|
||||||
Le_Deploy_haproxy_pem_path="${DEPLOY_HAPROXY_PEM_PATH}"
|
Le_Deploy_haproxy_pem_path="${DEPLOY_HAPROXY_PEM_PATH}"
|
||||||
_savedomainconf Le_Deploy_haproxy_pem_path "${Le_Deploy_haproxy_pem_path}"
|
_savedomainconf Le_Deploy_haproxy_pem_path "${Le_Deploy_haproxy_pem_path}"
|
||||||
@ -95,23 +82,14 @@ haproxy_deploy() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# PEM_NAME is optional. If not provided then assume "${DEPLOY_HAPROXY_PEM_NAME_DEFAULT}"
|
# PEM_NAME is optional. If not provided then assume "${DEPLOY_HAPROXY_PEM_NAME_DEFAULT}"
|
||||||
_getdeployconf DEPLOY_HAPROXY_PEM_NAME
|
|
||||||
_debug2 DEPLOY_HAPROXY_PEM_NAME "${DEPLOY_HAPROXY_PEM_NAME}"
|
|
||||||
if [ -n "${DEPLOY_HAPROXY_PEM_NAME}" ]; then
|
if [ -n "${DEPLOY_HAPROXY_PEM_NAME}" ]; then
|
||||||
Le_Deploy_haproxy_pem_name="${DEPLOY_HAPROXY_PEM_NAME}"
|
Le_Deploy_haproxy_pem_name="${DEPLOY_HAPROXY_PEM_NAME}"
|
||||||
_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}"
|
||||||
_getdeployconf DEPLOY_HAPROXY_BUNDLE
|
|
||||||
_debug2 DEPLOY_HAPROXY_BUNDLE "${DEPLOY_HAPROXY_BUNDLE}"
|
|
||||||
if [ -n "${DEPLOY_HAPROXY_BUNDLE}" ]; then
|
if [ -n "${DEPLOY_HAPROXY_BUNDLE}" ]; then
|
||||||
Le_Deploy_haproxy_bundle="${DEPLOY_HAPROXY_BUNDLE}"
|
Le_Deploy_haproxy_bundle="${DEPLOY_HAPROXY_BUNDLE}"
|
||||||
_savedomainconf Le_Deploy_haproxy_bundle "${Le_Deploy_haproxy_bundle}"
|
_savedomainconf Le_Deploy_haproxy_bundle "${Le_Deploy_haproxy_bundle}"
|
||||||
@ -120,8 +98,6 @@ haproxy_deploy() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# ISSUER is optional. If not provided then assume "${DEPLOY_HAPROXY_ISSUER_DEFAULT}"
|
# ISSUER is optional. If not provided then assume "${DEPLOY_HAPROXY_ISSUER_DEFAULT}"
|
||||||
_getdeployconf DEPLOY_HAPROXY_ISSUER
|
|
||||||
_debug2 DEPLOY_HAPROXY_ISSUER "${DEPLOY_HAPROXY_ISSUER}"
|
|
||||||
if [ -n "${DEPLOY_HAPROXY_ISSUER}" ]; then
|
if [ -n "${DEPLOY_HAPROXY_ISSUER}" ]; then
|
||||||
Le_Deploy_haproxy_issuer="${DEPLOY_HAPROXY_ISSUER}"
|
Le_Deploy_haproxy_issuer="${DEPLOY_HAPROXY_ISSUER}"
|
||||||
_savedomainconf Le_Deploy_haproxy_issuer "${Le_Deploy_haproxy_issuer}"
|
_savedomainconf Le_Deploy_haproxy_issuer "${Le_Deploy_haproxy_issuer}"
|
||||||
@ -130,8 +106,6 @@ haproxy_deploy() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# RELOAD is optional. If not provided then assume "${DEPLOY_HAPROXY_RELOAD_DEFAULT}"
|
# RELOAD is optional. If not provided then assume "${DEPLOY_HAPROXY_RELOAD_DEFAULT}"
|
||||||
_getdeployconf DEPLOY_HAPROXY_RELOAD
|
|
||||||
_debug2 DEPLOY_HAPROXY_RELOAD "${DEPLOY_HAPROXY_RELOAD}"
|
|
||||||
if [ -n "${DEPLOY_HAPROXY_RELOAD}" ]; then
|
if [ -n "${DEPLOY_HAPROXY_RELOAD}" ]; then
|
||||||
Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD}"
|
Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD}"
|
||||||
_savedomainconf Le_Deploy_haproxy_reload "${Le_Deploy_haproxy_reload}"
|
_savedomainconf Le_Deploy_haproxy_reload "${Le_Deploy_haproxy_reload}"
|
||||||
@ -139,36 +113,6 @@ 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"
|
||||||
@ -193,13 +137,12 @@ 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 "${_ccert}" "${_cca}" "${_ckey}" | grep . >"${_temppem}"
|
cat "${_ckey}" "${_ccert}" "${_cca}" >"${_temppem}"
|
||||||
_ret="$?"
|
_ret="$?"
|
||||||
|
|
||||||
# Check that we could create the temporary file
|
# Check that we could create the temporary file
|
||||||
@ -247,7 +190,7 @@ haproxy_deploy() {
|
|||||||
_info "Updating OCSP stapling info"
|
_info "Updating OCSP stapling info"
|
||||||
_debug _ocsp "${_ocsp}"
|
_debug _ocsp "${_ocsp}"
|
||||||
_info "Extracting OCSP URL"
|
_info "Extracting OCSP URL"
|
||||||
_ocsp_url=$(${ACME_OPENSSL_BIN:-openssl} x509 -noout -ocsp_uri -in "${_pem}")
|
_ocsp_url=$(openssl x509 -noout -ocsp_uri -in "${_pem}")
|
||||||
_debug _ocsp_url "${_ocsp_url}"
|
_debug _ocsp_url "${_ocsp_url}"
|
||||||
|
|
||||||
# Only process OCSP if URL was present
|
# Only process OCSP if URL was present
|
||||||
@ -260,9 +203,9 @@ haproxy_deploy() {
|
|||||||
# Only process the certificate if we have a .issuer file
|
# Only process the certificate if we have a .issuer file
|
||||||
if [ -r "${_issuer}" ]; then
|
if [ -r "${_issuer}" ]; then
|
||||||
# Check if issuer cert is also a root CA cert
|
# Check if issuer cert is also a root CA cert
|
||||||
_subjectdn=$(${ACME_OPENSSL_BIN:-openssl} x509 -in "${_issuer}" -subject -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
|
_subjectdn=$(openssl x509 -in "${_issuer}" -subject -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
|
||||||
_debug _subjectdn "${_subjectdn}"
|
_debug _subjectdn "${_subjectdn}"
|
||||||
_issuerdn=$(${ACME_OPENSSL_BIN:-openssl} x509 -in "${_issuer}" -issuer -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
|
_issuerdn=$(openssl x509 -in "${_issuer}" -issuer -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
|
||||||
_debug _issuerdn "${_issuerdn}"
|
_debug _issuerdn "${_issuerdn}"
|
||||||
_info "Requesting OCSP response"
|
_info "Requesting OCSP response"
|
||||||
# If the issuer is a CA cert then our command line has "-CAfile" added
|
# If the issuer is a CA cert then our command line has "-CAfile" added
|
||||||
@ -273,7 +216,7 @@ haproxy_deploy() {
|
|||||||
fi
|
fi
|
||||||
_debug _cafile_argument "${_cafile_argument}"
|
_debug _cafile_argument "${_cafile_argument}"
|
||||||
# if OpenSSL/LibreSSL is v1.1 or above, the format for the -header option has changed
|
# if OpenSSL/LibreSSL is v1.1 or above, the format for the -header option has changed
|
||||||
_openssl_version=$(${ACME_OPENSSL_BIN:-openssl} version | cut -d' ' -f2)
|
_openssl_version=$(openssl version | cut -d' ' -f2)
|
||||||
_debug _openssl_version "${_openssl_version}"
|
_debug _openssl_version "${_openssl_version}"
|
||||||
_openssl_major=$(echo "${_openssl_version}" | cut -d '.' -f1)
|
_openssl_major=$(echo "${_openssl_version}" | cut -d '.' -f1)
|
||||||
_openssl_minor=$(echo "${_openssl_version}" | cut -d '.' -f2)
|
_openssl_minor=$(echo "${_openssl_version}" | cut -d '.' -f2)
|
||||||
@ -283,7 +226,7 @@ haproxy_deploy() {
|
|||||||
_header_sep=" "
|
_header_sep=" "
|
||||||
fi
|
fi
|
||||||
# Request the OCSP response from the issuer and store it
|
# Request the OCSP response from the issuer and store it
|
||||||
_openssl_ocsp_cmd="${ACME_OPENSSL_BIN:-openssl} ocsp \
|
_openssl_ocsp_cmd="openssl ocsp \
|
||||||
-issuer \"${_issuer}\" \
|
-issuer \"${_issuer}\" \
|
||||||
-cert \"${_pem}\" \
|
-cert \"${_pem}\" \
|
||||||
-url \"${_ocsp_url}\" \
|
-url \"${_ocsp_url}\" \
|
||||||
@ -317,86 +260,15 @@ haproxy_deploy() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "${Le_Deploy_haproxy_hot_update}" = "yes" ]; then
|
# Reload HAProxy
|
||||||
# set the socket name for messages
|
_debug _reload "${_reload}"
|
||||||
if [ -n "${_cmdpfx}" ]; then
|
eval "${_reload}"
|
||||||
_socketname="master CLI"
|
_ret=$?
|
||||||
else
|
if [ "${_ret}" != "0" ]; then
|
||||||
_socketname="stats socket"
|
_err "Error code ${_ret} during reload"
|
||||||
fi
|
return ${_ret}
|
||||||
|
|
||||||
# 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
|
else
|
||||||
# Reload HAProxy
|
_info "Reload successful"
|
||||||
_debug _reload "${_reload}"
|
|
||||||
eval "${_reload}"
|
|
||||||
_ret=$?
|
|
||||||
if [ "${_ret}" != "0" ]; then
|
|
||||||
_err "Error code ${_ret} during reload"
|
|
||||||
return ${_ret}
|
|
||||||
else
|
|
||||||
_info "Reload successful"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@ -45,7 +45,7 @@ kong_deploy() {
|
|||||||
#Generate data for request (Multipart/form-data with mixed content)
|
#Generate data for request (Multipart/form-data with mixed content)
|
||||||
if [ -z "$ssl_uuid" ]; then
|
if [ -z "$ssl_uuid" ]; then
|
||||||
#set sni to domain
|
#set sni to domain
|
||||||
content="--$delim${nl}Content-Disposition: form-data; name=\"snis[]\"${nl}${nl}$_cdomain"
|
content="--$delim${nl}Content-Disposition: form-data; name=\"snis\"${nl}${nl}$_cdomain"
|
||||||
fi
|
fi
|
||||||
#add key
|
#add key
|
||||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
|
||||||
|
|||||||
@ -1,280 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
# Script for acme.sh to deploy certificates to lighttpd
|
|
||||||
#
|
|
||||||
# The following variables can be exported:
|
|
||||||
#
|
|
||||||
# export DEPLOY_LIGHTTPD_PEM_NAME="${domain}.pem"
|
|
||||||
#
|
|
||||||
# Defines the name of the PEM file.
|
|
||||||
# Defaults to "<domain>.pem"
|
|
||||||
#
|
|
||||||
# export DEPLOY_LIGHTTPD_PEM_PATH="/etc/lighttpd"
|
|
||||||
#
|
|
||||||
# Defines location of PEM file for Lighttpd.
|
|
||||||
# Defaults to /etc/lighttpd
|
|
||||||
#
|
|
||||||
# export DEPLOY_LIGHTTPD_RELOAD="systemctl reload lighttpd"
|
|
||||||
#
|
|
||||||
# OPTIONAL: Reload command used post deploy
|
|
||||||
# This defaults to be a no-op (ie "true").
|
|
||||||
# It is strongly recommended to set this something that makes sense
|
|
||||||
# for your distro.
|
|
||||||
#
|
|
||||||
# export DEPLOY_LIGHTTPD_ISSUER="yes"
|
|
||||||
#
|
|
||||||
# OPTIONAL: Places CA file as "${DEPLOY_LIGHTTPD_PEM}.issuer"
|
|
||||||
# Note: Required for OCSP stapling to work
|
|
||||||
#
|
|
||||||
# export DEPLOY_LIGHTTPD_BUNDLE="no"
|
|
||||||
#
|
|
||||||
# OPTIONAL: Deploy this certificate as part of a multi-cert bundle
|
|
||||||
# This adds a suffix to the certificate based on the certificate type
|
|
||||||
# eg RSA certificates will have .rsa as a suffix to the file name
|
|
||||||
# Lighttpd will load all certificates and provide one or the other
|
|
||||||
# depending on client capabilities
|
|
||||||
# Note: This functionality requires Lighttpd was compiled against
|
|
||||||
# a version of OpenSSL that supports this.
|
|
||||||
#
|
|
||||||
|
|
||||||
######## Public functions #####################
|
|
||||||
|
|
||||||
#domain keyfile certfile cafile fullchain
|
|
||||||
lighttpd_deploy() {
|
|
||||||
_cdomain="$1"
|
|
||||||
_ckey="$2"
|
|
||||||
_ccert="$3"
|
|
||||||
_cca="$4"
|
|
||||||
_cfullchain="$5"
|
|
||||||
|
|
||||||
# Some defaults
|
|
||||||
DEPLOY_LIGHTTPD_PEM_PATH_DEFAULT="/etc/lighttpd"
|
|
||||||
DEPLOY_LIGHTTPD_PEM_NAME_DEFAULT="${_cdomain}.pem"
|
|
||||||
DEPLOY_LIGHTTPD_BUNDLE_DEFAULT="no"
|
|
||||||
DEPLOY_LIGHTTPD_ISSUER_DEFAULT="yes"
|
|
||||||
DEPLOY_LIGHTTPD_RELOAD_DEFAULT="true"
|
|
||||||
|
|
||||||
_debug _cdomain "${_cdomain}"
|
|
||||||
_debug _ckey "${_ckey}"
|
|
||||||
_debug _ccert "${_ccert}"
|
|
||||||
_debug _cca "${_cca}"
|
|
||||||
_debug _cfullchain "${_cfullchain}"
|
|
||||||
|
|
||||||
# PEM_PATH is optional. If not provided then assume "${DEPLOY_LIGHTTPD_PEM_PATH_DEFAULT}"
|
|
||||||
_getdeployconf DEPLOY_LIGHTTPD_PEM_PATH
|
|
||||||
_debug2 DEPLOY_LIGHTTPD_PEM_PATH "${DEPLOY_LIGHTTPD_PEM_PATH}"
|
|
||||||
if [ -n "${DEPLOY_LIGHTTPD_PEM_PATH}" ]; then
|
|
||||||
Le_Deploy_lighttpd_pem_path="${DEPLOY_LIGHTTPD_PEM_PATH}"
|
|
||||||
_savedomainconf Le_Deploy_lighttpd_pem_path "${Le_Deploy_lighttpd_pem_path}"
|
|
||||||
elif [ -z "${Le_Deploy_lighttpd_pem_path}" ]; then
|
|
||||||
Le_Deploy_lighttpd_pem_path="${DEPLOY_LIGHTTPD_PEM_PATH_DEFAULT}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Ensure PEM_PATH exists
|
|
||||||
if [ -d "${Le_Deploy_lighttpd_pem_path}" ]; then
|
|
||||||
_debug "PEM_PATH ${Le_Deploy_lighttpd_pem_path} exists"
|
|
||||||
else
|
|
||||||
_err "PEM_PATH ${Le_Deploy_lighttpd_pem_path} does not exist"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# PEM_NAME is optional. If not provided then assume "${DEPLOY_LIGHTTPD_PEM_NAME_DEFAULT}"
|
|
||||||
_getdeployconf DEPLOY_LIGHTTPD_PEM_NAME
|
|
||||||
_debug2 DEPLOY_LIGHTTPD_PEM_NAME "${DEPLOY_LIGHTTPD_PEM_NAME}"
|
|
||||||
if [ -n "${DEPLOY_LIGHTTPD_PEM_NAME}" ]; then
|
|
||||||
Le_Deploy_lighttpd_pem_name="${DEPLOY_LIGHTTPD_PEM_NAME}"
|
|
||||||
_savedomainconf Le_Deploy_lighttpd_pem_name "${Le_Deploy_lighttpd_pem_name}"
|
|
||||||
elif [ -z "${Le_Deploy_lighttpd_pem_name}" ]; then
|
|
||||||
Le_Deploy_lighttpd_pem_name="${DEPLOY_LIGHTTPD_PEM_NAME_DEFAULT}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# BUNDLE is optional. If not provided then assume "${DEPLOY_LIGHTTPD_BUNDLE_DEFAULT}"
|
|
||||||
_getdeployconf DEPLOY_LIGHTTPD_BUNDLE
|
|
||||||
_debug2 DEPLOY_LIGHTTPD_BUNDLE "${DEPLOY_LIGHTTPD_BUNDLE}"
|
|
||||||
if [ -n "${DEPLOY_LIGHTTPD_BUNDLE}" ]; then
|
|
||||||
Le_Deploy_lighttpd_bundle="${DEPLOY_LIGHTTPD_BUNDLE}"
|
|
||||||
_savedomainconf Le_Deploy_lighttpd_bundle "${Le_Deploy_lighttpd_bundle}"
|
|
||||||
elif [ -z "${Le_Deploy_lighttpd_bundle}" ]; then
|
|
||||||
Le_Deploy_lighttpd_bundle="${DEPLOY_LIGHTTPD_BUNDLE_DEFAULT}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# ISSUER is optional. If not provided then assume "${DEPLOY_LIGHTTPD_ISSUER_DEFAULT}"
|
|
||||||
_getdeployconf DEPLOY_LIGHTTPD_ISSUER
|
|
||||||
_debug2 DEPLOY_LIGHTTPD_ISSUER "${DEPLOY_LIGHTTPD_ISSUER}"
|
|
||||||
if [ -n "${DEPLOY_LIGHTTPD_ISSUER}" ]; then
|
|
||||||
Le_Deploy_lighttpd_issuer="${DEPLOY_LIGHTTPD_ISSUER}"
|
|
||||||
_savedomainconf Le_Deploy_lighttpd_issuer "${Le_Deploy_lighttpd_issuer}"
|
|
||||||
elif [ -z "${Le_Deploy_lighttpd_issuer}" ]; then
|
|
||||||
Le_Deploy_lighttpd_issuer="${DEPLOY_LIGHTTPD_ISSUER_DEFAULT}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# RELOAD is optional. If not provided then assume "${DEPLOY_LIGHTTPD_RELOAD_DEFAULT}"
|
|
||||||
_getdeployconf DEPLOY_LIGHTTPD_RELOAD
|
|
||||||
_debug2 DEPLOY_LIGHTTPD_RELOAD "${DEPLOY_LIGHTTPD_RELOAD}"
|
|
||||||
if [ -n "${DEPLOY_LIGHTTPD_RELOAD}" ]; then
|
|
||||||
Le_Deploy_lighttpd_reload="${DEPLOY_LIGHTTPD_RELOAD}"
|
|
||||||
_savedomainconf Le_Deploy_lighttpd_reload "${Le_Deploy_lighttpd_reload}"
|
|
||||||
elif [ -z "${Le_Deploy_lighttpd_reload}" ]; then
|
|
||||||
Le_Deploy_lighttpd_reload="${DEPLOY_LIGHTTPD_RELOAD_DEFAULT}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Set the suffix depending if we are creating a bundle or not
|
|
||||||
if [ "${Le_Deploy_lighttpd_bundle}" = "yes" ]; then
|
|
||||||
_info "Bundle creation requested"
|
|
||||||
# Initialise $Le_Keylength if its not already set
|
|
||||||
if [ -z "${Le_Keylength}" ]; then
|
|
||||||
Le_Keylength=""
|
|
||||||
fi
|
|
||||||
if _isEccKey "${Le_Keylength}"; then
|
|
||||||
_info "ECC key type detected"
|
|
||||||
_suffix=".ecdsa"
|
|
||||||
else
|
|
||||||
_info "RSA key type detected"
|
|
||||||
_suffix=".rsa"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
_suffix=""
|
|
||||||
fi
|
|
||||||
_debug _suffix "${_suffix}"
|
|
||||||
|
|
||||||
# Set variables for later
|
|
||||||
_pem="${Le_Deploy_lighttpd_pem_path}/${Le_Deploy_lighttpd_pem_name}${_suffix}"
|
|
||||||
_issuer="${_pem}.issuer"
|
|
||||||
_ocsp="${_pem}.ocsp"
|
|
||||||
_reload="${Le_Deploy_lighttpd_reload}"
|
|
||||||
|
|
||||||
_info "Deploying PEM file"
|
|
||||||
# Create a temporary PEM file
|
|
||||||
_temppem="$(_mktemp)"
|
|
||||||
_debug _temppem "${_temppem}"
|
|
||||||
cat "${_ckey}" "${_ccert}" "${_cca}" >"${_temppem}"
|
|
||||||
_ret="$?"
|
|
||||||
|
|
||||||
# Check that we could create the temporary file
|
|
||||||
if [ "${_ret}" != "0" ]; then
|
|
||||||
_err "Error code ${_ret} returned during PEM file creation"
|
|
||||||
[ -f "${_temppem}" ] && rm -f "${_temppem}"
|
|
||||||
return ${_ret}
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Move PEM file into place
|
|
||||||
_info "Moving new certificate into place"
|
|
||||||
_debug _pem "${_pem}"
|
|
||||||
cat "${_temppem}" >"${_pem}"
|
|
||||||
_ret=$?
|
|
||||||
|
|
||||||
# Clean up temp file
|
|
||||||
[ -f "${_temppem}" ] && rm -f "${_temppem}"
|
|
||||||
|
|
||||||
# Deal with any failure of moving PEM file into place
|
|
||||||
if [ "${_ret}" != "0" ]; then
|
|
||||||
_err "Error code ${_ret} returned while moving new certificate into place"
|
|
||||||
return ${_ret}
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Update .issuer file if requested
|
|
||||||
if [ "${Le_Deploy_lighttpd_issuer}" = "yes" ]; then
|
|
||||||
_info "Updating .issuer file"
|
|
||||||
_debug _issuer "${_issuer}"
|
|
||||||
cat "${_cca}" >"${_issuer}"
|
|
||||||
_ret="$?"
|
|
||||||
|
|
||||||
if [ "${_ret}" != "0" ]; then
|
|
||||||
_err "Error code ${_ret} returned while copying issuer/CA certificate into place"
|
|
||||||
return ${_ret}
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
[ -f "${_issuer}" ] && _err "Issuer file update not requested but .issuer file exists"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Update .ocsp file if certificate was requested with --ocsp/--ocsp-must-staple option
|
|
||||||
if [ -z "${Le_OCSP_Staple}" ]; then
|
|
||||||
Le_OCSP_Staple="0"
|
|
||||||
fi
|
|
||||||
if [ "${Le_OCSP_Staple}" = "1" ]; then
|
|
||||||
_info "Updating OCSP stapling info"
|
|
||||||
_debug _ocsp "${_ocsp}"
|
|
||||||
_info "Extracting OCSP URL"
|
|
||||||
_ocsp_url=$(${ACME_OPENSSL_BIN:-openssl} x509 -noout -ocsp_uri -in "${_pem}")
|
|
||||||
_debug _ocsp_url "${_ocsp_url}"
|
|
||||||
|
|
||||||
# Only process OCSP if URL was present
|
|
||||||
if [ "${_ocsp_url}" != "" ]; then
|
|
||||||
# Extract the hostname from the OCSP URL
|
|
||||||
_info "Extracting OCSP URL"
|
|
||||||
_ocsp_host=$(echo "${_ocsp_url}" | cut -d/ -f3)
|
|
||||||
_debug _ocsp_host "${_ocsp_host}"
|
|
||||||
|
|
||||||
# Only process the certificate if we have a .issuer file
|
|
||||||
if [ -r "${_issuer}" ]; then
|
|
||||||
# Check if issuer cert is also a root CA cert
|
|
||||||
_subjectdn=$(${ACME_OPENSSL_BIN:-openssl} x509 -in "${_issuer}" -subject -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
|
|
||||||
_debug _subjectdn "${_subjectdn}"
|
|
||||||
_issuerdn=$(${ACME_OPENSSL_BIN:-openssl} x509 -in "${_issuer}" -issuer -noout | cut -d'/' -f2,3,4,5,6,7,8,9,10)
|
|
||||||
_debug _issuerdn "${_issuerdn}"
|
|
||||||
_info "Requesting OCSP response"
|
|
||||||
# If the issuer is a CA cert then our command line has "-CAfile" added
|
|
||||||
if [ "${_subjectdn}" = "${_issuerdn}" ]; then
|
|
||||||
_cafile_argument="-CAfile \"${_issuer}\""
|
|
||||||
else
|
|
||||||
_cafile_argument=""
|
|
||||||
fi
|
|
||||||
_debug _cafile_argument "${_cafile_argument}"
|
|
||||||
# if OpenSSL/LibreSSL is v1.1 or above, the format for the -header option has changed
|
|
||||||
_openssl_version=$(${ACME_OPENSSL_BIN:-openssl} version | cut -d' ' -f2)
|
|
||||||
_debug _openssl_version "${_openssl_version}"
|
|
||||||
_openssl_major=$(echo "${_openssl_version}" | cut -d '.' -f1)
|
|
||||||
_openssl_minor=$(echo "${_openssl_version}" | cut -d '.' -f2)
|
|
||||||
if [ "${_openssl_major}" -eq "1" ] && [ "${_openssl_minor}" -ge "1" ] || [ "${_openssl_major}" -ge "2" ]; then
|
|
||||||
_header_sep="="
|
|
||||||
else
|
|
||||||
_header_sep=" "
|
|
||||||
fi
|
|
||||||
# Request the OCSP response from the issuer and store it
|
|
||||||
_openssl_ocsp_cmd="${ACME_OPENSSL_BIN:-openssl} ocsp \
|
|
||||||
-issuer \"${_issuer}\" \
|
|
||||||
-cert \"${_pem}\" \
|
|
||||||
-url \"${_ocsp_url}\" \
|
|
||||||
-header Host${_header_sep}\"${_ocsp_host}\" \
|
|
||||||
-respout \"${_ocsp}\" \
|
|
||||||
-verify_other \"${_issuer}\" \
|
|
||||||
${_cafile_argument} \
|
|
||||||
| grep -q \"${_pem}: good\""
|
|
||||||
_debug _openssl_ocsp_cmd "${_openssl_ocsp_cmd}"
|
|
||||||
eval "${_openssl_ocsp_cmd}"
|
|
||||||
_ret=$?
|
|
||||||
else
|
|
||||||
# Non fatal: No issuer file was present so no OCSP stapling file created
|
|
||||||
_err "OCSP stapling in use but no .issuer file was present"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# Non fatal: No OCSP url was found int the certificate
|
|
||||||
_err "OCSP update requested but no OCSP URL was found in certificate"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Non fatal: Check return code of openssl command
|
|
||||||
if [ "${_ret}" != "0" ]; then
|
|
||||||
_err "Updating OCSP stapling failed with return code ${_ret}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# An OCSP file was already present but certificate did not have OCSP extension
|
|
||||||
if [ -f "${_ocsp}" ]; then
|
|
||||||
_err "OCSP was not requested but .ocsp file exists."
|
|
||||||
# Could remove the file at this step, although Lighttpd just ignores it in this case
|
|
||||||
# rm -f "${_ocsp}" || _err "Problem removing stale .ocsp file"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Reload Lighttpd
|
|
||||||
_debug _reload "${_reload}"
|
|
||||||
eval "${_reload}"
|
|
||||||
_ret=$?
|
|
||||||
if [ "${_ret}" != "0" ]; then
|
|
||||||
_err "Error code ${_ret} during reload"
|
|
||||||
return ${_ret}
|
|
||||||
else
|
|
||||||
_info "Reload successful"
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
@ -20,23 +20,18 @@ mailcow_deploy() {
|
|||||||
_debug _cca "$_cca"
|
_debug _cca "$_cca"
|
||||||
_debug _cfullchain "$_cfullchain"
|
_debug _cfullchain "$_cfullchain"
|
||||||
|
|
||||||
_getdeployconf DEPLOY_MAILCOW_PATH
|
_mailcow_path="${DEPLOY_MAILCOW_PATH}"
|
||||||
_getdeployconf DEPLOY_MAILCOW_RELOAD
|
|
||||||
|
|
||||||
_debug DEPLOY_MAILCOW_PATH "$DEPLOY_MAILCOW_PATH"
|
if [ -z "$_mailcow_path" ]; then
|
||||||
_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
|
||||||
|
|
||||||
_savedeployconf DEPLOY_MAILCOW_PATH "$DEPLOY_MAILCOW_PATH"
|
#Tests if _ssl_path is the mailcow root directory.
|
||||||
[ -n "$DEPLOY_MAILCOW_RELOAD" ] && _savedeployconf DEPLOY_MAILCOW_RELOAD "$DEPLOY_MAILCOW_RELOAD"
|
if [ -f "${_mailcow_path}/generate_config.sh" ]; then
|
||||||
|
_ssl_path="${_mailcow_path}/data/assets/ssl/"
|
||||||
_ssl_path="$DEPLOY_MAILCOW_PATH"
|
else
|
||||||
if [ -f "$DEPLOY_MAILCOW_PATH/generate_config.sh" ]; then
|
_ssl_path="${_mailcow_path}"
|
||||||
_ssl_path="$DEPLOY_MAILCOW_PATH/data/assets/ssl/"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -d "$_ssl_path" ]; then
|
if [ ! -d "$_ssl_path" ]; then
|
||||||
@ -44,20 +39,31 @@ 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/key.pem"
|
_real_key="$_ssl_path/${_cert_name_prefix}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.pem"
|
_real_fullchain="$_ssl_path/${_cert_name_prefix}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 --quiet --filter name=nginx-mailcow --filter name=dovecot-mailcow --filter name=postfix-mailcow)"
|
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)"
|
||||||
_reload="${DEPLOY_MAILCOW_RELOAD:-$DEFAULT_MAILCOW_RELOAD}"
|
_reload="${DEPLOY_MAILCOW_RELOAD:-$DEFAULT_MAILCOW_RELOAD}"
|
||||||
|
|
||||||
_info "Run reload: $_reload"
|
_info "Run reload: $_reload"
|
||||||
|
|||||||
@ -1,156 +0,0 @@
|
|||||||
#!/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
|
|
||||||
}
|
|
||||||
183
deploy/panos.sh
183
deploy/panos.sh
@ -7,18 +7,11 @@
|
|||||||
#
|
#
|
||||||
# Firewall admin with superuser and IP address is required.
|
# Firewall admin with superuser and IP address is required.
|
||||||
#
|
#
|
||||||
# REQURED:
|
# export PANOS_USER="" # required
|
||||||
# export PANOS_HOST=""
|
# export PANOS_PASS="" # required
|
||||||
# export PANOS_USER="" #User *MUST* have Commit and Import Permissions in XML API for Admin Role
|
# export PANOS_HOST="" # required
|
||||||
# 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 response from the firewall
|
# This function is to parse the XML
|
||||||
parse_response() {
|
parse_response() {
|
||||||
type=$2
|
type=$2
|
||||||
if [ "$type" = 'keygen' ]; then
|
if [ "$type" = 'keygen' ]; then
|
||||||
@ -30,46 +23,25 @@ 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" | tr -d '\n' | sed 's/^.*"\([a-z]*\)".*/\1/g')
|
status=$(echo "$1" | sed 's/^.*"\([a-z]*\)".*/\1/g')
|
||||||
message=$(echo "$1" | tr -d '\n' | sed 's/.*\(<result>\|<msg>\|<line>\)\([^<]*\).*/\2/g')
|
message=$(echo "$1" | sed 's/^.*<result>\(.*\)<\/result.*/\1/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 keytest, keygen, cert, key, commit
|
type=$1 # Types are 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
|
||||||
_debug "**** Deploying $type ****"
|
#Generate DEIM
|
||||||
#Generate DELIM
|
|
||||||
delim="-----MultipartDelimiter$(date "+%s%N")"
|
delim="-----MultipartDelimiter$(date "+%s%N")"
|
||||||
nl="\015\012"
|
nl="\015\012"
|
||||||
#Set Header
|
#Set Header
|
||||||
@ -81,9 +53,6 @@ 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"
|
||||||
@ -92,10 +61,7 @@ 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 "$_cdomain.key")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
|
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_ckey")\"${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}"
|
||||||
@ -103,25 +69,16 @@ 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"
|
||||||
#Check for force commit - will commit ALL uncommited changes to the firewall. Use with caution!
|
cmd=$(printf "%s" "<commit><partial><$_panos_user></$_panos_user></partial></commit>" | _url_encode)
|
||||||
if [ "$FORCE" ]; then
|
content="type=commit&key=$_panos_key&cmd=$cmd"
|
||||||
_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
|
|
||||||
content="type=commit&action=partial&key=$_panos_key&cmd=$cmd"
|
|
||||||
fi
|
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"
|
||||||
@ -135,95 +92,43 @@ 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=$(echo "$1" | sed 's/*/WILDCARD_/g') #Wildcard Safe Filename
|
_cdomain="$1"
|
||||||
_ckey="$2"
|
_ckey="$2"
|
||||||
_cfullchain="$5"
|
_cfullchain="$5"
|
||||||
|
# PANOS ENV VAR check
|
||||||
# VALID FILE CHECK
|
if [ -z "$PANOS_USER" ] || [ -z "$PANOS_PASS" ] || [ -z "$PANOS_HOST" ]; then
|
||||||
if [ ! -f "$_ckey" ] || [ ! -f "$_cfullchain" ]; then
|
_debug "No ENV variables found lets check for saved variables"
|
||||||
_err "Unable to find a valid key and/or cert. If this is an ECDSA/ECC cert, use the --ecc flag when deploying."
|
|
||||||
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
|
|
||||||
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
|
_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
|
_getdeployconf PANOS_PASS
|
||||||
fi
|
_getdeployconf PANOS_HOST
|
||||||
|
_panos_user=$PANOS_USER
|
||||||
# PANOS_KEY
|
_panos_pass=$PANOS_PASS
|
||||||
_getdeployconf PANOS_KEY
|
_panos_host=$PANOS_HOST
|
||||||
if [ "$PANOS_KEY" ]; then
|
if [ -z "$_panos_user" ] && [ -z "$_panos_pass" ] && [ -z "$_panos_host" ]; then
|
||||||
_debug "Detected saved key."
|
_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."
|
||||||
_panos_key=$PANOS_KEY
|
return 1
|
||||||
else
|
else
|
||||||
_debug "No key detected"
|
_debug "Using saved env variables."
|
||||||
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_pass=$PANOS_PASS
|
|
||||||
_panos_template=$PANOS_TEMPLATE
|
|
||||||
|
|
||||||
#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
|
|
||||||
else
|
|
||||||
# Generate a new API key if no valid API key is found
|
|
||||||
if [ -z "$_panos_key" ]; then
|
|
||||||
_debug "**** Generating new PANOS API KEY ****"
|
|
||||||
deployer keygen
|
|
||||||
_savedeployconf PANOS_KEY "$_panos_key" 1
|
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
# Confirm that a valid key was generated
|
_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 "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"
|
_err "Missing apikey."
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
deployer cert
|
deployer cert
|
||||||
|
|||||||
@ -1,132 +0,0 @@
|
|||||||
#!/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)
|
sslcert_response=$(_post "$sslcerl_body" "$QINIU_API_BASE$sslcert_path" 0 "POST" "application/json" | _dbase64 "multiline")
|
||||||
|
|
||||||
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)
|
update_response=$(_post "$update_body" "$QINIU_API_BASE$update_path" 0 "PUT" "application/json" | _dbase64 "multiline")
|
||||||
|
|
||||||
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,7 +23,6 @@
|
|||||||
# ```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
|
||||||
# ```
|
# ```
|
||||||
@ -49,16 +48,6 @@
|
|||||||
# 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 #####################
|
||||||
@ -70,7 +59,6 @@ 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"
|
||||||
@ -78,70 +66,29 @@ routeros_deploy() {
|
|||||||
_debug _cca "$_cca"
|
_debug _cca "$_cca"
|
||||||
_debug _cfullchain "$_cfullchain"
|
_debug _cfullchain "$_cfullchain"
|
||||||
|
|
||||||
_getdeployconf ROUTER_OS_HOST
|
|
||||||
|
|
||||||
if [ -z "$ROUTER_OS_HOST" ]; then
|
if [ -z "$ROUTER_OS_HOST" ]; then
|
||||||
_debug "Using _cdomain as ROUTER_OS_HOST, please set if not correct."
|
_debug "Using _cdomain as ROUTER_OS_HOST, please set if not correct."
|
||||||
ROUTER_OS_HOST="$_cdomain"
|
ROUTER_OS_HOST="$_cdomain"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_getdeployconf ROUTER_OS_USERNAME
|
|
||||||
|
|
||||||
if [ -z "$ROUTER_OS_USERNAME" ]; then
|
if [ -z "$ROUTER_OS_USERNAME" ]; then
|
||||||
_err "Need to set the env variable ROUTER_OS_USERNAME"
|
_err "Need to set the env variable ROUTER_OS_USERNAME"
|
||||||
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
|
|
||||||
|
|
||||||
if [ -z "$ROUTER_OS_ADDITIONAL_SERVICES" ]; then
|
if [ -z "$ROUTER_OS_ADDITIONAL_SERVICES" ]; then
|
||||||
_debug "Not enabling additional services"
|
_debug "Not enabling additional services"
|
||||||
ROUTER_OS_ADDITIONAL_SERVICES=""
|
ROUTER_OS_ADDITIONAL_SERVICES=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_savedeployconf ROUTER_OS_HOST "$ROUTER_OS_HOST"
|
_info "Trying to push key '$_ckey' to router"
|
||||||
_savedeployconf ROUTER_OS_USERNAME "$ROUTER_OS_USERNAME"
|
scp "$_ckey" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.key"
|
||||||
_savedeployconf ROUTER_OS_PORT "$ROUTER_OS_PORT"
|
_info "Trying to push cert '$_cfullchain' to router"
|
||||||
_savedeployconf ROUTER_OS_SSH_CMD "$ROUTER_OS_SSH_CMD"
|
scp "$_cfullchain" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.cer"
|
||||||
_savedeployconf ROUTER_OS_SCP_CMD "$ROUTER_OS_SCP_CMD"
|
DEPLOY_SCRIPT_CMD="/system script add name=\"LE Cert Deploy - $_cdomain\" owner=admin policy=ftp,read,write,password,sensitive \
|
||||||
_savedeployconf ROUTER_OS_ADDITIONAL_SERVICES "$ROUTER_OS_ADDITIONAL_SERVICES"
|
source=\"## generated by routeros deploy script in acme.sh;\
|
||||||
|
\n/certificate remove [ find name=$_cdomain.cer_0 ];\
|
||||||
# push key to routeros
|
|
||||||
if ! _scp_certificate "$_ckey" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.key"; then
|
|
||||||
return $_err_code
|
|
||||||
fi
|
|
||||||
|
|
||||||
# push certificate chain to routeros
|
|
||||||
if ! _scp_certificate "$_cfullchain" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.cer"; then
|
|
||||||
return $_err_code
|
|
||||||
fi
|
|
||||||
|
|
||||||
DEPLOY_SCRIPT_CMD="/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=\\\"\\\";\
|
||||||
@ -153,51 +100,12 @@ source=\"/certificate remove [ find name=$_cdomain.cer_0 ];\
|
|||||||
\n$ROUTER_OS_ADDITIONAL_SERVICES;\
|
\n$ROUTER_OS_ADDITIONAL_SERVICES;\
|
||||||
\n\"
|
\n\"
|
||||||
"
|
"
|
||||||
|
# shellcheck disable=SC2029
|
||||||
if ! _ssh_remote_cmd "$DEPLOY_SCRIPT_CMD"; then
|
ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "$DEPLOY_SCRIPT_CMD"
|
||||||
return $_err_code
|
# shellcheck disable=SC2029
|
||||||
fi
|
ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script run \"LE Cert Deploy - $_cdomain\""
|
||||||
|
# shellcheck disable=SC2029
|
||||||
if ! _ssh_remote_cmd "/system script run \"LECertDeploy-$_cdomain\""; then
|
ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script remove \"LE Cert Deploy - $_cdomain\""
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|||||||
416
deploy/ssh.sh
416
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="host1 host2:8022 192.168.0.1:9022" # defaults to domain name, support multiple servers with optional port
|
# export DEPLOY_SSH_SERVER="qnap" # defaults to domain name
|
||||||
# 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,8 +23,6 @@
|
|||||||
# 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 #####################
|
||||||
|
|
||||||
@ -37,6 +35,11 @@ ssh_deploy() {
|
|||||||
_cfullchain="$5"
|
_cfullchain="$5"
|
||||||
_deploy_ssh_servers=""
|
_deploy_ssh_servers=""
|
||||||
|
|
||||||
|
if [ -f "$DOMAIN_CONF" ]; then
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
. "$DOMAIN_CONF"
|
||||||
|
fi
|
||||||
|
|
||||||
_debug _cdomain "$_cdomain"
|
_debug _cdomain "$_cdomain"
|
||||||
_debug _ckey "$_ckey"
|
_debug _ckey "$_ckey"
|
||||||
_debug _ccert "$_ccert"
|
_debug _ccert "$_ccert"
|
||||||
@ -44,134 +47,60 @@ 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
|
|
||||||
_debug2 DEPLOY_SSH_USER "$DEPLOY_SSH_USER"
|
|
||||||
if [ -z "$DEPLOY_SSH_USER" ]; then
|
if [ -z "$DEPLOY_SSH_USER" ]; then
|
||||||
_err "DEPLOY_SSH_USER not defined."
|
if [ -z "$Le_Deploy_ssh_user" ]; then
|
||||||
return 1
|
_err "DEPLOY_SSH_USER not defined."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
Le_Deploy_ssh_user="$DEPLOY_SSH_USER"
|
||||||
|
_savedomainconf Le_Deploy_ssh_user "$Le_Deploy_ssh_user"
|
||||||
fi
|
fi
|
||||||
_savedeployconf DEPLOY_SSH_USER "$DEPLOY_SSH_USER"
|
|
||||||
|
|
||||||
# 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
|
if [ -n "$DEPLOY_SSH_SERVER" ]; then
|
||||||
_getdeployconf DEPLOY_SSH_SERVER
|
Le_Deploy_ssh_server="$DEPLOY_SSH_SERVER"
|
||||||
_debug2 DEPLOY_SSH_SERVER "$DEPLOY_SSH_SERVER"
|
_savedomainconf Le_Deploy_ssh_server "$Le_Deploy_ssh_server"
|
||||||
if [ -z "$DEPLOY_SSH_SERVER" ]; then
|
elif [ -z "$Le_Deploy_ssh_server" ]; then
|
||||||
DEPLOY_SSH_SERVER="$_cdomain"
|
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
|
if [ -n "$DEPLOY_SSH_CMD" ]; then
|
||||||
_getdeployconf DEPLOY_SSH_CMD
|
Le_Deploy_ssh_cmd="$DEPLOY_SSH_CMD"
|
||||||
_debug2 DEPLOY_SSH_CMD "$DEPLOY_SSH_CMD"
|
_savedomainconf Le_Deploy_ssh_cmd "$Le_Deploy_ssh_cmd"
|
||||||
if [ -z "$DEPLOY_SSH_CMD" ]; then
|
elif [ -z "$Le_Deploy_ssh_cmd" ]; then
|
||||||
DEPLOY_SSH_CMD="ssh -T"
|
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
|
if [ "$DEPLOY_SSH_BACKUP" = "no" ]; then
|
||||||
_getdeployconf DEPLOY_SSH_BACKUP
|
Le_Deploy_ssh_backup="no"
|
||||||
_debug2 DEPLOY_SSH_BACKUP "$DEPLOY_SSH_BACKUP"
|
elif [ -z "$Le_Deploy_ssh_backup" ] || [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||||
if [ -z "$DEPLOY_SSH_BACKUP" ]; then
|
Le_Deploy_ssh_backup="yes"
|
||||||
DEPLOY_SSH_BACKUP="yes"
|
|
||||||
fi
|
fi
|
||||||
_savedeployconf DEPLOY_SSH_BACKUP "$DEPLOY_SSH_BACKUP"
|
_savedomainconf Le_Deploy_ssh_backup "$Le_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
|
if [ -n "$DEPLOY_SSH_BACKUP_PATH" ]; then
|
||||||
_getdeployconf DEPLOY_SSH_BACKUP_PATH
|
Le_Deploy_ssh_backup_path="$DEPLOY_SSH_BACKUP_PATH"
|
||||||
_debug2 DEPLOY_SSH_BACKUP_PATH "$DEPLOY_SSH_BACKUP_PATH"
|
elif [ -z "$Le_Deploy_ssh_backup_path" ]; then
|
||||||
if [ -z "$DEPLOY_SSH_BACKUP_PATH" ]; then
|
Le_Deploy_ssh_backup_path=".acme_ssh_deploy"
|
||||||
DEPLOY_SSH_BACKUP_PATH=".acme_ssh_deploy"
|
|
||||||
fi
|
fi
|
||||||
_savedeployconf DEPLOY_SSH_BACKUP_PATH "$DEPLOY_SSH_BACKUP_PATH"
|
_savedomainconf Le_Deploy_ssh_backup_path "$Le_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
|
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||||
_getdeployconf DEPLOY_SSH_MULTI_CALL
|
Le_Deploy_ssh_multi_call="yes"
|
||||||
_debug2 DEPLOY_SSH_MULTI_CALL "$DEPLOY_SSH_MULTI_CALL"
|
_savedomainconf Le_Deploy_ssh_multi_call "$Le_Deploy_ssh_multi_call"
|
||||||
if [ -z "$DEPLOY_SSH_MULTI_CALL" ]; then
|
elif [ "$DEPLOY_SSH_MULTI_CALL" = "no" ]; then
|
||||||
DEPLOY_SSH_MULTI_CALL="no"
|
Le_Deploy_ssh_multi_call=""
|
||||||
fi
|
_cleardomainconf Le_Deploy_ssh_multi_call
|
||||||
_savedeployconf DEPLOY_SSH_MULTI_CALL "$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
|
||||||
|
|
||||||
# CERTFILE is optional.
|
_deploy_ssh_servers=$Le_Deploy_ssh_server
|
||||||
# If provided then certificate will be copied or appended to provided filename.
|
for Le_Deploy_ssh_server in $_deploy_ssh_servers; do
|
||||||
_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
|
||||||
}
|
}
|
||||||
@ -181,25 +110,16 @@ _ssh_deploy() {
|
|||||||
_cmdstr=""
|
_cmdstr=""
|
||||||
_backupprefix=""
|
_backupprefix=""
|
||||||
_backupdir=""
|
_backupdir=""
|
||||||
_local_cert_file=""
|
|
||||||
_local_ca_file=""
|
|
||||||
_local_full_file=""
|
|
||||||
|
|
||||||
case $DEPLOY_SSH_SERVER in
|
_info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server"
|
||||||
*:*)
|
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||||
_host=${DEPLOY_SSH_SERVER%:*}
|
_info "Using MULTI_CALL mode... Required commands sent in multiple calls to remote host"
|
||||||
_port=${DEPLOY_SSH_SERVER##*:}
|
else
|
||||||
;;
|
_info "Required commands batched and sent in single call to remote host"
|
||||||
*)
|
fi
|
||||||
_host=$DEPLOY_SSH_SERVER
|
|
||||||
_port=
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
_info "Deploy certificates to remote server $DEPLOY_SSH_USER@$_host:$_port"
|
if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||||
|
_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).
|
||||||
@ -211,7 +131,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 [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
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
|
||||||
@ -219,184 +139,119 @@ 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.
|
||||||
if [ -n "$DEPLOY_SSH_KEYFILE" ]; then
|
if [ -n "$DEPLOY_SSH_KEYFILE" ]; then
|
||||||
if [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
Le_Deploy_ssh_keyfile="$DEPLOY_SSH_KEYFILE"
|
||||||
|
_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 $DEPLOY_SSH_KEYFILE $_backupdir >/dev/null;"
|
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir >/dev/null;"
|
||||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
|
||||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
|
||||||
return $_err_code
|
|
||||||
fi
|
|
||||||
_cmdstr=""
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
# copy new certificate into file.
|
||||||
# copy new key into file.
|
_cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile;"
|
||||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
_info "will copy private key to remote file $Le_Deploy_ssh_keyfile"
|
||||||
# scp the file
|
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||||
if ! _scp_remote_cmd "$_ckey" "$DEPLOY_SSH_KEYFILE"; then
|
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||||
return $_err_code
|
return $_err_code
|
||||||
fi
|
fi
|
||||||
else
|
_cmdstr=""
|
||||||
# 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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# CERTFILE is optional.
|
||||||
|
# If provided then certificate will be copied or appended to provided filename.
|
||||||
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 [ "$DEPLOY_SSH_CERTFILE" = "$DEPLOY_SSH_KEYFILE" ]; then
|
if [ "$Le_Deploy_ssh_certfile" = "$Le_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 [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||||
# backup file we are about to overwrite.
|
# backup file we are about to overwrite.
|
||||||
_cmdstr="$_cmdstr cp $DEPLOY_SSH_CERTFILE $_backupdir >/dev/null;"
|
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir >/dev/null;"
|
||||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
|
||||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
|
||||||
return $_err_code
|
|
||||||
fi
|
|
||||||
_cmdstr=""
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# copy new certificate into file.
|
# copy new certificate into file.
|
||||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
_cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile;"
|
||||||
# scp the file
|
_info "will copy certificate to remote file $Le_Deploy_ssh_certfile"
|
||||||
_local_cert_file=$(_mktemp)
|
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||||
if [ "$DEPLOY_SSH_CERTFILE" = "$DEPLOY_SSH_KEYFILE" ]; then
|
if ! _ssh_remote_cmd "$_cmdstr"; 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
|
return $_err_code
|
||||||
fi
|
fi
|
||||||
else
|
_cmdstr=""
|
||||||
# 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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# CAFILE is optional.
|
||||||
|
# If provided then CA intermediate certificate will be copied or appended to provided filename.
|
||||||
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 [ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_KEYFILE" ] ||
|
if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] ||
|
||||||
[ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_CERTFILE" ]; then
|
[ "$Le_Deploy_ssh_cafile" = "$Le_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 [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||||
# backup file we are about to overwrite.
|
# backup file we are about to overwrite.
|
||||||
_cmdstr="$_cmdstr cp $DEPLOY_SSH_CAFILE $_backupdir >/dev/null;"
|
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir >/dev/null;"
|
||||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
|
||||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
|
||||||
return $_err_code
|
|
||||||
fi
|
|
||||||
_cmdstr=""
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# copy new certificate into file.
|
# copy new certificate into file.
|
||||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
_cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile;"
|
||||||
# scp the file
|
_info "will copy CA file to remote file $Le_Deploy_ssh_cafile"
|
||||||
_local_ca_file=$(_mktemp)
|
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||||
if [ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_KEYFILE" ]; then
|
if ! _ssh_remote_cmd "$_cmdstr"; 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
|
return $_err_code
|
||||||
fi
|
fi
|
||||||
else
|
_cmdstr=""
|
||||||
# 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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# FULLCHAIN is optional.
|
||||||
|
# If provided then fullchain certificate will be copied or appended to provided filename.
|
||||||
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 [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_KEYFILE" ] ||
|
if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] ||
|
||||||
[ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CERTFILE" ] ||
|
[ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] ||
|
||||||
[ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CAFILE" ]; then
|
[ "$Le_Deploy_ssh_fullchain" = "$Le_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 [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||||
# backup file we are about to overwrite.
|
# backup file we are about to overwrite.
|
||||||
_cmdstr="$_cmdstr cp $DEPLOY_SSH_FULLCHAIN $_backupdir >/dev/null;"
|
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir >/dev/null;"
|
||||||
if [ "$DEPLOY_SSH_FULLCHAIN" = "yes" ]; then
|
|
||||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
|
||||||
return $_err_code
|
|
||||||
fi
|
|
||||||
_cmdstr=""
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# copy new certificate into file.
|
# copy new certificate into file.
|
||||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
_cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain;"
|
||||||
# scp the file
|
_info "will copy fullchain to remote file $Le_Deploy_ssh_fullchain"
|
||||||
_local_full_file=$(_mktemp)
|
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||||
if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_KEYFILE" ]; then
|
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||||
cat "$_ckey" >>"$_local_full_file"
|
|
||||||
fi
|
|
||||||
if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CERTFILE" ]; then
|
|
||||||
cat "$_ccert" >>"$_local_full_file"
|
|
||||||
fi
|
|
||||||
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
|
return $_err_code
|
||||||
fi
|
fi
|
||||||
else
|
_cmdstr=""
|
||||||
# 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
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# cleanup local files if any
|
# REMOTE_CMD is optional.
|
||||||
if [ -f "$_local_cert_file" ]; then
|
# If provided then this command will be executed on remote host.
|
||||||
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
|
if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
|
||||||
_cmdstr="$_cmdstr $DEPLOY_SSH_REMOTE_CMD;"
|
Le_Deploy_ssh_remote_cmd="$DEPLOY_SSH_REMOTE_CMD"
|
||||||
_info "Will execute remote command $DEPLOY_SSH_REMOTE_CMD"
|
_savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd"
|
||||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
fi
|
||||||
|
if [ -n "$Le_Deploy_ssh_remote_cmd" ]; then
|
||||||
|
_cmdstr="$_cmdstr $Le_Deploy_ssh_remote_cmd;"
|
||||||
|
_info "Will execute remote command $Le_Deploy_ssh_remote_cmd"
|
||||||
|
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
|
||||||
@ -410,25 +265,17 @@ 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_cmd"
|
_info "Submitting sequence of commands to remote server by ssh"
|
||||||
|
|
||||||
# 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
|
||||||
$_ssh_cmd "$DEPLOY_SSH_USER@$_host" sh -c "'$_cmd'"
|
$Le_Deploy_ssh_cmd "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh -c "'$_cmd'"
|
||||||
_err_code="$?"
|
_err_code="$?"
|
||||||
|
|
||||||
if [ "$_err_code" != "0" ]; then
|
if [ "$_err_code" != "0" ]; then
|
||||||
@ -437,26 +284,3 @@ _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,53 +1,29 @@
|
|||||||
#!/bin/bash
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
################################################################################
|
# Here is a script to deploy cert to Synology DSM
|
||||||
# ACME.sh 3rd party deploy plugin for Synology DSM
|
#
|
||||||
################################################################################
|
# it requires the jq and curl are in the $PATH and the following
|
||||||
# Authors: Brian Hartvigsen (creator), https://github.com/tresni
|
# environment variables must be set:
|
||||||
# Martin Arndt (contributor), https://troublezone.net/
|
#
|
||||||
# Updated: 2023-07-03
|
# SYNO_Username - Synology Username to login (must be an administrator)
|
||||||
# Issues: https://github.com/acmesh-official/acme.sh/issues/2727
|
# SYNO_Password - Synology Password to login
|
||||||
################################################################################
|
# SYNO_Certificate - Certificate description to target for replacement
|
||||||
# Usage (shown values are the examples):
|
#
|
||||||
# 1. Set required environment variables:
|
# The following environmental variables may be set if you don't like their
|
||||||
# - use automatically created temp admin user to authenticate
|
# default values:
|
||||||
# export SYNO_USE_TEMP_ADMIN=1
|
#
|
||||||
# - or provide your own admin user credential to authenticate
|
# SYNO_Scheme - defaults to http
|
||||||
# 1. export SYNO_USERNAME="adminUser"
|
# SYNO_Hostname - defaults to localhost
|
||||||
# 2. export SYNO_PASSWORD="adminPassword"
|
# SYNO_Port - defaults to 5000
|
||||||
# 2. Set optional environment variables
|
# SYNO_DID - device ID to skip OTP - defaults to empty
|
||||||
# - common optional variables
|
#
|
||||||
# - export SYNO_SCHEME="http" - defaults to "http"
|
#returns 0 means success, otherwise error.
|
||||||
# - export SYNO_HOSTNAME="localhost" - defaults to "localhost"
|
|
||||||
# - export SYNO_PORT="5000" - defaults to "5000"
|
######## Public functions #####################
|
||||||
# - 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:
|
|
||||||
# - curl
|
|
||||||
# - synouser & synogroup (When available and SYNO_USE_TEMP_ADMIN is set)
|
|
||||||
################################################################################
|
|
||||||
# Return value:
|
|
||||||
# 0 means success, otherwise error.
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
########## 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"
|
||||||
@ -55,380 +31,135 @@ synology_dsm_deploy() {
|
|||||||
|
|
||||||
_debug _cdomain "$_cdomain"
|
_debug _cdomain "$_cdomain"
|
||||||
|
|
||||||
# Get username and password, but don't save until we authenticated successfully
|
# Get Username and Password, but don't save until we successfully authenticate
|
||||||
_migratedeployconf SYNO_Username SYNO_USERNAME
|
_getdeployconf SYNO_Username
|
||||||
_migratedeployconf SYNO_Password SYNO_PASSWORD
|
_getdeployconf SYNO_Password
|
||||||
_migratedeployconf SYNO_Device_ID SYNO_DEVICE_ID
|
_getdeployconf SYNO_Create
|
||||||
_migratedeployconf SYNO_Device_Name SYNO_DEVICE_NAME
|
_getdeployconf SYNO_DID
|
||||||
_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
|
|
||||||
_debug2 SYNO_USE_TEMP_ADMIN "$SYNO_USE_TEMP_ADMIN"
|
|
||||||
_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; then
|
|
||||||
_err "Tools are missing for creating temp admin user, please set SYNO_USERNAME and SYNO_PASSWORD instead."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
[ -n "$SYNO_USERNAME" ] || _savedeployconf SYNO_USERNAME ""
|
|
||||||
[ -n "$SYNO_PASSWORD" ] || _savedeployconf SYNO_PASSWORD ""
|
|
||||||
|
|
||||||
_debug "Setting temp admin user credential..."
|
|
||||||
SYNO_USERNAME=sc-acmesh-tmp
|
|
||||||
SYNO_PASSWORD=$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 16)
|
|
||||||
# Set 2FA-OTP settings to empty consider they won't be needed.
|
|
||||||
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
|
|
||||||
|
|
||||||
if [ -z "$SYNO_USERNAME" ] || [ -z "$SYNO_PASSWORD" ]; then
|
|
||||||
_err "You must set either SYNO_USE_TEMP_ADMIN, or set both SYNO_USERNAME and SYNO_PASSWORD."
|
|
||||||
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
|
# Optional scheme, hostname, and port for Synology DSM
|
||||||
_migratedeployconf SYNO_Scheme SYNO_SCHEME
|
_getdeployconf SYNO_Scheme
|
||||||
_migratedeployconf SYNO_Hostname SYNO_HOSTNAME
|
_getdeployconf SYNO_Hostname
|
||||||
_migratedeployconf SYNO_Port SYNO_PORT
|
_getdeployconf SYNO_Port
|
||||||
_getdeployconf SYNO_SCHEME
|
|
||||||
_getdeployconf SYNO_HOSTNAME
|
|
||||||
_getdeployconf SYNO_PORT
|
|
||||||
|
|
||||||
# Default values for scheme, hostname and port
|
# default vaules for scheme, hostname, and port
|
||||||
# Defaulting to localhost and http, because it's localhost…
|
# defaulting to localhost and http because it's localhost...
|
||||||
[ -n "$SYNO_SCHEME" ] || SYNO_SCHEME="http"
|
[ -n "${SYNO_Scheme}" ] || SYNO_Scheme="http"
|
||||||
[ -n "$SYNO_HOSTNAME" ] || SYNO_HOSTNAME="localhost"
|
[ -n "${SYNO_Hostname}" ] || SYNO_Hostname="localhost"
|
||||||
[ -n "$SYNO_PORT" ] || SYNO_PORT="5000"
|
[ -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
|
_savedeployconf SYNO_Scheme "$SYNO_Scheme"
|
||||||
_migratedeployconf SYNO_Certificate SYNO_CERTIFICATE "base64"
|
_savedeployconf SYNO_Hostname "$SYNO_Hostname"
|
||||||
_getdeployconf SYNO_CERTIFICATE
|
_savedeployconf SYNO_Port "$SYNO_Port"
|
||||||
_check2cleardeployconfexp SYNO_CERTIFICATE
|
|
||||||
_debug SYNO_CERTIFICATE "${SYNO_CERTIFICATE:-}"
|
_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 verfiy it's real
|
||||||
|
_getdeployconf 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
|
||||||
|
|
||||||
_debug "Getting API version..."
|
_base_url="$SYNO_Scheme://$SYNO_Hostname:$SYNO_Port"
|
||||||
_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 session ID and SynoToken from JSON
|
# Login, get the token from JSON and session id from cookie
|
||||||
_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
|
if [ -n "$SYNO_DID" ]; then
|
||||||
_getdeployconf SYNO_TOTP_SECRET
|
_H1="Cookie: did=$SYNO_DID"
|
||||||
|
export _H1
|
||||||
if [ -n "$SYNO_TOTP_SECRET" ]; then
|
_debug3 H1 "${_H1}"
|
||||||
_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
|
|
||||||
DEPRECATED_otp_code="$(oathtool --base32 --totp "$SYNO_TOTP_SECRET" 2>/dev/null)"
|
|
||||||
|
|
||||||
if [ -z "$SYNO_DEVICE_ID" ]; then
|
|
||||||
_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
|
|
||||||
_debug3 H1 "${_H1}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
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/auth.cgi?enable_syno_token=yes")
|
|
||||||
_debug3 response "$response"
|
|
||||||
# ## END ## - DEPRECATED, for backward compatibility
|
|
||||||
# If SYNO_DEVICE_ID or SYNO_OTP_CODE is set, we treat current account enabled 2FA-OTP.
|
|
||||||
# Notice that if SYNO_USE_TEMP_ADMIN=1, both variables will be unset
|
|
||||||
else
|
|
||||||
if [ -n "$SYNO_DEVICE_ID" ] || [ -n "$SYNO_OTP_CODE" ]; then
|
|
||||||
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 locally deployment, if you are sure that hostname $SYNO_HOSTNAME is targeting to your **current local machine**, execute 'export SYNO_LOCAL_HOSTNAME=1' then rerun."
|
|
||||||
return 1
|
|
||||||
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 "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
|
|
||||||
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 "Temporary disabled enforce 2FA-OTP to complete authentication."
|
|
||||||
_info "previous_otp_enforce_option" "$otp_enforce_option"
|
|
||||||
else
|
|
||||||
otp_enforce_option=""
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
response=$(_get "$_base_url/webapi/entry.cgi?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
|
fi
|
||||||
|
|
||||||
error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*')
|
response=$(_post "method=login&account=$encoded_username&passwd=$encoded_password&api=SYNO.API.Auth&version=$api_version&enable_syno_token=yes" "$_base_url/webapi/auth.cgi?enable_syno_token=yes")
|
||||||
_debug2 error_code "$error_code"
|
|
||||||
# Account has 2FA-OTP enabled, since error 403 reported.
|
|
||||||
# https://global.download.synology.com/download/Document/Software/DeveloperGuide/Firmware/DSM/All/enu/Synology_DiskStation_Administration_CLI_Guide.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 "SYNO_USE_TEMP_ADMIN=1 is not supported if enforce auth with 2FA-OTP is enabled."
|
|
||||||
else
|
|
||||||
_err "Enforce auth with 2FA-OTP enabled, please configure the user to enable 2FA-OTP to continue."
|
|
||||||
fi
|
|
||||||
elif [ "$error_code" == "400" ] || [ "$error_code" == "401" ] || [ "$error_code" == "408" ] || [ "$error_code" == "409" ] || [ "$error_code" == "410" ]; then
|
|
||||||
_err "Failed to authenticate with a non-existent or disabled account, or the account password is incorrect or has expired."
|
|
||||||
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')
|
|
||||||
token=$(echo "$response" | grep "synotoken" | sed -n 's/.*"synotoken" *: *"\([^"]*\).*/\1/p')
|
token=$(echo "$response" | grep "synotoken" | sed -n 's/.*"synotoken" *: *"\([^"]*\).*/\1/p')
|
||||||
_debug "Session ID" "$sid"
|
_debug3 response "$response"
|
||||||
_debug SynoToken "$token"
|
_debug token "$token"
|
||||||
if [ -z "$sid" ] || [ -z "$token" ]; then
|
|
||||||
# Still can't get necessary info even got no errors, may Synology have API updated?
|
if [ -z "$token" ]; then
|
||||||
_err "Unable to authenticate to $_base_url, you may report the full log to the community."
|
_err "Unable to authenticate to $SYNO_Hostname:$SYNO_Port using $SYNO_Scheme."
|
||||||
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
_err "Check your username and password."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
sid=$(echo "$response" | grep "sid" | sed -n 's/.*"sid" *: *"\([^"]*\).*/\1/p')
|
||||||
|
|
||||||
_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 if not in temp admin mode.
|
# Now that we know the username and password are good, save them
|
||||||
if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
|
_savedeployconf SYNO_Username "$SYNO_Username"
|
||||||
_cleardeployconf SYNO_USERNAME
|
_savedeployconf SYNO_Password "$SYNO_Password"
|
||||||
_cleardeployconf SYNO_PASSWORD
|
_savedeployconf SYNO_DID "$SYNO_DID"
|
||||||
_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"
|
||||||
|
|
||||||
error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*')
|
if [ -z "$id" ] && [ -z "${SYNO_Create:-}" ]; then
|
||||||
_debug2 error_code "$error_code"
|
_err "Unable to find certificate: $SYNO_Certificate and \$SYNO_Create is not set"
|
||||||
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 with error: $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
|
||||||
|
|
||||||
_migratedeployconf SYNO_Create SYNO_CREATE
|
# we've verified this certificate description is a thing, so save it
|
||||||
_getdeployconf SYNO_CREATE
|
_savedeployconf SYNO_Certificate "$SYNO_Certificate" "base64"
|
||||||
_debug2 SYNO_CREATE "$SYNO_CREATE"
|
|
||||||
|
|
||||||
if [ -z "$id" ] && [ -z "$SYNO_CREATE" ]; then
|
_info "Generate form POST request"
|
||||||
_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 "Restart HTTP services succeeded."
|
_info "http services were restarted"
|
||||||
else
|
else
|
||||||
_info "Restart HTTP services failed."
|
_info "http services were NOT restarted"
|
||||||
fi
|
fi
|
||||||
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
|
||||||
_logout
|
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
_err "Unable to update certificate, error code $response"
|
||||||
_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
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,223 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
# Here is a scipt to deploy the cert to your TrueNAS using the REST API.
|
|
||||||
# https://www.truenas.com/docs/hub/additional-topics/api/rest_api.html
|
|
||||||
#
|
|
||||||
# Written by Frank Plass github@f-plass.de
|
|
||||||
# https://github.com/danb35/deploy-freenas/blob/master/deploy_freenas.py
|
|
||||||
# Thanks to danb35 for your template!
|
|
||||||
#
|
|
||||||
# Following environment variables must be set:
|
|
||||||
#
|
|
||||||
# export DEPLOY_TRUENAS_APIKEY="<API_KEY_GENERATED_IN_THE_WEB_UI"
|
|
||||||
#
|
|
||||||
# The following environmental variables may be set if you don't like their
|
|
||||||
# default values:
|
|
||||||
#
|
|
||||||
# DEPLOY_TRUENAS_HOSTNAME - defaults to localhost
|
|
||||||
# DEPLOY_TRUENAS_SCHEME - defaults to http, set alternatively to https
|
|
||||||
#
|
|
||||||
#returns 0 means success, otherwise error.
|
|
||||||
|
|
||||||
######## Public functions #####################
|
|
||||||
|
|
||||||
#domain keyfile certfile cafile fullchain
|
|
||||||
truenas_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_TRUENAS_APIKEY
|
|
||||||
|
|
||||||
if [ -z "$DEPLOY_TRUENAS_APIKEY" ]; then
|
|
||||||
_err "TrueNAS API key not found, please set the DEPLOY_TRUENAS_APIKEY environment variable."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_secure_debug2 DEPLOY_TRUENAS_APIKEY "$DEPLOY_TRUENAS_APIKEY"
|
|
||||||
|
|
||||||
# Optional hostname, scheme for TrueNAS
|
|
||||||
_getdeployconf DEPLOY_TRUENAS_HOSTNAME
|
|
||||||
_getdeployconf DEPLOY_TRUENAS_SCHEME
|
|
||||||
|
|
||||||
# default values for hostname and scheme
|
|
||||||
[ -n "${DEPLOY_TRUENAS_HOSTNAME}" ] || DEPLOY_TRUENAS_HOSTNAME="localhost"
|
|
||||||
[ -n "${DEPLOY_TRUENAS_SCHEME}" ] || DEPLOY_TRUENAS_SCHEME="http"
|
|
||||||
|
|
||||||
_debug2 DEPLOY_TRUENAS_HOSTNAME "$DEPLOY_TRUENAS_HOSTNAME"
|
|
||||||
_debug2 DEPLOY_TRUENAS_SCHEME "$DEPLOY_TRUENAS_SCHEME"
|
|
||||||
|
|
||||||
_api_url="$DEPLOY_TRUENAS_SCHEME://$DEPLOY_TRUENAS_HOSTNAME/api/v2.0"
|
|
||||||
_debug _api_url "$_api_url"
|
|
||||||
|
|
||||||
_H1="Authorization: Bearer $DEPLOY_TRUENAS_APIKEY"
|
|
||||||
_secure_debug3 _H1 "$_H1"
|
|
||||||
|
|
||||||
_info "Testing Connection TrueNAS"
|
|
||||||
_response=$(_get "$_api_url/system/state")
|
|
||||||
_info "TrueNAS system state: $_response."
|
|
||||||
|
|
||||||
if [ -z "$_response" ]; then
|
|
||||||
_err "Unable to authenticate to $_api_url."
|
|
||||||
_err 'Check your connection settings are correct, e.g.'
|
|
||||||
_err 'DEPLOY_TRUENAS_HOSTNAME="192.168.x.y" or DEPLOY_TRUENAS_HOSTNAME="truenas.example.com".'
|
|
||||||
_err 'DEPLOY_TRUENAS_SCHEME="https" or DEPLOY_TRUENAS_SCHEME="http".'
|
|
||||||
_err "Verify your TrueNAS API key is valid and set correctly, e.g. DEPLOY_TRUENAS_APIKEY=xxxx...."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
_savedeployconf DEPLOY_TRUENAS_APIKEY "$DEPLOY_TRUENAS_APIKEY"
|
|
||||||
_savedeployconf DEPLOY_TRUENAS_HOSTNAME "$DEPLOY_TRUENAS_HOSTNAME"
|
|
||||||
_savedeployconf DEPLOY_TRUENAS_SCHEME "$DEPLOY_TRUENAS_SCHEME"
|
|
||||||
|
|
||||||
_info "Getting current active certificate from TrueNAS"
|
|
||||||
_response=$(_get "$_api_url/system/general")
|
|
||||||
_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')
|
|
||||||
_param_httpsredirect=$(echo "$_response" | grep '"ui_httpsredirect":' | sed -n 's/.*": \(.\{1,\}\),$/\1/p')
|
|
||||||
_debug Active_UI_Certificate_ID "$_active_cert_id"
|
|
||||||
_debug Active_UI_Certificate_Name "$_active_cert_name"
|
|
||||||
_debug Active_UI_http_redirect "$_param_httpsredirect"
|
|
||||||
|
|
||||||
if [ "$DEPLOY_TRUENAS_SCHEME" = "http" ] && [ "$_param_httpsredirect" = "true" ]; then
|
|
||||||
_info "HTTP->HTTPS redirection is enabled"
|
|
||||||
_info "Setting DEPLOY_TRUENAS_SCHEME to 'https'"
|
|
||||||
DEPLOY_TRUENAS_SCHEME="https"
|
|
||||||
_api_url="$DEPLOY_TRUENAS_SCHEME://$DEPLOY_TRUENAS_HOSTNAME/api/v2.0"
|
|
||||||
_savedeployconf DEPLOY_TRUENAS_SCHEME "$DEPLOY_TRUENAS_SCHEME"
|
|
||||||
fi
|
|
||||||
|
|
||||||
_info "Uploading new certificate to TrueNAS"
|
|
||||||
_certname="Letsencrypt_$(_utc_date | tr ' ' '_' | tr -d -- ':')"
|
|
||||||
_debug3 _certname "$_certname"
|
|
||||||
|
|
||||||
_certData="{\"create_type\": \"CERTIFICATE_CREATE_IMPORTED\", \"name\": \"${_certname}\", \"certificate\": \"$(_json_encode <"$_cfullchain")\", \"privatekey\": \"$(_json_encode <"$_ckey")\"}"
|
|
||||||
_add_cert_result="$(_post "$_certData" "$_api_url/certificate" "" "POST" "application/json")"
|
|
||||||
|
|
||||||
_debug3 _add_cert_result "$_add_cert_result"
|
|
||||||
|
|
||||||
_info "Fetching list of installed certificates"
|
|
||||||
_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')
|
|
||||||
|
|
||||||
_debug3 _cert_id "$_cert_id"
|
|
||||||
|
|
||||||
_info "Current activate certificate ID: $_cert_id"
|
|
||||||
_activateData="{\"ui_certificate\": \"${_cert_id}\"}"
|
|
||||||
_activate_result="$(_post "$_activateData" "$_api_url/system/general" "" "PUT" "application/json")"
|
|
||||||
|
|
||||||
_debug3 _activate_result "$_activate_result"
|
|
||||||
|
|
||||||
_info "Checking if WebDAV certificate is the same as the TrueNAS web UI"
|
|
||||||
_webdav_list=$(_get "$_api_url/webdav")
|
|
||||||
_webdav_cert_id=$(echo "$_webdav_list" | grep '"certssl":' | tr -d -- '"certsl: ,')
|
|
||||||
|
|
||||||
if [ "$_webdav_cert_id" = "$_active_cert_id" ]; then
|
|
||||||
_info "Updating the WebDAV certificate"
|
|
||||||
_debug _webdav_cert_id "$_webdav_cert_id"
|
|
||||||
_webdav_data="{\"certssl\": \"${_cert_id}\"}"
|
|
||||||
_activate_webdav_cert="$(_post "$_webdav_data" "$_api_url/webdav" "" "PUT" "application/json")"
|
|
||||||
_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
|
|
||||||
_info "WebDAV certificate updated successfully"
|
|
||||||
else
|
|
||||||
_err "Unable to set WebDAV certificate"
|
|
||||||
_debug3 _activate_webdav_cert "$_activate_webdav_cert"
|
|
||||||
_debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
|
|
||||||
else
|
|
||||||
_info "WebDAV certificate is not configured or is not the same as TrueNAS web UI"
|
|
||||||
fi
|
|
||||||
|
|
||||||
_info "Checking if FTP certificate is the same as the TrueNAS web UI"
|
|
||||||
_ftp_list=$(_get "$_api_url/ftp")
|
|
||||||
_ftp_cert_id=$(echo "$_ftp_list" | grep '"ssltls_certificate":' | tr -d -- '"certislfa:_ ,')
|
|
||||||
|
|
||||||
if [ "$_ftp_cert_id" = "$_active_cert_id" ]; then
|
|
||||||
_info "Updating the FTP certificate"
|
|
||||||
_debug _ftp_cert_id "$_ftp_cert_id"
|
|
||||||
_ftp_data="{\"ssltls_certificate\": \"${_cert_id}\"}"
|
|
||||||
_activate_ftp_cert="$(_post "$_ftp_data" "$_api_url/ftp" "" "PUT" "application/json")"
|
|
||||||
_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
|
|
||||||
_info "FTP certificate updated successfully"
|
|
||||||
else
|
|
||||||
_err "Unable to set FTP certificate"
|
|
||||||
_debug3 _activate_ftp_cert "$_activate_ftp_cert"
|
|
||||||
_debug3 _ftp_new_cert_id "$_ftp_new_cert_id"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_debug3 _activate_ftp_cert "$_activate_ftp_cert"
|
|
||||||
else
|
|
||||||
_info "FTP certificate is not configured or is not the same as TrueNAS web UI"
|
|
||||||
fi
|
|
||||||
|
|
||||||
_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")"
|
|
||||||
|
|
||||||
_debug3 _delete_result "$_delete_result"
|
|
||||||
|
|
||||||
_info "Reloading TrueNAS web UI"
|
|
||||||
_restart_UI=$(_get "$_api_url/system/general/ui_restart")
|
|
||||||
_debug2 _restart_UI "$_restart_UI"
|
|
||||||
|
|
||||||
if [ -n "$_add_cert_result" ] && [ -n "$_activate_result" ]; then
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
_err "Certificate update was not succesful, please try again with --debug"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
@ -7,16 +7,13 @@
|
|||||||
#
|
#
|
||||||
# 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
|
||||||
|
|
||||||
#returns 0 means success, otherwise error.
|
#returns 0 means success, otherwise error.
|
||||||
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
#domain keyfile certfile cafile fullchain
|
#domain keyfile certfile cafile fullchain
|
||||||
vault_deploy() {
|
vault_deploy() {
|
||||||
@ -48,26 +45,6 @@ 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 -z 's/\n/\\n/g' <"$2")
|
||||||
@ -75,57 +52,16 @@ vault_deploy() {
|
|||||||
_cca=$(sed -z 's/\n/\\n/g' <"$4")
|
_cca=$(sed -z 's/\n/\\n/g' <"$4")
|
||||||
_cfullchain=$(sed -z 's/\n/\\n/g' <"$5")
|
_cfullchain=$(sed -z '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 "$VAULT_RENEW_TOKEN" ]; then
|
if [ -n "$FABIO" ]; then
|
||||||
URL="$VAULT_ADDR/v1/auth/token/renew-self"
|
_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL"
|
||||||
_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
|
|
||||||
_post "{ \"data\": {\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"} }" "$URL" >/dev/null || return 1
|
|
||||||
else
|
|
||||||
_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL" >/dev/null || return 1
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
if [ -n "$VAULT_KV_V2" ]; then
|
_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem"
|
||||||
_info "Writing certificate to $URL/cert.pem"
|
_post "{\"value\": \"$_ckey\"}" "$URL/cert.key"
|
||||||
_post "{\"data\": {\"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 "{\"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
|
|
||||||
_info "Writing certificate to $URL/cert.pem"
|
|
||||||
_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem" >/dev/null || return 1
|
|
||||||
_info "Writing key to $URL/cert.key"
|
|
||||||
_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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,8 +8,6 @@
|
|||||||
#
|
#
|
||||||
# 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
|
||||||
@ -35,36 +33,15 @@ 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
|
||||||
@ -72,33 +49,13 @@ vault_cli_deploy() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$VAULT_RENEW_TOKEN" ]; then
|
if [ -n "$FABIO" ]; 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
|
||||||
_info "Writing CA certificate to ${VAULT_PREFIX}/${_cdomain}/ca.pem"
|
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/chain.pem" value=@"$_cca" || return 1
|
||||||
$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,175 +1,167 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
# This file name is "dns_1984hosting.sh"
|
#This file name is "dns_1984hosting.sh"
|
||||||
# So, here must be a method dns_1984hosting_add()
|
#So, here must be a method dns_1984hosting_add()
|
||||||
# Which will be called by acme.sh to add the txt record to your api system.
|
#Which will be called by acme.sh to add the txt record to your api system.
|
||||||
# returns 0 means success, otherwise error.
|
#returns 0 means success, otherwise error.
|
||||||
|
|
||||||
# Author: Adrian Fedoreanu
|
#Author: Adrian Fedoreanu
|
||||||
# Report Bugs here: https://github.com/acmesh-official/acme.sh
|
#Report Bugs here: https://github.com/acmesh-official/acme.sh
|
||||||
# or here... https://github.com/acmesh-official/acme.sh/issues/2851
|
# or here... https://github.com/acmesh-official/acme.sh/issues/2851
|
||||||
|
#
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
# Export 1984HOSTING username and password in following variables
|
# Export 1984HOSTING username and password in following variables
|
||||||
#
|
#
|
||||||
# One984HOSTING_Username=username
|
# One984HOSTING_Username=username
|
||||||
# One984HOSTING_Password=password
|
# One984HOSTING_Password=password
|
||||||
#
|
#
|
||||||
# username/password and csrftoken/sessionid cookies are saved in ~/.acme.sh/account.conf
|
# 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"
|
#Usage: dns_1984hosting_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||||
# Add a text record.
|
|
||||||
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://1984.hosting/domains/entry/"
|
url="https://management.1984hosting.com/domains/entry/"
|
||||||
|
|
||||||
postdata="entry=new"
|
postdata="entry=new"
|
||||||
postdata="$postdata&type=TXT"
|
postdata="$postdata&type=TXT"
|
||||||
postdata="$postdata&ttl=900"
|
postdata="$postdata&ttl=3600"
|
||||||
postdata="$postdata&zone=$_domain"
|
postdata="$postdata&zone=$_domain"
|
||||||
postdata="$postdata&host=$_sub_domain"
|
postdata="$postdata&host=$_sub_domain"
|
||||||
postdata="$postdata&rdata=%22$value%22"
|
postdata="$postdata&rdata=%22$value%22"
|
||||||
_debug2 postdata "$postdata"
|
_debug2 postdata "$postdata"
|
||||||
|
|
||||||
_authpost "$postdata" "$url"
|
_authpost "$postdata" "$url"
|
||||||
if _contains "$_response" '"haserrors": true'; then
|
response="$(echo "$_response" | _normalizeJson)"
|
||||||
_err "1984Hosting failed to add TXT record for $_sub_domain bad RC from _post."
|
_debug2 response "$response"
|
||||||
|
|
||||||
|
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."
|
|
||||||
|
|
||||||
url="https://1984.hosting/domains"
|
_debug "Delete $fulldomain TXT record"
|
||||||
if ! _get_zone_id "$url" "$_domain"; then
|
url="https://management.1984hosting.com/domains"
|
||||||
_err "Invalid zone '$_domain'."
|
|
||||||
|
_htmlget "$url" "$_domain"
|
||||||
|
_debug2 _response "$_response"
|
||||||
|
zone_id="$(echo "$_response" | _egrep_o 'zone\/[0-9]+')"
|
||||||
|
_debug2 zone_id "$zone_id"
|
||||||
|
if [ -z "$zone_id" ]; then
|
||||||
|
_err "Error getting zone_id for $1"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_htmlget "$url/$_zone_id" "$txtvalue"
|
_htmlget "$url/$zone_id" "$_sub_domain"
|
||||||
|
_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/"
|
||||||
if ! _contains "$_response" '"ok": true'; then
|
response="$(echo "$_response" | _normalizeJson)"
|
||||||
_err "1984Hosting failed to delete TXT record for $entry_id bad RC from _post."
|
_debug2 response "$response"
|
||||||
|
|
||||||
|
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_cookie; 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://1984.hosting/api/auth/"
|
url="https://management.1984hosting.com/accounts/checkuserauth/"
|
||||||
|
|
||||||
_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)"
|
||||||
_debug2 response "$response"
|
_debug2 response "$response"
|
||||||
|
|
||||||
if _contains "$response" '"loggedin": true'; then
|
if _contains "$response" '"loggedin": true'; then
|
||||||
One984HOSTING_SESSIONID_COOKIE="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'sessionid=[^;]*;' | tr -d ';')"
|
One984HOSTING_COOKIE="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _tail_n 1 | _egrep_o 'sessionid=[^;]*;' | tr -d ';')"
|
||||||
One984HOSTING_CSRFTOKEN_COOKIE="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'csrftoken=[^;]*;' | tr -d ';')"
|
export One984HOSTING_COOKIE
|
||||||
export One984HOSTING_SESSIONID_COOKIE
|
_saveaccountconf_mutable One984HOSTING_COOKIE "$One984HOSTING_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_CSRFTOKEN_COOKIE "$One984HOSTING_CSRFTOKEN_COOKIE"
|
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
_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
|
||||||
@ -177,47 +169,43 @@ _check_credentials() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
_check_cookies() {
|
_check_cookie() {
|
||||||
One984HOSTING_SESSIONID_COOKIE="${One984HOSTING_SESSIONID_COOKIE:-$(_readaccountconf_mutable One984HOSTING_SESSIONID_COOKIE)}"
|
One984HOSTING_COOKIE="${One984HOSTING_COOKIE:-$(_readaccountconf_mutable One984HOSTING_COOKIE)}"
|
||||||
One984HOSTING_CSRFTOKEN_COOKIE="${One984HOSTING_CSRFTOKEN_COOKIE:-$(_readaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE)}"
|
if [ -z "$One984HOSTING_COOKIE" ]; then
|
||||||
if [ -z "$One984HOSTING_SESSIONID_COOKIE" ] || [ -z "$One984HOSTING_CSRFTOKEN_COOKIE" ]; then
|
_debug "No cached cookie found"
|
||||||
_debug "No cached cookie(s) found."
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_authget "https://1984.hosting/api/auth/"
|
_authget "https://management.1984hosting.com/accounts/loginstatus/"
|
||||||
if _contains "$_response" '"ok": true'; then
|
if _contains "$response" '"ok": true'; then
|
||||||
_debug "Cached cookies still valid."
|
_debug "Cached cookie still valid"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
_debug "Cached cookie no longer valid"
|
||||||
_debug "Cached cookies no longer valid. Clearing cookies."
|
One984HOSTING_COOKIE=""
|
||||||
One984HOSTING_SESSIONID_COOKIE=""
|
_saveaccountconf_mutable One984HOSTING_COOKIE "$One984HOSTING_COOKIE"
|
||||||
One984HOSTING_CSRFTOKEN_COOKIE=""
|
|
||||||
_clearaccountconf_mutable One984HOSTING_SESSIONID_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() {
|
||||||
domain="$1"
|
domain="$1"
|
||||||
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://1984.hosting/domains/soacheck/?zone=$h&nameserver=ns0.1984.is."
|
_authget "https://management.1984hosting.com/domains/soacheck/?zone=$h&nameserver=ns0.1984.is."
|
||||||
if _contains "$_response" "serial" && ! _contains "$_response" "null"; then
|
if _contains "$_response" "serial" && ! _contains "$_response" 'null}'; 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
|
||||||
@ -227,47 +215,22 @@ _get_root() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# Usage: _get_zone_id url domain.com
|
# add extra headers to request
|
||||||
# Returns zone id for domain.com
|
|
||||||
_get_zone_id() {
|
|
||||||
url=$1
|
|
||||||
domain=$2
|
|
||||||
_htmlget "$url" "$domain"
|
|
||||||
_zone_id="$(echo "$_response" | _egrep_o 'zone\/[0-9]+' | _head_n 1)"
|
|
||||||
_debug2 _zone_id "$_zone_id"
|
|
||||||
if [ -z "$_zone_id" ]; then
|
|
||||||
_err "Error getting _zone_id for $2."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# Add extra headers to request
|
|
||||||
_authget() {
|
_authget() {
|
||||||
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE; $One984HOSTING_SESSIONID_COOKIE"
|
export _H1="Cookie: $One984HOSTING_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
|
# echo: Argument list too long
|
||||||
_htmlget() {
|
_htmlget() {
|
||||||
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE; $One984HOSTING_SESSIONID_COOKIE"
|
export _H1="Cookie: $One984HOSTING_COOKIE"
|
||||||
_response=$(_get "$1" | grep "$2")
|
_response=$(_get "$1" | grep "$2" | _head_n 1)
|
||||||
if _contains "$_response" "@$2"; then
|
|
||||||
_response=$(echo "$_response" | grep -v "[@]" | _head_n 1)
|
|
||||||
fi
|
|
||||||
_debug2 _response "$_response"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Add extra headers to request
|
# add extra headers to request
|
||||||
_authpost() {
|
_authpost() {
|
||||||
url="https://1984.hosting/domains"
|
export _H1="Cookie: $One984HOSTING_COOKIE"
|
||||||
_get_zone_id "$url" "$_domain"
|
_response=$(_post "$1" "$2")
|
||||||
csrf_header="$(echo "$One984HOSTING_CSRFTOKEN_COOKIE" | _egrep_o "=[^=][0-9a-zA-Z]*" | tr -d "=")"
|
|
||||||
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE; $One984HOSTING_SESSIONID_COOKIE"
|
|
||||||
export _H2="Referer: https://1984.hosting/domains/$_zone_id"
|
|
||||||
export _H3="X-CSRFToken: $csrf_header"
|
|
||||||
_response="$(_post "$1" "$2" | _normalizeJson)"
|
|
||||||
_debug2 _response "$_response"
|
|
||||||
}
|
}
|
||||||
|
|||||||
63
dnsapi/dns_acmedns.sh
Executable file → Normal file
63
dnsapi/dns_acmedns.sh
Executable file → Normal file
@ -1,70 +1,31 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
#
|
#
|
||||||
#Author: Wolfgang Ebner
|
#Author: Wolfgang Ebner
|
||||||
#Author: Sven Neubuaer
|
#Report Bugs here: https://github.com/webner/acme.sh
|
||||||
#Report Bugs here: https://github.com/dampfklon/acme.sh
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# export ACMEDNS_BASE_URL="https://auth.acme-dns.io"
|
|
||||||
#
|
|
||||||
# You can optionally define an already existing account:
|
|
||||||
#
|
|
||||||
# export ACMEDNS_USERNAME="<username>"
|
|
||||||
# export ACMEDNS_PASSWORD="<password>"
|
|
||||||
# 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"
|
||||||
# Used to add txt record
|
|
||||||
dns_acmedns_add() {
|
dns_acmedns_add() {
|
||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
txtvalue=$2
|
txtvalue=$2
|
||||||
_info "Using acme-dns"
|
_info "Using acme-dns"
|
||||||
_debug "fulldomain $fulldomain"
|
_debug fulldomain "$fulldomain"
|
||||||
_debug "txtvalue $txtvalue"
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
#for compatiblity from account conf
|
ACMEDNS_UPDATE_URL="${ACMEDNS_UPDATE_URL:-$(_readaccountconf_mutable ACMEDNS_UPDATE_URL)}"
|
||||||
ACMEDNS_USERNAME="${ACMEDNS_USERNAME:-$(_readaccountconf_mutable ACMEDNS_USERNAME)}"
|
ACMEDNS_USERNAME="${ACMEDNS_USERNAME:-$(_readaccountconf_mutable ACMEDNS_USERNAME)}"
|
||||||
_clearaccountconf_mutable ACMEDNS_USERNAME
|
|
||||||
ACMEDNS_PASSWORD="${ACMEDNS_PASSWORD:-$(_readaccountconf_mutable ACMEDNS_PASSWORD)}"
|
ACMEDNS_PASSWORD="${ACMEDNS_PASSWORD:-$(_readaccountconf_mutable ACMEDNS_PASSWORD)}"
|
||||||
_clearaccountconf_mutable ACMEDNS_PASSWORD
|
|
||||||
ACMEDNS_SUBDOMAIN="${ACMEDNS_SUBDOMAIN:-$(_readaccountconf_mutable ACMEDNS_SUBDOMAIN)}"
|
ACMEDNS_SUBDOMAIN="${ACMEDNS_SUBDOMAIN:-$(_readaccountconf_mutable ACMEDNS_SUBDOMAIN)}"
|
||||||
_clearaccountconf_mutable ACMEDNS_SUBDOMAIN
|
|
||||||
|
|
||||||
ACMEDNS_BASE_URL="${ACMEDNS_BASE_URL:-$(_readdomainconf ACMEDNS_BASE_URL)}"
|
if [ "$ACMEDNS_UPDATE_URL" = "" ]; then
|
||||||
ACMEDNS_USERNAME="${ACMEDNS_USERNAME:-$(_readdomainconf ACMEDNS_USERNAME)}"
|
ACMEDNS_UPDATE_URL="https://auth.acme-dns.io/update"
|
||||||
ACMEDNS_PASSWORD="${ACMEDNS_PASSWORD:-$(_readdomainconf ACMEDNS_PASSWORD)}"
|
|
||||||
ACMEDNS_SUBDOMAIN="${ACMEDNS_SUBDOMAIN:-$(_readdomainconf ACMEDNS_SUBDOMAIN)}"
|
|
||||||
|
|
||||||
if [ "$ACMEDNS_BASE_URL" = "" ]; then
|
|
||||||
ACMEDNS_BASE_URL="https://auth.acme-dns.io"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ACMEDNS_UPDATE_URL="$ACMEDNS_BASE_URL/update"
|
_saveaccountconf_mutable ACMEDNS_UPDATE_URL "$ACMEDNS_UPDATE_URL"
|
||||||
ACMEDNS_REGISTER_URL="$ACMEDNS_BASE_URL/register"
|
_saveaccountconf_mutable ACMEDNS_USERNAME "$ACMEDNS_USERNAME"
|
||||||
|
_saveaccountconf_mutable ACMEDNS_PASSWORD "$ACMEDNS_PASSWORD"
|
||||||
if [ -z "$ACMEDNS_USERNAME" ] || [ -z "$ACMEDNS_PASSWORD" ]; then
|
_saveaccountconf_mutable ACMEDNS_SUBDOMAIN "$ACMEDNS_SUBDOMAIN"
|
||||||
response="$(_post "" "$ACMEDNS_REGISTER_URL" "" "POST")"
|
|
||||||
_debug response "$response"
|
|
||||||
ACMEDNS_USERNAME=$(echo "$response" | sed -n 's/^{.*\"username\":[ ]*\"\([^\"]*\)\".*}/\1/p')
|
|
||||||
_debug "received username: $ACMEDNS_USERNAME"
|
|
||||||
ACMEDNS_PASSWORD=$(echo "$response" | sed -n 's/^{.*\"password\":[ ]*\"\([^\"]*\)\".*}/\1/p')
|
|
||||||
_debug "received password: $ACMEDNS_PASSWORD"
|
|
||||||
ACMEDNS_SUBDOMAIN=$(echo "$response" | sed -n 's/^{.*\"subdomain\":[ ]*\"\([^\"]*\)\".*}/\1/p')
|
|
||||||
_debug "received subdomain: $ACMEDNS_SUBDOMAIN"
|
|
||||||
ACMEDNS_FULLDOMAIN=$(echo "$response" | sed -n 's/^{.*\"fulldomain\":[ ]*\"\([^\"]*\)\".*}/\1/p')
|
|
||||||
_info "##########################################################"
|
|
||||||
_info "# Create $fulldomain CNAME $ACMEDNS_FULLDOMAIN DNS entry #"
|
|
||||||
_info "##########################################################"
|
|
||||||
_info "Press enter to continue... "
|
|
||||||
read -r _
|
|
||||||
fi
|
|
||||||
|
|
||||||
_savedomainconf ACMEDNS_BASE_URL "$ACMEDNS_BASE_URL"
|
|
||||||
_savedomainconf ACMEDNS_USERNAME "$ACMEDNS_USERNAME"
|
|
||||||
_savedomainconf ACMEDNS_PASSWORD "$ACMEDNS_PASSWORD"
|
|
||||||
_savedomainconf ACMEDNS_SUBDOMAIN "$ACMEDNS_SUBDOMAIN"
|
|
||||||
|
|
||||||
export _H1="X-Api-User: $ACMEDNS_USERNAME"
|
export _H1="X-Api-User: $ACMEDNS_USERNAME"
|
||||||
export _H2="X-Api-Key: $ACMEDNS_PASSWORD"
|
export _H2="X-Api-Key: $ACMEDNS_PASSWORD"
|
||||||
@ -87,8 +48,8 @@ dns_acmedns_rm() {
|
|||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
txtvalue=$2
|
txtvalue=$2
|
||||||
_info "Using acme-dns"
|
_info "Using acme-dns"
|
||||||
_debug "fulldomain $fulldomain"
|
_debug fulldomain "$fulldomain"
|
||||||
_debug "txtvalue $txtvalue"
|
_debug txtvalue "$txtvalue"
|
||||||
}
|
}
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
#################### Private functions below ##################################
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
## Acmeproxy DNS provider to be used with acmeproxy (https://github.com/mdbraber/acmeproxy)
|
## Acmeproxy DNS provider to be used with acmeproxy (http://github.com/mdbraber/acmeproxy)
|
||||||
## API integration by Maarten den Braber
|
## API integration by Maarten den Braber
|
||||||
##
|
##
|
||||||
## Report any bugs via https://github.com/mdbraber/acme.sh
|
## Report any bugs via https://github.com/mdbraber/acme.sh
|
||||||
|
|||||||
@ -117,7 +117,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" | sed 's/%N//g'
|
date +"%s%N"
|
||||||
}
|
}
|
||||||
|
|
||||||
_check_exist_query() {
|
_check_exist_query() {
|
||||||
|
|||||||
@ -1,180 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# ACME.sh 3rd party DNS API plugin for ArtFiles.de
|
|
||||||
################################################################################
|
|
||||||
# Author: Martin Arndt, https://troublezone.net/
|
|
||||||
# Released: 2022-02-27
|
|
||||||
# Issues: https://github.com/acmesh-official/acme.sh/issues/4718
|
|
||||||
################################################################################
|
|
||||||
# Usage:
|
|
||||||
# 1. export AF_API_USERNAME='api12345678'
|
|
||||||
# 2. export AF_API_PASSWORD='apiPassword'
|
|
||||||
# 3. acme.sh --issue -d example.com --dns dns_artfiles
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
########## 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,10 +1,10 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
# Arvan_Token="Apikey xxxx"
|
#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
|
#Author: Vahid Fardi
|
||||||
# Report Bugs here: https://github.com/Neilpang/acme.sh
|
#Report Bugs here: https://github.com/Neilpang/acme.sh
|
||||||
#
|
#
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
@ -18,7 +18,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.ir/profile/api-keys"
|
_err "You can get yours from here https://npanel.arvancloud.com/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 +40,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 duplicate"; then
|
elif _contains "$response" "Record Data is Duplicated"; then
|
||||||
_info "Already exists, OK"
|
_info "Already exists, OK"
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
@ -141,7 +141,6 @@ _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
|
||||||
|
|||||||
@ -32,7 +32,7 @@ dns_aws_add() {
|
|||||||
if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
|
if [ -z "$AWS_ACCESS_KEY_ID" ] || [ -z "$AWS_SECRET_ACCESS_KEY" ]; then
|
||||||
AWS_ACCESS_KEY_ID=""
|
AWS_ACCESS_KEY_ID=""
|
||||||
AWS_SECRET_ACCESS_KEY=""
|
AWS_SECRET_ACCESS_KEY=""
|
||||||
_err "You haven't specified the aws route53 api key id and and api key secret yet."
|
_err "You haven't specifed the aws route53 api key id and and api key secret yet."
|
||||||
_err "Please create your key and try again. see $(__green $AWS_WIKI)"
|
_err "Please create your key and try again. see $(__green $AWS_WIKI)"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
@ -145,29 +145,41 @@ 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=1
|
i=2
|
||||||
p=1
|
p=1
|
||||||
|
|
||||||
# iterate over names (a.b.c.d -> b.c.d -> c.d -> d)
|
if aws_rest GET "2013-04-01/hostedzone"; then
|
||||||
while true; do
|
|
||||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100 | sed 's/\./\\./g')
|
|
||||||
_debug "Checking domain: $h"
|
|
||||||
if [ -z "$h" ]; then
|
|
||||||
_error "invalid domain"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# iterate over paginated result for list_hosted_zones
|
|
||||||
aws_rest GET "2013-04-01/hostedzone"
|
|
||||||
while true; do
|
while true; do
|
||||||
|
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||||
|
_debug2 "Checking domain: $h"
|
||||||
|
if [ -z "$h" ]; then
|
||||||
|
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"
|
||||||
|
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
|
||||||
|
fi
|
||||||
|
|
||||||
if _contains "$response" "<Name>$h.</Name>"; then
|
if _contains "$response" "<Name>$h.</Name>"; then
|
||||||
hostedzone="$(echo "$response" | tr -d '\n' | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<PrivateZone>false<.PrivateZone>.*<.HostedZone>")"
|
hostedzone="$(echo "$response" | 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 "<>")
|
||||||
@ -180,19 +192,10 @@ _get_root() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
if _contains "$response" "<IsTruncated>true</IsTruncated>" && _contains "$response" "<NextMarker>"; then
|
p=$i
|
||||||
_debug "IsTruncated"
|
i=$(_math "$i" + 1)
|
||||||
_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
|
done
|
||||||
p=$i
|
fi
|
||||||
i=$(_math "$i" + 1)
|
|
||||||
done
|
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,40 +209,24 @@ _use_container_role() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_use_instance_role() {
|
_use_instance_role() {
|
||||||
_instance_role_name_url="http://169.254.169.254/latest/meta-data/iam/security-credentials/"
|
_url="http://169.254.169.254/latest/meta-data/iam/security-credentials/"
|
||||||
|
_debug "_url" "$_url"
|
||||||
if _get "$_instance_role_name_url" true 1 | _head_n 1 | grep -Fq 401; then
|
if ! _get "$_url" true 1 | _head_n 1 | grep -Fq 200; 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)
|
||||||
_instance_role_name=$(_get "$_instance_role_name_url" "" 1)
|
_debug "_aws_role" "$_aws_role"
|
||||||
_debug "_instance_role_name" "$_instance_role_name"
|
_use_metadata "$_url$_aws_role"
|
||||||
_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,204 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
#
|
|
||||||
#AZION_Email=""
|
|
||||||
#AZION_Password=""
|
|
||||||
#
|
|
||||||
|
|
||||||
AZION_Api="https://api.azionapi.net"
|
|
||||||
|
|
||||||
######## Public functions ########
|
|
||||||
|
|
||||||
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
|
||||||
# Used to add txt record
|
|
||||||
dns_azion_add() {
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
|
|
||||||
_debug "Detect the root zone"
|
|
||||||
if ! _get_root "$fulldomain"; then
|
|
||||||
_err "Domain not found"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
_debug _sub_domain "$_sub_domain"
|
|
||||||
_debug _domain "$_domain"
|
|
||||||
_debug _domain_id "$_domain_id"
|
|
||||||
|
|
||||||
_info "Add or update record"
|
|
||||||
_get_record "$_domain_id" "$_sub_domain"
|
|
||||||
if [ "$record_id" ]; then
|
|
||||||
_payload="{\"record_type\": \"TXT\", \"entry\": \"$_sub_domain\", \"answers_list\": [$answers_list, \"$txtvalue\"], \"ttl\": 20}"
|
|
||||||
if _azion_rest PUT "intelligent_dns/$_domain_id/records/$record_id" "$_payload"; then
|
|
||||||
if _contains "$response" "$txtvalue"; then
|
|
||||||
_info "Record updated."
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
_payload="{\"record_type\": \"TXT\", \"entry\": \"$_sub_domain\", \"answers_list\": [\"$txtvalue\"], \"ttl\": 20}"
|
|
||||||
if _azion_rest POST "intelligent_dns/$_domain_id/records" "$_payload"; then
|
|
||||||
if _contains "$response" "$txtvalue"; then
|
|
||||||
_info "Record added."
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
_err "Failed to add or update record."
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Usage: fulldomain txtvalue
|
|
||||||
# Used to remove the txt record after validation
|
|
||||||
dns_azion_rm() {
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
|
|
||||||
_debug "Detect the root zone"
|
|
||||||
if ! _get_root "$fulldomain"; then
|
|
||||||
_err "Domain not found"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
_debug _sub_domain "$_sub_domain"
|
|
||||||
_debug _domain "$_domain"
|
|
||||||
_debug _domain_id "$_domain_id"
|
|
||||||
|
|
||||||
_info "Removing record"
|
|
||||||
_get_record "$_domain_id" "$_sub_domain"
|
|
||||||
if [ "$record_id" ]; then
|
|
||||||
if _azion_rest DELETE "intelligent_dns/$_domain_id/records/$record_id"; then
|
|
||||||
_info "Record removed."
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
_err "Failed to remove record."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
_info "Record not found or already removed."
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
|
||||||
# Usage: _acme-challenge.www.domain.com
|
|
||||||
# returns
|
|
||||||
# _sub_domain=_acme-challenge.www
|
|
||||||
# _domain=domain.com
|
|
||||||
# _domain_id=sdjkglgdfewsdfg
|
|
||||||
_get_root() {
|
|
||||||
domain=$1
|
|
||||||
i=1
|
|
||||||
p=1
|
|
||||||
|
|
||||||
if ! _azion_rest GET "intelligent_dns"; 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" "\"domain\":\"$h\""; then
|
|
||||||
_domain_id=$(echo "$response" | tr '{' "\n" | grep "\"domain\":\"$h\"" | _egrep_o "\"id\":[0-9]*" | _head_n 1 | 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)
|
|
||||||
_domain=$h
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
p=$i
|
|
||||||
i=$(_math "$i" + 1)
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_record() {
|
|
||||||
_domain_id=$1
|
|
||||||
_record=$2
|
|
||||||
|
|
||||||
if ! _azion_rest GET "intelligent_dns/$_domain_id/records"; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if _contains "$response" "\"entry\":\"$_record\""; then
|
|
||||||
_json_record=$(echo "$response" | tr '{' "\n" | grep "\"entry\":\"$_record\"")
|
|
||||||
if [ "$_json_record" ]; then
|
|
||||||
record_id=$(echo "$_json_record" | _egrep_o "\"record_id\":[0-9]*" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
|
||||||
answers_list=$(echo "$_json_record" | _egrep_o "\"answers_list\":\[.*\]" | _head_n 1 | cut -d : -f 2 | tr -d \[\])
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_token() {
|
|
||||||
AZION_Email="${AZION_Email:-$(_readaccountconf_mutable AZION_Email)}"
|
|
||||||
AZION_Password="${AZION_Password:-$(_readaccountconf_mutable AZION_Password)}"
|
|
||||||
|
|
||||||
if ! _contains "$AZION_Email" "@"; then
|
|
||||||
_err "It seems that the AZION_Email is not a valid email address. Revalidate your environments."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$AZION_Email" ] || [ -z "$AZION_Password" ]; then
|
|
||||||
_err "You didn't specified a AZION_Email/AZION_Password to generate Azion token."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
_saveaccountconf_mutable AZION_Email "$AZION_Email"
|
|
||||||
_saveaccountconf_mutable AZION_Password "$AZION_Password"
|
|
||||||
|
|
||||||
_basic_auth=$(printf "%s:%s" "$AZION_Email" "$AZION_Password" | _base64)
|
|
||||||
_debug _basic_auth "$_basic_auth"
|
|
||||||
|
|
||||||
export _H1="Accept: application/json; version=3"
|
|
||||||
export _H2="Content-Type: application/json"
|
|
||||||
export _H3="Authorization: Basic $_basic_auth"
|
|
||||||
|
|
||||||
response="$(_post "" "$AZION_Api/tokens" "" "POST")"
|
|
||||||
if _contains "$response" "\"token\":\"" >/dev/null; then
|
|
||||||
_azion_token=$(echo "$response" | _egrep_o "\"token\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")
|
|
||||||
export AZION_Token="$_azion_token"
|
|
||||||
else
|
|
||||||
_err "Failed to generate Azion token"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_azion_rest() {
|
|
||||||
_method=$1
|
|
||||||
_uri="$2"
|
|
||||||
_data="$3"
|
|
||||||
|
|
||||||
if [ -z "$AZION_Token" ]; then
|
|
||||||
_get_token
|
|
||||||
fi
|
|
||||||
_debug2 token "$AZION_Token"
|
|
||||||
|
|
||||||
export _H1="Accept: application/json; version=3"
|
|
||||||
export _H2="Content-Type: application/json"
|
|
||||||
export _H3="Authorization: token $AZION_Token"
|
|
||||||
|
|
||||||
if [ "$_method" != "GET" ]; then
|
|
||||||
_debug _data "$_data"
|
|
||||||
response="$(_post "$_data" "$AZION_Api/$_uri" "" "$_method")"
|
|
||||||
else
|
|
||||||
response="$(_get "$AZION_Api/$_uri")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
_debug2 response "$response"
|
|
||||||
|
|
||||||
if [ "$?" != "0" ]; then
|
|
||||||
_err "error $_method $_uri $_data"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
@ -9,72 +9,57 @@ 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 [ -z "$AZUREDNS_TENANTID" ]; then
|
||||||
if [ "$AZUREDNS_MANAGEDIDENTITY" = true ]; then
|
AZUREDNS_SUBSCRIPTIONID=""
|
||||||
_info "Using Azure managed identity"
|
AZUREDNS_TENANTID=""
|
||||||
#save managed identity as preferred authentication method, clear service principal credentials from conf file.
|
AZUREDNS_APPID=""
|
||||||
_saveaccountconf_mutable AZUREDNS_MANAGEDIDENTITY "$AZUREDNS_MANAGEDIDENTITY"
|
AZUREDNS_CLIENTSECRET=""
|
||||||
_saveaccountconf_mutable AZUREDNS_TENANTID ""
|
_err "You didn't specify the Azure Tenant ID "
|
||||||
_saveaccountconf_mutable AZUREDNS_APPID ""
|
return 1
|
||||||
_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
|
|
||||||
AZUREDNS_SUBSCRIPTIONID=""
|
|
||||||
AZUREDNS_TENANTID=""
|
|
||||||
AZUREDNS_APPID=""
|
|
||||||
AZUREDNS_CLIENTSECRET=""
|
|
||||||
_err "You didn't specify the Azure Tenant ID "
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$AZUREDNS_APPID" ]; then
|
|
||||||
AZUREDNS_SUBSCRIPTIONID=""
|
|
||||||
AZUREDNS_TENANTID=""
|
|
||||||
AZUREDNS_APPID=""
|
|
||||||
AZUREDNS_CLIENTSECRET=""
|
|
||||||
_err "You didn't specify the Azure App ID"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
|
|
||||||
AZUREDNS_SUBSCRIPTIONID=""
|
|
||||||
AZUREDNS_TENANTID=""
|
|
||||||
AZUREDNS_APPID=""
|
|
||||||
AZUREDNS_CLIENTSECRET=""
|
|
||||||
_err "You didn't specify the Azure Client Secret"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
#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_APPID "$AZUREDNS_APPID"
|
|
||||||
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
|
if [ -z "$AZUREDNS_APPID" ]; then
|
||||||
|
AZUREDNS_SUBSCRIPTIONID=""
|
||||||
|
AZUREDNS_TENANTID=""
|
||||||
|
AZUREDNS_APPID=""
|
||||||
|
AZUREDNS_CLIENTSECRET=""
|
||||||
|
_err "You didn't specify the Azure App ID"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
|
||||||
|
AZUREDNS_SUBSCRIPTIONID=""
|
||||||
|
AZUREDNS_TENANTID=""
|
||||||
|
AZUREDNS_APPID=""
|
||||||
|
AZUREDNS_CLIENTSECRET=""
|
||||||
|
_err "You didn't specify the Azure Client Secret"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
#save account details to account conf file.
|
||||||
|
_saveaccountconf_mutable AZUREDNS_SUBSCRIPTIONID "$AZUREDNS_SUBSCRIPTIONID"
|
||||||
|
_saveaccountconf_mutable AZUREDNS_TENANTID "$AZUREDNS_TENANTID"
|
||||||
|
_saveaccountconf_mutable AZUREDNS_APPID "$AZUREDNS_APPID"
|
||||||
|
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET "$AZUREDNS_CLIENTSECRET"
|
||||||
|
|
||||||
|
accesstoken=$(_azure_getaccess_token "$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"
|
||||||
@ -131,6 +116,10 @@ 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=""
|
||||||
@ -140,44 +129,34 @@ dns_azure_rm() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AZUREDNS_MANAGEDIDENTITY="${AZUREDNS_MANAGEDIDENTITY:-$(_readaccountconf_mutable AZUREDNS_MANAGEDIDENTITY)}"
|
if [ -z "$AZUREDNS_TENANTID" ]; then
|
||||||
if [ "$AZUREDNS_MANAGEDIDENTITY" = true ]; then
|
AZUREDNS_SUBSCRIPTIONID=""
|
||||||
_info "Using Azure managed identity"
|
AZUREDNS_TENANTID=""
|
||||||
else
|
AZUREDNS_APPID=""
|
||||||
_info "You didn't ask to use Azure managed identity, checking service principal credentials"
|
AZUREDNS_CLIENTSECRET=""
|
||||||
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
|
_err "You didn't specify the Azure Tenant ID "
|
||||||
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
|
return 1
|
||||||
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
|
|
||||||
|
|
||||||
if [ -z "$AZUREDNS_TENANTID" ]; then
|
|
||||||
AZUREDNS_SUBSCRIPTIONID=""
|
|
||||||
AZUREDNS_TENANTID=""
|
|
||||||
AZUREDNS_APPID=""
|
|
||||||
AZUREDNS_CLIENTSECRET=""
|
|
||||||
_err "You didn't specify the Azure Tenant ID "
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$AZUREDNS_APPID" ]; then
|
|
||||||
AZUREDNS_SUBSCRIPTIONID=""
|
|
||||||
AZUREDNS_TENANTID=""
|
|
||||||
AZUREDNS_APPID=""
|
|
||||||
AZUREDNS_CLIENTSECRET=""
|
|
||||||
_err "You didn't specify the Azure App ID"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
|
|
||||||
AZUREDNS_SUBSCRIPTIONID=""
|
|
||||||
AZUREDNS_TENANTID=""
|
|
||||||
AZUREDNS_APPID=""
|
|
||||||
AZUREDNS_CLIENTSECRET=""
|
|
||||||
_err "You didn't specify the Azure Client Secret"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
|
if [ -z "$AZUREDNS_APPID" ]; then
|
||||||
|
AZUREDNS_SUBSCRIPTIONID=""
|
||||||
|
AZUREDNS_TENANTID=""
|
||||||
|
AZUREDNS_APPID=""
|
||||||
|
AZUREDNS_CLIENTSECRET=""
|
||||||
|
_err "You didn't specify the Azure App ID"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$AZUREDNS_CLIENTSECRET" ]; then
|
||||||
|
AZUREDNS_SUBSCRIPTIONID=""
|
||||||
|
AZUREDNS_TENANTID=""
|
||||||
|
AZUREDNS_APPID=""
|
||||||
|
AZUREDNS_CLIENTSECRET=""
|
||||||
|
_err "You didn't specify the Azure Client Secret"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
accesstoken=$(_azure_getaccess_token "$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"
|
||||||
@ -279,10 +258,9 @@ _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() {
|
||||||
managedIdentity=$1
|
tenantID=$1
|
||||||
tenantID=$2
|
clientID=$2
|
||||||
clientID=$3
|
clientSecret=$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)}"
|
||||||
@ -300,25 +278,17 @@ _azure_getaccess_token() {
|
|||||||
fi
|
fi
|
||||||
_debug "getting new bearer token"
|
_debug "getting new bearer token"
|
||||||
|
|
||||||
if [ "$managedIdentity" = true ]; then
|
export _H1="accept: application/json"
|
||||||
# https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http
|
export _H2="Content-Type: application/x-www-form-urlencoded"
|
||||||
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/)"
|
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"
|
||||||
response="$(echo "$response" | _normalizeJson)"
|
_secure_debug2 "data $body"
|
||||||
accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
response="$(_post "$body" "https://login.microsoftonline.com/$tenantID/oauth2/token" "" "POST")"
|
||||||
expires_on=$(echo "$response" | _egrep_o "\"expires_on\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
_ret="$?"
|
||||||
else
|
_secure_debug2 "response $response"
|
||||||
export _H1="accept: application/json"
|
response="$(echo "$response" | _normalizeJson)"
|
||||||
export _H2="Content-Type: application/x-www-form-urlencoded"
|
accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||||
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"
|
expires_on=$(echo "$response" | _egrep_o "\"expires_on\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||||
_secure_debug2 "data $body"
|
|
||||||
response="$(_post "$body" "https://login.microsoftonline.com/$tenantID/oauth2/token" "" "POST")"
|
|
||||||
_ret="$?"
|
|
||||||
_secure_debug2 "response $response"
|
|
||||||
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 \")
|
|
||||||
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"
|
||||||
|
|||||||
@ -1,89 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
#Here is a sample custom api script.
|
|
||||||
#This file name is "dns_bookmyname.sh"
|
|
||||||
#So, here must be a method dns_bookmyname_add()
|
|
||||||
#Which will be called by acme.sh to add the txt record to your api system.
|
|
||||||
#returns 0 means success, otherwise error.
|
|
||||||
#
|
|
||||||
#Author: Neilpang
|
|
||||||
#Report Bugs here: https://github.com/acmesh-official/acme.sh
|
|
||||||
#
|
|
||||||
######## Public functions #####################
|
|
||||||
|
|
||||||
# Please Read this guide first: https://github.com/acmesh-official/acme.sh/wiki/DNS-API-Dev-Guide
|
|
||||||
|
|
||||||
# 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 ##################################
|
|
||||||
@ -1,248 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
## Will be called by acme.sh to add the TXT record via the Bunny DNS API.
|
|
||||||
## returns 0 means success, otherwise error.
|
|
||||||
|
|
||||||
## Author: nosilver4u <nosilver4u at ewww.io>
|
|
||||||
## GitHub: https://github.com/nosilver4u/acme.sh
|
|
||||||
|
|
||||||
##
|
|
||||||
## Environment Variables Required:
|
|
||||||
##
|
|
||||||
## BUNNY_API_KEY="75310dc4-ca77-9ac3-9a19-f6355db573b49ce92ae1-2655-3ebd-61ac-3a3ae34834cc"
|
|
||||||
##
|
|
||||||
|
|
||||||
##################### 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
|
|
||||||
}
|
|
||||||
@ -25,16 +25,9 @@ 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
|
_saveaccountconf_mutable CF_Token "$CF_Token"
|
||||||
_savedomainconf CF_Token "$CF_Token"
|
_saveaccountconf_mutable CF_Account_ID "$CF_Account_ID"
|
||||||
_savedomainconf CF_Account_ID "$CF_Account_ID"
|
_saveaccountconf_mutable CF_Zone_ID "$CF_Zone_ID"
|
||||||
_savedomainconf CF_Zone_ID "$CF_Zone_ID"
|
|
||||||
else
|
|
||||||
_saveaccountconf_mutable CF_Token "$CF_Token"
|
|
||||||
_saveaccountconf_mutable CF_Account_ID "$CF_Account_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=""
|
||||||
@ -52,14 +45,6 @@ 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"
|
||||||
|
|||||||
@ -2,14 +2,11 @@
|
|||||||
|
|
||||||
# Author: Boyan Peychev <boyan at cloudns dot net>
|
# Author: Boyan Peychev <boyan at cloudns dot net>
|
||||||
# Repository: https://github.com/ClouDNS/acme.sh/
|
# Repository: https://github.com/ClouDNS/acme.sh/
|
||||||
# Editor: I Komang Suryadana
|
|
||||||
|
|
||||||
#CLOUDNS_AUTH_ID=XXXXX
|
#CLOUDNS_AUTH_ID=XXXXX
|
||||||
#CLOUDNS_SUB_AUTH_ID=XXXXX
|
#CLOUDNS_SUB_AUTH_ID=XXXXX
|
||||||
#CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"
|
#CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"
|
||||||
CLOUDNS_API="https://api.cloudns.net"
|
CLOUDNS_API="https://api.cloudns.net"
|
||||||
DOMAIN_TYPE=
|
|
||||||
DOMAIN_MASTER=
|
|
||||||
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
@ -64,21 +61,12 @@ dns_cloudns_rm() {
|
|||||||
host="$(echo "$1" | sed "s/\.$zone\$//")"
|
host="$(echo "$1" | sed "s/\.$zone\$//")"
|
||||||
record=$2
|
record=$2
|
||||||
|
|
||||||
_dns_cloudns_get_zone_info "$zone"
|
|
||||||
|
|
||||||
_debug "Type" "$DOMAIN_TYPE"
|
|
||||||
_debug "Cloud Master" "$DOMAIN_MASTER"
|
|
||||||
if _contains "$DOMAIN_TYPE" "cloud"; then
|
|
||||||
zone=$DOMAIN_MASTER
|
|
||||||
fi
|
|
||||||
_debug "ZONE" "$zone"
|
|
||||||
|
|
||||||
_dns_cloudns_http_api_call "dns/records.json" "domain-name=$zone&host=$host&type=TXT"
|
_dns_cloudns_http_api_call "dns/records.json" "domain-name=$zone&host=$host&type=TXT"
|
||||||
if ! _contains "$response" "\"id\":"; then
|
if ! _contains "$response" "\"id\":"; then
|
||||||
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
|
||||||
@ -146,18 +134,6 @@ _dns_cloudns_init_check() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
_dns_cloudns_get_zone_info() {
|
|
||||||
zone=$1
|
|
||||||
_dns_cloudns_http_api_call "dns/get-zone-info.json" "domain-name=$zone"
|
|
||||||
if ! _contains "$response" "\"status\":\"Failed\""; then
|
|
||||||
DOMAIN_TYPE=$(echo "$response" | _egrep_o '"type":"[^"]*"' | cut -d : -f 2 | tr -d '"')
|
|
||||||
if _contains "$DOMAIN_TYPE" "cloud"; then
|
|
||||||
DOMAIN_MASTER=$(echo "$response" | _egrep_o '"cloud-master":"[^"]*"' | cut -d : -f 2 | tr -d '"')
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
_dns_cloudns_get_zone_name() {
|
_dns_cloudns_get_zone_name() {
|
||||||
i=2
|
i=2
|
||||||
while true; do
|
while true; do
|
||||||
|
|||||||
@ -1,160 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
#
|
|
||||||
#Author: Bjarne Saltbaek
|
|
||||||
#Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/3732
|
|
||||||
#
|
|
||||||
#
|
|
||||||
######## 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
|
|
||||||
dns_cpanel_add() {
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
|
|
||||||
_info "Adding TXT record to cPanel based system"
|
|
||||||
_debug fulldomain "$fulldomain"
|
|
||||||
_debug txtvalue "$txtvalue"
|
|
||||||
_debug cPanel_Username "$cPanel_Username"
|
|
||||||
_debug cPanel_Apitoken "$cPanel_Apitoken"
|
|
||||||
_debug cPanel_Hostname "$cPanel_Hostname"
|
|
||||||
|
|
||||||
if ! _cpanel_login; then
|
|
||||||
_err "cPanel Login failed for user $cPanel_Username. Check $HTTP_HEADER file"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
_debug "First detect the root zone"
|
|
||||||
if ! _get_root "$fulldomain"; then
|
|
||||||
_err "No matching root domain for $fulldomain found"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
# adding entry
|
|
||||||
_info "Adding the entry"
|
|
||||||
stripped_fulldomain=$(echo "$fulldomain" | sed "s/.$_domain//")
|
|
||||||
_debug "Adding $stripped_fulldomain to $_domain zone"
|
|
||||||
_myget "json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=add_zone_record&domain=$_domain&name=$stripped_fulldomain&type=TXT&txtdata=$txtvalue&ttl=1"
|
|
||||||
if _successful_update; then return 0; fi
|
|
||||||
_err "Couldn't create entry!"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Usage: fulldomain txtvalue
|
|
||||||
# Used to remove the txt record after validation
|
|
||||||
dns_cpanel_rm() {
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
|
|
||||||
_info "Using cPanel based system"
|
|
||||||
_debug fulldomain "$fulldomain"
|
|
||||||
_debug txtvalue "$txtvalue"
|
|
||||||
|
|
||||||
if ! _cpanel_login; then
|
|
||||||
_err "cPanel Login failed for user $cPanel_Username. Check $HTTP_HEADER file"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! _get_root; 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..."
|
|
||||||
_myget "json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=remove_zone_record&domain=$_domain&line=$_id"
|
|
||||||
# removing entry
|
|
||||||
_debug "_result is: $_result"
|
|
||||||
|
|
||||||
if _successful_update; then return 0; fi
|
|
||||||
_err "Couldn't delete entry!"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
|
||||||
|
|
||||||
_checkcredentials() {
|
|
||||||
cPanel_Username="${cPanel_Username:-$(_readaccountconf_mutable cPanel_Username)}"
|
|
||||||
cPanel_Apitoken="${cPanel_Apitoken:-$(_readaccountconf_mutable cPanel_Apitoken)}"
|
|
||||||
cPanel_Hostname="${cPanel_Hostname:-$(_readaccountconf_mutable cPanel_Hostname)}"
|
|
||||||
|
|
||||||
if [ -z "$cPanel_Username" ] || [ -z "$cPanel_Apitoken" ] || [ -z "$cPanel_Hostname" ]; then
|
|
||||||
cPanel_Username=""
|
|
||||||
cPanel_Apitoken=""
|
|
||||||
cPanel_Hostname=""
|
|
||||||
_err "You haven't specified cPanel username, apitoken and hostname yet."
|
|
||||||
_err "Please add credentials and try again."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
#save the credentials to the account conf file.
|
|
||||||
_saveaccountconf_mutable cPanel_Username "$cPanel_Username"
|
|
||||||
_saveaccountconf_mutable cPanel_Apitoken "$cPanel_Apitoken"
|
|
||||||
_saveaccountconf_mutable cPanel_Hostname "$cPanel_Hostname"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
_cpanel_login() {
|
|
||||||
if ! _checkcredentials; then return 1; fi
|
|
||||||
|
|
||||||
if ! _myget "json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=CustInfo&cpanel_jsonapi_func=displaycontactinfo"; then
|
|
||||||
_err "cPanel login failed for user $cPanel_Username."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
_myget() {
|
|
||||||
#Adds auth header to request
|
|
||||||
export _H1="Authorization: cpanel $cPanel_Username:$cPanel_Apitoken"
|
|
||||||
_result=$(_get "$cPanel_Hostname/$1")
|
|
||||||
}
|
|
||||||
|
|
||||||
_get_root() {
|
|
||||||
_myget 'json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=fetchzones'
|
|
||||||
_domains=$(echo "$_result" | _egrep_o '"[a-z0-9\.\-]*":\["; cPanel first' | cut -d':' -f1 | sed 's/"//g' | sed 's/{//g')
|
|
||||||
_debug "_result is: $_result"
|
|
||||||
_debug "_domains is: $_domains"
|
|
||||||
if [ -z "$_domains" ]; then
|
|
||||||
_err "Primary domain list not found!"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
for _domain in $_domains; do
|
|
||||||
_debug "Checking if $fulldomain ends with $_domain"
|
|
||||||
if (_endswith "$fulldomain" "$_domain"); then
|
|
||||||
_debug "Root domain: $_domain"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
_successful_update() {
|
|
||||||
if (echo "$_result" | _egrep_o 'data":\[[^]]*]' | grep -q '"newserial":null'); then return 1; fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
_findentry() {
|
|
||||||
_debug "In _findentry"
|
|
||||||
#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"
|
|
||||||
_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 "fulldomain. is $fulldomain."
|
|
||||||
_debug "txtvalue is $txtvalue"
|
|
||||||
_debug "_id is: $_id"
|
|
||||||
if [ -n "$_id" ]; then
|
|
||||||
_debug "Entry found with _id=$_id"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
@ -1,159 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
#Script to use with curanet.dk, scannet.dk, wannafind.dk, dandomain.dk DNS management.
|
|
||||||
#Requires api credentials with scope: dns
|
|
||||||
#Author: Peter L. Hansen <peter@r12.dk>
|
|
||||||
#Version 1.0
|
|
||||||
|
|
||||||
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
Executable file
185
dnsapi/dns_cx.sh
Executable file
@ -0,0 +1,185 @@
|
|||||||
|
#!/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'
|
||||||
|
|
||||||
|
}
|
||||||
@ -44,7 +44,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)"
|
CY_Password="$(printf "%s" "${CY_Password_B64}" | _dbase64 "multiline")"
|
||||||
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
|
||||||
|
|||||||
@ -12,7 +12,7 @@
|
|||||||
# --
|
# --
|
||||||
#
|
#
|
||||||
|
|
||||||
DDNSS_DNS_API="https://ddnss.de/upd.php"
|
DDNSS_DNS_API="https://ip4.ddnss.de/upd.php"
|
||||||
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
@ -77,7 +77,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=2"; then
|
if _ddnss_rest GET "key=$DDNSS_Token&host=$_ddnss_domain&txtm=1&txt=."; 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
|
||||||
|
|||||||
@ -192,7 +192,6 @@ _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
|
||||||
@ -206,7 +205,9 @@ _get_base_domain() {
|
|||||||
fi
|
fi
|
||||||
_debug2 domain_list "$domain_list"
|
_debug2 domain_list "$domain_list"
|
||||||
|
|
||||||
i=1
|
## for each shortening of our $fulldomain, check if it exists in the $domain_list
|
||||||
|
## 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")
|
||||||
|
|||||||
@ -1,185 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
#use dns-01 at DNSExit.com
|
|
||||||
|
|
||||||
#Author: Samuel Jimenez
|
|
||||||
#Report Bugs here: https://github.com/acmesh-official/acme.sh
|
|
||||||
|
|
||||||
#DNSEXIT_API_KEY=ABCDEFGHIJ0123456789abcdefghij
|
|
||||||
#DNSEXIT_AUTH_USER=login@email.address
|
|
||||||
#DNSEXIT_AUTH_PASS=aStrongPassword
|
|
||||||
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,87 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
# dnsHome.de API for acme.sh
|
|
||||||
#
|
|
||||||
# This Script adds the necessary TXT record to a Subdomain
|
|
||||||
#
|
|
||||||
# Author dnsHome.de (https://github.com/dnsHome-de)
|
|
||||||
#
|
|
||||||
# Report Bugs to https://github.com/acmesh-official/acme.sh/issues/3819
|
|
||||||
#
|
|
||||||
# export DNSHOME_Subdomain=""
|
|
||||||
# export DNSHOME_SubdomainPassword=""
|
|
||||||
|
|
||||||
# Usage: add subdomain.ddnsdomain.tld "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
|
||||||
# Used to add txt record
|
|
||||||
dns_dnshome_add() {
|
|
||||||
txtvalue=$2
|
|
||||||
|
|
||||||
DNSHOME_Subdomain="${DNSHOME_Subdomain:-$(_readdomainconf DNSHOME_Subdomain)}"
|
|
||||||
DNSHOME_SubdomainPassword="${DNSHOME_SubdomainPassword:-$(_readdomainconf DNSHOME_SubdomainPassword)}"
|
|
||||||
|
|
||||||
if [ -z "$DNSHOME_Subdomain" ] || [ -z "$DNSHOME_SubdomainPassword" ]; then
|
|
||||||
DNSHOME_Subdomain=""
|
|
||||||
DNSHOME_SubdomainPassword=""
|
|
||||||
_err "Please specify/export your dnsHome.de Subdomain and Password"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
#save the credentials to the account conf file.
|
|
||||||
_savedomainconf DNSHOME_Subdomain "$DNSHOME_Subdomain"
|
|
||||||
_savedomainconf DNSHOME_SubdomainPassword "$DNSHOME_SubdomainPassword"
|
|
||||||
|
|
||||||
DNSHOME_Api="https://$DNSHOME_Subdomain:$DNSHOME_SubdomainPassword@www.dnshome.de/dyndns.php"
|
|
||||||
|
|
||||||
_DNSHOME_rest POST "acme=add&txt=$txtvalue"
|
|
||||||
if ! echo "$response" | grep 'successfully' >/dev/null; then
|
|
||||||
_err "Error"
|
|
||||||
_err "$response"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# Usage: txtvalue
|
|
||||||
# Used to remove the txt record after validation
|
|
||||||
dns_dnshome_rm() {
|
|
||||||
txtvalue=$2
|
|
||||||
|
|
||||||
DNSHOME_Subdomain="${DNSHOME_Subdomain:-$(_readdomainconf DNSHOME_Subdomain)}"
|
|
||||||
DNSHOME_SubdomainPassword="${DNSHOME_SubdomainPassword:-$(_readdomainconf DNSHOME_SubdomainPassword)}"
|
|
||||||
|
|
||||||
DNSHOME_Api="https://$DNSHOME_Subdomain:$DNSHOME_SubdomainPassword@www.dnshome.de/dyndns.php"
|
|
||||||
|
|
||||||
if [ -z "$DNSHOME_Subdomain" ] || [ -z "$DNSHOME_SubdomainPassword" ]; then
|
|
||||||
DNSHOME_Subdomain=""
|
|
||||||
DNSHOME_SubdomainPassword=""
|
|
||||||
_err "Please specify/export your dnsHome.de Subdomain and Password"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
_DNSHOME_rest POST "acme=rm&txt=$txtvalue"
|
|
||||||
if ! echo "$response" | grep 'successfully' >/dev/null; then
|
|
||||||
_err "Error"
|
|
||||||
_err "$response"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
|
||||||
_DNSHOME_rest() {
|
|
||||||
method=$1
|
|
||||||
data="$2"
|
|
||||||
_debug "$data"
|
|
||||||
|
|
||||||
_debug data "$data"
|
|
||||||
response="$(_post "$data" "$DNSHOME_Api" "" "$method")"
|
|
||||||
|
|
||||||
if [ "$?" != "0" ]; then
|
|
||||||
_err "error $data"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_debug2 response "$response"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
@ -1,248 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
#This file name is "dns_dnsservices.sh"
|
|
||||||
#Script for Danish DNS registra and DNS hosting provider https://dns.services
|
|
||||||
|
|
||||||
#Author: Bjarke Bruun <bbruun@gmail.com>
|
|
||||||
#Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/4152
|
|
||||||
|
|
||||||
# Global variable to connect to the DNS.Services API
|
|
||||||
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
Executable file
148
dnsapi/dns_do.sh
Executable file
@ -0,0 +1,148 @@
|
|||||||
|
#!/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'
|
||||||
|
}
|
||||||
@ -94,8 +94,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 +143,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 +161,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
|
||||||
|
|||||||
@ -176,7 +176,6 @@ _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=""
|
||||||
@ -185,7 +184,6 @@ _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=""
|
||||||
@ -194,7 +192,6 @@ _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=""
|
||||||
@ -203,7 +200,6 @@ _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=""
|
||||||
@ -418,7 +414,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,146 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
#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,8 +1,7 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
# Gandi LiveDNS v5 API
|
# Gandi LiveDNS v5 API
|
||||||
# https://api.gandi.net/docs/livedns/
|
# http://doc.livedns.gandi.net/
|
||||||
# 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
|
# Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable
|
||||||
@ -13,27 +12,20 @@
|
|||||||
#
|
#
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
GANDI_LIVEDNS_API="https://api.gandi.net/v5/livedns"
|
GANDI_LIVEDNS_API="https://dns.api.gandi.net/api/v5"
|
||||||
|
|
||||||
#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" ] && [ -z "$GANDI_LIVEDNS_TOKEN" ]; then
|
if [ -z "$GANDI_LIVEDNS_KEY" ]; then
|
||||||
_err "No Token or API key (deprecated) specified for Gandi LiveDNS."
|
_err "No API key specified for Gandi LiveDNS."
|
||||||
_err "Create your token or key and export it as GANDI_LIVEDNS_KEY or GANDI_LIVEDNS_TOKEN respectively"
|
_err "Create your key and export it as GANDI_LIVEDNS_KEY"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Keep only one secret in configuration
|
_saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY"
|
||||||
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"
|
|
||||||
_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
|
||||||
@ -78,7 +70,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")"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +126,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")"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,11 +136,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
|
||||||
@ -165,12 +157,7 @@ _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")"
|
||||||
|
|||||||
@ -39,10 +39,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 removed"
|
_info "$fulldomain record added"
|
||||||
}
|
}
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
#################### Private functions below ##################################
|
||||||
@ -98,7 +98,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 +113,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"
|
||||||
@ -163,8 +163,5 @@ _dns_gcloud_get_rrdatas() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
ttl=$(echo "$rrdatas" | cut -f1)
|
ttl=$(echo "$rrdatas" | cut -f1)
|
||||||
# starting with version 353.0.0 gcloud seems to
|
rrdatas=$(echo "$rrdatas" | cut -f2 | sed 's/","/"\n"/g')
|
||||||
# separate records with a semicolon instead of commas
|
|
||||||
# see also https://cloud.google.com/sdk/docs/release-notes#35300_2021-08-17
|
|
||||||
rrdatas=$(echo "$rrdatas" | cut -f2 | sed 's/"[,;]"/"\n"/g')
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,187 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
#
|
|
||||||
#GCORE_Key='773$7b7adaf2a2b32bfb1b83787b4ff32a67eb178e3ada1af733e47b1411f2461f7f4fa7ed7138e2772a46124377bad7384b3bb8d87748f87b3f23db4b8bbe41b2bb'
|
|
||||||
#
|
|
||||||
|
|
||||||
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,12 +1,10 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
#Godaddy domain api
|
#Godaddy domain api
|
||||||
# Get API key and secret from https://developer.godaddy.com/
|
|
||||||
#
|
#
|
||||||
# GD_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
#GD_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||||
# GD_Secret="asdfsdfsfsdfsdfdfsdf"
|
|
||||||
#
|
#
|
||||||
# Ex.: acme.sh --issue --staging --dns dns_gd -d "*.s.example.com" -d "s.example.com"
|
#GD_Secret="asdfsdfsfsdfsdfdfsdf"
|
||||||
|
|
||||||
GD_Api="https://api.godaddy.com/v1"
|
GD_Api="https://api.godaddy.com/v1"
|
||||||
|
|
||||||
@ -22,8 +20,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 didn't specify godaddy api key and secret yet."
|
_err "You don't specify godaddy api key and secret yet."
|
||||||
_err "Please create your key and try again."
|
_err "Please create you key and try again."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -46,15 +44,14 @@ dns_gd_add() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if _contains "$response" "$txtvalue"; then
|
if _contains "$response" "$txtvalue"; then
|
||||||
_info "This record already exists, skipping"
|
_info "The record is existing, skip"
|
||||||
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"
|
||||||
# ignore empty (previously removed) records, to prevent useless _acme-challenge TXT entries
|
if [ "$t" ]; then
|
||||||
if [ "$t" ] && [ "$t" != '""' ]; then
|
|
||||||
_add_data="$_add_data,{\"data\":$t}"
|
_add_data="$_add_data,{\"data\":$t}"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@ -62,25 +59,13 @@ 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
|
||||||
_debug "Checking updated records of '${fulldomain}'"
|
_info "Added, sleeping 10 seconds"
|
||||||
|
_sleep 10
|
||||||
if ! _gd_rest GET "domains/$_domain/records/TXT/$_sub_domain"; then
|
#todo: check if the record takes effect
|
||||||
_err "Validating TXT record for '${fulldomain}' with rest error [$?]." "$response"
|
return 0
|
||||||
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
|
fi
|
||||||
|
_err "Add txt record error."
|
||||||
_sleep 10
|
return 1
|
||||||
_info "Added TXT record '${txtvalue}' for '${fulldomain}'."
|
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#fulldomain
|
#fulldomain
|
||||||
@ -122,20 +107,11 @@ dns_gd_rm() {
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
if [ -z "$_add_data" ]; then
|
if [ -z "$_add_data" ]; then
|
||||||
# delete empty record
|
_add_data="{\"data\":\"\"}"
|
||||||
_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
|
|
||||||
else
|
|
||||||
# remove specific TXT value, keeping other entries
|
|
||||||
_debug2 _add_data "$_add_data"
|
|
||||||
if ! _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then
|
|
||||||
_err "Cannot update TXT record for '$fulldomain'"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
_debug2 _add_data "$_add_data"
|
||||||
|
|
||||||
|
_gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"
|
||||||
}
|
}
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
#################### Private functions below ##################################
|
||||||
@ -180,15 +156,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" ] || [ "$m" = "DELETE" ]; then
|
if [ "$data" ]; then
|
||||||
_debug "data ($m): " "$data"
|
_debug data "$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 on rest call ($m): $ep"
|
_err "error $ep"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_debug2 response "$response"
|
_debug2 response "$response"
|
||||||
|
|||||||
177
dnsapi/dns_gdnsdk.sh
Executable file
177
dnsapi/dns_gdnsdk.sh
Executable file
@ -0,0 +1,177 @@
|
|||||||
|
#!/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
|
||||||
|
}
|
||||||
@ -1,232 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
########################################################################
|
|
||||||
# Geoscaling hook script for acme.sh
|
|
||||||
#
|
|
||||||
# Environment variables:
|
|
||||||
#
|
|
||||||
# - $GEOSCALING_Username (your Geoscaling username - this is usually NOT an amail address)
|
|
||||||
# - $GEOSCALING_Password (your Geoscaling 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:
|
|
||||||
@ -1,173 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
# Author: Alex Leigh <leigh at alexleigh dot me>
|
|
||||||
# Created: 2023-03-02
|
|
||||||
|
|
||||||
#GOOGLEDOMAINS_ACCESS_TOKEN="xxxx"
|
|
||||||
#GOOGLEDOMAINS_ZONE="xxxx"
|
|
||||||
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
|
|
||||||
}
|
|
||||||
@ -85,7 +85,7 @@ dns_he_rm() {
|
|||||||
_debug "The txt record is not found, just skip"
|
_debug "The txt record is not found, just skip"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
_record_id="$(echo "$response" | tr -d "#" | sed "s/<tr/#<tr/g" | tr -d "\n" | tr "#" "\n" | grep "$_full_domain" | grep '"dns_tr"' | grep -- "$_txt_value" | cut -d '"' -f 4)"
|
_record_id="$(echo "$response" | tr -d "#" | sed "s/<tr/#<tr/g" | tr -d "\n" | tr "#" "\n" | grep "$_full_domain" | grep '"dns_tr"' | grep "$_txt_value" | cut -d '"' -f 4)"
|
||||||
_debug2 _record_id "$_record_id"
|
_debug2 _record_id "$_record_id"
|
||||||
if [ -z "$_record_id" ]; then
|
if [ -z "$_record_id" ]; then
|
||||||
_err "Can not find record id"
|
_err "Can not find record id"
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# HUAWEICLOUD_Username
|
# HUAWEICLOUD_Username
|
||||||
# HUAWEICLOUD_Password
|
# HUAWEICLOUD_Password
|
||||||
# HUAWEICLOUD_DomainName
|
# HUAWEICLOUD_ProjectID
|
||||||
|
|
||||||
iam_api="https://iam.myhuaweicloud.com"
|
iam_api="https://iam.myhuaweicloud.com"
|
||||||
dns_api="https://dns.ap-southeast-1.myhuaweicloud.com" # Should work
|
dns_api="https://dns.ap-southeast-1.myhuaweicloud.com" # Should work
|
||||||
@ -14,8 +14,6 @@ dns_api="https://dns.ap-southeast-1.myhuaweicloud.com" # Should work
|
|||||||
#
|
#
|
||||||
# Ref: https://support.huaweicloud.com/intl/zh-cn/api-dns/zh-cn_topic_0132421999.html
|
# Ref: https://support.huaweicloud.com/intl/zh-cn/api-dns/zh-cn_topic_0132421999.html
|
||||||
#
|
#
|
||||||
# About "DomainName" parameters see: https://support.huaweicloud.com/api-iam/iam_01_0006.html
|
|
||||||
#
|
|
||||||
|
|
||||||
dns_huaweicloud_add() {
|
dns_huaweicloud_add() {
|
||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
@ -23,21 +21,21 @@ dns_huaweicloud_add() {
|
|||||||
|
|
||||||
HUAWEICLOUD_Username="${HUAWEICLOUD_Username:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
|
HUAWEICLOUD_Username="${HUAWEICLOUD_Username:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
|
||||||
HUAWEICLOUD_Password="${HUAWEICLOUD_Password:-$(_readaccountconf_mutable HUAWEICLOUD_Password)}"
|
HUAWEICLOUD_Password="${HUAWEICLOUD_Password:-$(_readaccountconf_mutable HUAWEICLOUD_Password)}"
|
||||||
HUAWEICLOUD_DomainName="${HUAWEICLOUD_DomainName:-$(_readaccountconf_mutable HUAWEICLOUD_DomainName)}"
|
HUAWEICLOUD_ProjectID="${HUAWEICLOUD_ProjectID:-$(_readaccountconf_mutable HUAWEICLOUD_ProjectID)}"
|
||||||
|
|
||||||
# Check information
|
# Check information
|
||||||
if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_DomainName}" ]; then
|
if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_ProjectID}" ]; then
|
||||||
_err "Not enough information provided to dns_huaweicloud!"
|
_err "Not enough information provided to dns_huaweicloud!"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
unset token # Clear token
|
unset token # Clear token
|
||||||
token="$(_get_token "${HUAWEICLOUD_Username}" "${HUAWEICLOUD_Password}" "${HUAWEICLOUD_DomainName}")"
|
token="$(_get_token "${HUAWEICLOUD_Username}" "${HUAWEICLOUD_Password}" "${HUAWEICLOUD_ProjectID}")"
|
||||||
if [ -z "${token}" ]; then # Check token
|
if [ -z "${token}" ]; then # Check token
|
||||||
_err "dns_api(dns_huaweicloud): Error getting token."
|
_err "dns_api(dns_huaweicloud): Error getting token."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_secure_debug "Access token is:" "${token}"
|
_debug "Access token is: ${token}"
|
||||||
|
|
||||||
unset zoneid
|
unset zoneid
|
||||||
zoneid="$(_get_zoneid "${token}" "${fulldomain}")"
|
zoneid="$(_get_zoneid "${token}" "${fulldomain}")"
|
||||||
@ -45,7 +43,7 @@ dns_huaweicloud_add() {
|
|||||||
_err "dns_api(dns_huaweicloud): Error getting zone id."
|
_err "dns_api(dns_huaweicloud): Error getting zone id."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_debug "Zone ID is:" "${zoneid}"
|
_debug "Zone ID is: ${zoneid}"
|
||||||
|
|
||||||
_debug "Adding Record"
|
_debug "Adding Record"
|
||||||
_add_record "${token}" "${fulldomain}" "${txtvalue}"
|
_add_record "${token}" "${fulldomain}" "${txtvalue}"
|
||||||
@ -58,7 +56,7 @@ dns_huaweicloud_add() {
|
|||||||
# Do saving work if all succeeded
|
# Do saving work if all succeeded
|
||||||
_saveaccountconf_mutable HUAWEICLOUD_Username "${HUAWEICLOUD_Username}"
|
_saveaccountconf_mutable HUAWEICLOUD_Username "${HUAWEICLOUD_Username}"
|
||||||
_saveaccountconf_mutable HUAWEICLOUD_Password "${HUAWEICLOUD_Password}"
|
_saveaccountconf_mutable HUAWEICLOUD_Password "${HUAWEICLOUD_Password}"
|
||||||
_saveaccountconf_mutable HUAWEICLOUD_DomainName "${HUAWEICLOUD_DomainName}"
|
_saveaccountconf_mutable HUAWEICLOUD_ProjectID "${HUAWEICLOUD_ProjectID}"
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,21 +72,21 @@ dns_huaweicloud_rm() {
|
|||||||
|
|
||||||
HUAWEICLOUD_Username="${HUAWEICLOUD_Username:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
|
HUAWEICLOUD_Username="${HUAWEICLOUD_Username:-$(_readaccountconf_mutable HUAWEICLOUD_Username)}"
|
||||||
HUAWEICLOUD_Password="${HUAWEICLOUD_Password:-$(_readaccountconf_mutable HUAWEICLOUD_Password)}"
|
HUAWEICLOUD_Password="${HUAWEICLOUD_Password:-$(_readaccountconf_mutable HUAWEICLOUD_Password)}"
|
||||||
HUAWEICLOUD_DomainName="${HUAWEICLOUD_DomainName:-$(_readaccountconf_mutable HUAWEICLOUD_DomainName)}"
|
HUAWEICLOUD_ProjectID="${HUAWEICLOUD_ProjectID:-$(_readaccountconf_mutable HUAWEICLOUD_ProjectID)}"
|
||||||
|
|
||||||
# Check information
|
# Check information
|
||||||
if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_DomainName}" ]; then
|
if [ -z "${HUAWEICLOUD_Username}" ] || [ -z "${HUAWEICLOUD_Password}" ] || [ -z "${HUAWEICLOUD_ProjectID}" ]; then
|
||||||
_err "Not enough information provided to dns_huaweicloud!"
|
_err "Not enough information provided to dns_huaweicloud!"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
unset token # Clear token
|
unset token # Clear token
|
||||||
token="$(_get_token "${HUAWEICLOUD_Username}" "${HUAWEICLOUD_Password}" "${HUAWEICLOUD_DomainName}")"
|
token="$(_get_token "${HUAWEICLOUD_Username}" "${HUAWEICLOUD_Password}" "${HUAWEICLOUD_ProjectID}")"
|
||||||
if [ -z "${token}" ]; then # Check token
|
if [ -z "${token}" ]; then # Check token
|
||||||
_err "dns_api(dns_huaweicloud): Error getting token."
|
_err "dns_api(dns_huaweicloud): Error getting token."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_secure_debug "Access token is:" "${token}"
|
_debug "Access token is: ${token}"
|
||||||
|
|
||||||
unset zoneid
|
unset zoneid
|
||||||
zoneid="$(_get_zoneid "${token}" "${fulldomain}")"
|
zoneid="$(_get_zoneid "${token}" "${fulldomain}")"
|
||||||
@ -96,61 +94,21 @@ dns_huaweicloud_rm() {
|
|||||||
_err "dns_api(dns_huaweicloud): Error getting zone id."
|
_err "dns_api(dns_huaweicloud): Error getting zone id."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_debug "Zone ID is:" "${zoneid}"
|
_debug "Zone ID is: ${zoneid}"
|
||||||
|
|
||||||
record_id="$(_get_recordset_id "${token}" "${fulldomain}" "${zoneid}")"
|
|
||||||
_recursive_rm_record "${token}" "${fulldomain}" "${zoneid}" "${record_id}"
|
|
||||||
ret="$?"
|
|
||||||
if [ "${ret}" != "0" ]; then
|
|
||||||
_err "dns_api(dns_huaweicloud): Error removing record."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
################### Private functions below ##################################
|
|
||||||
|
|
||||||
# _recursive_rm_record
|
|
||||||
# remove all records from the record set
|
|
||||||
#
|
|
||||||
# _token=$1
|
|
||||||
# _domain=$2
|
|
||||||
# _zoneid=$3
|
|
||||||
# _record_id=$4
|
|
||||||
#
|
|
||||||
# Returns 0 on success
|
|
||||||
_recursive_rm_record() {
|
|
||||||
_token=$1
|
|
||||||
_domain=$2
|
|
||||||
_zoneid=$3
|
|
||||||
_record_id=$4
|
|
||||||
|
|
||||||
# Most likely to have problems will huaweicloud side if more than 50 attempts but still cannot fully remove the record set
|
|
||||||
# Maybe can be removed manually in the dashboard
|
|
||||||
_retry_cnt=50
|
|
||||||
|
|
||||||
# Remove all records
|
# Remove all records
|
||||||
# Therotically HuaweiCloud does not allow more than one record set
|
# Therotically HuaweiCloud does not allow more than one record set
|
||||||
# But remove them recurringly to increase robusty
|
# But remove them recurringly to increase robusty
|
||||||
|
while [ "${record_id}" != "0" ]; do
|
||||||
while [ "${_record_id}" != "0" ] && [ "${_retry_cnt}" != "0" ]; do
|
|
||||||
_debug "Removing Record"
|
_debug "Removing Record"
|
||||||
_retry_cnt=$((_retry_cnt - 1))
|
_rm_record "${token}" "${zoneid}" "${record_id}"
|
||||||
_rm_record "${_token}" "${_zoneid}" "${_record_id}"
|
record_id="$(_get_recordset_id "${token}" "${fulldomain}" "${zoneid}")"
|
||||||
_record_id="$(_get_recordset_id "${_token}" "${_domain}" "${_zoneid}")"
|
|
||||||
_debug2 "Checking record exists: record_id=${_record_id}"
|
|
||||||
done
|
done
|
||||||
|
|
||||||
# Check if retry count is reached
|
|
||||||
if [ "${_retry_cnt}" = "0" ]; then
|
|
||||||
_debug "Failed to remove record after 50 attempts, please try removing it manually in the dashboard"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
################### Private functions below ##################################
|
||||||
|
|
||||||
# _get_zoneid
|
# _get_zoneid
|
||||||
#
|
#
|
||||||
# _token=$1
|
# _token=$1
|
||||||
@ -164,35 +122,21 @@ _get_zoneid() {
|
|||||||
|
|
||||||
i=1
|
i=1
|
||||||
while true; do
|
while true; do
|
||||||
h=$(printf "%s" "${_domain_string}" | cut -d . -f "$i"-100)
|
h=$(printf "%s" "${_domain_string}" | cut -d . -f $i-100)
|
||||||
if [ -z "$h" ]; then
|
if [ -z "$h" ]; then
|
||||||
#not valid
|
#not valid
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_debug "$h"
|
_debug "$h"
|
||||||
response=$(_get "${dns_api}/v2/zones?name=${h}")
|
response=$(_get "${dns_api}/v2/zones?name=${h}")
|
||||||
_debug2 "$response"
|
|
||||||
if _contains "${response}" '"id"'; then
|
if _contains "${response}" "id"; then
|
||||||
zoneidlist=$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
|
_debug "Get Zone ID Success."
|
||||||
zonenamelist=$(echo "${response}" | _egrep_o "\"name\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
|
_zoneid=$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")
|
||||||
_debug2 "Returned Zone ID(s):" "${zoneidlist}"
|
printf "%s" "${_zoneid}"
|
||||||
_debug2 "Returned Zone Name(s):" "${zonenamelist}"
|
return 0
|
||||||
zoneidnum=0
|
|
||||||
zoneidcount=$(echo "${zoneidlist}" | grep -c '^')
|
|
||||||
_debug "Returned Zone ID(s) Count:" "${zoneidcount}"
|
|
||||||
while [ "${zoneidnum}" -lt "${zoneidcount}" ]; do
|
|
||||||
zoneidnum=$(_math "$zoneidnum" + 1)
|
|
||||||
_zoneid=$(echo "${zoneidlist}" | sed -n "${zoneidnum}p")
|
|
||||||
zonename=$(echo "${zonenamelist}" | sed -n "${zoneidnum}p")
|
|
||||||
_debug "Check Zone Name" "${zonename}"
|
|
||||||
if [ "${zonename}" = "${h}." ]; then
|
|
||||||
_debug "Get Zone ID Success."
|
|
||||||
_debug "ZoneID:" "${_zoneid}"
|
|
||||||
printf "%s" "${_zoneid}"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
i=$(_math "$i" + 1)
|
i=$(_math "$i" + 1)
|
||||||
done
|
done
|
||||||
return 1
|
return 1
|
||||||
@ -205,7 +149,7 @@ _get_recordset_id() {
|
|||||||
export _H1="X-Auth-Token: ${_token}"
|
export _H1="X-Auth-Token: ${_token}"
|
||||||
|
|
||||||
response=$(_get "${dns_api}/v2/zones/${_zoneid}/recordsets?name=${_domain}")
|
response=$(_get "${dns_api}/v2/zones/${_zoneid}/recordsets?name=${_domain}")
|
||||||
if _contains "${response}" '"id"'; then
|
if _contains "${response}" "id"; then
|
||||||
_id="$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")"
|
_id="$(echo "${response}" | _egrep_o "\"id\": *\"[^\"]*\"" | cut -d : -f 2 | tr -d \" | tr -d " ")"
|
||||||
printf "%s" "${_id}"
|
printf "%s" "${_id}"
|
||||||
return 0
|
return 0
|
||||||
@ -246,24 +190,28 @@ _add_record() {
|
|||||||
\"type\": \"TXT\",
|
\"type\": \"TXT\",
|
||||||
\"ttl\": 1,
|
\"ttl\": 1,
|
||||||
\"records\": [
|
\"records\": [
|
||||||
${_exist_record},\"\\\"${_txtvalue}\\\"\"
|
${_exist_record},
|
||||||
|
\"\\\"${_txtvalue}\\\"\"
|
||||||
]
|
]
|
||||||
}"
|
}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_record_id="$(_get_recordset_id "${_token}" "${_domain}" "${zoneid}")"
|
_record_id="$(_get_recordset_id "${_token}" "${_domain}" "${zoneid}")"
|
||||||
_debug "Record Set ID is:" "${_record_id}"
|
_debug "Record Set ID is: ${_record_id}"
|
||||||
|
|
||||||
|
# Remove all records
|
||||||
|
while [ "${_record_id}" != "0" ]; do
|
||||||
|
_debug "Removing Record"
|
||||||
|
_rm_record "${_token}" "${zoneid}" "${_record_id}"
|
||||||
|
_record_id="$(_get_recordset_id "${_token}" "${_domain}" "${zoneid}")"
|
||||||
|
done
|
||||||
|
|
||||||
# Add brand new records with all old and new records
|
# Add brand new records with all old and new records
|
||||||
export _H2="Content-Type: application/json"
|
export _H2="Content-Type: application/json"
|
||||||
export _H1="X-Auth-Token: ${_token}"
|
export _H1="X-Auth-Token: ${_token}"
|
||||||
|
|
||||||
_debug2 "${_post_body}"
|
_debug2 "${_post_body}"
|
||||||
if [ -z "${_exist_record}" ]; then
|
_post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets" >/dev/null
|
||||||
_post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets" >/dev/null
|
|
||||||
else
|
|
||||||
_post "${_post_body}" "${dns_api}/v2/zones/${zoneid}/recordsets/${_record_id}" false "PUT" >/dev/null
|
|
||||||
fi
|
|
||||||
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
|
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
|
||||||
if [ "$_code" != "202" ]; then
|
if [ "$_code" != "202" ]; then
|
||||||
_err "dns_huaweicloud: http code ${_code}"
|
_err "dns_huaweicloud: http code ${_code}"
|
||||||
@ -291,7 +239,7 @@ _rm_record() {
|
|||||||
_get_token() {
|
_get_token() {
|
||||||
_username=$1
|
_username=$1
|
||||||
_password=$2
|
_password=$2
|
||||||
_domain_name=$3
|
_project=$3
|
||||||
|
|
||||||
_debug "Getting Token"
|
_debug "Getting Token"
|
||||||
body="{
|
body="{
|
||||||
@ -305,14 +253,14 @@ _get_token() {
|
|||||||
\"name\": \"${_username}\",
|
\"name\": \"${_username}\",
|
||||||
\"password\": \"${_password}\",
|
\"password\": \"${_password}\",
|
||||||
\"domain\": {
|
\"domain\": {
|
||||||
\"name\": \"${_domain_name}\"
|
\"name\": \"${_username}\"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
\"scope\": {
|
\"scope\": {
|
||||||
\"project\": {
|
\"project\": {
|
||||||
\"name\": \"ap-southeast-1\"
|
\"id\": \"${_project}\"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -321,7 +269,7 @@ _get_token() {
|
|||||||
_post "${body}" "${iam_api}/v3/auth/tokens" >/dev/null
|
_post "${body}" "${iam_api}/v3/auth/tokens" >/dev/null
|
||||||
_code=$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")
|
_code=$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")
|
||||||
_token=$(grep "^X-Subject-Token" "$HTTP_HEADER" | cut -d " " -f 2-)
|
_token=$(grep "^X-Subject-Token" "$HTTP_HEADER" | cut -d " " -f 2-)
|
||||||
_secure_debug "${_code}"
|
_debug2 "${_code}"
|
||||||
printf "%s" "${_token}"
|
printf "%s" "${_token}"
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ dns_infoblox_add() {
|
|||||||
## Nothing to see here, just some housekeeping
|
## Nothing to see here, just some housekeeping
|
||||||
fulldomain=$1
|
fulldomain=$1
|
||||||
txtvalue=$2
|
txtvalue=$2
|
||||||
|
baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View"
|
||||||
|
|
||||||
_info "Using Infoblox API"
|
_info "Using Infoblox API"
|
||||||
_debug fulldomain "$fulldomain"
|
_debug fulldomain "$fulldomain"
|
||||||
@ -18,13 +19,12 @@ dns_infoblox_add() {
|
|||||||
if [ -z "$Infoblox_Creds" ] || [ -z "$Infoblox_Server" ]; then
|
if [ -z "$Infoblox_Creds" ] || [ -z "$Infoblox_Server" ]; then
|
||||||
Infoblox_Creds=""
|
Infoblox_Creds=""
|
||||||
Infoblox_Server=""
|
Infoblox_Server=""
|
||||||
_err "You didn't specify the Infoblox credentials or server (Infoblox_Creds; Infoblox_Server)."
|
_err "You didn't specify the credentials, server or infoblox view yet (Infoblox_Creds, Infoblox_Server and Infoblox_View)."
|
||||||
_err "Please set them via EXPORT Infoblox_Creds=username:password or EXPORT Infoblox_server=ip/hostname and try again."
|
_err "Please set them via EXPORT ([username:password], [ip or hostname]) and try again."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$Infoblox_View" ]; then
|
if [ -z "$Infoblox_View" ]; then
|
||||||
_info "No Infoblox_View set, using fallback value 'default'"
|
|
||||||
Infoblox_View="default"
|
Infoblox_View="default"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -33,9 +33,6 @@ dns_infoblox_add() {
|
|||||||
_saveaccountconf Infoblox_Server "$Infoblox_Server"
|
_saveaccountconf Infoblox_Server "$Infoblox_Server"
|
||||||
_saveaccountconf Infoblox_View "$Infoblox_View"
|
_saveaccountconf Infoblox_View "$Infoblox_View"
|
||||||
|
|
||||||
## URLencode Infoblox View to deal with e.g. spaces
|
|
||||||
Infoblox_ViewEncoded=$(printf "%b" "$Infoblox_View" | _url_encode)
|
|
||||||
|
|
||||||
## Base64 encode the credentials
|
## Base64 encode the credentials
|
||||||
Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64)
|
Infoblox_CredsEncoded=$(printf "%b" "$Infoblox_Creds" | _base64)
|
||||||
|
|
||||||
@ -43,14 +40,11 @@ dns_infoblox_add() {
|
|||||||
export _H1="Accept-Language:en-US"
|
export _H1="Accept-Language:en-US"
|
||||||
export _H2="Authorization: Basic $Infoblox_CredsEncoded"
|
export _H2="Authorization: Basic $Infoblox_CredsEncoded"
|
||||||
|
|
||||||
## Construct the request URL
|
|
||||||
baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=${Infoblox_ViewEncoded}"
|
|
||||||
|
|
||||||
## Add the challenge record to the Infoblox grid member
|
## Add the challenge record to the Infoblox grid member
|
||||||
result="$(_post "" "$baseurlnObject" "" "POST")"
|
result="$(_post "" "$baseurlnObject" "" "POST")"
|
||||||
|
|
||||||
## Let's see if we get something intelligible back from the unit
|
## Let's see if we get something intelligible back from the unit
|
||||||
if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/${Infoblox_ViewEncoded}")" ]; then
|
if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then
|
||||||
_info "Successfully created the txt record"
|
_info "Successfully created the txt record"
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
@ -71,9 +65,6 @@ dns_infoblox_rm() {
|
|||||||
_debug fulldomain "$fulldomain"
|
_debug fulldomain "$fulldomain"
|
||||||
_debug txtvalue "$txtvalue"
|
_debug txtvalue "$txtvalue"
|
||||||
|
|
||||||
## URLencode Infoblox View to deal with e.g. spaces
|
|
||||||
Infoblox_ViewEncoded=$(printf "%b" "$Infoblox_View" | _url_encode)
|
|
||||||
|
|
||||||
## Base64 encode the credentials
|
## Base64 encode the credentials
|
||||||
Infoblox_CredsEncoded="$(printf "%b" "$Infoblox_Creds" | _base64)"
|
Infoblox_CredsEncoded="$(printf "%b" "$Infoblox_Creds" | _base64)"
|
||||||
|
|
||||||
@ -82,18 +73,18 @@ dns_infoblox_rm() {
|
|||||||
export _H2="Authorization: Basic $Infoblox_CredsEncoded"
|
export _H2="Authorization: Basic $Infoblox_CredsEncoded"
|
||||||
|
|
||||||
## Does the record exist? Let's check.
|
## Does the record exist? Let's check.
|
||||||
baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=${Infoblox_ViewEncoded}&_return_type=xml-pretty"
|
baseurlnObject="https://$Infoblox_Server/wapi/v2.2.2/record:txt?name=$fulldomain&text=$txtvalue&view=$Infoblox_View&_return_type=xml-pretty"
|
||||||
result="$(_get "$baseurlnObject")"
|
result="$(_get "$baseurlnObject")"
|
||||||
|
|
||||||
## Let's see if we get something intelligible back from the grid
|
## Let's see if we get something intelligible back from the grid
|
||||||
if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/${Infoblox_ViewEncoded}")" ]; then
|
if [ "$(echo "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then
|
||||||
## Extract the object reference
|
## Extract the object reference
|
||||||
objRef="$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/${Infoblox_ViewEncoded}")"
|
objRef="$(printf "%b" "$result" | _egrep_o "record:txt/.*:.*/$Infoblox_View")"
|
||||||
objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef"
|
objRmUrl="https://$Infoblox_Server/wapi/v2.2.2/$objRef"
|
||||||
## Delete them! All the stale records!
|
## Delete them! All the stale records!
|
||||||
rmResult="$(_post "" "$objRmUrl" "" "DELETE")"
|
rmResult="$(_post "" "$objRmUrl" "" "DELETE")"
|
||||||
## Let's see if that worked
|
## Let's see if that worked
|
||||||
if [ "$(echo "$rmResult" | _egrep_o "record:txt/.*:.*/${Infoblox_ViewEncoded}")" ]; then
|
if [ "$(echo "$rmResult" | _egrep_o "record:txt/.*:.*/$Infoblox_View")" ]; then
|
||||||
_info "Successfully deleted $objRef"
|
_info "Successfully deleted $objRef"
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
|
|||||||
@ -76,7 +76,7 @@ dns_infomaniak_add() {
|
|||||||
domain_id=${zone_and_id#* }
|
domain_id=${zone_and_id#* }
|
||||||
|
|
||||||
# extract first part of domain
|
# extract first part of domain
|
||||||
key=${fulldomain%."$zone"}
|
key=${fulldomain%.$zone}
|
||||||
|
|
||||||
_debug "zone:$zone id:$domain_id key:$key"
|
_debug "zone:$zone id:$domain_id key:$key"
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ dns_infomaniak_rm() {
|
|||||||
domain_id=${zone_and_id#* }
|
domain_id=${zone_and_id#* }
|
||||||
|
|
||||||
# extract first part of domain
|
# extract first part of domain
|
||||||
key=${fulldomain%."$zone"}
|
key=${fulldomain%.$zone}
|
||||||
|
|
||||||
_debug "zone:$zone id:$domain_id key:$key"
|
_debug "zone:$zone id:$domain_id key:$key"
|
||||||
|
|
||||||
|
|||||||
@ -194,7 +194,7 @@ _inwx_login() {
|
|||||||
|
|
||||||
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
|
response="$(_post "$xml_content" "$INWX_Api" "" "POST")"
|
||||||
|
|
||||||
INWX_Cookie=$(printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep -i "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')")
|
INWX_Cookie=$(printf "Cookie: %s" "$(grep "domrobot=" "$HTTP_HEADER" | grep "^Set-Cookie:" | _tail_n 1 | _egrep_o 'domrobot=[^;]*;' | tr -d ';')")
|
||||||
_H1=$INWX_Cookie
|
_H1=$INWX_Cookie
|
||||||
export _H1
|
export _H1
|
||||||
export INWX_Cookie
|
export INWX_Cookie
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
# Supports IONOS DNS API v1.0.1
|
# Supports IONOS DNS API Beta v1.0.0
|
||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# Export IONOS_PREFIX and IONOS_SECRET before calling acme.sh:
|
# Export IONOS_PREFIX and IONOS_SECRET before calling acme.sh:
|
||||||
@ -26,7 +26,7 @@ dns_ionos_add() {
|
|||||||
|
|
||||||
_body="[{\"name\":\"$_sub_domain.$_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":$IONOS_TXT_TTL,\"prio\":$IONOS_TXT_PRIO,\"disabled\":false}]"
|
_body="[{\"name\":\"$_sub_domain.$_domain\",\"type\":\"TXT\",\"content\":\"$txtvalue\",\"ttl\":$IONOS_TXT_TTL,\"prio\":$IONOS_TXT_PRIO,\"disabled\":false}]"
|
||||||
|
|
||||||
if _ionos_rest POST "$IONOS_ROUTE_ZONES/$_zone_id/records" "$_body" && [ "$_code" = "201" ]; then
|
if _ionos_rest POST "$IONOS_ROUTE_ZONES/$_zone_id/records" "$_body" && [ -z "$response" ]; then
|
||||||
_info "TXT record has been created successfully."
|
_info "TXT record has been created successfully."
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@ -47,7 +47,7 @@ dns_ionos_rm() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if _ionos_rest DELETE "$IONOS_ROUTE_ZONES/$_zone_id/records/$_record_id" && [ "$_code" = "200" ]; then
|
if _ionos_rest DELETE "$IONOS_ROUTE_ZONES/$_zone_id/records/$_record_id" && [ -z "$response" ]; then
|
||||||
_info "TXT record has been deleted successfully."
|
_info "TXT record has been deleted successfully."
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@ -85,7 +85,7 @@ _get_root() {
|
|||||||
p=1
|
p=1
|
||||||
|
|
||||||
if _ionos_rest GET "$IONOS_ROUTE_ZONES"; then
|
if _ionos_rest GET "$IONOS_ROUTE_ZONES"; then
|
||||||
_response="$(echo "$_response" | tr -d "\n")"
|
response="$(echo "$response" | tr -d "\n")"
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||||
@ -93,7 +93,7 @@ _get_root() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_zone="$(echo "$_response" | _egrep_o "\"name\":\"$h\".*\}")"
|
_zone="$(echo "$response" | _egrep_o "\"name\":\"$h\".*\}")"
|
||||||
if [ "$_zone" ]; then
|
if [ "$_zone" ]; then
|
||||||
_zone_id=$(printf "%s\n" "$_zone" | _egrep_o "\"id\":\"[a-fA-F0-9\-]*\"" | _head_n 1 | cut -d : -f 2 | tr -d '\"')
|
_zone_id=$(printf "%s\n" "$_zone" | _egrep_o "\"id\":\"[a-fA-F0-9\-]*\"" | _head_n 1 | cut -d : -f 2 | tr -d '\"')
|
||||||
if [ "$_zone_id" ]; then
|
if [ "$_zone_id" ]; then
|
||||||
@ -120,9 +120,9 @@ _ionos_get_record() {
|
|||||||
txtrecord=$3
|
txtrecord=$3
|
||||||
|
|
||||||
if _ionos_rest GET "$IONOS_ROUTE_ZONES/$zone_id?recordName=$fulldomain&recordType=TXT"; then
|
if _ionos_rest GET "$IONOS_ROUTE_ZONES/$zone_id?recordName=$fulldomain&recordType=TXT"; then
|
||||||
_response="$(echo "$_response" | tr -d "\n")"
|
response="$(echo "$response" | tr -d "\n")"
|
||||||
|
|
||||||
_record="$(echo "$_response" | _egrep_o "\"name\":\"$fulldomain\"[^\}]*\"type\":\"TXT\"[^\}]*\"content\":\"\\\\\"$txtrecord\\\\\"\".*\}")"
|
_record="$(echo "$response" | _egrep_o "\"name\":\"$fulldomain\"[^\}]*\"type\":\"TXT\"[^\}]*\"content\":\"\\\\\"$txtrecord\\\\\"\".*\}")"
|
||||||
if [ "$_record" ]; then
|
if [ "$_record" ]; then
|
||||||
_record_id=$(printf "%s\n" "$_record" | _egrep_o "\"id\":\"[a-fA-F0-9\-]*\"" | _head_n 1 | cut -d : -f 2 | tr -d '\"')
|
_record_id=$(printf "%s\n" "$_record" | _egrep_o "\"id\":\"[a-fA-F0-9\-]*\"" | _head_n 1 | cut -d : -f 2 | tr -d '\"')
|
||||||
|
|
||||||
@ -142,30 +142,22 @@ _ionos_rest() {
|
|||||||
|
|
||||||
export _H1="X-API-Key: $IONOS_API_KEY"
|
export _H1="X-API-Key: $IONOS_API_KEY"
|
||||||
|
|
||||||
# clear headers
|
|
||||||
: >"$HTTP_HEADER"
|
|
||||||
|
|
||||||
if [ "$method" != "GET" ]; then
|
if [ "$method" != "GET" ]; then
|
||||||
export _H2="Accept: application/json"
|
export _H2="Accept: application/json"
|
||||||
export _H3="Content-Type: application/json"
|
export _H3="Content-Type: application/json"
|
||||||
|
|
||||||
_response="$(_post "$data" "$IONOS_API$route" "" "$method" "application/json")"
|
response="$(_post "$data" "$IONOS_API$route" "" "$method" "application/json")"
|
||||||
else
|
else
|
||||||
export _H2="Accept: */*"
|
export _H2="Accept: */*"
|
||||||
export _H3=
|
export _H3=
|
||||||
|
response="$(_get "$IONOS_API$route")"
|
||||||
_response="$(_get "$IONOS_API$route")"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
|
|
||||||
|
|
||||||
if [ "$?" != "0" ]; then
|
if [ "$?" != "0" ]; then
|
||||||
_err "Error $route: $_response"
|
_err "Error $route: $response"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
_debug2 "response" "$response"
|
||||||
_debug2 "_response" "$_response"
|
|
||||||
_debug2 "_code" "$_code"
|
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,157 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
#Created by Roman Lumetsberger, to use ipv64.net's API to add/remove text records
|
|
||||||
#2022/11/29
|
|
||||||
|
|
||||||
# Pass credentials before "acme.sh --issue --dns dns_ipv64 ..."
|
|
||||||
# --
|
|
||||||
# export IPv64_Token="aaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
||||||
# --
|
|
||||||
#
|
|
||||||
|
|
||||||
IPv64_API="https://ipv64.net/api"
|
|
||||||
|
|
||||||
######## Public functions ######################
|
|
||||||
|
|
||||||
#Usage: dns_ipv64_add _acme-challenge.domain.ipv64.net "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
|
||||||
dns_ipv64_add() {
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
|
|
||||||
IPv64_Token="${IPv64_Token:-$(_readaccountconf_mutable IPv64_Token)}"
|
|
||||||
if [ -z "$IPv64_Token" ]; then
|
|
||||||
_err "You must export variable: IPv64_Token"
|
|
||||||
_err "The API Key for your IPv64 account is necessary."
|
|
||||||
_err "You can look it up in your IPv64 account."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Now save the credentials.
|
|
||||||
_saveaccountconf_mutable IPv64_Token "$IPv64_Token"
|
|
||||||
|
|
||||||
if ! _get_root "$fulldomain"; then
|
|
||||||
_err "invalid domain" "$fulldomain"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_debug _sub_domain "$_sub_domain"
|
|
||||||
_debug _domain "$_domain"
|
|
||||||
|
|
||||||
# convert to lower case
|
|
||||||
_domain="$(echo "$_domain" | _lower_case)"
|
|
||||||
_sub_domain="$(echo "$_sub_domain" | _lower_case)"
|
|
||||||
# Now add the TXT record
|
|
||||||
_info "Trying to add TXT record"
|
|
||||||
if _ipv64_rest "POST" "add_record=$_domain&praefix=$_sub_domain&type=TXT&content=$txtvalue"; then
|
|
||||||
_info "TXT record has been successfully added."
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
_err "Errors happened during adding the TXT record, response=$_response"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#Usage: fulldomain txtvalue
|
|
||||||
#Usage: dns_ipv64_rm _acme-challenge.domain.ipv64.net "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
|
||||||
#Remove the txt record after validation.
|
|
||||||
dns_ipv64_rm() {
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
|
|
||||||
IPv64_Token="${IPv64_Token:-$(_readaccountconf_mutable IPv64_Token)}"
|
|
||||||
if [ -z "$IPv64_Token" ]; then
|
|
||||||
_err "You must export variable: IPv64_Token"
|
|
||||||
_err "The API Key for your IPv64 account is necessary."
|
|
||||||
_err "You can look it up in your IPv64 account."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! _get_root "$fulldomain"; then
|
|
||||||
_err "invalid domain" "$fulldomain"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_debug _sub_domain "$_sub_domain"
|
|
||||||
_debug _domain "$_domain"
|
|
||||||
|
|
||||||
# convert to lower case
|
|
||||||
_domain="$(echo "$_domain" | _lower_case)"
|
|
||||||
_sub_domain="$(echo "$_sub_domain" | _lower_case)"
|
|
||||||
# Now delete the TXT record
|
|
||||||
_info "Trying to delete TXT record"
|
|
||||||
if _ipv64_rest "DELETE" "del_record=$_domain&praefix=$_sub_domain&type=TXT&content=$txtvalue"; then
|
|
||||||
_info "TXT record has been successfully deleted."
|
|
||||||
return 0
|
|
||||||
else
|
|
||||||
_err "Errors happened during deleting the TXT record, response=$_response"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
|
||||||
#_acme-challenge.www.domain.com
|
|
||||||
#returns
|
|
||||||
# _sub_domain=_acme-challenge.www
|
|
||||||
# _domain=domain.com
|
|
||||||
_get_root() {
|
|
||||||
domain="$1"
|
|
||||||
i=1
|
|
||||||
p=1
|
|
||||||
|
|
||||||
_ipv64_get "get_domains"
|
|
||||||
domain_data=$_response
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
|
||||||
if [ -z "$h" ]; then
|
|
||||||
#not valid
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
#if _contains "$domain_data" "\""$h"\"\:"; then
|
|
||||||
if _contains "$domain_data" "\"""$h""\"\:"; then
|
|
||||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
|
||||||
_domain="$h"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
p=$i
|
|
||||||
i=$(_math "$i" + 1)
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#send get request to api
|
|
||||||
# $1 has to set the api-function
|
|
||||||
_ipv64_get() {
|
|
||||||
url="$IPv64_API?$1"
|
|
||||||
export _H1="Authorization: Bearer $IPv64_Token"
|
|
||||||
|
|
||||||
_response=$(_get "$url")
|
|
||||||
_response="$(echo "$_response" | _normalizeJson)"
|
|
||||||
|
|
||||||
if _contains "$_response" "429 Too Many Requests"; then
|
|
||||||
_info "API throttled, sleeping to reset the limit"
|
|
||||||
_sleep 10
|
|
||||||
_response=$(_get "$url")
|
|
||||||
_response="$(echo "$_response" | _normalizeJson)"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
_ipv64_rest() {
|
|
||||||
url="$IPv64_API"
|
|
||||||
export _H1="Authorization: Bearer $IPv64_Token"
|
|
||||||
export _H2="Content-Type: application/x-www-form-urlencoded"
|
|
||||||
_response=$(_post "$2" "$url" "" "$1")
|
|
||||||
|
|
||||||
if _contains "$_response" "429 Too Many Requests"; then
|
|
||||||
_info "API throttled, sleeping to reset the limit"
|
|
||||||
_sleep 10
|
|
||||||
_response=$(_post "$2" "$url" "" "$1")
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! _contains "$_response" "\"info\":\"success\""; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_debug2 response "$_response"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
@ -32,11 +32,7 @@ dns_ispconfig_rm() {
|
|||||||
#################### Private functions below ##################################
|
#################### Private functions below ##################################
|
||||||
|
|
||||||
_ISPC_credentials() {
|
_ISPC_credentials() {
|
||||||
ISPC_User="${ISPC_User:-$(_readaccountconf_mutable ISPC_User)}"
|
if [ -z "${ISPC_User}" ] || [ -z "$ISPC_Password" ] || [ -z "${ISPC_Api}" ] || [ -z "${ISPC_Api_Insecure}" ]; then
|
||||||
ISPC_Password="${ISPC_Password:-$(_readaccountconf_mutable ISPC_Password)}"
|
|
||||||
ISPC_Api="${ISPC_Api:-$(_readaccountconf_mutable ISPC_Api)}"
|
|
||||||
ISPC_Api_Insecure="${ISPC_Api_Insecure:-$(_readaccountconf_mutable ISPC_Api_Insecure)}"
|
|
||||||
if [ -z "${ISPC_User}" ] || [ -z "${ISPC_Password}" ] || [ -z "${ISPC_Api}" ] || [ -z "${ISPC_Api_Insecure}" ]; then
|
|
||||||
ISPC_User=""
|
ISPC_User=""
|
||||||
ISPC_Password=""
|
ISPC_Password=""
|
||||||
ISPC_Api=""
|
ISPC_Api=""
|
||||||
@ -44,10 +40,10 @@ _ISPC_credentials() {
|
|||||||
_err "You haven't specified the ISPConfig Login data, URL and whether you want check the ISPC SSL cert. Please try again."
|
_err "You haven't specified the ISPConfig Login data, URL and whether you want check the ISPC SSL cert. Please try again."
|
||||||
return 1
|
return 1
|
||||||
else
|
else
|
||||||
_saveaccountconf_mutable ISPC_User "${ISPC_User}"
|
_saveaccountconf ISPC_User "${ISPC_User}"
|
||||||
_saveaccountconf_mutable ISPC_Password "${ISPC_Password}"
|
_saveaccountconf ISPC_Password "${ISPC_Password}"
|
||||||
_saveaccountconf_mutable ISPC_Api "${ISPC_Api}"
|
_saveaccountconf ISPC_Api "${ISPC_Api}"
|
||||||
_saveaccountconf_mutable ISPC_Api_Insecure "${ISPC_Api_Insecure}"
|
_saveaccountconf ISPC_Api_Insecure "${ISPC_Api_Insecure}"
|
||||||
# Set whether curl should use secure or insecure mode
|
# Set whether curl should use secure or insecure mode
|
||||||
export HTTPS_INSECURE="${ISPC_Api_Insecure}"
|
export HTTPS_INSECURE="${ISPC_Api_Insecure}"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -6,7 +6,8 @@
|
|||||||
|
|
||||||
#KAPPERNETDNS_Key="yourKAPPERNETapikey"
|
#KAPPERNETDNS_Key="yourKAPPERNETapikey"
|
||||||
#KAPPERNETDNS_Secret="yourKAPPERNETapisecret"
|
#KAPPERNETDNS_Secret="yourKAPPERNETapisecret"
|
||||||
#KAPPERNETDNS_Api="https://dnspanel.kapper.net/API/1.2?APIKey=$KAPPERNETDNS_Key&APISecret=$KAPPERNETDNS_Secret"
|
|
||||||
|
KAPPERNETDNS_Api="https://dnspanel.kapper.net/API/1.2?APIKey=$KAPPERNETDNS_Key&APISecret=$KAPPERNETDNS_Secret"
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# called with
|
# called with
|
||||||
@ -18,9 +19,10 @@ dns_kappernet_add() {
|
|||||||
|
|
||||||
KAPPERNETDNS_Key="${KAPPERNETDNS_Key:-$(_readaccountconf_mutable KAPPERNETDNS_Key)}"
|
KAPPERNETDNS_Key="${KAPPERNETDNS_Key:-$(_readaccountconf_mutable KAPPERNETDNS_Key)}"
|
||||||
KAPPERNETDNS_Secret="${KAPPERNETDNS_Secret:-$(_readaccountconf_mutable KAPPERNETDNS_Secret)}"
|
KAPPERNETDNS_Secret="${KAPPERNETDNS_Secret:-$(_readaccountconf_mutable KAPPERNETDNS_Secret)}"
|
||||||
KAPPERNETDNS_Api="https://dnspanel.kapper.net/API/1.2?APIKey=$KAPPERNETDNS_Key&APISecret=$KAPPERNETDNS_Secret"
|
|
||||||
|
|
||||||
if [ -z "$KAPPERNETDNS_Key" ] || [ -z "$KAPPERNETDNS_Secret" ]; then
|
if [ -z "$KAPPERNETDNS_Key" ] || [ -z "$KAPPERNETDNS_Secret" ]; then
|
||||||
|
KAPPERNETDNS_Key=""
|
||||||
|
KAPPERNETDNS_Secret=""
|
||||||
_err "Please specify your kapper.net api key and secret."
|
_err "Please specify your kapper.net api key and secret."
|
||||||
_err "If you have not received yours - send your mail to"
|
_err "If you have not received yours - send your mail to"
|
||||||
_err "support@kapper.net to get your key and secret."
|
_err "support@kapper.net to get your key and secret."
|
||||||
@ -39,12 +41,12 @@ dns_kappernet_add() {
|
|||||||
_debug _domain "DOMAIN: $_domain"
|
_debug _domain "DOMAIN: $_domain"
|
||||||
|
|
||||||
_info "Trying to add TXT DNS Record"
|
_info "Trying to add TXT DNS Record"
|
||||||
data="%7B%22name%22%3A%22$fullhostname%22%2C%22type%22%3A%22TXT%22%2C%22content%22%3A%22$txtvalue%22%2C%22ttl%22%3A%22300%22%2C%22prio%22%3A%22%22%7D"
|
data="%7B%22name%22%3A%22$fullhostname%22%2C%22type%22%3A%22TXT%22%2C%22content%22%3A%22$txtvalue%22%2C%22ttl%22%3A%223600%22%2C%22prio%22%3A%22%22%7D"
|
||||||
if _kappernet_api GET "action=new&subject=$_domain&data=$data"; then
|
if _kappernet_api GET "action=new&subject=$_domain&data=$data"; then
|
||||||
|
|
||||||
if _contains "$response" "{\"OK\":true"; then
|
if _contains "$response" "{\"OK\":true"; then
|
||||||
_info "Waiting 1 second for DNS to spread the new record"
|
_info "Waiting 120 seconds for DNS to spread the new record"
|
||||||
_sleep 1
|
_sleep 120
|
||||||
return 0
|
return 0
|
||||||
else
|
else
|
||||||
_err "Error creating a TXT DNS Record: $fullhostname TXT $txtvalue"
|
_err "Error creating a TXT DNS Record: $fullhostname TXT $txtvalue"
|
||||||
@ -64,9 +66,10 @@ dns_kappernet_rm() {
|
|||||||
|
|
||||||
KAPPERNETDNS_Key="${KAPPERNETDNS_Key:-$(_readaccountconf_mutable KAPPERNETDNS_Key)}"
|
KAPPERNETDNS_Key="${KAPPERNETDNS_Key:-$(_readaccountconf_mutable KAPPERNETDNS_Key)}"
|
||||||
KAPPERNETDNS_Secret="${KAPPERNETDNS_Secret:-$(_readaccountconf_mutable KAPPERNETDNS_Secret)}"
|
KAPPERNETDNS_Secret="${KAPPERNETDNS_Secret:-$(_readaccountconf_mutable KAPPERNETDNS_Secret)}"
|
||||||
KAPPERNETDNS_Api="https://dnspanel.kapper.net/API/1.2?APIKey=$KAPPERNETDNS_Key&APISecret=$KAPPERNETDNS_Secret"
|
|
||||||
|
|
||||||
if [ -z "$KAPPERNETDNS_Key" ] || [ -z "$KAPPERNETDNS_Secret" ]; then
|
if [ -z "$KAPPERNETDNS_Key" ] || [ -z "$KAPPERNETDNS_Secret" ]; then
|
||||||
|
KAPPERNETDNS_Key=""
|
||||||
|
KAPPERNETDNS_Secret=""
|
||||||
_err "Please specify your kapper.net api key and secret."
|
_err "Please specify your kapper.net api key and secret."
|
||||||
_err "If you have not received yours - send your mail to"
|
_err "If you have not received yours - send your mail to"
|
||||||
_err "support@kapper.net to get your key and secret."
|
_err "support@kapper.net to get your key and secret."
|
||||||
@ -78,7 +81,7 @@ dns_kappernet_rm() {
|
|||||||
_saveaccountconf_mutable KAPPERNETDNS_Secret "$KAPPERNETDNS_Secret"
|
_saveaccountconf_mutable KAPPERNETDNS_Secret "$KAPPERNETDNS_Secret"
|
||||||
|
|
||||||
_info "Trying to remove the TXT Record: $fullhostname containing $txtvalue"
|
_info "Trying to remove the TXT Record: $fullhostname containing $txtvalue"
|
||||||
data="%7B%22name%22%3A%22$fullhostname%22%2C%22type%22%3A%22TXT%22%2C%22content%22%3A%22$txtvalue%22%2C%22ttl%22%3A%22300%22%2C%22prio%22%3A%22%22%7D"
|
data="%7B%22name%22%3A%22$fullhostname%22%2C%22type%22%3A%22TXT%22%2C%22content%22%3A%22$txtvalue%22%2C%22ttl%22%3A%223600%22%2C%22prio%22%3A%22%22%7D"
|
||||||
if _kappernet_api GET "action=del&subject=$fullhostname&data=$data"; then
|
if _kappernet_api GET "action=del&subject=$fullhostname&data=$data"; then
|
||||||
if _contains "$response" "{\"OK\":true"; then
|
if _contains "$response" "{\"OK\":true"; then
|
||||||
return 0
|
return 0
|
||||||
@ -138,7 +141,7 @@ _kappernet_api() {
|
|||||||
if [ "$method" = "GET" ]; then
|
if [ "$method" = "GET" ]; then
|
||||||
response="$(_get "$url")"
|
response="$(_get "$url")"
|
||||||
else
|
else
|
||||||
_err "Unsupported method or missing Secret/Key"
|
_err "Unsupported method"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@ -5,81 +5,51 @@
|
|||||||
# Environment variables:
|
# Environment variables:
|
||||||
#
|
#
|
||||||
# - $KAS_Login (Kasserver API login name)
|
# - $KAS_Login (Kasserver API login name)
|
||||||
# - $KAS_Authtype (Kasserver API auth type. Default: plain)
|
# - $KAS_Authtype (Kasserver API auth type. Default: sha1)
|
||||||
# - $KAS_Authdata (Kasserver API auth data.)
|
# - $KAS_Authdata (Kasserver API auth data.)
|
||||||
#
|
#
|
||||||
# Last update: squared GmbH <github@squaredgmbh.de>
|
# Author: Martin Kammerlander, Phlegx Systems OG <martin.kammerlander@phlegx.com>
|
||||||
# Credits:
|
# Updated by: Marc-Oliver Lange <git@die-lang.es>
|
||||||
# - dns_he.sh. Thanks a lot man!
|
# Credits: Inspired by dns_he.sh. Thanks a lot man!
|
||||||
# - Martin Kammerlander, Phlegx Systems OG <martin.kammerlander@phlegx.com>
|
# Git repo: https://github.com/phlegx/acme.sh
|
||||||
# - Marc-Oliver Lange <git@die-lang.es>
|
# TODO: Better Error handling
|
||||||
# - https://github.com/o1oo11oo/kasapi.sh
|
|
||||||
########################################################################
|
########################################################################
|
||||||
KAS_Api_GET="$(_get "https://kasapi.kasserver.com/soap/wsdl/KasApi.wsdl")"
|
KAS_Api="https://kasapi.kasserver.com/dokumentation/formular.php"
|
||||||
KAS_Api="$(echo "$KAS_Api_GET" | tr -d ' ' | grep -i "<soap:addresslocation=" | sed "s/='/\n/g" | grep -i "http" | sed "s/'\/>//g")"
|
|
||||||
_info "[KAS] -> API URL $KAS_Api"
|
|
||||||
|
|
||||||
KAS_Auth_GET="$(_get "https://kasapi.kasserver.com/soap/wsdl/KasAuth.wsdl")"
|
|
||||||
KAS_Auth="$(echo "$KAS_Auth_GET" | tr -d ' ' | grep -i "<soap:addresslocation=" | sed "s/='/\n/g" | grep -i "http" | sed "s/'\/>//g")"
|
|
||||||
_info "[KAS] -> AUTH URL $KAS_Auth"
|
|
||||||
|
|
||||||
KAS_default_ratelimit=5 # TODO - Every response delivers a ratelimit (seconds) where KASAPI is blocking a request.
|
|
||||||
|
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
dns_kas_add() {
|
dns_kas_add() {
|
||||||
_fulldomain=$1
|
_fulldomain=$1
|
||||||
_txtvalue=$2
|
_txtvalue=$2
|
||||||
|
_info "Using DNS-01 All-inkl/Kasserver hook"
|
||||||
_info "[KAS] -> Using DNS-01 All-inkl/Kasserver hook"
|
_info "Adding $_fulldomain DNS TXT entry on All-inkl/Kasserver"
|
||||||
_info "[KAS] -> Check and Save Props"
|
_info "Check and Save Props"
|
||||||
_check_and_save
|
_check_and_save
|
||||||
|
_info "Checking Zone and Record_Name"
|
||||||
_info "[KAS] -> Adding $_fulldomain DNS TXT entry on all-inkl.com/Kasserver"
|
|
||||||
_info "[KAS] -> Retriving Credential Token"
|
|
||||||
_get_credential_token
|
|
||||||
|
|
||||||
_info "[KAS] -> Checking Zone and Record_Name"
|
|
||||||
_get_zone_and_record_name "$_fulldomain"
|
_get_zone_and_record_name "$_fulldomain"
|
||||||
|
_info "Getting Record ID"
|
||||||
_info "[KAS] -> Checking for existing Record entries"
|
|
||||||
_get_record_id
|
_get_record_id
|
||||||
|
|
||||||
# If there is a record_id, delete the entry
|
_info "Creating TXT DNS record"
|
||||||
if [ -n "$_record_id" ]; then
|
params="?kas_login=$KAS_Login"
|
||||||
_info "[KAS] -> Existing records found. Now deleting old entries"
|
params="$params&kas_auth_type=$KAS_Authtype"
|
||||||
for i in $_record_id; do
|
params="$params&kas_auth_data=$KAS_Authdata"
|
||||||
_delete_RecordByID "$i"
|
params="$params&var1=record_name"
|
||||||
done
|
params="$params&wert1=$_record_name"
|
||||||
else
|
params="$params&var2=record_type"
|
||||||
_info "[KAS] -> No record found."
|
params="$params&wert2=TXT"
|
||||||
fi
|
params="$params&var3=record_data"
|
||||||
|
params="$params&wert3=$_txtvalue"
|
||||||
|
params="$params&var4=record_aux"
|
||||||
|
params="$params&wert4=0"
|
||||||
|
params="$params&kas_action=add_dns_settings"
|
||||||
|
params="$params&var5=zone_host"
|
||||||
|
params="$params&wert5=$_zone"
|
||||||
|
_debug2 "Wait for 10 seconds by default before calling KAS API."
|
||||||
|
_sleep 10
|
||||||
|
response="$(_get "$KAS_Api$params")"
|
||||||
|
_debug2 "response" "$response"
|
||||||
|
|
||||||
_info "[KAS] -> Creating TXT DNS record"
|
if ! _contains "$response" "TRUE"; then
|
||||||
action="add_dns_settings"
|
_err "An unkown error occurred, please check manually."
|
||||||
kasReqParam="\"record_name\":\"$_record_name\""
|
|
||||||
kasReqParam="$kasReqParam,\"record_type\":\"TXT\""
|
|
||||||
kasReqParam="$kasReqParam,\"record_data\":\"$_txtvalue\""
|
|
||||||
kasReqParam="$kasReqParam,\"record_aux\":\"0\""
|
|
||||||
kasReqParam="$kasReqParam,\"zone_host\":\"$_zone\""
|
|
||||||
response="$(_callAPI "$action" "$kasReqParam")"
|
|
||||||
_debug2 "[KAS] -> Response" "$response"
|
|
||||||
|
|
||||||
if [ -z "$response" ]; then
|
|
||||||
_info "[KAS] -> Response was empty, please check manually."
|
|
||||||
return 1
|
|
||||||
elif _contains "$response" "<SOAP-ENV:Fault>"; then
|
|
||||||
faultstring="$(echo "$response" | tr -d '\n\r' | sed "s/<faultstring>/\n=> /g" | sed "s/<\/faultstring>/\n/g" | grep "=>" | sed "s/=> //g")"
|
|
||||||
case "${faultstring}" in
|
|
||||||
"record_already_exists")
|
|
||||||
_info "[KAS] -> The record already exists, which must not be a problem. Please check manually."
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
_err "[KAS] -> An error =>$faultstring<= occurred, please check manually."
|
|
||||||
return 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
elif ! _contains "$response" "<item><key xsi:type=\"xsd:string\">ReturnString</key><value xsi:type=\"xsd:string\">TRUE</value></item>"; then
|
|
||||||
_err "[KAS] -> An unknown error occurred, please check manually."
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
@ -88,62 +58,45 @@ dns_kas_add() {
|
|||||||
dns_kas_rm() {
|
dns_kas_rm() {
|
||||||
_fulldomain=$1
|
_fulldomain=$1
|
||||||
_txtvalue=$2
|
_txtvalue=$2
|
||||||
|
_info "Using DNS-01 All-inkl/Kasserver hook"
|
||||||
|
_info "Cleaning up after All-inkl/Kasserver hook"
|
||||||
|
_info "Removing $_fulldomain DNS TXT entry on All-inkl/Kasserver"
|
||||||
|
|
||||||
_info "[KAS] -> Using DNS-01 All-inkl/Kasserver hook"
|
_info "Check and Save Props"
|
||||||
_info "[KAS] -> Check and Save Props"
|
|
||||||
_check_and_save
|
_check_and_save
|
||||||
|
_info "Checking Zone and Record_Name"
|
||||||
_info "[KAS] -> Cleaning up after All-inkl/Kasserver hook"
|
|
||||||
_info "[KAS] -> Removing $_fulldomain DNS TXT entry on All-inkl/Kasserver"
|
|
||||||
_info "[KAS] -> Retriving Credential Token"
|
|
||||||
_get_credential_token
|
|
||||||
|
|
||||||
_info "[KAS] -> Checking Zone and Record_Name"
|
|
||||||
_get_zone_and_record_name "$_fulldomain"
|
_get_zone_and_record_name "$_fulldomain"
|
||||||
|
_info "Getting Record ID"
|
||||||
_info "[KAS] -> Getting Record ID"
|
|
||||||
_get_record_id
|
_get_record_id
|
||||||
|
|
||||||
_info "[KAS] -> Removing entries with ID: $_record_id"
|
|
||||||
# If there is a record_id, delete the entry
|
# If there is a record_id, delete the entry
|
||||||
if [ -n "$_record_id" ]; then
|
if [ -n "$_record_id" ]; then
|
||||||
|
params="?kas_login=$KAS_Login"
|
||||||
|
params="$params&kas_auth_type=$KAS_Authtype"
|
||||||
|
params="$params&kas_auth_data=$KAS_Authdata"
|
||||||
|
params="$params&kas_action=delete_dns_settings"
|
||||||
|
|
||||||
for i in $_record_id; do
|
for i in $_record_id; do
|
||||||
_delete_RecordByID "$i"
|
params2="$params&var1=record_id"
|
||||||
|
params2="$params2&wert1=$i"
|
||||||
|
_debug2 "Wait for 10 seconds by default before calling KAS API."
|
||||||
|
_sleep 10
|
||||||
|
response="$(_get "$KAS_Api$params2")"
|
||||||
|
_debug2 "response" "$response"
|
||||||
|
if ! _contains "$response" "TRUE"; then
|
||||||
|
_err "Either the txt record is not found or another error occurred, please check manually."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
else # Cannot delete or unkown error
|
else # Cannot delete or unkown error
|
||||||
_info "[KAS] -> No record_id found that can be deleted. Please check manually."
|
_err "No record_id found that can be deleted. Please check manually."
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
########################## PRIVATE FUNCTIONS ###########################
|
########################## PRIVATE FUNCTIONS ###########################
|
||||||
# Delete Record ID
|
|
||||||
_delete_RecordByID() {
|
|
||||||
recId=$1
|
|
||||||
action="delete_dns_settings"
|
|
||||||
kasReqParam="\"record_id\":\"$recId\""
|
|
||||||
response="$(_callAPI "$action" "$kasReqParam")"
|
|
||||||
_debug2 "[KAS] -> Response" "$response"
|
|
||||||
|
|
||||||
if [ -z "$response" ]; then
|
|
||||||
_info "[KAS] -> Response was empty, please check manually."
|
|
||||||
return 1
|
|
||||||
elif _contains "$response" "<SOAP-ENV:Fault>"; then
|
|
||||||
faultstring="$(echo "$response" | tr -d '\n\r' | sed "s/<faultstring>/\n=> /g" | sed "s/<\/faultstring>/\n/g" | grep "=>" | sed "s/=> //g")"
|
|
||||||
case "${faultstring}" in
|
|
||||||
"record_id_not_found")
|
|
||||||
_info "[KAS] -> The record was not found, which perhaps is not a problem. Please check manually."
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
_err "[KAS] -> An error =>$faultstring<= occurred, please check manually."
|
|
||||||
return 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
elif ! _contains "$response" "<item><key xsi:type=\"xsd:string\">ReturnString</key><value xsi:type=\"xsd:string\">TRUE</value></item>"; then
|
|
||||||
_err "[KAS] -> An unknown error occurred, please check manually."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
# Checks for the ENV variables and saves them
|
# Checks for the ENV variables and saves them
|
||||||
_check_and_save() {
|
_check_and_save() {
|
||||||
KAS_Login="${KAS_Login:-$(_readaccountconf_mutable KAS_Login)}"
|
KAS_Login="${KAS_Login:-$(_readaccountconf_mutable KAS_Login)}"
|
||||||
@ -154,7 +107,7 @@ _check_and_save() {
|
|||||||
KAS_Login=
|
KAS_Login=
|
||||||
KAS_Authtype=
|
KAS_Authtype=
|
||||||
KAS_Authdata=
|
KAS_Authdata=
|
||||||
_err "[KAS] -> No auth details provided. Please set user credentials using the \$KAS_Login, \$KAS_Authtype, and \$KAS_Authdata environment variables."
|
_err "No auth details provided. Please set user credentials using the \$KAS_Login, \$KAS_Authtype, and \$KAS_Authdata environment variables."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
_saveaccountconf_mutable KAS_Login "$KAS_Login"
|
_saveaccountconf_mutable KAS_Login "$KAS_Login"
|
||||||
@ -166,116 +119,50 @@ _check_and_save() {
|
|||||||
# Gets back the base domain/zone and record name.
|
# Gets back the base domain/zone and record name.
|
||||||
# See: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide
|
# See: https://github.com/Neilpang/acme.sh/wiki/DNS-API-Dev-Guide
|
||||||
_get_zone_and_record_name() {
|
_get_zone_and_record_name() {
|
||||||
action="get_domains"
|
params="?kas_login=$KAS_Login"
|
||||||
response="$(_callAPI "$action")"
|
params="?kas_login=$KAS_Login"
|
||||||
_debug2 "[KAS] -> Response" "$response"
|
params="$params&kas_auth_type=$KAS_Authtype"
|
||||||
|
params="$params&kas_auth_data=$KAS_Authdata"
|
||||||
|
params="$params&kas_action=get_domains"
|
||||||
|
|
||||||
if [ -z "$response" ]; then
|
_debug2 "Wait for 10 seconds by default before calling KAS API."
|
||||||
_info "[KAS] -> Response was empty, please check manually."
|
_sleep 10
|
||||||
return 1
|
response="$(_get "$KAS_Api$params")"
|
||||||
elif _contains "$response" "<SOAP-ENV:Fault>"; then
|
_debug2 "response" "$response"
|
||||||
faultstring="$(echo "$response" | tr -d '\n\r' | sed "s/<faultstring>/\n=> /g" | sed "s/<\/faultstring>/\n/g" | grep "=>" | sed "s/=> //g")"
|
_zonen="$(echo "$response" | tr -d "\n\r" | tr -d " " | tr '[]' '<>' | sed "s/=>Array/\n=> Array/g" | tr ' ' '\n' | grep "domain_name" | tr '<' '\n' | grep "domain_name" | sed "s/domain_name>=>//g")"
|
||||||
_err "[KAS] -> Either no domains were found or another error =>$faultstring<= occurred, please check manually."
|
_domain="$1"
|
||||||
return 1
|
_temp_domain="$(echo "$1" | sed 's/\.$//')"
|
||||||
fi
|
_rootzone="$_domain"
|
||||||
|
for i in $_zonen; do
|
||||||
zonen="$(echo "$response" | sed 's/<item>/\n/g' | sed -r 's/(.*<key xsi:type="xsd:string">domain_name<\/key><value xsi:type="xsd:string">)(.*)(<\/value.*)/\2/' | sed '/^</d')"
|
l1=${#_rootzone}
|
||||||
domain="$1"
|
|
||||||
temp_domain="$(echo "$1" | sed 's/\.$//')"
|
|
||||||
rootzone="$domain"
|
|
||||||
for i in $zonen; do
|
|
||||||
l1=${#rootzone}
|
|
||||||
l2=${#i}
|
l2=${#i}
|
||||||
if _endswith "$domain" "$i" && [ "$l1" -ge "$l2" ]; then
|
if _endswith "$_domain" "$i" && [ "$l1" -ge "$l2" ]; then
|
||||||
rootzone="$i"
|
_rootzone="$i"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
_zone="${rootzone}."
|
_zone="${_rootzone}."
|
||||||
temp_record_name="$(echo "$temp_domain" | sed "s/$rootzone//g")"
|
_temp_record_name="$(echo "$_temp_domain" | sed "s/$_rootzone//g")"
|
||||||
_record_name="$(echo "$temp_record_name" | sed 's/\.$//')"
|
_record_name="$(echo "$_temp_record_name" | sed 's/\.$//')"
|
||||||
_debug "[KAS] -> Zone:" "$_zone"
|
_debug2 "Zone:" "$_zone"
|
||||||
_debug "[KAS] -> Domain:" "$domain"
|
_debug2 "Domain:" "$_domain"
|
||||||
_debug "[KAS] -> Record_Name:" "$_record_name"
|
_debug2 "Record_Name:" "$_record_name"
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# Retrieve the DNS record ID
|
# Retrieve the DNS record ID
|
||||||
_get_record_id() {
|
_get_record_id() {
|
||||||
action="get_dns_settings"
|
params="?kas_login=$KAS_Login"
|
||||||
kasReqParam="\"zone_host\":\"$_zone\""
|
params="$params&kas_auth_type=$KAS_Authtype"
|
||||||
response="$(_callAPI "$action" "$kasReqParam")"
|
params="$params&kas_auth_data=$KAS_Authdata"
|
||||||
_debug2 "[KAS] -> Response" "$response"
|
params="$params&kas_action=get_dns_settings"
|
||||||
|
params="$params&var1=zone_host"
|
||||||
|
params="$params&wert1=$_zone"
|
||||||
|
|
||||||
if [ -z "$response" ]; then
|
_debug2 "Wait for 10 seconds by default before calling KAS API."
|
||||||
_info "[KAS] -> Response was empty, please check manually."
|
_sleep 10
|
||||||
return 1
|
response="$(_get "$KAS_Api$params")"
|
||||||
elif _contains "$response" "<SOAP-ENV:Fault>"; then
|
_debug2 "response" "$response"
|
||||||
faultstring="$(echo "$response" | tr -d '\n\r' | sed "s/<faultstring>/\n=> /g" | sed "s/<\/faultstring>/\n/g" | grep "=>" | sed "s/=> //g")"
|
_record_id="$(echo "$response" | tr -d "\n\r" | tr -d " " | tr '[]' '<>' | sed "s/=>Array/\n=> Array/g" | tr ' ' '\n' | grep "=>$_record_name<" | grep '>TXT<' | tr '<' '\n' | grep record_id | sed "s/record_id>=>//g")"
|
||||||
_err "[KAS] -> Either no domains were found or another error =>$faultstring<= occurred, please check manually."
|
_debug2 _record_id "$_record_id"
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
_record_id="$(echo "$response" | tr -d '\n\r' | sed "s/<item xsi:type=\"ns2:Map\">/\n/g" | grep -i "$_record_name" | grep -i ">TXT<" | sed "s/<item><key xsi:type=\"xsd:string\">record_id<\/key><value xsi:type=\"xsd:string\">/=>/g" | grep -i "$_txtvalue" | sed "s/<\/value><\/item>/\n/g" | grep "=>" | sed "s/=>//g")"
|
|
||||||
_debug "[KAS] -> Record Id: " "$_record_id"
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# Retrieve credential token
|
|
||||||
_get_credential_token() {
|
|
||||||
baseParamAuth="\"kas_login\":\"$KAS_Login\""
|
|
||||||
baseParamAuth="$baseParamAuth,\"kas_auth_type\":\"$KAS_Authtype\""
|
|
||||||
baseParamAuth="$baseParamAuth,\"kas_auth_data\":\"$KAS_Authdata\""
|
|
||||||
baseParamAuth="$baseParamAuth,\"session_lifetime\":600"
|
|
||||||
baseParamAuth="$baseParamAuth,\"session_update_lifetime\":\"Y\""
|
|
||||||
|
|
||||||
data='<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:xmethodsKasApiAuthentication" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:KasAuth><Params xsi:type="xsd:string">{'
|
|
||||||
data="$data$baseParamAuth}</Params></ns1:KasAuth></SOAP-ENV:Body></SOAP-ENV:Envelope>"
|
|
||||||
|
|
||||||
_debug "[KAS] -> Be friendly and wait $KAS_default_ratelimit seconds by default before calling KAS API."
|
|
||||||
_sleep $KAS_default_ratelimit
|
|
||||||
|
|
||||||
contentType="text/xml"
|
|
||||||
export _H1="SOAPAction: urn:xmethodsKasApiAuthentication#KasAuth"
|
|
||||||
response="$(_post "$data" "$KAS_Auth" "" "POST" "$contentType")"
|
|
||||||
_debug2 "[KAS] -> Response" "$response"
|
|
||||||
|
|
||||||
if [ -z "$response" ]; then
|
|
||||||
_info "[KAS] -> Response was empty, please check manually."
|
|
||||||
return 1
|
|
||||||
elif _contains "$response" "<SOAP-ENV:Fault>"; then
|
|
||||||
faultstring="$(echo "$response" | tr -d '\n\r' | sed "s/<faultstring>/\n=> /g" | sed "s/<\/faultstring>/\n/g" | grep "=>" | sed "s/=> //g")"
|
|
||||||
_err "[KAS] -> Could not retrieve login token or antoher error =>$faultstring<= occurred, please check manually."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
_credential_token="$(echo "$response" | tr '\n' ' ' | sed 's/.*return xsi:type="xsd:string">\(.*\)<\/return>/\1/' | sed 's/<\/ns1:KasAuthResponse\(.*\)Envelope>.*//')"
|
|
||||||
_debug "[KAS] -> Credential Token: " "$_credential_token"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
_callAPI() {
|
|
||||||
kasaction=$1
|
|
||||||
kasReqParams=$2
|
|
||||||
|
|
||||||
baseParamAuth="\"kas_login\":\"$KAS_Login\""
|
|
||||||
baseParamAuth="$baseParamAuth,\"kas_auth_type\":\"session\""
|
|
||||||
baseParamAuth="$baseParamAuth,\"kas_auth_data\":\"$_credential_token\""
|
|
||||||
|
|
||||||
data='<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:xmethodsKasApi" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><SOAP-ENV:Body><ns1:KasApi><Params xsi:type="xsd:string">{'
|
|
||||||
data="$data$baseParamAuth,\"kas_action\":\"$kasaction\""
|
|
||||||
if [ -n "$kasReqParams" ]; then
|
|
||||||
data="$data,\"KasRequestParams\":{$kasReqParams}"
|
|
||||||
fi
|
|
||||||
data="$data}</Params></ns1:KasApi></SOAP-ENV:Body></SOAP-ENV:Envelope>"
|
|
||||||
|
|
||||||
_debug2 "[KAS] -> Request" "$data"
|
|
||||||
|
|
||||||
_debug "[KAS] -> Be friendly and wait $KAS_default_ratelimit seconds by default before calling KAS API."
|
|
||||||
_sleep $KAS_default_ratelimit
|
|
||||||
|
|
||||||
contentType="text/xml"
|
|
||||||
export _H1="SOAPAction: urn:xmethodsKasApi#KasApi"
|
|
||||||
response="$(_post "$data" "$KAS_Api" "" "POST" "$contentType")"
|
|
||||||
_debug2 "[KAS] -> Response" "$response"
|
|
||||||
echo "$response"
|
|
||||||
}
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
############################################################
|
############################################################
|
||||||
# KingHost API support #
|
# KingHost API support #
|
||||||
# https://api.kinghost.net/doc/ #
|
# http://api.kinghost.net/doc/ #
|
||||||
# #
|
# #
|
||||||
# Author: Felipe Keller Braz <felipebraz@kinghost.com.br> #
|
# Author: Felipe Keller Braz <felipebraz@kinghost.com.br> #
|
||||||
# Report Bugs here: https://github.com/kinghost/acme.sh #
|
# Report Bugs here: https://github.com/kinghost/acme.sh #
|
||||||
|
|||||||
@ -19,9 +19,8 @@ dns_knot_add() {
|
|||||||
|
|
||||||
_info "Adding ${fulldomain}. 60 TXT \"${txtvalue}\""
|
_info "Adding ${fulldomain}. 60 TXT \"${txtvalue}\""
|
||||||
|
|
||||||
knsupdate <<EOF
|
knsupdate -y "${KNOT_KEY}" <<EOF
|
||||||
server ${KNOT_SERVER}
|
server ${KNOT_SERVER}
|
||||||
key ${KNOT_KEY}
|
|
||||||
zone ${_domain}.
|
zone ${_domain}.
|
||||||
update add ${fulldomain}. 60 TXT "${txtvalue}"
|
update add ${fulldomain}. 60 TXT "${txtvalue}"
|
||||||
send
|
send
|
||||||
@ -50,9 +49,8 @@ dns_knot_rm() {
|
|||||||
|
|
||||||
_info "Removing ${fulldomain}. TXT"
|
_info "Removing ${fulldomain}. TXT"
|
||||||
|
|
||||||
knsupdate <<EOF
|
knsupdate -y "${KNOT_KEY}" <<EOF
|
||||||
server ${KNOT_SERVER}
|
server ${KNOT_SERVER}
|
||||||
key ${KNOT_KEY}
|
|
||||||
zone ${_domain}.
|
zone ${_domain}.
|
||||||
update del ${fulldomain}. TXT
|
update del ${fulldomain}. TXT
|
||||||
send
|
send
|
||||||
|
|||||||
147
dnsapi/dns_la.sh
147
dnsapi/dns_la.sh
@ -1,147 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
#LA_Id="test123"
|
|
||||||
#LA_Key="d1j2fdo4dee3948"
|
|
||||||
|
|
||||||
LA_Api="https://api.dns.la/api"
|
|
||||||
|
|
||||||
######## Public functions #####################
|
|
||||||
|
|
||||||
#Usage: dns_la_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
|
||||||
dns_la_add() {
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
|
|
||||||
LA_Id="${LA_Id:-$(_readaccountconf_mutable LA_Id)}"
|
|
||||||
LA_Key="${LA_Key:-$(_readaccountconf_mutable LA_Key)}"
|
|
||||||
|
|
||||||
if [ -z "$LA_Id" ] || [ -z "$LA_Key" ]; then
|
|
||||||
LA_Id=""
|
|
||||||
LA_Key=""
|
|
||||||
_err "You didn't specify a dnsla api id and key yet."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
#save the api key and email to the account conf file.
|
|
||||||
_saveaccountconf_mutable LA_Id "$LA_Id"
|
|
||||||
_saveaccountconf_mutable LA_Key "$LA_Key"
|
|
||||||
|
|
||||||
_debug "First detect the root zone"
|
|
||||||
if ! _get_root "$fulldomain"; then
|
|
||||||
_err "invalid domain"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_debug _domain_id "$_domain_id"
|
|
||||||
_debug _sub_domain "$_sub_domain"
|
|
||||||
_debug _domain "$_domain"
|
|
||||||
|
|
||||||
_info "Adding record"
|
|
||||||
if _la_rest "record.ashx?cmd=create&apiid=$LA_Id&apipass=$LA_Key&rtype=json&domainid=$_domain_id&host=$_sub_domain&recordtype=TXT&recorddata=$txtvalue&recordline="; then
|
|
||||||
if _contains "$response" '"resultid":'; then
|
|
||||||
_info "Added, OK"
|
|
||||||
return 0
|
|
||||||
elif _contains "$response" '"code":532'; 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_la_rm() {
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
|
|
||||||
LA_Id="${LA_Id:-$(_readaccountconf_mutable LA_Id)}"
|
|
||||||
LA_Key="${LA_Key:-$(_readaccountconf_mutable LA_Key)}"
|
|
||||||
|
|
||||||
_debug "First detect the root zone"
|
|
||||||
if ! _get_root "$fulldomain"; then
|
|
||||||
_err "invalid domain"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_debug _domain_id "$_domain_id"
|
|
||||||
_debug _sub_domain "$_sub_domain"
|
|
||||||
_debug _domain "$_domain"
|
|
||||||
|
|
||||||
_debug "Getting txt records"
|
|
||||||
if ! _la_rest "record.ashx?cmd=listn&apiid=$LA_Id&apipass=$LA_Key&rtype=json&domainid=$_domain_id&domain=$_domain&host=$_sub_domain&recordtype=TXT&recorddata=$txtvalue"; then
|
|
||||||
_err "Error"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! _contains "$response" '"recordid":'; then
|
|
||||||
_info "Don't need to remove."
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
record_id=$(printf "%s" "$response" | grep '"recordid":' | cut -d : -f 2 | cut -d , -f 1 | tr -d '\r' | tr -d '\n')
|
|
||||||
_debug "record_id" "$record_id"
|
|
||||||
if [ -z "$record_id" ]; then
|
|
||||||
_err "Can not get record id to remove."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
if ! _la_rest "record.ashx?cmd=remove&apiid=$LA_Id&apipass=$LA_Key&rtype=json&domainid=$_domain_id&domain=$_domain&recordid=$record_id"; then
|
|
||||||
_err "Delete record error."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_contains "$response" '"code":300'
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#################### 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=1
|
|
||||||
p=1
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
|
||||||
if [ -z "$h" ]; then
|
|
||||||
#not valid
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! _la_rest "domain.ashx?cmd=get&apiid=$LA_Id&apipass=$LA_Key&rtype=json&domain=$h"; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if _contains "$response" '"domainid":'; then
|
|
||||||
_domain_id=$(printf "%s" "$response" | grep '"domainid":' | cut -d : -f 2 | cut -d , -f 1 | tr -d '\r' | tr -d '\n')
|
|
||||||
if [ "$_domain_id" ]; 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
|
|
||||||
}
|
|
||||||
|
|
||||||
#Usage: URI
|
|
||||||
_la_rest() {
|
|
||||||
url="$LA_Api/$1"
|
|
||||||
_debug "$url"
|
|
||||||
|
|
||||||
if ! response="$(_get "$url" | tr -d ' ' | tr "}" ",")"; then
|
|
||||||
_err "Error: $url"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
_debug2 response "$response"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
@ -3,10 +3,10 @@
|
|||||||
#Author: Rolph Haspers <r.haspers@global.leaseweb.com>
|
#Author: Rolph Haspers <r.haspers@global.leaseweb.com>
|
||||||
#Utilize leaseweb.com API to finish dns-01 verifications.
|
#Utilize leaseweb.com API to finish dns-01 verifications.
|
||||||
#Requires a Leaseweb API Key (export LSW_Key="Your Key")
|
#Requires a Leaseweb API Key (export LSW_Key="Your Key")
|
||||||
#See https://developer.leaseweb.com for more information.
|
#See http://developer.leaseweb.com for more information.
|
||||||
######## Public functions #####################
|
######## Public functions #####################
|
||||||
|
|
||||||
LSW_API="https://api.leaseweb.com/hosting/v2/domains"
|
LSW_API="https://api.leaseweb.com/hosting/v2/domains/"
|
||||||
|
|
||||||
#Usage: dns_leaseweb_add _acme-challenge.www.domain.com
|
#Usage: dns_leaseweb_add _acme-challenge.www.domain.com
|
||||||
dns_leaseweb_add() {
|
dns_leaseweb_add() {
|
||||||
|
|||||||
@ -1,94 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
# Created by Laraveluser
|
|
||||||
#
|
|
||||||
# Pass credentials before "acme.sh --issue --dns dns_limacity ..."
|
|
||||||
# --
|
|
||||||
# export LIMACITY_APIKEY="<API-KEY>"
|
|
||||||
# --
|
|
||||||
#
|
|
||||||
# Pleas note: APIKEY must have following roles: dns.admin, domains.reader
|
|
||||||
|
|
||||||
######## Public functions #####################
|
|
||||||
|
|
||||||
LIMACITY_APIKEY="${LIMACITY_APIKEY:-$(_readaccountconf_mutable LIMACITY_APIKEY)}"
|
|
||||||
AUTH=$(printf "%s" "api:$LIMACITY_APIKEY" | _base64 -w 0)
|
|
||||||
export _H1="Authorization: Basic $AUTH"
|
|
||||||
export _H2="Content-Type: application/json"
|
|
||||||
APIBASE=https://www.lima-city.de/usercp
|
|
||||||
|
|
||||||
#Usage: dns_limacity_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
|
||||||
dns_limacity_add() {
|
|
||||||
_debug LIMACITY_APIKEY "$LIMACITY_APIKEY"
|
|
||||||
if [ "$LIMACITY_APIKEY" = "" ]; then
|
|
||||||
_err "No Credentials given"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# save the dns server and key to the account conf file.
|
|
||||||
_saveaccountconf_mutable LIMACITY_APIKEY "${LIMACITY_APIKEY}"
|
|
||||||
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
if ! _lima_get_domain_id "$fulldomain"; then return 1; fi
|
|
||||||
|
|
||||||
msg=$(_post "{\"nameserver_record\":{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"${txtvalue}\",\"ttl\":60}}" "${APIBASE}/domains/${LIMACITY_DOMAINID}/records.json" "" "POST")
|
|
||||||
_debug "$msg"
|
|
||||||
|
|
||||||
if [ "$(echo "$msg" | _egrep_o "\"status\":\"ok\"")" = "" ]; then
|
|
||||||
_err "$msg"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
#Usage: dns_limacity_rm _acme-challenge.www.domain.com
|
|
||||||
dns_limacity_rm() {
|
|
||||||
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
if ! _lima_get_domain_id "$fulldomain"; then return 1; fi
|
|
||||||
|
|
||||||
for recordId in $(_get "${APIBASE}/domains/${LIMACITY_DOMAINID}/records.json" | _egrep_o "{\"id\":[0-9]*[^}]*,\"name\":\"${fulldomain}\"" | _egrep_o "[0-9]*"); do
|
|
||||||
_post "" "${APIBASE}/domains/${LIMACITY_DOMAINID}/records/${recordId}" "" "DELETE"
|
|
||||||
done
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
|
||||||
|
|
||||||
_lima_get_domain_id() {
|
|
||||||
domain="$1"
|
|
||||||
_debug "$domain"
|
|
||||||
i=2
|
|
||||||
p=1
|
|
||||||
|
|
||||||
domains=$(_get "${APIBASE}/domains.json")
|
|
||||||
if [ "$(echo "$domains" | _egrep_o "\{.*""domains""")" ]; then
|
|
||||||
response="$(echo "$domains" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
|
|
||||||
while true; do
|
|
||||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
|
||||||
_debug h "$h"
|
|
||||||
if [ -z "$h" ]; then
|
|
||||||
#not valid
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
hostedzone="$(echo "$response" | _egrep_o "\{.*""unicode_fqdn""[^,]+""$h"".*\}")"
|
|
||||||
if [ "$hostedzone" ]; then
|
|
||||||
LIMACITY_DOMAINID=$(printf "%s\n" "$hostedzone" | _egrep_o "\"id\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
|
|
||||||
if [ "$LIMACITY_DOMAINID" ]; 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
|
|
||||||
fi
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
@ -32,12 +32,8 @@ dns_loopia_add() {
|
|||||||
|
|
||||||
_info "Adding record"
|
_info "Adding record"
|
||||||
|
|
||||||
if ! _loopia_add_sub_domain "$_domain" "$_sub_domain"; then
|
_loopia_add_sub_domain "$_domain" "$_sub_domain"
|
||||||
return 1
|
_loopia_add_record "$_domain" "$_sub_domain" "$txtvalue"
|
||||||
fi
|
|
||||||
if ! _loopia_add_record "$_domain" "$_sub_domain" "$txtvalue"; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,13 +70,12 @@ dns_loopia_rm() {
|
|||||||
<value><string>%s</string></value>
|
<value><string>%s</string></value>
|
||||||
</param>
|
</param>
|
||||||
</params>
|
</params>
|
||||||
</methodCall>' "$LOOPIA_User" "$Encoded_Password" "$_domain" "$_sub_domain")
|
</methodCall>' "$LOOPIA_User" "$LOOPIA_Password" "$_domain" "$_sub_domain")
|
||||||
|
|
||||||
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
|
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
|
||||||
|
|
||||||
if ! _contains "$response" "OK"; then
|
if ! _contains "$response" "OK"; then
|
||||||
err_response=$(echo "$response" | sed 's/.*<string>\(.*\)<\/string>.*/\1/')
|
_err "Error could not get txt records"
|
||||||
_err "Error could not get txt records: $err_response"
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
@ -106,12 +101,6 @@ _loopia_load_config() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if _contains "$LOOPIA_Password" "'" || _contains "$LOOPIA_Password" '"'; then
|
|
||||||
_err "Password contains a quotation mark or double quotation marks and this is not supported by dns_loopia.sh"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
Encoded_Password=$(_xml_encode "$LOOPIA_Password")
|
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,12 +133,11 @@ _loopia_get_records() {
|
|||||||
<value><string>%s</string></value>
|
<value><string>%s</string></value>
|
||||||
</param>
|
</param>
|
||||||
</params>
|
</params>
|
||||||
</methodCall>' "$LOOPIA_User" "$Encoded_Password" "$domain" "$sub_domain")
|
</methodCall>' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain")
|
||||||
|
|
||||||
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
|
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
|
||||||
if ! _contains "$response" "<array>"; then
|
if ! _contains "$response" "<array>"; then
|
||||||
err_response=$(echo "$response" | sed 's/.*<string>\(.*\)<\/string>.*/\1/')
|
_err "Error"
|
||||||
_err "Error: $err_response"
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
@ -174,7 +162,7 @@ _get_root() {
|
|||||||
<value><string>%s</string></value>
|
<value><string>%s</string></value>
|
||||||
</param>
|
</param>
|
||||||
</params>
|
</params>
|
||||||
</methodCall>' "$LOOPIA_User" "$Encoded_Password")
|
</methodCall>' $LOOPIA_User $LOOPIA_Password)
|
||||||
|
|
||||||
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
|
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
|
||||||
while true; do
|
while true; do
|
||||||
@ -218,35 +206,32 @@ _loopia_add_record() {
|
|||||||
<value><string>%s</string></value>
|
<value><string>%s</string></value>
|
||||||
</param>
|
</param>
|
||||||
<param>
|
<param>
|
||||||
<value>
|
<struct>
|
||||||
<struct>
|
<member>
|
||||||
<member>
|
<name>type</name>
|
||||||
<name>type</name>
|
<value><string>TXT</string></value>
|
||||||
<value><string>TXT</string></value>
|
</member>
|
||||||
</member>
|
<member>
|
||||||
<member>
|
<name>priority</name>
|
||||||
<name>priority</name>
|
<value><int>0</int></value>
|
||||||
<value><int>0</int></value>
|
</member>
|
||||||
</member>
|
<member>
|
||||||
<member>
|
<name>ttl</name>
|
||||||
<name>ttl</name>
|
<value><int>300</int></value>
|
||||||
<value><int>300</int></value>
|
</member>
|
||||||
</member>
|
<member>
|
||||||
<member>
|
<name>rdata</name>
|
||||||
<name>rdata</name>
|
<value><string>%s</string></value>
|
||||||
<value><string>%s</string></value>
|
</member>
|
||||||
</member>
|
</struct>
|
||||||
</struct>
|
|
||||||
</value>
|
|
||||||
</param>
|
</param>
|
||||||
</params>
|
</params>
|
||||||
</methodCall>' "$LOOPIA_User" "$Encoded_Password" "$domain" "$sub_domain" "$txtval")
|
</methodCall>' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain" "$txtval")
|
||||||
|
|
||||||
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
|
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
|
||||||
|
|
||||||
if ! _contains "$response" "OK"; then
|
if ! _contains "$response" "OK"; then
|
||||||
err_response=$(echo "$response" | sed 's/.*<string>\(.*\)<\/string>.*/\1/')
|
_err "Error"
|
||||||
_err "Error: $err_response"
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
@ -270,7 +255,7 @@ _sub_domain_exists() {
|
|||||||
<value><string>%s</string></value>
|
<value><string>%s</string></value>
|
||||||
</param>
|
</param>
|
||||||
</params>
|
</params>
|
||||||
</methodCall>' "$LOOPIA_User" "$Encoded_Password" "$domain")
|
</methodCall>' $LOOPIA_User $LOOPIA_Password "$domain")
|
||||||
|
|
||||||
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
|
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
|
||||||
|
|
||||||
@ -305,22 +290,13 @@ _loopia_add_sub_domain() {
|
|||||||
<value><string>%s</string></value>
|
<value><string>%s</string></value>
|
||||||
</param>
|
</param>
|
||||||
</params>
|
</params>
|
||||||
</methodCall>' "$LOOPIA_User" "$Encoded_Password" "$domain" "$sub_domain")
|
</methodCall>' $LOOPIA_User $LOOPIA_Password "$domain" "$sub_domain")
|
||||||
|
|
||||||
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
|
response="$(_post "$xml_content" "$LOOPIA_Api" "" "POST")"
|
||||||
|
|
||||||
if ! _contains "$response" "OK"; then
|
if ! _contains "$response" "OK"; then
|
||||||
err_response=$(echo "$response" | sed 's/.*<string>\(.*\)<\/string>.*/\1/')
|
_err "Error"
|
||||||
_err "Error: $err_response"
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
_xml_encode() {
|
|
||||||
encoded_string=$1
|
|
||||||
encoded_string=$(echo "$encoded_string" | sed 's/&/\&/')
|
|
||||||
encoded_string=$(echo "$encoded_string" | sed 's/</\</')
|
|
||||||
encoded_string=$(echo "$encoded_string" | sed 's/>/\>/')
|
|
||||||
printf "%s" "$encoded_string"
|
|
||||||
}
|
|
||||||
|
|||||||
@ -163,7 +163,6 @@ _retrieve_miab_env() {
|
|||||||
_saveaccountconf_mutable MIAB_Username "$MIAB_Username"
|
_saveaccountconf_mutable MIAB_Username "$MIAB_Username"
|
||||||
_saveaccountconf_mutable MIAB_Password "$MIAB_Password"
|
_saveaccountconf_mutable MIAB_Password "$MIAB_Password"
|
||||||
_saveaccountconf_mutable MIAB_Server "$MIAB_Server"
|
_saveaccountconf_mutable MIAB_Server "$MIAB_Server"
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#Useage: _miab_rest "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" "custom/_acme-challenge.www.domain.com/txt "POST"
|
#Useage: _miab_rest "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs" "custom/_acme-challenge.www.domain.com/txt "POST"
|
||||||
|
|||||||
@ -74,7 +74,7 @@ dns_mydevil_rm() {
|
|||||||
validRecords="^${num}${w}${fulldomain}${w}TXT${w}${any}${txtvalue}$"
|
validRecords="^${num}${w}${fulldomain}${w}TXT${w}${any}${txtvalue}$"
|
||||||
for id in $(devil dns list "$domain" | tail -n+2 | grep "${validRecords}" | cut -w -s -f 1); do
|
for id in $(devil dns list "$domain" | tail -n+2 | grep "${validRecords}" | cut -w -s -f 1); do
|
||||||
_info "Removing record $id from domain $domain"
|
_info "Removing record $id from domain $domain"
|
||||||
echo "y" | devil dns del "$domain" "$id" || _err "Could not remove DNS record."
|
devil dns del "$domain" "$id" || _err "Could not remove DNS record."
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,9 +87,7 @@ mydevil_get_domain() {
|
|||||||
domain=""
|
domain=""
|
||||||
|
|
||||||
for domain in $(devil dns list | cut -w -s -f 1 | tail -n+2); do
|
for domain in $(devil dns list | cut -w -s -f 1 | tail -n+2); do
|
||||||
_debug "Checking domain: $domain"
|
|
||||||
if _endswith "$fulldomain" "$domain"; then
|
if _endswith "$fulldomain" "$domain"; then
|
||||||
_debug "Fulldomain '$fulldomain' matches '$domain'"
|
|
||||||
printf -- "%s" "$domain"
|
printf -- "%s" "$domain"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|||||||
@ -150,7 +150,7 @@ _get_root() {
|
|||||||
_mydnsjp_retrieve_domain() {
|
_mydnsjp_retrieve_domain() {
|
||||||
_debug "Login to MyDNS.JP"
|
_debug "Login to MyDNS.JP"
|
||||||
|
|
||||||
response="$(_post "MENU=100&masterid=$MYDNSJP_MasterID&masterpwd=$MYDNSJP_Password" "$MYDNSJP_API/members/")"
|
response="$(_post "masterid=$MYDNSJP_MasterID&masterpwd=$MYDNSJP_Password" "$MYDNSJP_API/?MENU=100")"
|
||||||
cookie="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2)"
|
cookie="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2)"
|
||||||
|
|
||||||
# If cookies is not empty then logon successful
|
# If cookies is not empty then logon successful
|
||||||
@ -159,8 +159,22 @@ _mydnsjp_retrieve_domain() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
_debug "Retrieve DOMAIN INFO page"
|
||||||
|
|
||||||
|
export _H1="Cookie:${cookie}"
|
||||||
|
|
||||||
|
response="$(_get "$MYDNSJP_API/?MENU=300")"
|
||||||
|
|
||||||
|
if [ "$?" != "0" ]; then
|
||||||
|
_err "Fail to retrieve DOMAIN INFO."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
_root_domain=$(echo "$response" | grep "DNSINFO\[domainname\]" | sed 's/^.*value="\([^"]*\)".*/\1/')
|
_root_domain=$(echo "$response" | grep "DNSINFO\[domainname\]" | sed 's/^.*value="\([^"]*\)".*/\1/')
|
||||||
|
|
||||||
|
# Logout
|
||||||
|
response="$(_get "$MYDNSJP_API/?MENU=090")"
|
||||||
|
|
||||||
_debug _root_domain "$_root_domain"
|
_debug _root_domain "$_root_domain"
|
||||||
|
|
||||||
if [ -z "$_root_domain" ]; then
|
if [ -z "$_root_domain" ]; then
|
||||||
|
|||||||
@ -1,261 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
# Mythic Beasts is a long-standing UK service provider using standards-based OAuth2 authentication
|
|
||||||
# To test: ./acme.sh --dns dns_mythic_beasts --test --debug 1 --output-insecure --issue --domain domain.com
|
|
||||||
# Cannot retest once cert is issued
|
|
||||||
# OAuth2 tokens only valid for 300 seconds so we do not store
|
|
||||||
# NOTE: This will remove all TXT records matching the fulldomain, not just the added ones (_acme-challenge.www.domain.com)
|
|
||||||
|
|
||||||
# Test OAuth2 credentials
|
|
||||||
#MB_AK="aaaaaaaaaaaaaaaa"
|
|
||||||
#MB_AS="bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
|
|
||||||
|
|
||||||
# URLs
|
|
||||||
MB_API='https://api.mythic-beasts.com/dns/v2/zones'
|
|
||||||
MB_AUTH='https://auth.mythic-beasts.com/login'
|
|
||||||
|
|
||||||
######## Public functions #####################
|
|
||||||
|
|
||||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
|
||||||
dns_mythic_beasts_add() {
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
|
|
||||||
_info "MYTHIC BEASTS Adding record $fulldomain = $txtvalue"
|
|
||||||
if ! _initAuth; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! _get_root "$fulldomain"; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# method path body_data
|
|
||||||
if _mb_rest POST "$_domain/records/$_sub_domain/TXT" "$txtvalue"; then
|
|
||||||
|
|
||||||
if _contains "$response" "1 records added"; then
|
|
||||||
_info "Added, verifying..."
|
|
||||||
# Max 120 seconds to publish
|
|
||||||
for i in $(seq 1 6); do
|
|
||||||
# Retry on error
|
|
||||||
if ! _mb_rest GET "$_domain/records/$_sub_domain/TXT?verify"; then
|
|
||||||
_sleep 20
|
|
||||||
else
|
|
||||||
_info "Record published!"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
else
|
|
||||||
_err "\n$response"
|
|
||||||
fi
|
|
||||||
|
|
||||||
fi
|
|
||||||
_err "Add txt record error."
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#Usage: rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
|
||||||
dns_mythic_beasts_rm() {
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
|
|
||||||
_info "MYTHIC BEASTS Removing record $fulldomain = $txtvalue"
|
|
||||||
if ! _initAuth; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if ! _get_root "$fulldomain"; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# method path body_data
|
|
||||||
if _mb_rest DELETE "$_domain/records/$_sub_domain/TXT" "$txtvalue"; then
|
|
||||||
_info "Record removed"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
_err "Remove txt record error."
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#################### Private functions below ##################################
|
|
||||||
|
|
||||||
#Possible formats:
|
|
||||||
# _acme-challenge.www.example.com
|
|
||||||
# _acme-challenge.example.com
|
|
||||||
# _acme-challenge.example.co.uk
|
|
||||||
# _acme-challenge.www.example.co.uk
|
|
||||||
# _acme-challenge.sub1.sub2.www.example.co.uk
|
|
||||||
# sub1.sub2.example.co.uk
|
|
||||||
# example.com
|
|
||||||
# example.co.uk
|
|
||||||
#returns
|
|
||||||
# _sub_domain=_acme-challenge.www
|
|
||||||
# _domain=domain.com
|
|
||||||
_get_root() {
|
|
||||||
domain=$1
|
|
||||||
i=1
|
|
||||||
p=1
|
|
||||||
|
|
||||||
_debug "Detect the root zone"
|
|
||||||
while true; do
|
|
||||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
|
||||||
if [ -z "$h" ]; then
|
|
||||||
_err "Domain exhausted"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Use the status errors to find the domain, continue on 403 Access denied
|
|
||||||
# method path body_data
|
|
||||||
_mb_rest GET "$h/records"
|
|
||||||
ret="$?"
|
|
||||||
if [ "$ret" -eq 0 ]; then
|
|
||||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
|
||||||
_domain="$h"
|
|
||||||
_debug _sub_domain "$_sub_domain"
|
|
||||||
_debug _domain "$_domain"
|
|
||||||
return 0
|
|
||||||
elif [ "$ret" -eq 1 ]; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
p=$i
|
|
||||||
i=$(_math "$i" + 1)
|
|
||||||
|
|
||||||
if [ "$i" -gt 50 ]; then
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
_err "Domain too long"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
_initAuth() {
|
|
||||||
MB_AK="${MB_AK:-$(_readaccountconf_mutable MB_AK)}"
|
|
||||||
MB_AS="${MB_AS:-$(_readaccountconf_mutable MB_AS)}"
|
|
||||||
|
|
||||||
if [ -z "$MB_AK" ] || [ -z "$MB_AS" ]; then
|
|
||||||
MB_AK=""
|
|
||||||
MB_AS=""
|
|
||||||
_err "Please specify an OAuth2 Key & Secret"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
_saveaccountconf_mutable MB_AK "$MB_AK"
|
|
||||||
_saveaccountconf_mutable MB_AS "$MB_AS"
|
|
||||||
|
|
||||||
if ! _oauth2; then
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
_info "Checking authentication"
|
|
||||||
_secure_debug access_token "$MB_TK"
|
|
||||||
_sleep 1
|
|
||||||
|
|
||||||
# GET a list of zones
|
|
||||||
# method path body_data
|
|
||||||
if ! _mb_rest GET ""; then
|
|
||||||
_err "The token is invalid"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_info "Token OK"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# Github appears to use an outbound proxy for requests which means subsequent requests may not have the same
|
|
||||||
# source IP. The standard Mythic Beasts OAuth2 tokens are tied to an IP, meaning github test requests fail
|
|
||||||
# authentication. This is a work around using an undocumented MB API to obtain a token not tied to an
|
|
||||||
# IP just for the github tests.
|
|
||||||
_oauth2() {
|
|
||||||
if [ "$GITHUB_ACTIONS" = "true" ]; then
|
|
||||||
_oauth2_github
|
|
||||||
else
|
|
||||||
_oauth2_std
|
|
||||||
fi
|
|
||||||
return $?
|
|
||||||
}
|
|
||||||
|
|
||||||
_oauth2_std() {
|
|
||||||
# HTTP Basic Authentication
|
|
||||||
_H1="Authorization: Basic $(echo "$MB_AK:$MB_AS" | _base64)"
|
|
||||||
_H2="Accepts: application/json"
|
|
||||||
export _H1 _H2
|
|
||||||
body="grant_type=client_credentials"
|
|
||||||
|
|
||||||
_info "Getting OAuth2 token..."
|
|
||||||
# body url [needbase64] [POST|PUT|DELETE] [ContentType]
|
|
||||||
response="$(_post "$body" "$MB_AUTH" "" "POST" "application/x-www-form-urlencoded")"
|
|
||||||
if _contains "$response" "\"token_type\":\"bearer\""; then
|
|
||||||
MB_TK="$(echo "$response" | _egrep_o "access_token\":\"[^\"]*\"" | cut -d : -f 2 | tr -d '"')"
|
|
||||||
if [ -z "$MB_TK" ]; then
|
|
||||||
_err "Unable to get access_token"
|
|
||||||
_err "\n$response"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
_err "OAuth2 token_type not Bearer"
|
|
||||||
_err "\n$response"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_debug2 response "$response"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
_oauth2_github() {
|
|
||||||
_H1="Accepts: application/json"
|
|
||||||
export _H1
|
|
||||||
body="{\"login\":{\"handle\":\"$MB_AK\",\"pass\":\"$MB_AS\",\"floating\":1}}"
|
|
||||||
|
|
||||||
_info "Getting Floating token..."
|
|
||||||
# body url [needbase64] [POST|PUT|DELETE] [ContentType]
|
|
||||||
response="$(_post "$body" "$MB_AUTH" "" "POST" "application/json")"
|
|
||||||
MB_TK="$(echo "$response" | _egrep_o "\"token\":\"[^\"]*\"" | cut -d : -f 2 | tr -d '"')"
|
|
||||||
if [ -z "$MB_TK" ]; then
|
|
||||||
_err "Unable to get token"
|
|
||||||
_err "\n$response"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_debug2 response "$response"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# method path body_data
|
|
||||||
_mb_rest() {
|
|
||||||
# URL encoded body for single API operations
|
|
||||||
m="$1"
|
|
||||||
ep="$2"
|
|
||||||
data="$3"
|
|
||||||
|
|
||||||
if [ -z "$ep" ]; then
|
|
||||||
_mb_url="$MB_API"
|
|
||||||
else
|
|
||||||
_mb_url="$MB_API/$ep"
|
|
||||||
fi
|
|
||||||
|
|
||||||
_H1="Authorization: Bearer $MB_TK"
|
|
||||||
_H2="Accepts: application/json"
|
|
||||||
export _H1 _H2
|
|
||||||
if [ "$data" ] || [ "$m" = "POST" ] || [ "$m" = "PUT" ] || [ "$m" = "DELETE" ]; then
|
|
||||||
# body url [needbase64] [POST|PUT|DELETE] [ContentType]
|
|
||||||
response="$(_post "data=$data" "$_mb_url" "" "$m" "application/x-www-form-urlencoded")"
|
|
||||||
else
|
|
||||||
response="$(_get "$_mb_url")"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$?" != "0" ]; then
|
|
||||||
_err "Request error"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
header="$(cat "$HTTP_HEADER")"
|
|
||||||
status="$(echo "$header" | _egrep_o "^HTTP[^ ]* .*$" | cut -d " " -f 2-100 | tr -d "\f\n")"
|
|
||||||
code="$(echo "$status" | _egrep_o "^[0-9]*")"
|
|
||||||
if [ "$code" -ge 400 ] || _contains "$response" "\"error\"" || _contains "$response" "invalid_client"; then
|
|
||||||
_err "error $status"
|
|
||||||
_err "\n$response"
|
|
||||||
_debug "\n$header"
|
|
||||||
return 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
_debug2 response "$response"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
@ -82,7 +82,7 @@ _get_root() {
|
|||||||
_debug "Failed domain lookup via domains.getList api call. Trying domain lookup via domains.dns.getHosts api."
|
_debug "Failed domain lookup via domains.getList api call. Trying domain lookup via domains.dns.getHosts api."
|
||||||
# The above "getList" api will only return hosts *owned* by the calling user. However, if the calling
|
# The above "getList" api will only return hosts *owned* by the calling user. However, if the calling
|
||||||
# user is not the owner, but still has administrative rights, we must query the getHosts api directly.
|
# user is not the owner, but still has administrative rights, we must query the getHosts api directly.
|
||||||
# See this comment and the official namecheap response: https://disq.us/p/1q6v9x9
|
# See this comment and the official namecheap response: http://disq.us/p/1q6v9x9
|
||||||
if ! _get_root_by_getHosts "$fulldomain"; then
|
if ! _get_root_by_getHosts "$fulldomain"; then
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
@ -259,7 +259,7 @@ _set_namecheap_TXT() {
|
|||||||
_debug hosts "$hosts"
|
_debug hosts "$hosts"
|
||||||
|
|
||||||
if [ -z "$hosts" ]; then
|
if [ -z "$hosts" ]; then
|
||||||
_err "Hosts not found"
|
_error "Hosts not found"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -313,7 +313,7 @@ _del_namecheap_TXT() {
|
|||||||
_debug hosts "$hosts"
|
_debug hosts "$hosts"
|
||||||
|
|
||||||
if [ -z "$hosts" ]; then
|
if [ -z "$hosts" ]; then
|
||||||
_err "Hosts not found"
|
_error "Hosts not found"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
@ -110,7 +110,7 @@ _get_root() {
|
|||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if _contains "$response" ">$host</domain>"; then
|
if _contains "$response" "<domain>$host"; then
|
||||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||||
_domain="$host"
|
_domain="$host"
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@ -1,59 +0,0 @@
|
|||||||
#!/usr/bin/env sh
|
|
||||||
|
|
||||||
# Official DNS API for Nanelo.com
|
|
||||||
|
|
||||||
# Provide the required API Key like this:
|
|
||||||
# NANELO_TOKEN="FmD408PdqT1E269gUK57"
|
|
||||||
|
|
||||||
NANELO_API="https://api.nanelo.com/v1/"
|
|
||||||
|
|
||||||
######## Public functions #####################
|
|
||||||
|
|
||||||
# Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
|
||||||
dns_nanelo_add() {
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
|
|
||||||
NANELO_TOKEN="${NANELO_TOKEN:-$(_readaccountconf_mutable NANELO_TOKEN)}"
|
|
||||||
if [ -z "$NANELO_TOKEN" ]; then
|
|
||||||
NANELO_TOKEN=""
|
|
||||||
_err "You didn't configure a Nanelo API Key yet."
|
|
||||||
_err "Please set NANELO_TOKEN and try again."
|
|
||||||
_err "Login to Nanelo.com and go to Settings > API Keys to get a Key"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_saveaccountconf_mutable NANELO_TOKEN "$NANELO_TOKEN"
|
|
||||||
|
|
||||||
_info "Adding TXT record to ${fulldomain}"
|
|
||||||
response="$(_get "$NANELO_API$NANELO_TOKEN/dns/addrecord?type=TXT&ttl=60&name=${fulldomain}&value=${txtvalue}")"
|
|
||||||
if _contains "${response}" 'success'; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
_err "Could not create resource record, please check the logs"
|
|
||||||
_err "${response}"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
dns_nanelo_rm() {
|
|
||||||
fulldomain=$1
|
|
||||||
txtvalue=$2
|
|
||||||
|
|
||||||
NANELO_TOKEN="${NANELO_TOKEN:-$(_readaccountconf_mutable NANELO_TOKEN)}"
|
|
||||||
if [ -z "$NANELO_TOKEN" ]; then
|
|
||||||
NANELO_TOKEN=""
|
|
||||||
_err "You didn't configure a Nanelo API Key yet."
|
|
||||||
_err "Please set NANELO_TOKEN and try again."
|
|
||||||
_err "Login to Nanelo.com and go to Settings > API Keys to get a Key"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
_saveaccountconf_mutable NANELO_TOKEN "$NANELO_TOKEN"
|
|
||||||
|
|
||||||
_info "Deleting resource record $fulldomain"
|
|
||||||
response="$(_get "$NANELO_API$NANELO_TOKEN/dns/deleterecord?type=TXT&ttl=60&name=${fulldomain}&value=${txtvalue}")"
|
|
||||||
if _contains "${response}" 'success'; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
_err "Could not delete resource record, please check the logs"
|
|
||||||
_err "${response}"
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
#NederHost_Key="sdfgikogfdfghjklkjhgfcdcfghj"
|
#NederHost_Key="sdfgikogfdfghjklkjhgfcdcfghjk"
|
||||||
|
|
||||||
NederHost_Api="https://api.nederhost.nl/dns/v1"
|
NederHost_Api="https://api.nederhost.nl/dns/v1"
|
||||||
|
|
||||||
@ -112,8 +112,12 @@ _nederhost_rest() {
|
|||||||
export _H1="Authorization: Bearer $NederHost_Key"
|
export _H1="Authorization: Bearer $NederHost_Key"
|
||||||
export _H2="Content-Type: application/json"
|
export _H2="Content-Type: application/json"
|
||||||
|
|
||||||
_debug data "$data"
|
if [ "$m" != "GET" ]; then
|
||||||
response="$(_post "$data" "$NederHost_Api/$ep" "" "$m")"
|
_debug data "$data"
|
||||||
|
response="$(_post "$data" "$NederHost_Api/$ep" "" "$m")"
|
||||||
|
else
|
||||||
|
response="$(_get "$NederHost_Api/$ep")"
|
||||||
|
fi
|
||||||
|
|
||||||
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
|
_code="$(grep "^HTTP" "$HTTP_HEADER" | _tail_n 1 | cut -d " " -f 2 | tr -d "\\r\\n")"
|
||||||
_debug "http response code $_code"
|
_debug "http response code $_code"
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user