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

|
||||

|
||||
@ -47,14 +51,12 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
|
||||
- [ruby-china.org](https://ruby-china.org/topics/31983)
|
||||
- [Proxmox](https://pve.proxmox.com/wiki/Certificate_Management)
|
||||
- [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)
|
||||
- [discourse.org](https://meta.discourse.org/t/setting-up-lets-encrypt/40709)
|
||||
- [Centminmod](https://centminmod.com/letsencrypt-acmetool-https.html)
|
||||
- [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)
|
||||
- [CentOS Web Panel](http://centos-webpanel.com/)
|
||||
- [CentOS Web Panel](https://control-webpanel.com)
|
||||
- [lnmp.org](https://lnmp.org/)
|
||||
- [more...](https://github.com/acmesh-official/acme.sh/wiki/Blogs-and-tutorials)
|
||||
|
||||
@ -68,21 +70,24 @@ Twitter: [@neilpangxa](https://twitter.com/neilpangxa)
|
||||
|4|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Solaris.yml)|Solaris
|
||||
|5|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Ubuntu.yml)| Ubuntu
|
||||
|6|NA|pfsense
|
||||
|7|NA|OpenBSD
|
||||
|8|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)| Debian
|
||||
|9|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|CentOS
|
||||
|10|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|openSUSE
|
||||
|11|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Alpine Linux (with curl)
|
||||
|12|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Archlinux
|
||||
|13|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|fedora
|
||||
|14|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Kali Linux
|
||||
|15|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Oracle Linux
|
||||
|16|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Mageia
|
||||
|17|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Gentoo Linux
|
||||
|18|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|ClearLinux
|
||||
|19|-----| Cloud Linux https://github.com/acmesh-official/acme.sh/issues/111
|
||||
|20|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/acmesh-official/acme.sh/wiki/How-to-run-on-OpenWRT)
|
||||
|21|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)| Proxmox: See Proxmox VE Wiki. Version [4.x, 5.0, 5.1](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x,_5.0_and_5.1)#Let.27s_Encrypt_using_acme.sh), version [5.2 and up](https://pve.proxmox.com/wiki/Certificate_Management)
|
||||
|7|[](https://github.com/acmesh-official/acme.sh/actions/workflows/OpenBSD.yml)|OpenBSD
|
||||
|8|[](https://github.com/acmesh-official/acme.sh/actions/workflows/NetBSD.yml)|NetBSD
|
||||
|9|[](https://github.com/acmesh-official/acme.sh/actions/workflows/DragonFlyBSD.yml)|DragonFlyBSD
|
||||
|10|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Omnios.yml)|Omnios
|
||||
|11|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)| Debian
|
||||
|12|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|CentOS
|
||||
|13|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|openSUSE
|
||||
|14|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Alpine Linux (with curl)
|
||||
|15|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Archlinux
|
||||
|16|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|fedora
|
||||
|17|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Kali Linux
|
||||
|18|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Oracle Linux
|
||||
|19|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Mageia
|
||||
|10|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|Gentoo Linux
|
||||
|11|[](https://github.com/acmesh-official/acme.sh/actions/workflows/Linux.yml)|ClearLinux
|
||||
|22|-----| Cloud Linux https://github.com/acmesh-official/acme.sh/issues/111
|
||||
|23|-----| OpenWRT: Tested and working. See [wiki page](https://github.com/acmesh-official/acme.sh/wiki/How-to-run-on-OpenWRT)
|
||||
|24|[](https://github.com/acmesh-official/letest#here-are-the-latest-status)| Proxmox: See Proxmox VE Wiki. Version [4.x, 5.0, 5.1](https://pve.proxmox.com/wiki/HTTPS_Certificate_Configuration_(Version_4.x,_5.0_and_5.1)#Let.27s_Encrypt_using_acme.sh), version [5.2 and up](https://pve.proxmox.com/wiki/Certificate_Management)
|
||||
|
||||
|
||||
Check our [testing project](https://github.com/acmesh-official/acmetest):
|
||||
@ -95,6 +100,7 @@ https://github.com/acmesh-official/acmetest
|
||||
- Letsencrypt.org 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)
|
||||
- Any other [RFC8555](https://tools.ietf.org/html/rfc8555)-compliant CA
|
||||
|
||||
@ -354,10 +360,6 @@ Ok, it's done.
|
||||
|
||||
# 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-`.
|
||||
|
||||
For example:
|
||||
@ -378,10 +380,12 @@ Please look at the `keylength` parameter above.
|
||||
|
||||
Valid values are:
|
||||
|
||||
1. **ec-256 (prime256v1, "ECDSA P-256")**
|
||||
1. **ec-256 (prime256v1, "ECDSA P-256", which is the default key type)**
|
||||
2. **ec-384 (secp384r1, "ECDSA P-384")**
|
||||
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
|
||||
@ -502,6 +506,8 @@ Support this project with your organization. Your logo will show up here with a
|
||||
<a href="https://opencollective.com/acmesh/organization/8/website"><img src="https://opencollective.com/acmesh/organization/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/acmesh/organization/9/website"><img src="https://opencollective.com/acmesh/organization/9/avatar.svg"></a>
|
||||
|
||||
|
||||
|
||||
# 19. License & Others
|
||||
|
||||
License is GPLv3
|
||||
|
@ -3,18 +3,29 @@
|
||||
# Uses command line uapi. --user option is needed only if run as root.
|
||||
# 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
|
||||
# or contact me, visit https://forum.webseodesigners.com/web-design-seo-and-hosting-f16/
|
||||
#
|
||||
# Written by Santeri Kannisto <santeri.kannisto@webseodesigners.com>
|
||||
# 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 #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
|
||||
cpanel_uapi_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
@ -22,6 +33,9 @@ cpanel_uapi_deploy() {
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
# re-declare vars inherited from acme.sh but not passed to make ShellCheck happy
|
||||
: "${Le_Alt:=""}"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
@ -32,31 +46,166 @@ cpanel_uapi_deploy() {
|
||||
_err "The command uapi is not found."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# declare useful constants
|
||||
uapi_error_response='status: 0'
|
||||
|
||||
# read cert and key files and urlencode both
|
||||
_cert=$(_url_encode <"$_ccert")
|
||||
_key=$(_url_encode <"$_ckey")
|
||||
|
||||
_debug _cert "$_cert"
|
||||
_debug _key "$_key"
|
||||
_debug2 _cert "$_cert"
|
||||
_debug2 _key "$_key"
|
||||
|
||||
if [ "$(id -u)" = 0 ]; then
|
||||
if [ -z "$DEPLOY_CPANEL_USER" ]; then
|
||||
_getdeployconf DEPLOY_CPANEL_USER
|
||||
# fallback to _readdomainconf for old installs
|
||||
if [ -z "${DEPLOY_CPANEL_USER:=$(_readdomainconf DEPLOY_CPANEL_USER)}" ]; then
|
||||
_err "It seems that you are root, please define the target user name: export DEPLOY_CPANEL_USER=username"
|
||||
return 1
|
||||
fi
|
||||
_savedomainconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER"
|
||||
_response=$(uapi --user="$DEPLOY_CPANEL_USER" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
||||
else
|
||||
_response=$(uapi SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
||||
fi
|
||||
error_response="status: 0"
|
||||
if test "${_response#*$error_response}" != "$_response"; then
|
||||
_err "Error in deploying certificate:"
|
||||
_err "$_response"
|
||||
return 1
|
||||
_debug DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER"
|
||||
_savedeployconf DEPLOY_CPANEL_USER "$DEPLOY_CPANEL_USER"
|
||||
|
||||
_uapi_user="$DEPLOY_CPANEL_USER"
|
||||
fi
|
||||
|
||||
_debug response "$_response"
|
||||
_info "Certificate successfully deployed"
|
||||
return 0
|
||||
# Load all AUTO envars and set defaults - see above for usage
|
||||
__cpanel_initautoparam ENABLED 'true'
|
||||
__cpanel_initautoparam NOMATCH 'false'
|
||||
__cpanel_initautoparam INCLUDE '*'
|
||||
__cpanel_initautoparam EXCLUDE ''
|
||||
|
||||
# Auto mode
|
||||
if [ "$DEPLOY_CPANEL_AUTO_ENABLED" = "true" ]; then
|
||||
# call API for site config
|
||||
_response=$(uapi DomainInfo list_domains)
|
||||
# exit if error in response
|
||||
if [ -z "$_response" ] || [ "${_response#*"$uapi_error_response"}" != "$_response" ]; then
|
||||
_err "Error in deploying certificate - cannot retrieve sitelist:"
|
||||
_err "\n$_response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# parse response to create site list
|
||||
sitelist=$(__cpanel_parse_response "$_response")
|
||||
_debug "UAPI sites found: $sitelist"
|
||||
|
||||
# filter sitelist using configured domains
|
||||
# skip if NOMATCH is "true"
|
||||
if [ "$DEPLOY_CPANEL_AUTO_NOMATCH" = "true" ]; then
|
||||
_debug "DEPLOY_CPANEL_AUTO_NOMATCH is true"
|
||||
_info "UAPI nomatch mode is enabled - Will not validate sites are valid for the certificate"
|
||||
else
|
||||
_debug "DEPLOY_CPANEL_AUTO_NOMATCH is false"
|
||||
d="$(echo "${Le_Alt}," | sed -e "s/^$_cdomain,//" -e "s/,$_cdomain,/,/")"
|
||||
d="$(echo "$_cdomain,$d" | tr ',' '\n' | sed -e 's/\./\\./g' -e 's/\*/\[\^\.\]\*/g')"
|
||||
sitelist="$(echo "$sitelist" | grep -ix "$d")"
|
||||
_debug2 "Matched UAPI sites: $sitelist"
|
||||
fi
|
||||
|
||||
# filter sites that do not match $DEPLOY_CPANEL_AUTO_INCLUDE
|
||||
_info "Applying sitelist filter DEPLOY_CPANEL_AUTO_INCLUDE: $DEPLOY_CPANEL_AUTO_INCLUDE"
|
||||
sitelist="$(echo "$sitelist" | grep -ix "$(echo "$DEPLOY_CPANEL_AUTO_INCLUDE" | tr ',' '\n' | sed -e 's/\./\\./g' -e 's/\*/\.\*/g')")"
|
||||
_debug2 "Remaining sites: $sitelist"
|
||||
|
||||
# filter sites that match $DEPLOY_CPANEL_AUTO_EXCLUDE
|
||||
_info "Applying sitelist filter DEPLOY_CPANEL_AUTO_EXCLUDE: $DEPLOY_CPANEL_AUTO_EXCLUDE"
|
||||
sitelist="$(echo "$sitelist" | grep -vix "$(echo "$DEPLOY_CPANEL_AUTO_EXCLUDE" | tr ',' '\n' | sed -e 's/\./\\./g' -e 's/\*/\.\*/g')")"
|
||||
_debug2 "Remaining sites: $sitelist"
|
||||
|
||||
# counter for success / failure check
|
||||
successes=0
|
||||
if [ -n "$sitelist" ]; then
|
||||
sitetotal="$(echo "$sitelist" | wc -l)"
|
||||
_debug "$sitetotal sites to deploy"
|
||||
else
|
||||
sitetotal=0
|
||||
_debug "No sites to deploy"
|
||||
fi
|
||||
|
||||
# for each site: call uapi to publish cert and log result. Only return failure if all fail
|
||||
for site in $sitelist; do
|
||||
# call uapi to publish cert, check response for errors and log them.
|
||||
if [ -n "$_uapi_user" ]; then
|
||||
_response=$(uapi --user="$_uapi_user" SSL install_ssl domain="$site" cert="$_cert" key="$_key")
|
||||
else
|
||||
_response=$(uapi SSL install_ssl domain="$site" cert="$_cert" key="$_key")
|
||||
fi
|
||||
if [ "${_response#*"$uapi_error_response"}" != "$_response" ]; then
|
||||
_err "Error in deploying certificate to $site:"
|
||||
_err "$_response"
|
||||
else
|
||||
successes=$((successes + 1))
|
||||
_debug "$_response"
|
||||
_info "Succcessfully deployed to $site"
|
||||
fi
|
||||
done
|
||||
|
||||
# Raise error if all updates fail
|
||||
if [ "$sitetotal" -gt 0 ] && [ "$successes" -eq 0 ]; then
|
||||
_err "Could not deploy to any of $sitetotal sites via UAPI"
|
||||
_debug "successes: $successes, sitetotal: $sitetotal"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Successfully deployed certificate to $successes of $sitetotal sites via UAPI"
|
||||
return 0
|
||||
else
|
||||
# "classic" mode - will only try to deploy to the primary domain; will not check UAPI first
|
||||
if [ -n "$_uapi_user" ]; then
|
||||
_response=$(uapi --user="$_uapi_user" SSL install_ssl domain="$_cdomain" cert="$_cert" key="$_key")
|
||||
else
|
||||
_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
|
||||
}
|
||||
|
||||
######## Private functions #####################
|
||||
|
||||
# Internal utility to process YML from UAPI - looks at main_domain, sub_domains, addon domains and parked domains
|
||||
#[response]
|
||||
__cpanel_parse_response() {
|
||||
if [ $# -gt 0 ]; then resp="$*"; else resp="$(cat)"; fi
|
||||
|
||||
echo "$resp" |
|
||||
sed -En \
|
||||
-e 's/\r$//' \
|
||||
-e 's/^( *)([_.[:alnum:]]+) *: *(.*)/\1,\2,\3/p' \
|
||||
-e 's/^( *)- (.*)/\1,-,\2/p' |
|
||||
awk -F, '{
|
||||
level = length($1)/2;
|
||||
section[level] = $2;
|
||||
for (i in section) {if (i > level) {delete section[i]}}
|
||||
if (length($3) > 0) {
|
||||
prefix="";
|
||||
for (i=0; i < level; i++)
|
||||
{ prefix = (prefix)(section[i])("/") }
|
||||
printf("%s%s=%s\n", prefix, $2, $3);
|
||||
}
|
||||
}' |
|
||||
sed -En -e 's/^result\/data\/(main_domain|sub_domains\/-|addon_domains\/-|parked_domains\/-)=(.*)$/\2/p'
|
||||
}
|
||||
|
||||
# Load parameter by prefix+name - fallback to default if not set, and save to config
|
||||
#pname pdefault
|
||||
__cpanel_initautoparam() {
|
||||
pname="$1"
|
||||
pdefault="$2"
|
||||
pkey="DEPLOY_CPANEL_AUTO_$pname"
|
||||
|
||||
_getdeployconf "$pkey"
|
||||
[ -n "$(eval echo "\"\$$pkey\"")" ] || eval "$pkey=\"$pdefault\""
|
||||
_debug2 "$pkey" "$(eval echo "\"\$$pkey\"")"
|
||||
_savedeployconf "$pkey" "$(eval echo "\"\$$pkey\"")"
|
||||
}
|
||||
|
@ -273,16 +273,27 @@ _check_curl_version() {
|
||||
_minor="$(_getfield "$_cversion" 2 '.')"
|
||||
_debug2 "_minor" "$_minor"
|
||||
|
||||
if [ "$_major$_minor" -lt "740" ]; then
|
||||
if [ "$_major" -ge "8" ]; then
|
||||
#ok
|
||||
return 0
|
||||
fi
|
||||
if [ "$_major" = "7" ]; then
|
||||
if [ "$_minor" -lt "40" ]; then
|
||||
_err "curl v$_cversion doesn't support unit socket"
|
||||
_err "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 "Please upgrade to curl 7.40 or later."
|
||||
return 1
|
||||
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
|
||||
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Here is the script to deploy the cert to G-Core CDN service (https://gcorelabs.com/ru/) using the G-Core Labs API (https://docs.gcorelabs.com/cdn/).
|
||||
# Here is the script to deploy the cert to G-Core CDN service (https://gcore.com/) using the G-Core Labs API (https://apidocs.gcore.com/cdn).
|
||||
# Returns 0 when success.
|
||||
#
|
||||
# Written by temoffey <temofffey@gmail.com>
|
||||
# Public domain, 2019
|
||||
# Update by DreamOfIce <admin@dreamofice.cn> in 2023
|
||||
|
||||
#export DEPLOY_GCORE_CDN_USERNAME=myusername
|
||||
#export DEPLOY_GCORE_CDN_PASSWORD=mypassword
|
||||
@ -56,7 +57,7 @@ gcore_cdn_deploy() {
|
||||
_request="{\"username\":\"$Le_Deploy_gcore_cdn_username\",\"password\":\"$Le_Deploy_gcore_cdn_password\"}"
|
||||
_debug _request "$_request"
|
||||
export _H1="Content-Type:application/json"
|
||||
_response=$(_post "$_request" "https://api.gcdn.co/auth/jwt/login")
|
||||
_response=$(_post "$_request" "https://api.gcore.com/auth/jwt/login")
|
||||
_debug _response "$_response"
|
||||
_regex=".*\"access\":\"\([-._0-9A-Za-z]*\)\".*$"
|
||||
_debug _regex "$_regex"
|
||||
@ -69,8 +70,8 @@ gcore_cdn_deploy() {
|
||||
fi
|
||||
|
||||
_info "Find CDN resource with cname $_cdomain"
|
||||
export _H2="Authorization:Token $_token"
|
||||
_response=$(_get "https://api.gcdn.co/resources")
|
||||
export _H2="Authorization:Bearer $_token"
|
||||
_response=$(_get "https://api.gcore.com/cdn/resources")
|
||||
_debug _response "$_response"
|
||||
_regex="\"primary_resource\":null},"
|
||||
_debug _regex "$_regex"
|
||||
@ -102,7 +103,7 @@ gcore_cdn_deploy() {
|
||||
_date=$(date "+%d.%m.%Y %H:%M:%S")
|
||||
_request="{\"name\":\"$_cdomain ($_date)\",\"sslCertificate\":\"$_fullchain\",\"sslPrivateKey\":\"$_key\"}"
|
||||
_debug _request "$_request"
|
||||
_response=$(_post "$_request" "https://api.gcdn.co/sslData")
|
||||
_response=$(_post "$_request" "https://api.gcore.com/cdn/sslData")
|
||||
_debug _response "$_response"
|
||||
_regex=".*\"id\":\([0-9]*\).*$"
|
||||
_debug _regex "$_regex"
|
||||
@ -117,7 +118,7 @@ gcore_cdn_deploy() {
|
||||
_info "Update CDN resource"
|
||||
_request="{\"originGroup\":$_originGroup,\"sslData\":$_sslDataAdd}"
|
||||
_debug _request "$_request"
|
||||
_response=$(_post "$_request" "https://api.gcdn.co/resources/$_resourceId" '' "PUT")
|
||||
_response=$(_post "$_request" "https://api.gcore.com/cdn/resources/$_resourceId" '' "PUT")
|
||||
_debug _response "$_response"
|
||||
_regex=".*\"sslData\":\([0-9]*\).*$"
|
||||
_debug _regex "$_regex"
|
||||
@ -133,7 +134,7 @@ gcore_cdn_deploy() {
|
||||
_info "Not found old SSL certificate"
|
||||
else
|
||||
_info "Delete old SSL certificate"
|
||||
_response=$(_post '' "https://api.gcdn.co/sslData/$_sslDataOld" '' "DELETE")
|
||||
_response=$(_post '' "https://api.gcore.com/cdn/sslData/$_sslDataOld" '' "DELETE")
|
||||
_debug _response "$_response"
|
||||
fi
|
||||
|
||||
|
@ -67,7 +67,7 @@ gitlab_deploy() {
|
||||
|
||||
error_response="error"
|
||||
|
||||
if test "${_response#*$error_response}" != "$_response"; then
|
||||
if test "${_response#*"$error_response"}" != "$_response"; then
|
||||
_err "Error in deploying certificate:"
|
||||
_err "$_response"
|
||||
return 1
|
||||
|
@ -36,6 +36,19 @@
|
||||
# Note: This functionality requires HAProxy was compiled against
|
||||
# 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 #####################
|
||||
|
||||
@ -46,6 +59,7 @@ haproxy_deploy() {
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
_cmdpfx=""
|
||||
|
||||
# Some defaults
|
||||
DEPLOY_HAPROXY_PEM_PATH_DEFAULT="/etc/haproxy"
|
||||
@ -53,6 +67,8 @@ haproxy_deploy() {
|
||||
DEPLOY_HAPROXY_BUNDLE_DEFAULT="no"
|
||||
DEPLOY_HAPROXY_ISSUER_DEFAULT="no"
|
||||
DEPLOY_HAPROXY_RELOAD_DEFAULT="true"
|
||||
DEPLOY_HAPROXY_HOT_UPDATE_DEFAULT="no"
|
||||
DEPLOY_HAPROXY_STATS_SOCKET_DEFAULT="UNIX:/run/haproxy/admin.sock"
|
||||
|
||||
_debug _cdomain "${_cdomain}"
|
||||
_debug _ckey "${_ckey}"
|
||||
@ -86,6 +102,11 @@ haproxy_deploy() {
|
||||
_savedomainconf Le_Deploy_haproxy_pem_name "${Le_Deploy_haproxy_pem_name}"
|
||||
elif [ -z "${Le_Deploy_haproxy_pem_name}" ]; then
|
||||
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
|
||||
|
||||
# BUNDLE is optional. If not provided then assume "${DEPLOY_HAPROXY_BUNDLE_DEFAULT}"
|
||||
@ -118,6 +139,36 @@ haproxy_deploy() {
|
||||
Le_Deploy_haproxy_reload="${DEPLOY_HAPROXY_RELOAD_DEFAULT}"
|
||||
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
|
||||
if [ "${Le_Deploy_haproxy_bundle}" = "yes" ]; then
|
||||
_info "Bundle creation requested"
|
||||
@ -142,12 +193,13 @@ haproxy_deploy() {
|
||||
_issuer="${_pem}.issuer"
|
||||
_ocsp="${_pem}.ocsp"
|
||||
_reload="${Le_Deploy_haproxy_reload}"
|
||||
_statssock="${Le_Deploy_haproxy_stats_socket}"
|
||||
|
||||
_info "Deploying PEM file"
|
||||
# Create a temporary PEM file
|
||||
_temppem="$(_mktemp)"
|
||||
_debug _temppem "${_temppem}"
|
||||
cat "${_ckey}" "${_ccert}" "${_cca}" >"${_temppem}"
|
||||
cat "${_ccert}" "${_cca}" "${_ckey}" | grep . >"${_temppem}"
|
||||
_ret="$?"
|
||||
|
||||
# Check that we could create the temporary file
|
||||
@ -265,15 +317,86 @@ haproxy_deploy() {
|
||||
fi
|
||||
fi
|
||||
|
||||
# Reload HAProxy
|
||||
_debug _reload "${_reload}"
|
||||
eval "${_reload}"
|
||||
_ret=$?
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Error code ${_ret} during reload"
|
||||
return ${_ret}
|
||||
if [ "${Le_Deploy_haproxy_hot_update}" = "yes" ]; then
|
||||
# set the socket name for messages
|
||||
if [ -n "${_cmdpfx}" ]; then
|
||||
_socketname="master CLI"
|
||||
else
|
||||
_socketname="stats socket"
|
||||
fi
|
||||
|
||||
# Update certificate over HAProxy stats socket or master CLI.
|
||||
if _exists socat; then
|
||||
# look for the certificate on the stats socket, to chose between updating or creating one
|
||||
_socat_cert_cmd="echo '${_cmdpfx}show ssl cert' | socat '${_statssock}' - | grep -q '^${_pem}$'"
|
||||
_debug _socat_cert_cmd "${_socat_cert_cmd}"
|
||||
eval "${_socat_cert_cmd}"
|
||||
_ret=$?
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_newcert="1"
|
||||
_info "Creating new certificate '${_pem}' over HAProxy ${_socketname}."
|
||||
# certificate wasn't found, it's a new one. We should check if the crt-list exists and creates/inserts the certificate.
|
||||
_socat_crtlist_show_cmd="echo '${_cmdpfx}show ssl crt-list' | socat '${_statssock}' - | grep -q '^${Le_Deploy_haproxy_pem_path}$'"
|
||||
_debug _socat_crtlist_show_cmd "${_socat_crtlist_show_cmd}"
|
||||
eval "${_socat_crtlist_show_cmd}"
|
||||
_ret=$?
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Couldn't find '${Le_Deploy_haproxy_pem_path}' in haproxy 'show ssl crt-list'"
|
||||
return "${_ret}"
|
||||
fi
|
||||
# create a new certificate
|
||||
_socat_new_cmd="echo '${_cmdpfx}new ssl cert ${_pem}' | socat '${_statssock}' - | grep -q 'New empty'"
|
||||
_debug _socat_new_cmd "${_socat_new_cmd}"
|
||||
eval "${_socat_new_cmd}"
|
||||
_ret=$?
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Couldn't create '${_pem}' in haproxy"
|
||||
return "${_ret}"
|
||||
fi
|
||||
else
|
||||
_info "Update existing certificate '${_pem}' over HAProxy ${_socketname}."
|
||||
fi
|
||||
_socat_cert_set_cmd="echo -e '${_cmdpfx}set ssl cert ${_pem} <<\n$(cat "${_pem}")\n' | socat '${_statssock}' - | grep -q 'Transaction created'"
|
||||
_debug _socat_cert_set_cmd "${_socat_cert_set_cmd}"
|
||||
eval "${_socat_cert_set_cmd}"
|
||||
_ret=$?
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Can't update '${_pem}' in haproxy"
|
||||
return "${_ret}"
|
||||
fi
|
||||
_socat_cert_commit_cmd="echo '${_cmdpfx}commit ssl cert ${_pem}' | socat '${_statssock}' - | grep -q '^Success!$'"
|
||||
_debug _socat_cert_commit_cmd "${_socat_cert_commit_cmd}"
|
||||
eval "${_socat_cert_commit_cmd}"
|
||||
_ret=$?
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Can't commit '${_pem}' in haproxy"
|
||||
return ${_ret}
|
||||
fi
|
||||
if [ "${_newcert}" = "1" ]; then
|
||||
# if this is a new certificate, it needs to be inserted into the crt-list`
|
||||
_socat_cert_add_cmd="echo '${_cmdpfx}add ssl crt-list ${Le_Deploy_haproxy_pem_path} ${_pem}' | socat '${_statssock}' - | grep -q 'Success!'"
|
||||
_debug _socat_cert_add_cmd "${_socat_cert_add_cmd}"
|
||||
eval "${_socat_cert_add_cmd}"
|
||||
_ret=$?
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Can't update '${_pem}' in haproxy"
|
||||
return "${_ret}"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
_err "'socat' is not available, couldn't update over ${_socketname}"
|
||||
fi
|
||||
else
|
||||
_info "Reload successful"
|
||||
# Reload HAProxy
|
||||
_debug _reload "${_reload}"
|
||||
eval "${_reload}"
|
||||
_ret=$?
|
||||
if [ "${_ret}" != "0" ]; then
|
||||
_err "Error code ${_ret} during reload"
|
||||
return ${_ret}
|
||||
else
|
||||
_info "Reload successful"
|
||||
fi
|
||||
fi
|
||||
|
||||
return 0
|
||||
|
@ -20,18 +20,23 @@ mailcow_deploy() {
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
_mailcow_path="${DEPLOY_MAILCOW_PATH}"
|
||||
_getdeployconf DEPLOY_MAILCOW_PATH
|
||||
_getdeployconf DEPLOY_MAILCOW_RELOAD
|
||||
|
||||
if [ -z "$_mailcow_path" ]; then
|
||||
_debug DEPLOY_MAILCOW_PATH "$DEPLOY_MAILCOW_PATH"
|
||||
_debug DEPLOY_MAILCOW_RELOAD "$DEPLOY_MAILCOW_RELOAD"
|
||||
|
||||
if [ -z "$DEPLOY_MAILCOW_PATH" ]; then
|
||||
_err "Mailcow path is not found, please define DEPLOY_MAILCOW_PATH."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#Tests if _ssl_path is the mailcow root directory.
|
||||
if [ -f "${_mailcow_path}/generate_config.sh" ]; then
|
||||
_ssl_path="${_mailcow_path}/data/assets/ssl/"
|
||||
else
|
||||
_ssl_path="${_mailcow_path}"
|
||||
_savedeployconf DEPLOY_MAILCOW_PATH "$DEPLOY_MAILCOW_PATH"
|
||||
[ -n "$DEPLOY_MAILCOW_RELOAD" ] && _savedeployconf DEPLOY_MAILCOW_RELOAD "$DEPLOY_MAILCOW_RELOAD"
|
||||
|
||||
_ssl_path="$DEPLOY_MAILCOW_PATH"
|
||||
if [ -f "$DEPLOY_MAILCOW_PATH/generate_config.sh" ]; then
|
||||
_ssl_path="$DEPLOY_MAILCOW_PATH/data/assets/ssl/"
|
||||
fi
|
||||
|
||||
if [ ! -d "$_ssl_path" ]; then
|
||||
@ -39,31 +44,20 @@ mailcow_deploy() {
|
||||
return 1
|
||||
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"
|
||||
_real_key="$_ssl_path/${_cert_name_prefix}key.pem"
|
||||
_real_key="$_ssl_path/key.pem"
|
||||
if ! cat "$_ckey" >"$_real_key"; then
|
||||
_err "Error: write key file to: $_real_key"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_real_fullchain="$_ssl_path/${_cert_name_prefix}cert.pem"
|
||||
_real_fullchain="$_ssl_path/cert.pem"
|
||||
if ! cat "$_cfullchain" >"$_real_fullchain"; then
|
||||
_err "Error: write cert file to: $_real_fullchain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
DEFAULT_MAILCOW_RELOAD="docker restart $(docker ps -qaf name=postfix-mailcow); docker restart $(docker ps -qaf name=nginx-mailcow); docker restart $(docker ps -qaf name=dovecot-mailcow)"
|
||||
DEFAULT_MAILCOW_RELOAD="docker restart \$(docker ps --quiet --filter name=nginx-mailcow --filter name=dovecot-mailcow --filter name=postfix-mailcow)"
|
||||
_reload="${DEPLOY_MAILCOW_RELOAD:-$DEFAULT_MAILCOW_RELOAD}"
|
||||
|
||||
_info "Run reload: $_reload"
|
||||
|
156
deploy/openmediavault.sh
Normal file
156
deploy/openmediavault.sh
Normal file
@ -0,0 +1,156 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# This deploy hook is tested on OpenMediaVault 5.x. It supports both local and remote deployment.
|
||||
# The way it works is that if a cert with the matching domain name is not found, it will firstly create a dummy cert to get its uuid, and then replace it with your cert.
|
||||
#
|
||||
# DEPLOY_OMV_WEBUI_ADMIN - This is OMV web gui admin account. Default value is admin. It's required as the user parameter (-u) for the omv-rpc command.
|
||||
# DEPLOY_OMV_HOST and DEPLOY_OMV_SSH_USER are optional. They are used for remote deployment through ssh (support public key authentication only). Per design, OMV web gui admin doesn't have ssh permission, so another account is needed for ssh.
|
||||
#
|
||||
# returns 0 means success, otherwise error.
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
openmediavault_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
_getdeployconf DEPLOY_OMV_WEBUI_ADMIN
|
||||
|
||||
if [ -z "$DEPLOY_OMV_WEBUI_ADMIN" ]; then
|
||||
DEPLOY_OMV_WEBUI_ADMIN="admin"
|
||||
fi
|
||||
|
||||
_savedeployconf DEPLOY_OMV_WEBUI_ADMIN "$DEPLOY_OMV_WEBUI_ADMIN"
|
||||
|
||||
_getdeployconf DEPLOY_OMV_HOST
|
||||
_getdeployconf DEPLOY_OMV_SSH_USER
|
||||
|
||||
if [ -n "$DEPLOY_OMV_HOST" ] && [ -n "$DEPLOY_OMV_SSH_USER" ]; then
|
||||
_info "[OMV deploy-hook] Deploy certificate remotely through ssh."
|
||||
_savedeployconf DEPLOY_OMV_HOST "$DEPLOY_OMV_HOST"
|
||||
_savedeployconf DEPLOY_OMV_SSH_USER "$DEPLOY_OMV_SSH_USER"
|
||||
else
|
||||
_info "[OMV deploy-hook] Deploy certificate locally."
|
||||
fi
|
||||
|
||||
if [ -n "$DEPLOY_OMV_HOST" ] && [ -n "$DEPLOY_OMV_SSH_USER" ]; then
|
||||
|
||||
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'getList' '{\"start\": 0, \"limit\": -1}' | jq -r '.data[] | select(.name==\"/CN='$_cdomain'\") | .uuid'"
|
||||
# shellcheck disable=SC2029
|
||||
_uuid=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
|
||||
_debug _command "$_command"
|
||||
|
||||
if [ -z "$_uuid" ]; then
|
||||
_info "[OMV deploy-hook] Domain $_cdomain has no certificate in openmediavault, creating it!"
|
||||
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'create' '{\"cn\": \"test.example.com\", \"size\": 4096, \"days\": 3650, \"c\": \"\", \"st\": \"\", \"l\": \"\", \"o\": \"\", \"ou\": \"\", \"email\": \"\"}' | jq -r '.uuid'"
|
||||
# shellcheck disable=SC2029
|
||||
_uuid=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
|
||||
_debug _command "$_command"
|
||||
|
||||
if [ -z "$_uuid" ]; then
|
||||
_err "[OMV deploy-hook] An error occured while creating the certificate"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
_info "[OMV deploy-hook] Domain $_cdomain has uuid: $_uuid"
|
||||
_fullchain=$(jq <"$_cfullchain" -aRs .)
|
||||
_key=$(jq <"$_ckey" -aRs .)
|
||||
|
||||
_debug _fullchain "$_fullchain"
|
||||
_debug _key "$_key"
|
||||
|
||||
_info "[OMV deploy-hook] Updating key and certificate in openmediavault"
|
||||
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'set' '{\"uuid\":\"$_uuid\", \"certificate\":$_fullchain, \"privatekey\":$_key, \"comment\":\"acme.sh deployed $(date)\"}'"
|
||||
# shellcheck disable=SC2029
|
||||
_result=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
|
||||
|
||||
_debug _command "$_command"
|
||||
_debug _result "$_result"
|
||||
|
||||
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'WebGui' 'setSettings' \$(omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'WebGui' 'getSettings' | jq -c '.sslcertificateref=\"$_uuid\"')"
|
||||
# shellcheck disable=SC2029
|
||||
_result=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
|
||||
|
||||
_debug _command "$_command"
|
||||
_debug _result "$_result"
|
||||
|
||||
_info "[OMV deploy-hook] Asking openmediavault to apply changes... (this could take some time, hang in there)"
|
||||
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'Config' 'applyChanges' '{\"modules\":[], \"force\": false}'"
|
||||
# shellcheck disable=SC2029
|
||||
_result=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
|
||||
|
||||
_debug _command "$_command"
|
||||
_debug _result "$_result"
|
||||
|
||||
_info "[OMV deploy-hook] Asking nginx to reload"
|
||||
_command="nginx -s reload"
|
||||
# shellcheck disable=SC2029
|
||||
_result=$(ssh "$DEPLOY_OMV_SSH_USER@$DEPLOY_OMV_HOST" "$_command")
|
||||
|
||||
_debug _command "$_command"
|
||||
_debug _result "$_result"
|
||||
|
||||
else
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
_uuid=$(omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'getList' '{"start": 0, "limit": -1}' | jq -r '.data[] | select(.name=="/CN='$_cdomain'") | .uuid')
|
||||
if [ -z "$_uuid" ]; then
|
||||
_info "[OMV deploy-hook] Domain $_cdomain has no certificate in openmediavault, creating it!"
|
||||
# shellcheck disable=SC2086
|
||||
_uuid=$(omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'create' '{"cn": "test.example.com", "size": 4096, "days": 3650, "c": "", "st": "", "l": "", "o": "", "ou": "", "email": ""}' | jq -r '.uuid')
|
||||
|
||||
if [ -z "$_uuid" ]; then
|
||||
_err "[OMB deploy-hook] An error occured while creating the certificate"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
_info "[OMV deploy-hook] Domain $_cdomain has uuid: $_uuid"
|
||||
_fullchain=$(jq <"$_cfullchain" -aRs .)
|
||||
_key=$(jq <"$_ckey" -aRs .)
|
||||
|
||||
_debug _fullchain "$_fullchain"
|
||||
_debug _key "$_key"
|
||||
|
||||
_info "[OMV deploy-hook] Updating key and certificate in openmediavault"
|
||||
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'CertificateMgmt' 'set' '{\"uuid\":\"$_uuid\", \"certificate\":$_fullchain, \"privatekey\":$_key, \"comment\":\"acme.sh deployed $(date)\"}'"
|
||||
_result=$(eval "$_command")
|
||||
|
||||
_debug _command "$_command"
|
||||
_debug _result "$_result"
|
||||
|
||||
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'WebGui' 'setSettings' \$(omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'WebGui' 'getSettings' | jq -c '.sslcertificateref=\"$_uuid\"')"
|
||||
_result=$(eval "$_command")
|
||||
|
||||
_debug _command "$_command"
|
||||
_debug _result "$_result"
|
||||
|
||||
_info "[OMV deploy-hook] Asking openmediavault to apply changes... (this could take some time, hang in there)"
|
||||
_command="omv-rpc -u $DEPLOY_OMV_WEBUI_ADMIN 'Config' 'applyChanges' '{\"modules\":[], \"force\": false}'"
|
||||
_result=$(eval "$_command")
|
||||
|
||||
_debug _command "$_command"
|
||||
_debug _result "$_result"
|
||||
|
||||
_info "[OMV deploy-hook] Asking nginx to reload"
|
||||
_command="nginx -s reload"
|
||||
_result=$(eval "$_command")
|
||||
|
||||
_debug _command "$_command"
|
||||
_debug _result "$_result"
|
||||
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
183
deploy/panos.sh
183
deploy/panos.sh
@ -7,11 +7,18 @@
|
||||
#
|
||||
# Firewall admin with superuser and IP address is required.
|
||||
#
|
||||
# export PANOS_USER="" # required
|
||||
# export PANOS_PASS="" # required
|
||||
# export PANOS_HOST="" # required
|
||||
# REQURED:
|
||||
# export PANOS_HOST=""
|
||||
# export PANOS_USER="" #User *MUST* have Commit and Import Permissions in XML API for Admin Role
|
||||
# export PANOS_PASS=""
|
||||
#
|
||||
# OPTIONAL
|
||||
# export PANOS_TEMPLATE="" #Template Name of panorama managed devices
|
||||
#
|
||||
# The script will automatically generate a new API key if
|
||||
# no key is found, or if a saved key has expired or is invalid.
|
||||
|
||||
# This function is to parse the XML
|
||||
# This function is to parse the XML response from the firewall
|
||||
parse_response() {
|
||||
type=$2
|
||||
if [ "$type" = 'keygen' ]; then
|
||||
@ -23,25 +30,46 @@ parse_response() {
|
||||
message="PAN-OS Key could not be set."
|
||||
fi
|
||||
else
|
||||
status=$(echo "$1" | sed 's/^.*"\([a-z]*\)".*/\1/g')
|
||||
message=$(echo "$1" | sed 's/^.*<result>\(.*\)<\/result.*/\1/g')
|
||||
status=$(echo "$1" | tr -d '\n' | sed 's/^.*"\([a-z]*\)".*/\1/g')
|
||||
message=$(echo "$1" | tr -d '\n' | sed 's/.*\(<result>\|<msg>\|<line>\)\([^<]*\).*/\2/g')
|
||||
_debug "Firewall message: $message"
|
||||
if [ "$type" = 'keytest' ] && [ "$status" != "success" ]; then
|
||||
_debug "**** API Key has EXPIRED or is INVALID ****"
|
||||
unset _panos_key
|
||||
fi
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
#This function is used to deploy to the firewall
|
||||
deployer() {
|
||||
content=""
|
||||
type=$1 # Types are keygen, cert, key, commit
|
||||
_debug "**** Deploying $type *****"
|
||||
type=$1 # Types are keytest, keygen, cert, key, commit
|
||||
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
|
||||
_debug "**** Generating new API Key ****"
|
||||
_H1="Content-Type: application/x-www-form-urlencoded"
|
||||
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}"
|
||||
fi
|
||||
|
||||
# Deploy Cert or Key
|
||||
if [ "$type" = 'cert' ] || [ "$type" = 'key' ]; then
|
||||
#Generate DEIM
|
||||
_debug "**** Deploying $type ****"
|
||||
#Generate DELIM
|
||||
delim="-----MultipartDelimiter$(date "+%s%N")"
|
||||
nl="\015\012"
|
||||
#Set Header
|
||||
@ -53,6 +81,9 @@ deployer() {
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"\r\n\r\n$_panos_key"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"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")"
|
||||
if [ "$_panos_template" ]; then
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"target-tpl\"\r\n\r\n$_panos_template"
|
||||
fi
|
||||
fi
|
||||
if [ "$type" = 'key' ]; then
|
||||
panos_url="${panos_url}?type=import"
|
||||
@ -61,7 +92,10 @@ deployer() {
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"key\"\r\n\r\n$_panos_key"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"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=\"file\"; filename=\"$(basename "$_ckey")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"file\"; filename=\"$(basename "$_cdomain.key")\"${nl}Content-Type: application/octet-stream${nl}${nl}$(cat "$_ckey")"
|
||||
if [ "$_panos_template" ]; then
|
||||
content="$content${nl}--$delim${nl}Content-Disposition: form-data; name=\"target-tpl\"\r\n\r\n$_panos_template"
|
||||
fi
|
||||
fi
|
||||
#Close multipart
|
||||
content="$content${nl}--$delim--${nl}${nl}"
|
||||
@ -69,16 +103,25 @@ deployer() {
|
||||
content=$(printf %b "$content")
|
||||
fi
|
||||
|
||||
# Commit changes
|
||||
if [ "$type" = 'commit' ]; then
|
||||
_debug "**** Committing changes ****"
|
||||
export _H1="Content-Type: application/x-www-form-urlencoded"
|
||||
cmd=$(printf "%s" "<commit><partial><$_panos_user></$_panos_user></partial></commit>" | _url_encode)
|
||||
content="type=commit&key=$_panos_key&cmd=$cmd"
|
||||
#Check for force commit - will commit ALL uncommited changes to the firewall. Use with caution!
|
||||
if [ "$FORCE" ]; then
|
||||
_debug "Force switch detected. Committing ALL changes to the firewall."
|
||||
cmd=$(printf "%s" "<commit><partial><force><admin><member>$_panos_user</member></admin></force></partial></commit>" | _url_encode)
|
||||
else
|
||||
_exclude_scope="<policy-and-objects>exclude</policy-and-objects><device-and-network>exclude</device-and-network>"
|
||||
cmd=$(printf "%s" "<commit><partial>$_exclude_scope<admin><member>$_panos_user</member></admin></partial></commit>" | _url_encode)
|
||||
fi
|
||||
content="type=commit&action=partial&key=$_panos_key&cmd=$cmd"
|
||||
fi
|
||||
|
||||
response=$(_post "$content" "$panos_url" "" "POST")
|
||||
parse_response "$response" "$type"
|
||||
# Saving response to variables
|
||||
response_status=$status
|
||||
#DEBUG
|
||||
_debug response_status "$response_status"
|
||||
if [ "$response_status" = "success" ]; then
|
||||
_debug "Successfully deployed $type"
|
||||
@ -92,43 +135,95 @@ deployer() {
|
||||
|
||||
# This is the main function that will call the other functions to deploy everything.
|
||||
panos_deploy() {
|
||||
_cdomain="$1"
|
||||
_cdomain=$(echo "$1" | sed 's/*/WILDCARD_/g') #Wildcard Safe Filename
|
||||
_ckey="$2"
|
||||
_cfullchain="$5"
|
||||
# PANOS ENV VAR check
|
||||
if [ -z "$PANOS_USER" ] || [ -z "$PANOS_PASS" ] || [ -z "$PANOS_HOST" ]; then
|
||||
_debug "No ENV variables found lets check for saved variables"
|
||||
_getdeployconf PANOS_USER
|
||||
_getdeployconf PANOS_PASS
|
||||
_getdeployconf PANOS_HOST
|
||||
_panos_user=$PANOS_USER
|
||||
_panos_pass=$PANOS_PASS
|
||||
_panos_host=$PANOS_HOST
|
||||
if [ -z "$_panos_user" ] && [ -z "$_panos_pass" ] && [ -z "$_panos_host" ]; then
|
||||
_err "No host, user and pass found.. If this is the first time deploying please set PANOS_HOST, PANOS_USER and PANOS_PASS in environment variables. Delete them after you have succesfully deployed certs."
|
||||
return 1
|
||||
else
|
||||
_debug "Using saved env variables."
|
||||
fi
|
||||
else
|
||||
_debug "Detected ENV variables to be saved to the deploy conf."
|
||||
# Encrypt and save user
|
||||
_savedeployconf PANOS_USER "$PANOS_USER" 1
|
||||
_savedeployconf PANOS_PASS "$PANOS_PASS" 1
|
||||
_savedeployconf PANOS_HOST "$PANOS_HOST" 1
|
||||
_panos_user="$PANOS_USER"
|
||||
_panos_pass="$PANOS_PASS"
|
||||
_panos_host="$PANOS_HOST"
|
||||
|
||||
# VALID FILE CHECK
|
||||
if [ ! -f "$_ckey" ] || [ ! -f "$_cfullchain" ]; then
|
||||
_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
|
||||
_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"
|
||||
|
||||
# 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
|
||||
fi
|
||||
|
||||
# PANOS_PASS
|
||||
if [ "$PANOS_PASS" ]; then
|
||||
_debug "Detected ENV variable PANOS_PASS. Saving to file."
|
||||
_savedeployconf PANOS_PASS "$PANOS_PASS" 1
|
||||
else
|
||||
_debug "Attempting to load variable PANOS_PASS from file."
|
||||
_getdeployconf PANOS_PASS
|
||||
fi
|
||||
|
||||
# PANOS_KEY
|
||||
_getdeployconf PANOS_KEY
|
||||
if [ "$PANOS_KEY" ]; then
|
||||
_debug "Detected saved key."
|
||||
_panos_key=$PANOS_KEY
|
||||
else
|
||||
_debug "No key detected"
|
||||
unset _panos_key
|
||||
fi
|
||||
|
||||
# PANOS_TEMPLATE
|
||||
if [ "$PANOS_TEMPLATE" ]; then
|
||||
_debug "Detected ENV variable PANOS_TEMPLATE. Saving to file."
|
||||
_savedeployconf PANOS_TEMPLATE "$PANOS_TEMPLATE" 1
|
||||
else
|
||||
_debug "Attempting to load variable PANOS_TEMPLATE from file."
|
||||
_getdeployconf PANOS_TEMPLATE
|
||||
fi
|
||||
|
||||
#Store variables
|
||||
_panos_host=$PANOS_HOST
|
||||
_panos_user=$PANOS_USER
|
||||
_panos_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
|
||||
_debug "Getting PANOS KEY"
|
||||
deployer keygen
|
||||
# Generate a new API key if no valid API key is found
|
||||
if [ -z "$_panos_key" ]; then
|
||||
_err "Missing apikey."
|
||||
_debug "**** Generating new PANOS API KEY ****"
|
||||
deployer keygen
|
||||
_savedeployconf PANOS_KEY "$_panos_key" 1
|
||||
fi
|
||||
|
||||
# Confirm that a valid key was generated
|
||||
if [ -z "$_panos_key" ]; then
|
||||
_err "Unable to generate an API key. The user and pass may be invalid or not authorized to generate a new key. Please check the PANOS_USER and PANOS_PASS credentials and try again"
|
||||
return 1
|
||||
else
|
||||
deployer cert
|
||||
|
132
deploy/proxmoxve.sh
Normal file
132
deploy/proxmoxve.sh
Normal file
@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Deploy certificates to a proxmox virtual environment node using the API.
|
||||
#
|
||||
# Environment variables that can be set are:
|
||||
# `DEPLOY_PROXMOXVE_SERVER`: The hostname of the proxmox ve node. Defaults to
|
||||
# _cdomain.
|
||||
# `DEPLOY_PROXMOXVE_SERVER_PORT`: The port number the management interface is on.
|
||||
# Defaults to 8006.
|
||||
# `DEPLOY_PROXMOXVE_NODE_NAME`: The name of the node we'll be connecting to.
|
||||
# Defaults to the host portion of the server
|
||||
# domain name.
|
||||
# `DEPLOY_PROXMOXVE_USER`: The user we'll connect as. Defaults to root.
|
||||
# `DEPLOY_PROXMOXVE_USER_REALM`: The authentication realm the user authenticates
|
||||
# with. Defaults to pam.
|
||||
# `DEPLOY_PROXMOXVE_API_TOKEN_NAME`: The name of the API token created for the
|
||||
# user account. Defaults to acme.
|
||||
# `DEPLOY_PROXMOXVE_API_TOKEN_KEY`: The API token. Required.
|
||||
|
||||
proxmoxve_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug2 _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
# "Sane" defaults.
|
||||
_getdeployconf DEPLOY_PROXMOXVE_SERVER
|
||||
if [ -z "$DEPLOY_PROXMOXVE_SERVER" ]; then
|
||||
_target_hostname="$_cdomain"
|
||||
else
|
||||
_target_hostname="$DEPLOY_PROXMOXVE_SERVER"
|
||||
_savedeployconf DEPLOY_PROXMOXVE_SERVER "$DEPLOY_PROXMOXVE_SERVER"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXVE_SERVER "$_target_hostname"
|
||||
|
||||
_getdeployconf DEPLOY_PROXMOXVE_SERVER_PORT
|
||||
if [ -z "$DEPLOY_PROXMOXVE_SERVER_PORT" ]; then
|
||||
_target_port="8006"
|
||||
else
|
||||
_target_port="$DEPLOY_PROXMOXVE_SERVER_PORT"
|
||||
_savedeployconf DEPLOY_PROXMOXVE_SERVER_PORT "$DEPLOY_PROXMOXVE_SERVER_PORT"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXVE_SERVER_PORT "$_target_port"
|
||||
|
||||
_getdeployconf DEPLOY_PROXMOXVE_NODE_NAME
|
||||
if [ -z "$DEPLOY_PROXMOXVE_NODE_NAME" ]; then
|
||||
_node_name=$(echo "$_target_hostname" | cut -d. -f1)
|
||||
else
|
||||
_node_name="$DEPLOY_PROXMOXVE_NODE_NAME"
|
||||
_savedeployconf DEPLOY_PROXMOXVE_NODE_NAME "$DEPLOY_PROXMOXVE_NODE_NAME"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXVE_NODE_NAME "$_node_name"
|
||||
|
||||
# Complete URL.
|
||||
_target_url="https://${_target_hostname}:${_target_port}/api2/json/nodes/${_node_name}/certificates/custom"
|
||||
_debug TARGET_URL "$_target_url"
|
||||
|
||||
# More "sane" defaults.
|
||||
_getdeployconf DEPLOY_PROXMOXVE_USER
|
||||
if [ -z "$DEPLOY_PROXMOXVE_USER" ]; then
|
||||
_proxmoxve_user="root"
|
||||
else
|
||||
_proxmoxve_user="$DEPLOY_PROXMOXVE_USER"
|
||||
_savedeployconf DEPLOY_PROXMOXVE_USER "$DEPLOY_PROXMOXVE_USER"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXVE_USER "$_proxmoxve_user"
|
||||
|
||||
_getdeployconf DEPLOY_PROXMOXVE_USER_REALM
|
||||
if [ -z "$DEPLOY_PROXMOXVE_USER_REALM" ]; then
|
||||
_proxmoxve_user_realm="pam"
|
||||
else
|
||||
_proxmoxve_user_realm="$DEPLOY_PROXMOXVE_USER_REALM"
|
||||
_savedeployconf DEPLOY_PROXMOXVE_USER_REALM "$DEPLOY_PROXMOXVE_USER_REALM"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXVE_USER_REALM "$_proxmoxve_user_realm"
|
||||
|
||||
_getdeployconf DEPLOY_PROXMOXVE_API_TOKEN_NAME
|
||||
if [ -z "$DEPLOY_PROXMOXVE_API_TOKEN_NAME" ]; then
|
||||
_proxmoxve_api_token_name="acme"
|
||||
else
|
||||
_proxmoxve_api_token_name="$DEPLOY_PROXMOXVE_API_TOKEN_NAME"
|
||||
_savedeployconf DEPLOY_PROXMOXVE_API_TOKEN_NAME "$DEPLOY_PROXMOXVE_API_TOKEN_NAME"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXVE_API_TOKEN_NAME "$_proxmoxve_api_token_name"
|
||||
|
||||
# This is required.
|
||||
_getdeployconf DEPLOY_PROXMOXVE_API_TOKEN_KEY
|
||||
if [ -z "$DEPLOY_PROXMOXVE_API_TOKEN_KEY" ]; then
|
||||
_err "API key not provided."
|
||||
return 1
|
||||
else
|
||||
_proxmoxve_api_token_key="$DEPLOY_PROXMOXVE_API_TOKEN_KEY"
|
||||
_savedeployconf DEPLOY_PROXMOXVE_API_TOKEN_KEY "$DEPLOY_PROXMOXVE_API_TOKEN_KEY"
|
||||
fi
|
||||
_debug2 DEPLOY_PROXMOXVE_API_TOKEN_KEY "$_proxmoxve_api_token_key"
|
||||
|
||||
# PVE API Token header value. Used in "Authorization: PVEAPIToken".
|
||||
_proxmoxve_header_api_token="${_proxmoxve_user}@${_proxmoxve_user_realm}!${_proxmoxve_api_token_name}=${_proxmoxve_api_token_key}"
|
||||
_debug2 "Auth Header" "$_proxmoxve_header_api_token"
|
||||
|
||||
# Ugly. I hate putting heredocs inside functions because heredocs don't
|
||||
# account for whitespace correctly but it _does_ work and is several times
|
||||
# cleaner than anything else I had here.
|
||||
#
|
||||
# This dumps the json payload to a variable that should be passable to the
|
||||
# _psot function.
|
||||
_json_payload=$(
|
||||
cat <<HEREDOC
|
||||
{
|
||||
"certificates": "$(tr '\n' ':' <"$_cfullchain" | sed 's/:/\\n/g')",
|
||||
"key": "$(tr '\n' ':' <"$_ckey" | sed 's/:/\\n/g')",
|
||||
"node":"$_node_name",
|
||||
"restart":"1",
|
||||
"force":"1"
|
||||
}
|
||||
HEREDOC
|
||||
)
|
||||
_debug2 Payload "$_json_payload"
|
||||
|
||||
_info "Push certificates to server"
|
||||
export HTTPS_INSECURE=1
|
||||
export _H1="Authorization: PVEAPIToken=${_proxmoxve_header_api_token}"
|
||||
_post "$_json_payload" "$_target_url" "" POST "application/json"
|
||||
|
||||
}
|
@ -53,7 +53,7 @@ qiniu_deploy() {
|
||||
sslcert_access_token="$(_make_access_token "$sslcert_path")"
|
||||
_debug sslcert_access_token "$sslcert_access_token"
|
||||
export _H1="Authorization: QBox $sslcert_access_token"
|
||||
sslcert_response=$(_post "$sslcerl_body" "$QINIU_API_BASE$sslcert_path" 0 "POST" "application/json" | _dbase64 "multiline")
|
||||
sslcert_response=$(_post "$sslcerl_body" "$QINIU_API_BASE$sslcert_path" 0 "POST" "application/json" | _dbase64)
|
||||
|
||||
if ! _contains "$sslcert_response" "certID"; then
|
||||
_err "Error in creating certificate:"
|
||||
@ -75,7 +75,7 @@ qiniu_deploy() {
|
||||
update_access_token="$(_make_access_token "$update_path")"
|
||||
_debug update_access_token "$update_access_token"
|
||||
export _H1="Authorization: QBox $update_access_token"
|
||||
update_response=$(_post "$update_body" "$QINIU_API_BASE$update_path" 0 "PUT" "application/json" | _dbase64 "multiline")
|
||||
update_response=$(_post "$update_body" "$QINIU_API_BASE$update_path" 0 "PUT" "application/json" | _dbase64)
|
||||
|
||||
if _contains "$update_response" "error"; then
|
||||
_err "Error in updating domain $domain httpsconf:"
|
||||
|
@ -23,6 +23,7 @@
|
||||
# ```sh
|
||||
# export ROUTER_OS_USERNAME=certuser
|
||||
# export ROUTER_OS_HOST=router.example.com
|
||||
# export ROUTER_OS_PORT=22
|
||||
#
|
||||
# acme.sh --deploy -d ftp.example.com --deploy-hook routeros
|
||||
# ```
|
||||
@ -48,6 +49,16 @@
|
||||
# One optional thing to do as well is to create a script that updates
|
||||
# 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.
|
||||
|
||||
######## Public functions #####################
|
||||
@ -59,6 +70,7 @@ routeros_deploy() {
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
_err_code=0
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
@ -80,6 +92,27 @@ routeros_deploy() {
|
||||
return 1
|
||||
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
|
||||
@ -89,33 +122,83 @@ routeros_deploy() {
|
||||
|
||||
_savedeployconf ROUTER_OS_HOST "$ROUTER_OS_HOST"
|
||||
_savedeployconf ROUTER_OS_USERNAME "$ROUTER_OS_USERNAME"
|
||||
_savedeployconf ROUTER_OS_PORT "$ROUTER_OS_PORT"
|
||||
_savedeployconf ROUTER_OS_SSH_CMD "$ROUTER_OS_SSH_CMD"
|
||||
_savedeployconf ROUTER_OS_SCP_CMD "$ROUTER_OS_SCP_CMD"
|
||||
_savedeployconf ROUTER_OS_ADDITIONAL_SERVICES "$ROUTER_OS_ADDITIONAL_SERVICES"
|
||||
|
||||
_info "Trying to push key '$_ckey' to router"
|
||||
scp "$_ckey" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.key"
|
||||
_info "Trying to push cert '$_cfullchain' to router"
|
||||
scp "$_cfullchain" "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST:$_cdomain.cer"
|
||||
DEPLOY_SCRIPT_CMD="/system script add name=\"LE Cert Deploy - $_cdomain\" owner=admin policy=ftp,read,write,password,sensitive \
|
||||
source=\"## generated by routeros deploy script in acme.sh;\
|
||||
\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=":do {/system script remove \"LECertDeploy-$_cdomain\" } on-error={ }; \
|
||||
/system script add name=\"LECertDeploy-$_cdomain\" owner=$ROUTER_OS_USERNAME \
|
||||
comment=\"generated by routeros deploy script in acme.sh\" \
|
||||
source=\"/certificate remove [ find name=$_cdomain.cer_0 ];\
|
||||
\n/certificate remove [ find name=$_cdomain.cer_1 ];\
|
||||
\n/certificate remove [ find name=$_cdomain.cer_2 ];\
|
||||
\ndelay 1;\
|
||||
\n/certificate import file-name=$_cdomain.cer passphrase=\\\"\\\";\
|
||||
\n/certificate import file-name=$_cdomain.key passphrase=\\\"\\\";\
|
||||
\ndelay 1;\
|
||||
\n/file remove $_cdomain.cer;\
|
||||
\n/file remove $_cdomain.key;\
|
||||
\n:do {/file remove $_cdomain.cer; } on-error={ }\
|
||||
\n:do {/file remove $_cdomain.key; } on-error={ }\
|
||||
\ndelay 2;\
|
||||
\n/ip service set www-ssl certificate=$_cdomain.cer_0;\
|
||||
\n$ROUTER_OS_ADDITIONAL_SERVICES;\
|
||||
\n\"
|
||||
"
|
||||
# shellcheck disable=SC2029
|
||||
ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "$DEPLOY_SCRIPT_CMD"
|
||||
# shellcheck disable=SC2029
|
||||
ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script run \"LE Cert Deploy - $_cdomain\""
|
||||
# shellcheck disable=SC2029
|
||||
ssh "$ROUTER_OS_USERNAME@$ROUTER_OS_HOST" "/system script remove \"LE Cert Deploy - $_cdomain\""
|
||||
|
||||
if ! _ssh_remote_cmd "$DEPLOY_SCRIPT_CMD"; then
|
||||
return $_err_code
|
||||
fi
|
||||
|
||||
if ! _ssh_remote_cmd "/system script run \"LECertDeploy-$_cdomain\""; then
|
||||
return $_err_code
|
||||
fi
|
||||
|
||||
if ! _ssh_remote_cmd "/system script remove \"LECertDeploy-$_cdomain\""; then
|
||||
return $_err_code
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# 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
|
||||
}
|
||||
|
409
deploy/ssh.sh
409
deploy/ssh.sh
@ -14,7 +14,7 @@
|
||||
# The following examples are for QNAP NAS running QTS 4.2
|
||||
# export DEPLOY_SSH_CMD="" # defaults to "ssh -T"
|
||||
# export DEPLOY_SSH_USER="admin" # required
|
||||
# export DEPLOY_SSH_SERVER="qnap" # defaults to domain name
|
||||
# export DEPLOY_SSH_SERVER="host1 host2:8022 192.168.0.1:9022" # defaults to domain name, support multiple servers with optional port
|
||||
# export DEPLOY_SSH_KEYFILE="/etc/stunnel/stunnel.pem"
|
||||
# export DEPLOY_SSH_CERTFILE="/etc/stunnel/stunnel.pem"
|
||||
# export DEPLOY_SSH_CAFILE="/etc/stunnel/uca.pem"
|
||||
@ -23,6 +23,8 @@
|
||||
# export DEPLOY_SSH_BACKUP="" # yes or no, default to yes or previously saved value
|
||||
# export DEPLOY_SSH_BACKUP_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_USE_SCP="" yes or no, default to no
|
||||
# export DEPLOY_SSH_SCP_CMD="" defaults to "scp -q"
|
||||
#
|
||||
######## Public functions #####################
|
||||
|
||||
@ -42,72 +44,134 @@ ssh_deploy() {
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
# 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 "$Le_Deploy_ssh_user" ]; then
|
||||
_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"
|
||||
_err "DEPLOY_SSH_USER not defined."
|
||||
return 1
|
||||
fi
|
||||
_savedeployconf DEPLOY_SSH_USER "$DEPLOY_SSH_USER"
|
||||
|
||||
# SERVER is optional. If not provided then use _cdomain
|
||||
_migratedeployconf Le_Deploy_ssh_server DEPLOY_SSH_SERVER
|
||||
_getdeployconf DEPLOY_SSH_SERVER
|
||||
_debug2 DEPLOY_SSH_SERVER "$DEPLOY_SSH_SERVER"
|
||||
if [ -n "$DEPLOY_SSH_SERVER" ]; then
|
||||
Le_Deploy_ssh_server="$DEPLOY_SSH_SERVER"
|
||||
_savedomainconf Le_Deploy_ssh_server "$Le_Deploy_ssh_server"
|
||||
elif [ -z "$Le_Deploy_ssh_server" ]; then
|
||||
Le_Deploy_ssh_server="$_cdomain"
|
||||
if [ -z "$DEPLOY_SSH_SERVER" ]; then
|
||||
DEPLOY_SSH_SERVER="$_cdomain"
|
||||
fi
|
||||
_savedeployconf DEPLOY_SSH_SERVER "$DEPLOY_SSH_SERVER"
|
||||
|
||||
# CMD is optional. If not provided then use ssh
|
||||
_migratedeployconf Le_Deploy_ssh_cmd DEPLOY_SSH_CMD
|
||||
_getdeployconf DEPLOY_SSH_CMD
|
||||
_debug2 DEPLOY_SSH_CMD "$DEPLOY_SSH_CMD"
|
||||
if [ -n "$DEPLOY_SSH_CMD" ]; then
|
||||
Le_Deploy_ssh_cmd="$DEPLOY_SSH_CMD"
|
||||
_savedomainconf Le_Deploy_ssh_cmd "$Le_Deploy_ssh_cmd"
|
||||
elif [ -z "$Le_Deploy_ssh_cmd" ]; then
|
||||
Le_Deploy_ssh_cmd="ssh -T"
|
||||
if [ -z "$DEPLOY_SSH_CMD" ]; then
|
||||
DEPLOY_SSH_CMD="ssh -T"
|
||||
fi
|
||||
_savedeployconf DEPLOY_SSH_CMD "$DEPLOY_SSH_CMD"
|
||||
|
||||
# BACKUP is optional. If not provided then default to previously saved value or yes.
|
||||
_migratedeployconf Le_Deploy_ssh_backup DEPLOY_SSH_BACKUP
|
||||
_getdeployconf DEPLOY_SSH_BACKUP
|
||||
_debug2 DEPLOY_SSH_BACKUP "$DEPLOY_SSH_BACKUP"
|
||||
if [ "$DEPLOY_SSH_BACKUP" = "no" ]; then
|
||||
Le_Deploy_ssh_backup="no"
|
||||
elif [ -z "$Le_Deploy_ssh_backup" ] || [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
Le_Deploy_ssh_backup="yes"
|
||||
if [ -z "$DEPLOY_SSH_BACKUP" ]; then
|
||||
DEPLOY_SSH_BACKUP="yes"
|
||||
fi
|
||||
_savedomainconf Le_Deploy_ssh_backup "$Le_Deploy_ssh_backup"
|
||||
_savedeployconf DEPLOY_SSH_BACKUP "$DEPLOY_SSH_BACKUP"
|
||||
|
||||
# BACKUP_PATH is optional. If not provided then default to previously saved value or .acme_ssh_deploy
|
||||
_migratedeployconf Le_Deploy_ssh_backup_path DEPLOY_SSH_BACKUP_PATH
|
||||
_getdeployconf DEPLOY_SSH_BACKUP_PATH
|
||||
_debug2 DEPLOY_SSH_BACKUP_PATH "$DEPLOY_SSH_BACKUP_PATH"
|
||||
if [ -n "$DEPLOY_SSH_BACKUP_PATH" ]; then
|
||||
Le_Deploy_ssh_backup_path="$DEPLOY_SSH_BACKUP_PATH"
|
||||
elif [ -z "$Le_Deploy_ssh_backup_path" ]; then
|
||||
Le_Deploy_ssh_backup_path=".acme_ssh_deploy"
|
||||
if [ -z "$DEPLOY_SSH_BACKUP_PATH" ]; then
|
||||
DEPLOY_SSH_BACKUP_PATH=".acme_ssh_deploy"
|
||||
fi
|
||||
_savedomainconf Le_Deploy_ssh_backup_path "$Le_Deploy_ssh_backup_path"
|
||||
_savedeployconf DEPLOY_SSH_BACKUP_PATH "$DEPLOY_SSH_BACKUP_PATH"
|
||||
|
||||
# MULTI_CALL is optional. If not provided then default to previously saved
|
||||
# value (which may be undefined... equivalent to "no").
|
||||
_migratedeployconf Le_Deploy_ssh_multi_call DEPLOY_SSH_MULTI_CALL
|
||||
_getdeployconf DEPLOY_SSH_MULTI_CALL
|
||||
_debug2 DEPLOY_SSH_MULTI_CALL "$DEPLOY_SSH_MULTI_CALL"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
Le_Deploy_ssh_multi_call="yes"
|
||||
_savedomainconf Le_Deploy_ssh_multi_call "$Le_Deploy_ssh_multi_call"
|
||||
elif [ "$DEPLOY_SSH_MULTI_CALL" = "no" ]; then
|
||||
Le_Deploy_ssh_multi_call=""
|
||||
_cleardomainconf Le_Deploy_ssh_multi_call
|
||||
if [ -z "$DEPLOY_SSH_MULTI_CALL" ]; then
|
||||
DEPLOY_SSH_MULTI_CALL="no"
|
||||
fi
|
||||
_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
|
||||
|
||||
_deploy_ssh_servers=$Le_Deploy_ssh_server
|
||||
for Le_Deploy_ssh_server in $_deploy_ssh_servers; do
|
||||
# CERTFILE is optional.
|
||||
# If provided then certificate will be copied or appended to provided filename.
|
||||
_migratedeployconf Le_Deploy_ssh_certfile DEPLOY_SSH_CERTFILE
|
||||
_getdeployconf DEPLOY_SSH_CERTFILE
|
||||
_debug2 DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
|
||||
if [ -n "$DEPLOY_SSH_CERTFILE" ]; then
|
||||
_savedeployconf DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
|
||||
fi
|
||||
|
||||
# CAFILE is optional.
|
||||
# If provided then CA intermediate certificate will be copied or appended to provided filename.
|
||||
_migratedeployconf Le_Deploy_ssh_cafile DEPLOY_SSH_CAFILE
|
||||
_getdeployconf DEPLOY_SSH_CAFILE
|
||||
_debug2 DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
|
||||
if [ -n "$DEPLOY_SSH_CAFILE" ]; then
|
||||
_savedeployconf DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
|
||||
fi
|
||||
|
||||
# FULLCHAIN is optional.
|
||||
# If provided then fullchain certificate will be copied or appended to provided filename.
|
||||
_migratedeployconf Le_Deploy_ssh_fullchain DEPLOY_SSH_FULLCHAIN
|
||||
_getdeployconf DEPLOY_SSH_FULLCHAIN
|
||||
_debug2 DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
|
||||
if [ -n "$DEPLOY_SSH_FULLCHAIN" ]; then
|
||||
_savedeployconf DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
|
||||
fi
|
||||
|
||||
# REMOTE_CMD is optional.
|
||||
# If provided then this command will be executed on remote host.
|
||||
_migratedeployconf Le_Deploy_ssh_remote_cmd DEPLOY_SSH_REMOTE_CMD
|
||||
_getdeployconf DEPLOY_SSH_REMOTE_CMD
|
||||
_debug2 DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
|
||||
if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
|
||||
_savedeployconf DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
|
||||
fi
|
||||
|
||||
# USE_SCP is optional. If not provided then default to previously saved
|
||||
# value (which may be undefined... equivalent to "no").
|
||||
_getdeployconf DEPLOY_SSH_USE_SCP
|
||||
_debug2 DEPLOY_SSH_USE_SCP "$DEPLOY_SSH_USE_SCP"
|
||||
if [ -z "$DEPLOY_SSH_USE_SCP" ]; then
|
||||
DEPLOY_SSH_USE_SCP="no"
|
||||
fi
|
||||
_savedeployconf DEPLOY_SSH_USE_SCP "$DEPLOY_SSH_USE_SCP"
|
||||
|
||||
# SCP_CMD is optional. If not provided then use scp
|
||||
_getdeployconf DEPLOY_SSH_SCP_CMD
|
||||
_debug2 DEPLOY_SSH_SCP_CMD "$DEPLOY_SSH_SCP_CMD"
|
||||
if [ -z "$DEPLOY_SSH_SCP_CMD" ]; then
|
||||
DEPLOY_SSH_SCP_CMD="scp -q"
|
||||
fi
|
||||
_savedeployconf DEPLOY_SSH_SCP_CMD "$DEPLOY_SSH_SCP_CMD"
|
||||
|
||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||
DEPLOY_SSH_MULTI_CALL="yes"
|
||||
_info "Using scp as alternate method for copying files. Multicall Mode is implicit"
|
||||
elif [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
_info "Using MULTI_CALL mode... Required commands sent in multiple calls to remote host"
|
||||
else
|
||||
_info "Required commands batched and sent in single call to remote host"
|
||||
fi
|
||||
|
||||
_deploy_ssh_servers="$DEPLOY_SSH_SERVER"
|
||||
for DEPLOY_SSH_SERVER in $_deploy_ssh_servers; do
|
||||
_ssh_deploy
|
||||
done
|
||||
}
|
||||
@ -117,16 +181,25 @@ _ssh_deploy() {
|
||||
_cmdstr=""
|
||||
_backupprefix=""
|
||||
_backupdir=""
|
||||
_local_cert_file=""
|
||||
_local_ca_file=""
|
||||
_local_full_file=""
|
||||
|
||||
_info "Deploy certificates to remote server $Le_Deploy_ssh_user@$Le_Deploy_ssh_server"
|
||||
if [ "$Le_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
|
||||
case $DEPLOY_SSH_SERVER in
|
||||
*:*)
|
||||
_host=${DEPLOY_SSH_SERVER%:*}
|
||||
_port=${DEPLOY_SSH_SERVER##*:}
|
||||
;;
|
||||
*)
|
||||
_host=$DEPLOY_SSH_SERVER
|
||||
_port=
|
||||
;;
|
||||
esac
|
||||
|
||||
if [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||
_backupprefix="$Le_Deploy_ssh_backup_path/$_cdomain-backup"
|
||||
_info "Deploy certificates to remote server $DEPLOY_SSH_USER@$_host:$_port"
|
||||
|
||||
if [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
_backupprefix="$DEPLOY_SSH_BACKUP_PATH/$_cdomain-backup"
|
||||
_backupdir="$_backupprefix-$(_utc_date | tr ' ' '-')"
|
||||
# run cleanup on the backup directory, erase all older
|
||||
# than 180 days (15552000 seconds).
|
||||
@ -138,7 +211,7 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
||||
_cmdstr="mkdir -p $_backupdir; $_cmdstr"
|
||||
_info "Backup of old certificate files will be placed in remote directory $_backupdir"
|
||||
_info "Backup directories erased after 180 days."
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
@ -146,129 +219,184 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
||||
fi
|
||||
fi
|
||||
|
||||
# KEYFILE is optional.
|
||||
# If provided then private key will be copied to provided filename.
|
||||
_getdeployconf DEPLOY_SSH_KEYFILE
|
||||
_debug2 DEPLOY_SSH_KEYFILE "$DEPLOY_SSH_KEYFILE"
|
||||
if [ -n "$DEPLOY_SSH_KEYFILE" ]; then
|
||||
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
|
||||
if [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
# backup file we are about to overwrite.
|
||||
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_keyfile $_backupdir >/dev/null;"
|
||||
_cmdstr="$_cmdstr cp $DEPLOY_SSH_KEYFILE $_backupdir >/dev/null;"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
# copy new certificate into file.
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $Le_Deploy_ssh_keyfile;"
|
||||
_info "will copy private key to remote file $Le_Deploy_ssh_keyfile"
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
|
||||
# copy new key into file.
|
||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||
# scp the file
|
||||
if ! _scp_remote_cmd "$_ckey" "$DEPLOY_SSH_KEYFILE"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
else
|
||||
# ssh echo to the file
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_ckey")\" > $DEPLOY_SSH_KEYFILE;"
|
||||
_info "will copy private key to remote file $DEPLOY_SSH_KEYFILE"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# CERTFILE is optional.
|
||||
# If provided then certificate will be copied or appended to provided filename.
|
||||
_getdeployconf DEPLOY_SSH_CERTFILE
|
||||
_debug2 DEPLOY_SSH_CERTFILE "$DEPLOY_SSH_CERTFILE"
|
||||
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=">"
|
||||
if [ "$Le_Deploy_ssh_certfile" = "$Le_Deploy_ssh_keyfile" ]; then
|
||||
if [ "$DEPLOY_SSH_CERTFILE" = "$DEPLOY_SSH_KEYFILE" ]; then
|
||||
# if filename is same as previous file then append.
|
||||
_pipe=">>"
|
||||
elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||
elif [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
# backup file we are about to overwrite.
|
||||
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_certfile $_backupdir >/dev/null;"
|
||||
_cmdstr="$_cmdstr cp $DEPLOY_SSH_CERTFILE $_backupdir >/dev/null;"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
|
||||
# copy new certificate into file.
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $Le_Deploy_ssh_certfile;"
|
||||
_info "will copy certificate to remote file $Le_Deploy_ssh_certfile"
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||
# scp the file
|
||||
_local_cert_file=$(_mktemp)
|
||||
if [ "$DEPLOY_SSH_CERTFILE" = "$DEPLOY_SSH_KEYFILE" ]; then
|
||||
cat "$_ckey" >>"$_local_cert_file"
|
||||
fi
|
||||
cat "$_ccert" >>"$_local_cert_file"
|
||||
if ! _scp_remote_cmd "$_local_cert_file" "$DEPLOY_SSH_CERTFILE"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
else
|
||||
# ssh echo to the file
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_ccert")\" $_pipe $DEPLOY_SSH_CERTFILE;"
|
||||
_info "will copy certificate to remote file $DEPLOY_SSH_CERTFILE"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# CAFILE is optional.
|
||||
# If provided then CA intermediate certificate will be copied or appended to provided filename.
|
||||
_getdeployconf DEPLOY_SSH_CAFILE
|
||||
_debug2 DEPLOY_SSH_CAFILE "$DEPLOY_SSH_CAFILE"
|
||||
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=">"
|
||||
if [ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_keyfile" ] ||
|
||||
[ "$Le_Deploy_ssh_cafile" = "$Le_Deploy_ssh_certfile" ]; then
|
||||
if [ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_KEYFILE" ] ||
|
||||
[ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_CERTFILE" ]; then
|
||||
# if filename is same as previous file then append.
|
||||
_pipe=">>"
|
||||
elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||
elif [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
# backup file we are about to overwrite.
|
||||
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_cafile $_backupdir >/dev/null;"
|
||||
_cmdstr="$_cmdstr cp $DEPLOY_SSH_CAFILE $_backupdir >/dev/null;"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
|
||||
# copy new certificate into file.
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $Le_Deploy_ssh_cafile;"
|
||||
_info "will copy CA file to remote file $Le_Deploy_ssh_cafile"
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||
# scp the file
|
||||
_local_ca_file=$(_mktemp)
|
||||
if [ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_KEYFILE" ]; then
|
||||
cat "$_ckey" >>"$_local_ca_file"
|
||||
fi
|
||||
if [ "$DEPLOY_SSH_CAFILE" = "$DEPLOY_SSH_CERTFILE" ]; then
|
||||
cat "$_ccert" >>"$_local_ca_file"
|
||||
fi
|
||||
cat "$_cca" >>"$_local_ca_file"
|
||||
if ! _scp_remote_cmd "$_local_ca_file" "$DEPLOY_SSH_CAFILE"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
else
|
||||
# ssh echo to the file
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_cca")\" $_pipe $DEPLOY_SSH_CAFILE;"
|
||||
_info "will copy CA file to remote file $DEPLOY_SSH_CAFILE"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# FULLCHAIN is optional.
|
||||
# If provided then fullchain certificate will be copied or appended to provided filename.
|
||||
_getdeployconf DEPLOY_SSH_FULLCHAIN
|
||||
_debug2 DEPLOY_SSH_FULLCHAIN "$DEPLOY_SSH_FULLCHAIN"
|
||||
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=">"
|
||||
if [ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_keyfile" ] ||
|
||||
[ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_certfile" ] ||
|
||||
[ "$Le_Deploy_ssh_fullchain" = "$Le_Deploy_ssh_cafile" ]; then
|
||||
if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_KEYFILE" ] ||
|
||||
[ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CERTFILE" ] ||
|
||||
[ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_CAFILE" ]; then
|
||||
# if filename is same as previous file then append.
|
||||
_pipe=">>"
|
||||
elif [ "$Le_Deploy_ssh_backup" = "yes" ]; then
|
||||
elif [ "$DEPLOY_SSH_BACKUP" = "yes" ]; then
|
||||
# backup file we are about to overwrite.
|
||||
_cmdstr="$_cmdstr cp $Le_Deploy_ssh_fullchain $_backupdir >/dev/null;"
|
||||
_cmdstr="$_cmdstr cp $DEPLOY_SSH_FULLCHAIN $_backupdir >/dev/null;"
|
||||
if [ "$DEPLOY_SSH_FULLCHAIN" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
|
||||
# copy new certificate into file.
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $Le_Deploy_ssh_fullchain;"
|
||||
_info "will copy fullchain to remote file $Le_Deploy_ssh_fullchain"
|
||||
if [ "$Le_Deploy_ssh_multi_call" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
if [ "$DEPLOY_SSH_USE_SCP" = "yes" ]; then
|
||||
# scp the file
|
||||
_local_full_file=$(_mktemp)
|
||||
if [ "$DEPLOY_SSH_FULLCHAIN" = "$DEPLOY_SSH_KEYFILE" ]; 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
|
||||
fi
|
||||
_cmdstr=""
|
||||
else
|
||||
# ssh echo to the file
|
||||
_cmdstr="$_cmdstr echo \"$(cat "$_cfullchain")\" $_pipe $DEPLOY_SSH_FULLCHAIN;"
|
||||
_info "will copy fullchain to remote file $DEPLOY_SSH_FULLCHAIN"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
_cmdstr=""
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# REMOTE_CMD is optional.
|
||||
# If provided then this command will be executed on remote host.
|
||||
_getdeployconf DEPLOY_SSH_REMOTE_CMD
|
||||
_debug2 DEPLOY_SSH_REMOTE_CMD "$DEPLOY_SSH_REMOTE_CMD"
|
||||
if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
|
||||
Le_Deploy_ssh_remote_cmd="$DEPLOY_SSH_REMOTE_CMD"
|
||||
_savedomainconf Le_Deploy_ssh_remote_cmd "$Le_Deploy_ssh_remote_cmd"
|
||||
# cleanup local files if any
|
||||
if [ -f "$_local_cert_file" ]; then
|
||||
rm -f "$_local_cert_file"
|
||||
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 [ -f "$_local_ca_file" ]; then
|
||||
rm -f "$_local_ca_file"
|
||||
fi
|
||||
if [ -f "$_local_full_file" ]; then
|
||||
rm -f "$_local_full_file"
|
||||
fi
|
||||
|
||||
if [ -n "$DEPLOY_SSH_REMOTE_CMD" ]; then
|
||||
_cmdstr="$_cmdstr $DEPLOY_SSH_REMOTE_CMD;"
|
||||
_info "Will execute remote command $DEPLOY_SSH_REMOTE_CMD"
|
||||
if [ "$DEPLOY_SSH_MULTI_CALL" = "yes" ]; then
|
||||
if ! _ssh_remote_cmd "$_cmdstr"; then
|
||||
return $_err_code
|
||||
fi
|
||||
@ -282,17 +410,25 @@ then rm -rf \"\$fn\"; echo \"Backup \$fn deleted as older than 180 days\"; fi; d
|
||||
return $_err_code
|
||||
fi
|
||||
fi
|
||||
# cleanup in case all is ok
|
||||
return 0
|
||||
}
|
||||
|
||||
#cmd
|
||||
_ssh_remote_cmd() {
|
||||
_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"
|
||||
_info "Submitting sequence of commands to remote server by ssh"
|
||||
_info "Submitting sequence of commands to remote server by $_ssh_cmd"
|
||||
|
||||
# quotations in bash cmd below intended. Squash travis spellcheck error
|
||||
# shellcheck disable=SC2029
|
||||
$Le_Deploy_ssh_cmd "$Le_Deploy_ssh_user@$Le_Deploy_ssh_server" sh -c "'$_cmd'"
|
||||
$_ssh_cmd "$DEPLOY_SSH_USER@$_host" sh -c "'$_cmd'"
|
||||
_err_code="$?"
|
||||
|
||||
if [ "$_err_code" != "0" ]; then
|
||||
@ -301,3 +437,26 @@ _ssh_remote_cmd() {
|
||||
|
||||
return $_err_code
|
||||
}
|
||||
|
||||
# cmd scp
|
||||
_scp_remote_cmd() {
|
||||
_src=$1
|
||||
_dest=$2
|
||||
|
||||
_scp_cmd="$DEPLOY_SSH_SCP_CMD"
|
||||
if [ -n "$_port" ]; then
|
||||
_scp_cmd="$_scp_cmd -P $_port"
|
||||
fi
|
||||
|
||||
_secure_debug "Remote copy source $_src to destination $_dest"
|
||||
_info "Submitting secure copy by $_scp_cmd"
|
||||
|
||||
$_scp_cmd "$_src" "$DEPLOY_SSH_USER"@"$_host":"$_dest"
|
||||
_err_code="$?"
|
||||
|
||||
if [ "$_err_code" != "0" ]; then
|
||||
_err "Error code $_err_code returned from scp"
|
||||
fi
|
||||
|
||||
return $_err_code
|
||||
}
|
||||
|
@ -1,34 +1,53 @@
|
||||
#!/usr/bin/env sh
|
||||
#!/bin/bash
|
||||
|
||||
# Here is a script to deploy cert to Synology DSM
|
||||
#
|
||||
# It requires following environment variables:
|
||||
#
|
||||
# SYNO_Username - Synology Username to login (must be an administrator)
|
||||
# SYNO_Password - Synology Password to login
|
||||
# SYNO_Certificate - Certificate description to target for replacement
|
||||
#
|
||||
# The following environmental variables may be set if you don't like their
|
||||
# default values:
|
||||
#
|
||||
# SYNO_Scheme - defaults to http
|
||||
# SYNO_Hostname - defaults to localhost
|
||||
# SYNO_Port - defaults to 5000
|
||||
# SYNO_DID - device ID to skip OTP - defaults to empty
|
||||
# SYNO_TOTP_SECRET - TOTP secret to generate OTP - defaults to empty
|
||||
#
|
||||
################################################################################
|
||||
# ACME.sh 3rd party deploy plugin for Synology DSM
|
||||
################################################################################
|
||||
# Authors: Brian Hartvigsen (creator), https://github.com/tresni
|
||||
# Martin Arndt (contributor), https://troublezone.net/
|
||||
# Updated: 2023-07-03
|
||||
# Issues: https://github.com/acmesh-official/acme.sh/issues/2727
|
||||
################################################################################
|
||||
# Usage (shown values are the examples):
|
||||
# 1. Set required environment variables:
|
||||
# - use automatically created temp admin user to authenticate
|
||||
# export SYNO_USE_TEMP_ADMIN=1
|
||||
# - or provide your own admin user credential to authenticate
|
||||
# 1. export SYNO_USERNAME="adminUser"
|
||||
# 2. export SYNO_PASSWORD="adminPassword"
|
||||
# 2. Set optional environment variables
|
||||
# - common optional variables
|
||||
# - export SYNO_SCHEME="http" - defaults to "http"
|
||||
# - export SYNO_HOSTNAME="localhost" - defaults to "localhost"
|
||||
# - export SYNO_PORT="5000" - defaults to "5000"
|
||||
# - export SYNO_CREATE=1 - to allow creating the cert if it doesn't exist
|
||||
# - export SYNO_CERTIFICATE="" - to replace a specific cert by its
|
||||
# description
|
||||
# - temp admin optional variables
|
||||
# - export SYNO_LOCAL_HOSTNAME=1 - if set to 1, force to treat hostname is
|
||||
# targeting current local machine (since
|
||||
# this method only locally supported)
|
||||
# - exsiting admin 2FA-OTP optional variables
|
||||
# - export SYNO_OTP_CODE="XXXXXX" - if set, script won't require to
|
||||
# interactive input the OTP code
|
||||
# - export SYNO_DEVICE_NAME="CertRenewal" - if set, script won't require to
|
||||
# interactive input the device name
|
||||
# - export SYNO_DEVICE_ID="" - (deprecated, auth with OTP code instead)
|
||||
# required for omitting 2FA-OTP
|
||||
# 3. Run command:
|
||||
# acme.sh --deploy --deploy-hook synology_dsm -d example.com
|
||||
################################################################################
|
||||
# Dependencies:
|
||||
# -------------
|
||||
# - jq and curl
|
||||
# - oathtool (When using 2 Factor Authentication and SYNO_TOTP_SECRET is set)
|
||||
#
|
||||
#returns 0 means success, otherwise error.
|
||||
|
||||
######## Public functions #####################
|
||||
# - curl
|
||||
# - synouser & synogroup & synosetkeyvalue (Required for SYNO_USE_TEMP_ADMIN=1)
|
||||
################################################################################
|
||||
# Return value:
|
||||
# 0 means success, otherwise error.
|
||||
################################################################################
|
||||
|
||||
########## Public functions ####################################################
|
||||
#domain keyfile certfile cafile fullchain
|
||||
synology_dsm_deploy() {
|
||||
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
@ -36,143 +55,391 @@ synology_dsm_deploy() {
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
|
||||
# Get Username and Password, but don't save until we successfully authenticate
|
||||
_getdeployconf SYNO_Username
|
||||
_getdeployconf SYNO_Password
|
||||
_getdeployconf SYNO_Create
|
||||
_getdeployconf SYNO_DID
|
||||
_getdeployconf SYNO_TOTP_SECRET
|
||||
if [ -z "${SYNO_Username:-}" ] || [ -z "${SYNO_Password:-}" ]; then
|
||||
_err "SYNO_Username & SYNO_Password must be set"
|
||||
# Get username and password, but don't save until we authenticated successfully
|
||||
_migratedeployconf SYNO_Username SYNO_USERNAME
|
||||
_migratedeployconf SYNO_Password SYNO_PASSWORD
|
||||
_migratedeployconf SYNO_Device_ID SYNO_DEVICE_ID
|
||||
_migratedeployconf SYNO_Device_Name SYNO_DEVICE_NAME
|
||||
_getdeployconf SYNO_USERNAME
|
||||
_getdeployconf SYNO_PASSWORD
|
||||
_getdeployconf SYNO_DEVICE_ID
|
||||
_getdeployconf SYNO_DEVICE_NAME
|
||||
|
||||
# Prepare to use temp admin if SYNO_USE_TEMP_ADMIN is set
|
||||
_getdeployconf SYNO_USE_TEMP_ADMIN
|
||||
_check2cleardeployconfexp SYNO_USE_TEMP_ADMIN
|
||||
_debug2 SYNO_USE_TEMP_ADMIN "$SYNO_USE_TEMP_ADMIN"
|
||||
|
||||
if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
|
||||
if ! _exists synouser || ! _exists synogroup || ! _exists synosetkeyvalue; then
|
||||
_err "Missing required tools to creat temp admin user, please set SYNO_USERNAME and SYNO_PASSWORD instead."
|
||||
_err "Notice: temp admin user authorization method only supports local deployment on DSM."
|
||||
return 1
|
||||
fi
|
||||
if synouser --help 2>&1 | grep -q 'Permission denied'; then
|
||||
_err "For creating temp admin user, the deploy script must be run as root."
|
||||
return 1
|
||||
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
|
||||
fi
|
||||
_debug2 SYNO_Username "$SYNO_Username"
|
||||
_secure_debug2 SYNO_Password "$SYNO_Password"
|
||||
|
||||
# Optional scheme, hostname, and port for Synology DSM
|
||||
_getdeployconf SYNO_Scheme
|
||||
_getdeployconf SYNO_Hostname
|
||||
_getdeployconf SYNO_Port
|
||||
# Optional scheme, hostname and port for Synology DSM
|
||||
_migratedeployconf SYNO_Scheme SYNO_SCHEME
|
||||
_migratedeployconf SYNO_Hostname SYNO_HOSTNAME
|
||||
_migratedeployconf SYNO_Port SYNO_PORT
|
||||
_getdeployconf SYNO_SCHEME
|
||||
_getdeployconf SYNO_HOSTNAME
|
||||
_getdeployconf SYNO_PORT
|
||||
|
||||
# default vaules for scheme, hostname, and port
|
||||
# defaulting to localhost and http because it's localhost...
|
||||
[ -n "${SYNO_Scheme}" ] || SYNO_Scheme="http"
|
||||
[ -n "${SYNO_Hostname}" ] || SYNO_Hostname="localhost"
|
||||
[ -n "${SYNO_Port}" ] || SYNO_Port="5000"
|
||||
# Default values for scheme, hostname and port
|
||||
# Defaulting to localhost and http, because it's localhost…
|
||||
[ -n "$SYNO_SCHEME" ] || SYNO_SCHEME="http"
|
||||
[ -n "$SYNO_HOSTNAME" ] || SYNO_HOSTNAME="localhost"
|
||||
[ -n "$SYNO_PORT" ] || SYNO_PORT="5000"
|
||||
_savedeployconf SYNO_SCHEME "$SYNO_SCHEME"
|
||||
_savedeployconf SYNO_HOSTNAME "$SYNO_HOSTNAME"
|
||||
_savedeployconf SYNO_PORT "$SYNO_PORT"
|
||||
_debug2 SYNO_SCHEME "$SYNO_SCHEME"
|
||||
_debug2 SYNO_HOSTNAME "$SYNO_HOSTNAME"
|
||||
_debug2 SYNO_PORT "$SYNO_PORT"
|
||||
|
||||
_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 verfiy it's real
|
||||
_getdeployconf SYNO_Certificate
|
||||
_debug SYNO_Certificate "${SYNO_Certificate:-}"
|
||||
# Get the certificate description, but don't save it until we verify it's real
|
||||
_migratedeployconf SYNO_Certificate SYNO_CERTIFICATE "base64"
|
||||
_getdeployconf SYNO_CERTIFICATE
|
||||
_check2cleardeployconfexp SYNO_CERTIFICATE
|
||||
_debug SYNO_CERTIFICATE "${SYNO_CERTIFICATE:-}"
|
||||
|
||||
# shellcheck disable=SC1003 # We are not trying to escape a single quote
|
||||
if printf "%s" "$SYNO_Certificate" | grep '\\'; then
|
||||
if printf "%s" "$SYNO_CERTIFICATE" | grep '\\'; then
|
||||
_err "Do not use a backslash (\) in your certificate description"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_base_url="$SYNO_Scheme://$SYNO_Hostname:$SYNO_Port"
|
||||
_debug "Getting API version..."
|
||||
_base_url="$SYNO_SCHEME://$SYNO_HOSTNAME:$SYNO_PORT"
|
||||
_debug _base_url "$_base_url"
|
||||
|
||||
_debug "Getting API version"
|
||||
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')
|
||||
_debug3 response "$response"
|
||||
_debug3 api_path "$api_path"
|
||||
_debug3 api_version "$api_version"
|
||||
|
||||
# Login, get the token from JSON and session id from cookie
|
||||
_info "Logging into $SYNO_Hostname:$SYNO_Port"
|
||||
encoded_username="$(printf "%s" "$SYNO_Username" | _url_encode)"
|
||||
encoded_password="$(printf "%s" "$SYNO_Password" | _url_encode)"
|
||||
# Login, get the session ID and SynoToken from JSON
|
||||
_info "Logging into $SYNO_HOSTNAME:$SYNO_PORT..."
|
||||
encoded_username="$(printf "%s" "$SYNO_USERNAME" | _url_encode)"
|
||||
encoded_password="$(printf "%s" "$SYNO_PASSWORD" | _url_encode)"
|
||||
|
||||
# ## START ## - DEPRECATED, for backward compatibility
|
||||
_getdeployconf SYNO_TOTP_SECRET
|
||||
|
||||
otp_code=""
|
||||
if [ -n "$SYNO_TOTP_SECRET" ]; then
|
||||
otp_code="$(oathtool --base32 --totp "${SYNO_TOTP_SECRET}" 2>/dev/null)"
|
||||
_info "WARNING: Usage of SYNO_TOTP_SECRET is deprecated!"
|
||||
_info " See synology_dsm.sh script or ACME.sh Wiki page for details:"
|
||||
_info " https://github.com/acmesh-official/acme.sh/wiki/Synology-NAS-Guide"
|
||||
if ! _exists oathtool; then
|
||||
_err "oathtool could not be found, install oathtool to use SYNO_TOTP_SECRET"
|
||||
return 1
|
||||
fi
|
||||
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/$api_path?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 local deployment, though if you are sure that the hostname $SYNO_HOSTNAME is targeting to your **current local machine**, execute 'export SYNO_LOCAL_HOSTNAME=1' then rerun."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_debug "Creating temp admin user in Synology DSM..."
|
||||
if synogroup --help | grep -q '\-\-memberadd '; then
|
||||
_temp_admin_create "$SYNO_USERNAME" "$SYNO_PASSWORD"
|
||||
synogroup --memberadd administrators "$SYNO_USERNAME" >/dev/null
|
||||
elif synogroup --help | grep -q '\-\-member '; then
|
||||
# For supporting DSM 6.x which only has `--member` parameter.
|
||||
cur_admins=$(synogroup --get administrators | awk -F '[][]' '/Group Members/,0{if(NF>1)printf "%s ", $2}')
|
||||
if [ -n "$cur_admins" ]; then
|
||||
_temp_admin_create "$SYNO_USERNAME" "$SYNO_PASSWORD"
|
||||
_secure_debug3 admin_users "$cur_admins$SYNO_USERNAME"
|
||||
# shellcheck disable=SC2086
|
||||
synogroup --member administrators $cur_admins $SYNO_USERNAME >/dev/null
|
||||
else
|
||||
_err "The tool synogroup may be broken, please set SYNO_USERNAME and SYNO_PASSWORD instead."
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
_err "Unsupported synogroup tool detected, please set SYNO_USERNAME and SYNO_PASSWORD instead."
|
||||
return 1
|
||||
fi
|
||||
# havig a workaround to temporary disable enforce 2FA-OTP, will restore
|
||||
# it soon (after a single request), though if any accident occurs like
|
||||
# unexpected interruption, this setting can be easily reverted manually.
|
||||
otp_enforce_option=$(synogetkeyvalue /etc/synoinfo.conf otp_enforce_option)
|
||||
if [ -n "$otp_enforce_option" ] && [ "${otp_enforce_option:-"none"}" != "none" ]; then
|
||||
synosetkeyvalue /etc/synoinfo.conf otp_enforce_option none
|
||||
_info "Enforcing 2FA-OTP has been disabled to complete temp admin authentication."
|
||||
_info "Notice: it will be restored soon, if not, you can restore it manually via Control Panel."
|
||||
_info "previous_otp_enforce_option" "$otp_enforce_option"
|
||||
else
|
||||
otp_enforce_option=""
|
||||
fi
|
||||
fi
|
||||
response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes")
|
||||
if [ -n "$SYNO_USE_TEMP_ADMIN" ] && [ -n "$otp_enforce_option" ]; then
|
||||
synosetkeyvalue /etc/synoinfo.conf otp_enforce_option "$otp_enforce_option"
|
||||
_info "Restored previous enforce 2FA-OTP option."
|
||||
fi
|
||||
_debug3 response "$response"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$SYNO_DID" ]; then
|
||||
_H1="Cookie: did=$SYNO_DID"
|
||||
export _H1
|
||||
_debug3 H1 "${_H1}"
|
||||
error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*')
|
||||
_debug2 error_code "$error_code"
|
||||
# Account has 2FA-OTP enabled, since error 403 reported.
|
||||
# https://global.download.synology.com/download/Document/Software/DeveloperGuide/Os/DSM/All/enu/DSM_Login_Web_API_Guide_enu.pdf
|
||||
if [ "$error_code" == "403" ]; then
|
||||
if [ -z "$SYNO_DEVICE_NAME" ]; then
|
||||
printf "Enter device name or leave empty for default (CertRenewal): "
|
||||
read -r SYNO_DEVICE_NAME
|
||||
[ -n "$SYNO_DEVICE_NAME" ] || SYNO_DEVICE_NAME="CertRenewal"
|
||||
fi
|
||||
|
||||
if [ -n "$SYNO_DEVICE_ID" ]; then
|
||||
# Omit OTP code with SYNO_DEVICE_ID.
|
||||
response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes&device_name=$SYNO_DEVICE_NAME&device_id=$SYNO_DEVICE_ID")
|
||||
_secure_debug3 response "$response"
|
||||
else
|
||||
# Require the OTP code if still unset.
|
||||
if [ -z "$SYNO_OTP_CODE" ]; then
|
||||
printf "Enter OTP code for user '%s': " "$SYNO_USERNAME"
|
||||
read -r SYNO_OTP_CODE
|
||||
fi
|
||||
_secure_debug SYNO_OTP_CODE "${SYNO_OTP_CODE:-}"
|
||||
|
||||
if [ -z "$SYNO_OTP_CODE" ]; then
|
||||
response='{"error":{"code":404}}'
|
||||
else
|
||||
response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=login&format=sid&account=$encoded_username&passwd=$encoded_password&enable_syno_token=yes&enable_device_token=yes&device_name=$SYNO_DEVICE_NAME&otp_code=$SYNO_OTP_CODE")
|
||||
_secure_debug3 response "$response"
|
||||
|
||||
id_property='device_id'
|
||||
[ "${api_version}" -gt '6' ] || id_property='did'
|
||||
SYNO_DEVICE_ID=$(echo "$response" | grep "$id_property" | sed -n 's/.*"'$id_property'" *: *"\([^"]*\).*/\1/p')
|
||||
_secure_debug2 SYNO_DEVICE_ID "$SYNO_DEVICE_ID"
|
||||
fi
|
||||
fi
|
||||
error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*')
|
||||
_debug2 error_code "$error_code"
|
||||
fi
|
||||
|
||||
response=$(_post "method=login&account=$encoded_username&passwd=$encoded_password&api=SYNO.API.Auth&version=$api_version&enable_syno_token=yes&otp_code=$otp_code" "$_base_url/webapi/auth.cgi?enable_syno_token=yes")
|
||||
token=$(echo "$response" | grep "synotoken" | sed -n 's/.*"synotoken" *: *"\([^"]*\).*/\1/p')
|
||||
_debug3 response "$response"
|
||||
_debug token "$token"
|
||||
|
||||
if [ -z "$token" ]; then
|
||||
_err "Unable to authenticate to $SYNO_Hostname:$SYNO_Port using $SYNO_Scheme."
|
||||
_err "Check your username and password."
|
||||
_err "If two-factor authentication is enabled for the user, set SYNO_TOTP_SECRET."
|
||||
if [ -n "$error_code" ]; then
|
||||
if [ "$error_code" == "403" ] && [ -n "$SYNO_DEVICE_ID" ]; then
|
||||
_cleardeployconf SYNO_DEVICE_ID
|
||||
_err "Failed to authenticate with SYNO_DEVICE_ID (may expired or invalid), please try again in a new terminal window."
|
||||
elif [ "$error_code" == "404" ]; then
|
||||
_err "Failed to authenticate with provided 2FA-OTP code, please try again in a new terminal window."
|
||||
elif [ "$error_code" == "406" ]; then
|
||||
if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
|
||||
_err "Failed with unexcepted error, please report this by providing full log with '--debug 3'."
|
||||
else
|
||||
_err "Enforce auth with 2FA-OTP enabled, please configure the user to enable 2FA-OTP to continue."
|
||||
fi
|
||||
elif [ "$error_code" == "400" ]; then
|
||||
_err "Failed to authenticate, no such account or incorrect password."
|
||||
elif [ "$error_code" == "401" ]; then
|
||||
_err "Failed to authenticate with a non-existent account."
|
||||
elif [ "$error_code" == "408" ] || [ "$error_code" == "409" ] || [ "$error_code" == "410" ]; then
|
||||
_err "Failed to authenticate, the account password has expired or must be changed."
|
||||
else
|
||||
_err "Failed to authenticate with error: $error_code."
|
||||
fi
|
||||
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||
return 1
|
||||
fi
|
||||
|
||||
sid=$(echo "$response" | grep "sid" | sed -n 's/.*"sid" *: *"\([^"]*\).*/\1/p')
|
||||
token=$(echo "$response" | grep "synotoken" | sed -n 's/.*"synotoken" *: *"\([^"]*\).*/\1/p')
|
||||
_debug "Session ID" "$sid"
|
||||
_debug SynoToken "$token"
|
||||
if [ -z "$sid" ] || [ -z "$token" ]; then
|
||||
# Still can't get necessary info even got no errors, may Synology have API updated?
|
||||
_err "Unable to authenticate to $_base_url, you may report this by providing full log with '--debug 3'."
|
||||
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_H1="X-SYNO-TOKEN: $token"
|
||||
export _H1
|
||||
_debug2 H1 "${_H1}"
|
||||
|
||||
# Now that we know the username and password are good, save them
|
||||
_savedeployconf SYNO_Username "$SYNO_Username"
|
||||
_savedeployconf SYNO_Password "$SYNO_Password"
|
||||
_savedeployconf SYNO_DID "$SYNO_DID"
|
||||
_savedeployconf SYNO_TOTP_SECRET "$SYNO_TOTP_SECRET"
|
||||
# Now that we know the username and password are good, save them if not in temp admin mode.
|
||||
if [ -n "$SYNO_USE_TEMP_ADMIN" ]; then
|
||||
_cleardeployconf SYNO_USERNAME
|
||||
_cleardeployconf SYNO_PASSWORD
|
||||
_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")
|
||||
_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"
|
||||
id=$(echo "$response" | sed -n "s/.*\"desc\":\"$escaped_certificate\",\"id\":\"\([^\"]*\).*/\1/p")
|
||||
_debug2 id "$id"
|
||||
|
||||
if [ -z "$id" ] && [ -z "${SYNO_Create:-}" ]; then
|
||||
_err "Unable to find certificate: $SYNO_Certificate and \$SYNO_Create is not set"
|
||||
error_code=$(echo "$response" | grep '"error":' | grep -o '"code":[0-9]*' | grep -o '[0-9]*')
|
||||
_debug2 error_code "$error_code"
|
||||
if [ -n "$error_code" ]; then
|
||||
if [ "$error_code" -eq 105 ]; then
|
||||
_err "Current user is not administrator and does not have sufficient permission for deploying."
|
||||
else
|
||||
_err "Failed to fetch certificate info: $error_code, please try again or contact Synology to learn more."
|
||||
fi
|
||||
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# we've verified this certificate description is a thing, so save it
|
||||
_savedeployconf SYNO_Certificate "$SYNO_Certificate" "base64"
|
||||
_migratedeployconf SYNO_Create SYNO_CREATE
|
||||
_getdeployconf SYNO_CREATE
|
||||
_debug2 SYNO_CREATE "$SYNO_CREATE"
|
||||
|
||||
_info "Generate form POST request"
|
||||
if [ -z "$id" ] && [ -z "$SYNO_CREATE" ]; then
|
||||
_err "Unable to find certificate: $SYNO_CERTIFICATE and $SYNO_CREATE is not set."
|
||||
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# We've verified this certificate description is a thing, so save it
|
||||
_savedeployconf SYNO_CERTIFICATE "$SYNO_CERTIFICATE" "base64"
|
||||
|
||||
_info "Generating form POST request..."
|
||||
nl="\0015\0012"
|
||||
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="$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=\"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
|
||||
_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"
|
||||
else
|
||||
_debug2 default "this is NOT the default certificate"
|
||||
_debug2 default "This is NOT the default certificate"
|
||||
fi
|
||||
content="$content${nl}--$delim--${nl}"
|
||||
content="$(printf "%b_" "$content")"
|
||||
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}")
|
||||
_debug3 response "$response"
|
||||
|
||||
if ! echo "$response" | grep '"error":' >/dev/null; then
|
||||
if echo "$response" | grep '"restart_httpd":true' >/dev/null; then
|
||||
_info "http services were restarted"
|
||||
_info "Restart HTTP services succeeded."
|
||||
else
|
||||
_info "http services were NOT restarted"
|
||||
_info "Restart HTTP services failed."
|
||||
fi
|
||||
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||
_logout
|
||||
return 0
|
||||
else
|
||||
_err "Unable to update certificate, error code $response"
|
||||
_temp_admin_cleanup "$SYNO_USE_TEMP_ADMIN" "$SYNO_USERNAME"
|
||||
_err "Unable to update certificate, got error response: $response."
|
||||
_logout
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
_logout() {
|
||||
# Logout CERT user only to not occupy a permanent session, e.g. in DSM's "Connected Users" widget (based on previous variables)
|
||||
response=$(_get "$_base_url/webapi/$api_path?api=SYNO.API.Auth&version=$api_version&method=logout&_sid=$sid")
|
||||
_debug3 response "$response"
|
||||
}
|
||||
|
||||
_temp_admin_create() {
|
||||
_username="$1"
|
||||
_password="$2"
|
||||
synouser --del "$_username" >/dev/null 2>/dev/null
|
||||
synouser --add "$_username" "$_password" "" 0 "scruelt@hotmail.com" 0 >/dev/null
|
||||
}
|
||||
|
||||
_temp_admin_cleanup() {
|
||||
_flag=$1
|
||||
_username=$2
|
||||
|
||||
if [ -n "${_flag}" ]; then
|
||||
_debug "Cleanuping temp admin info..."
|
||||
synouser --del "$_username" >/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
#_cleardeployconf key
|
||||
_cleardeployconf() {
|
||||
_cleardomainconf "SAVED_$1"
|
||||
}
|
||||
|
||||
# key
|
||||
_check2cleardeployconfexp() {
|
||||
_key="$1"
|
||||
_clear_key="CLEAR_$_key"
|
||||
# Clear saved settings if explicitly requested
|
||||
if [ -n "$(eval echo \$"$_clear_key")" ]; then
|
||||
_debug2 "$_key: value cleared from config, exported value will be ignored."
|
||||
_cleardeployconf "$_key"
|
||||
eval "$_key"=
|
||||
export "$_key"=
|
||||
eval SAVED_"$_key"=
|
||||
export SAVED_"$_key"=
|
||||
fi
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ truenas_deploy() {
|
||||
_getdeployconf DEPLOY_TRUENAS_APIKEY
|
||||
|
||||
if [ -z "$DEPLOY_TRUENAS_APIKEY" ]; then
|
||||
_err "TrueNAS Api Key is not found, please define DEPLOY_TRUENAS_APIKEY."
|
||||
_err "TrueNAS API key not found, please set the DEPLOY_TRUENAS_APIKEY environment variable."
|
||||
return 1
|
||||
fi
|
||||
_secure_debug2 DEPLOY_TRUENAS_APIKEY "$DEPLOY_TRUENAS_APIKEY"
|
||||
@ -62,15 +62,14 @@ truenas_deploy() {
|
||||
|
||||
_info "Testing Connection TrueNAS"
|
||||
_response=$(_get "$_api_url/system/state")
|
||||
_info "TrueNAS System State: $_response."
|
||||
_info "TrueNAS system state: $_response."
|
||||
|
||||
if [ -z "$_response" ]; then
|
||||
_err "Unable to authenticate to $_api_url."
|
||||
_err 'Check your Connection and set DEPLOY_TRUENAS_HOSTNAME="192.168.178.x".'
|
||||
_err 'or'
|
||||
_err 'set DEPLOY_TRUENAS_HOSTNAME="<truenas_dnsname>".'
|
||||
_err 'Check your Connection and set DEPLOY_TRUENAS_SCHEME="https".'
|
||||
_err "Check your Api Key."
|
||||
_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
|
||||
|
||||
@ -78,7 +77,7 @@ truenas_deploy() {
|
||||
_savedeployconf DEPLOY_TRUENAS_HOSTNAME "$DEPLOY_TRUENAS_HOSTNAME"
|
||||
_savedeployconf DEPLOY_TRUENAS_SCHEME "$DEPLOY_TRUENAS_SCHEME"
|
||||
|
||||
_info "Getting active certificate from TrueNAS"
|
||||
_info "Getting current active certificate from TrueNAS"
|
||||
_response=$(_get "$_api_url/system/general")
|
||||
_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')
|
||||
@ -88,14 +87,14 @@ truenas_deploy() {
|
||||
_debug Active_UI_http_redirect "$_param_httpsredirect"
|
||||
|
||||
if [ "$DEPLOY_TRUENAS_SCHEME" = "http" ] && [ "$_param_httpsredirect" = "true" ]; then
|
||||
_info "http Redirect active"
|
||||
_info "HTTP->HTTPS redirection is enabled"
|
||||
_info "Setting DEPLOY_TRUENAS_SCHEME to 'https'"
|
||||
DEPLOY_TRUENAS_SCHEME="https"
|
||||
_api_url="$DEPLOY_TRUENAS_SCHEME://$DEPLOY_TRUENAS_HOSTNAME/api/v2.0"
|
||||
_savedeployconf DEPLOY_TRUENAS_SCHEME "$DEPLOY_TRUENAS_SCHEME"
|
||||
fi
|
||||
|
||||
_info "Upload new certifikate to TrueNAS"
|
||||
_info "Uploading new certificate to TrueNAS"
|
||||
_certname="Letsencrypt_$(_utc_date | tr ' ' '_' | tr -d -- ':')"
|
||||
_debug3 _certname "$_certname"
|
||||
|
||||
@ -104,30 +103,30 @@ truenas_deploy() {
|
||||
|
||||
_debug3 _add_cert_result "$_add_cert_result"
|
||||
|
||||
_info "Getting Certificate list to get new Cert ID"
|
||||
_info "Fetching list of installed certificates"
|
||||
_cert_list=$(_get "$_api_url/system/general/ui_certificate_choices")
|
||||
_cert_id=$(echo "$_cert_list" | grep "$_certname" | sed -n 's/.*"\([0-9]\{1,\}\)".*$/\1/p')
|
||||
|
||||
_debug3 _cert_id "$_cert_id"
|
||||
|
||||
_info "Activate Certificate 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 "Check if WebDAV certificate is the same as the WEB UI"
|
||||
_info "Checking if WebDAV certificate is the same as the TrueNAS web UI"
|
||||
_webdav_list=$(_get "$_api_url/webdav")
|
||||
_webdav_cert_id=$(echo "$_webdav_list" | grep '"certssl":' | tr -d -- '"certsl: ,')
|
||||
|
||||
if [ "$_webdav_cert_id" = "$_active_cert_id" ]; then
|
||||
_info "Update the WebDAV Certificate"
|
||||
_info "Updating the WebDAV certificate"
|
||||
_debug _webdav_cert_id "$_webdav_cert_id"
|
||||
_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 | sed -n 's/.*: \([0-9]\{1,\}\) }$/\1/p')
|
||||
_webdav_new_cert_id=$(echo "$_activate_webdav_cert" | _json_decode | grep '"certssl":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
|
||||
if [ "$_webdav_new_cert_id" -eq "$_cert_id" ]; then
|
||||
_info "WebDAV Certificate update successfully"
|
||||
_info "WebDAV certificate updated successfully"
|
||||
else
|
||||
_err "Unable to set WebDAV certificate"
|
||||
_debug3 _activate_webdav_cert "$_activate_webdav_cert"
|
||||
@ -136,21 +135,21 @@ truenas_deploy() {
|
||||
fi
|
||||
_debug3 _webdav_new_cert_id "$_webdav_new_cert_id"
|
||||
else
|
||||
_info "WebDAV certificate not set or not the same as Web UI"
|
||||
_info "WebDAV certificate is not configured or is not the same as TrueNAS web UI"
|
||||
fi
|
||||
|
||||
_info "Check if FTP certificate is the same as the WEB UI"
|
||||
_info "Checking if FTP certificate is the same as the TrueNAS web UI"
|
||||
_ftp_list=$(_get "$_api_url/ftp")
|
||||
_ftp_cert_id=$(echo "$_ftp_list" | grep '"ssltls_certificate":' | tr -d -- '"certislfa:_ ,')
|
||||
|
||||
if [ "$_ftp_cert_id" = "$_active_cert_id" ]; then
|
||||
_info "Update the FTP Certificate"
|
||||
_info "Updating the FTP certificate"
|
||||
_debug _ftp_cert_id "$_ftp_cert_id"
|
||||
_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 | sed -n 's/.*: \([0-9]\{1,\}\) }$/\1/p')
|
||||
_ftp_new_cert_id=$(echo "$_activate_ftp_cert" | _json_decode | grep '"ssltls_certificate":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
|
||||
if [ "$_ftp_new_cert_id" -eq "$_cert_id" ]; then
|
||||
_info "FTP Certificate update successfully"
|
||||
_info "FTP certificate updated successfully"
|
||||
else
|
||||
_err "Unable to set FTP certificate"
|
||||
_debug3 _activate_ftp_cert "$_activate_ftp_cert"
|
||||
@ -159,22 +158,66 @@ truenas_deploy() {
|
||||
fi
|
||||
_debug3 _activate_ftp_cert "$_activate_ftp_cert"
|
||||
else
|
||||
_info "FTP certificate not set or not the same as Web UI"
|
||||
_info "FTP certificate is not configured or is not the same as TrueNAS web UI"
|
||||
fi
|
||||
|
||||
_info "Delete old Certificate"
|
||||
_info "Checking if S3 certificate is the same as the TrueNAS web UI"
|
||||
_s3_list=$(_get "$_api_url/s3")
|
||||
_s3_cert_id=$(echo "$_s3_list" | grep '"certificate":' | tr -d -- '"certifa:_ ,')
|
||||
|
||||
if [ "$_s3_cert_id" = "$_active_cert_id" ]; then
|
||||
_info "Updating the S3 certificate"
|
||||
_debug _s3_cert_id "$_s3_cert_id"
|
||||
_s3_data="{\"certificate\": \"${_cert_id}\"}"
|
||||
_activate_s3_cert="$(_post "$_s3_data" "$_api_url/s3" "" "PUT" "application/json")"
|
||||
_s3_new_cert_id=$(echo "$_activate_s3_cert" | _json_decode | grep '"certificate":' | sed -n 's/.*: \([0-9]\{1,\}\),\{0,1\}$/\1/p')
|
||||
if [ "$_s3_new_cert_id" -eq "$_cert_id" ]; then
|
||||
_info "S3 certificate updated successfully"
|
||||
else
|
||||
_err "Unable to set S3 certificate"
|
||||
_debug3 _activate_s3_cert "$_activate_s3_cert"
|
||||
_debug3 _s3_new_cert_id "$_s3_new_cert_id"
|
||||
return 1
|
||||
fi
|
||||
_debug3 _activate_s3_cert "$_activate_s3_cert"
|
||||
else
|
||||
_info "S3 certificate is not configured or is not the same as TrueNAS web UI"
|
||||
fi
|
||||
|
||||
_info "Checking if any chart release Apps is using the same certificate as TrueNAS web UI. Tool 'jq' is required"
|
||||
if _exists jq; then
|
||||
_info "Query all chart release"
|
||||
_release_list=$(_get "$_api_url/chart/release")
|
||||
_related_name_list=$(printf "%s" "$_release_list" | jq -r "[.[] | {name,certId: .config.ingress?.main.tls[]?.scaleCert} | select(.certId==$_active_cert_id) | .name ] | unique")
|
||||
_release_length=$(printf "%s" "$_related_name_list" | jq -r "length")
|
||||
_info "Found $_release_length related chart release in list: $_related_name_list"
|
||||
for i in $(seq 0 $((_release_length - 1))); do
|
||||
_release_name=$(echo "$_related_name_list" | jq -r ".[$i]")
|
||||
_info "Updating certificate from $_active_cert_id to $_cert_id for chart release: $_release_name"
|
||||
#Read the chart release configuration
|
||||
_chart_config=$(printf "%s" "$_release_list" | jq -r ".[] | select(.name==\"$_release_name\")")
|
||||
#Replace the old certificate id with the new one in path .config.ingress.main.tls[].scaleCert. Then update .config.ingress
|
||||
_updated_chart_config=$(printf "%s" "$_chart_config" | jq "(.config.ingress?.main.tls[]? | select(.scaleCert==$_active_cert_id) | .scaleCert ) |= $_cert_id | .config.ingress ")
|
||||
_update_chart_result="$(_post "{\"values\" : { \"ingress\" : $_updated_chart_config } }" "$_api_url/chart/release/id/$_release_name" "" "PUT" "application/json")"
|
||||
_debug3 _update_chart_result "$_update_chart_result"
|
||||
done
|
||||
else
|
||||
_info "Tool 'jq' does not exists, skip chart release checking"
|
||||
fi
|
||||
|
||||
_info "Deleting old certificate"
|
||||
_delete_result="$(_post "" "$_api_url/certificate/id/$_active_cert_id" "" "DELETE" "application/json")"
|
||||
|
||||
_debug3 _delete_result "$_delete_result"
|
||||
|
||||
_info "Reload WebUI from TrueNAS"
|
||||
_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 "Certupdate was not succesfull, please use --debug"
|
||||
_err "Certificate update was not succesful, please try again with --debug"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
@ -7,13 +7,16 @@
|
||||
#
|
||||
# VAULT_PREFIX - this contains the prefix path in vault
|
||||
# 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
|
||||
# to access the vault server
|
||||
|
||||
#returns 0 means success, otherwise error.
|
||||
|
||||
######## Public functions #####################
|
||||
######## Public functions #####################
|
||||
|
||||
#domain keyfile certfile cafile fullchain
|
||||
vault_deploy() {
|
||||
@ -45,33 +48,83 @@ vault_deploy() {
|
||||
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_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.
|
||||
# So replacing new-lines with "\n" here
|
||||
_ckey=$(sed -z 's/\n/\\n/g' <"$2")
|
||||
_ccert=$(sed -z 's/\n/\\n/g' <"$3")
|
||||
_cca=$(sed -z 's/\n/\\n/g' <"$4")
|
||||
_cfullchain=$(sed -z 's/\n/\\n/g' <"$5")
|
||||
_ckey=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$2")
|
||||
_ccert=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$3")
|
||||
_cca=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$4")
|
||||
_cfullchain=$(sed -e ':a' -e N -e '$ ! ba' -e 's/\n/\\n/g' <"$5")
|
||||
|
||||
URL="$VAULT_ADDR/v1/$VAULT_PREFIX/$_cdomain"
|
||||
export _H1="X-Vault-Token: $VAULT_TOKEN"
|
||||
|
||||
if [ -n "$FABIO" ]; then
|
||||
if [ -n "$VAULT_RENEW_TOKEN" ]; then
|
||||
URL="$VAULT_ADDR/v1/auth/token/renew-self"
|
||||
_info "Renew the Vault token to default TTL"
|
||||
if ! _post "" "$URL" >/dev/null; then
|
||||
_err "Failed to renew the Vault token"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
URL="$VAULT_ADDR/v1/$VAULT_PREFIX/$_cdomain"
|
||||
|
||||
if [ -n "$VAULT_FABIO_MODE" ]; then
|
||||
_info "Writing certificate and key to $URL in Fabio mode"
|
||||
if [ -n "$VAULT_KV_V2" ]; then
|
||||
_post "{ \"data\": {\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"} }" "$URL"
|
||||
_post "{ \"data\": {\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"} }" "$URL" >/dev/null || return 1
|
||||
else
|
||||
_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL"
|
||||
_post "{\"cert\": \"$_cfullchain\", \"key\": \"$_ckey\"}" "$URL" >/dev/null || return 1
|
||||
fi
|
||||
else
|
||||
if [ -n "$VAULT_KV_V2" ]; then
|
||||
_post "{\"data\": {\"value\": \"$_ccert\"}}" "$URL/cert.pem"
|
||||
_post "{\"data\": {\"value\": \"$_ckey\"}}" "$URL/cert.key"
|
||||
_post "{\"data\": {\"value\": \"$_cca\"}}" "$URL/chain.pem"
|
||||
_post "{\"data\": {\"value\": \"$_cfullchain\"}}" "$URL/fullchain.pem"
|
||||
_info "Writing certificate to $URL/cert.pem"
|
||||
_post "{\"data\": {\"value\": \"$_ccert\"}}" "$URL/cert.pem" >/dev/null || return 1
|
||||
_info "Writing key to $URL/cert.key"
|
||||
_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
|
||||
_post "{\"value\": \"$_ccert\"}" "$URL/cert.pem"
|
||||
_post "{\"value\": \"$_ckey\"}" "$URL/cert.key"
|
||||
_post "{\"value\": \"$_cca\"}" "$URL/chain.pem"
|
||||
_post "{\"value\": \"$_cfullchain\"}" "$URL/fullchain.pem"
|
||||
_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
|
||||
|
||||
|
@ -8,6 +8,8 @@
|
||||
#
|
||||
# VAULT_PREFIX - this contains the prefix path in vault
|
||||
# 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
|
||||
# `vault auth` has applied the appropriate authorization for the vault binary
|
||||
@ -33,15 +35,36 @@ vault_cli_deploy() {
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
# validate required env vars
|
||||
_getdeployconf VAULT_PREFIX
|
||||
if [ -z "$VAULT_PREFIX" ]; then
|
||||
_err "VAULT_PREFIX needs to be defined (contains prefix path in vault)"
|
||||
return 1
|
||||
fi
|
||||
_savedeployconf VAULT_PREFIX "$VAULT_PREFIX"
|
||||
|
||||
_getdeployconf VAULT_ADDR
|
||||
if [ -z "$VAULT_ADDR" ]; then
|
||||
_err "VAULT_ADDR needs to be defined (contains vault connection address)"
|
||||
return 1
|
||||
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)
|
||||
if [ ! $? ]; then
|
||||
@ -49,13 +72,33 @@ vault_cli_deploy() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -n "$FABIO" ]; then
|
||||
if [ -n "$VAULT_RENEW_TOKEN" ]; then
|
||||
_info "Renew the Vault token to default TTL"
|
||||
if ! $VAULT_CMD token renew; then
|
||||
_err "Failed to renew the Vault token"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$VAULT_FABIO_MODE" ]; then
|
||||
_info "Writing certificate and key to ${VAULT_PREFIX}/${_cdomain} in Fabio mode"
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}" cert=@"$_cfullchain" key=@"$_ckey" || return 1
|
||||
else
|
||||
_info "Writing certificate to ${VAULT_PREFIX}/${_cdomain}/cert.pem"
|
||||
$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}/chain.pem" value=@"$_cca" || return 1
|
||||
_info "Writing CA certificate to ${VAULT_PREFIX}/${_cdomain}/ca.pem"
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/ca.pem" value=@"$_cca" || return 1
|
||||
_info "Writing full-chain certificate to ${VAULT_PREFIX}/${_cdomain}/fullchain.pem"
|
||||
$VAULT_CMD kv put "${VAULT_PREFIX}/${_cdomain}/fullchain.pem" value=@"$_cfullchain" || return 1
|
||||
|
||||
# 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
|
||||
|
||||
}
|
||||
|
@ -1,48 +1,44 @@
|
||||
#!/usr/bin/env sh
|
||||
#This file name is "dns_1984hosting.sh"
|
||||
#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.
|
||||
#returns 0 means success, otherwise error.
|
||||
# shellcheck disable=SC2034
|
||||
dns_1984hosting_info='1984.hosting
|
||||
Domains: 1984.is
|
||||
Site: 1984.hosting
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_1984hosting
|
||||
Options:
|
||||
One984HOSTING_Username Username
|
||||
One984HOSTING_Password Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2851
|
||||
Author: Adrian Fedoreanu
|
||||
'
|
||||
|
||||
#Author: Adrian Fedoreanu
|
||||
#Report Bugs here: https://github.com/acmesh-official/acme.sh
|
||||
# or here... https://github.com/acmesh-official/acme.sh/issues/2851
|
||||
#
|
||||
######## Public functions #####################
|
||||
######## Public functions #####################
|
||||
|
||||
# Export 1984HOSTING username and password in following variables
|
||||
#
|
||||
# One984HOSTING_Username=username
|
||||
# One984HOSTING_Password=password
|
||||
#
|
||||
# sessionid cookie is saved in ~/.acme.sh/account.conf
|
||||
# username/password need to be set only when changed.
|
||||
|
||||
#Usage: dns_1984hosting_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Usage: dns_1984hosting_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Add a text record.
|
||||
dns_1984hosting_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_info "Add TXT record using 1984Hosting"
|
||||
_info "Add TXT record using 1984Hosting."
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
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
|
||||
fi
|
||||
|
||||
_debug "First detect the root zone"
|
||||
_debug "First detect the root zone."
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain" "$fulldomain"
|
||||
_err "Invalid domain '$fulldomain'."
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_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)"
|
||||
url="https://management.1984hosting.com/domains/entry/"
|
||||
url="https://1984.hosting/domains/entry/"
|
||||
|
||||
postdata="entry=new"
|
||||
postdata="$postdata&type=TXT"
|
||||
@ -53,92 +49,96 @@ dns_1984hosting_add() {
|
||||
_debug2 postdata "$postdata"
|
||||
|
||||
_authpost "$postdata" "$url"
|
||||
response="$(echo "$_response" | _normalizeJson)"
|
||||
_debug2 response "$response"
|
||||
|
||||
if _contains "$response" '"haserrors": true'; then
|
||||
_err "1984Hosting failed to add TXT record for $_sub_domain bad RC from _post"
|
||||
if _contains "$_response" '"haserrors": true'; then
|
||||
_err "1984Hosting failed to add TXT record for $_sub_domain bad RC from _post."
|
||||
return 1
|
||||
elif _contains "$response" "html>"; then
|
||||
_err "1984Hosting failed to add TXT record for $_sub_domain. Check $HTTP_HEADER file"
|
||||
elif _contains "$_response" "html>"; then
|
||||
_err "1984Hosting failed to add TXT record for $_sub_domain. Check $HTTP_HEADER file."
|
||||
return 1
|
||||
elif _contains "$response" '"auth": false'; then
|
||||
_err "1984Hosting failed to add TXT record for $_sub_domain. Invalid or expired cookie"
|
||||
elif _contains "$_response" '"auth": false'; then
|
||||
_err "1984Hosting failed to add TXT record for $_sub_domain. Invalid or expired cookie."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Added acme challenge TXT record for $fulldomain at 1984Hosting"
|
||||
_info "Added acme challenge TXT record for $fulldomain at 1984Hosting."
|
||||
return 0
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
# Usage: fulldomain txtvalue
|
||||
# Remove the txt record after validation.
|
||||
dns_1984hosting_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_info "Delete TXT record using 1984Hosting"
|
||||
_info "Delete TXT record using 1984Hosting."
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
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
|
||||
fi
|
||||
|
||||
_debug "First detect the root zone"
|
||||
_debug "First detect the root zone."
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain" "$fulldomain"
|
||||
_err "Invalid domain '$fulldomain'."
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
_debug "Delete $fulldomain TXT record"
|
||||
_debug "Delete $fulldomain TXT record."
|
||||
|
||||
url="https://management.1984hosting.com/domains"
|
||||
url="https://1984.hosting/domains"
|
||||
if ! _get_zone_id "$url" "$_domain"; then
|
||||
_err "invalid zone" "$_domain"
|
||||
_err "Invalid zone '$_domain'."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_htmlget "$url/$_zone_id" "$txtvalue"
|
||||
_debug2 _response "$_response"
|
||||
entry_id="$(echo "$_response" | _egrep_o 'entry_[0-9]+' | sed 's/entry_//')"
|
||||
_debug2 entry_id "$entry_id"
|
||||
if [ -z "$entry_id" ]; then
|
||||
_err "Error getting TXT entry_id for $1"
|
||||
_err "Error getting TXT entry_id for $1."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_authpost "entry=$entry_id" "$url/delentry/"
|
||||
response="$(echo "$_response" | _normalizeJson)"
|
||||
_debug2 response "$response"
|
||||
|
||||
if ! _contains "$response" '"ok": true'; then
|
||||
_err "1984Hosting failed to delete TXT record for $entry_id bad RC from _post"
|
||||
if ! _contains "$_response" '"ok": true'; then
|
||||
_err "1984Hosting failed to delete TXT record for $entry_id bad RC from _post."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Deleted acme challenge TXT record for $fulldomain at 1984Hosting"
|
||||
_info "Deleted acme challenge TXT record for $fulldomain at 1984Hosting."
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
# usage: _1984hosting_login username password
|
||||
# returns 0 success
|
||||
_1984hosting_login() {
|
||||
if ! _check_credentials; then return 1; fi
|
||||
|
||||
if _check_cookies; then
|
||||
_debug "Already logged in"
|
||||
_debug "Already logged in."
|
||||
return 0
|
||||
fi
|
||||
|
||||
_debug "Login to 1984Hosting as user $One984HOSTING_Username"
|
||||
_debug "Login to 1984Hosting as user $One984HOSTING_Username."
|
||||
username=$(printf '%s' "$One984HOSTING_Username" | _url_encode)
|
||||
password=$(printf '%s' "$One984HOSTING_Password" | _url_encode)
|
||||
url="https://management.1984hosting.com/accounts/checkuserauth/"
|
||||
url="https://1984.hosting/api/auth/"
|
||||
|
||||
_get "https://1984.hosting/accounts/login/" | grep "csrfmiddlewaretoken"
|
||||
csrftoken="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'csrftoken=[^;]*;' | tr -d ';')"
|
||||
sessionid="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'sessionid=[^;]*;' | tr -d ';')"
|
||||
|
||||
if [ -z "$csrftoken" ] || [ -z "$sessionid" ]; then
|
||||
_err "One or more cookies are empty: '$csrftoken', '$sessionid'."
|
||||
return 1
|
||||
fi
|
||||
|
||||
export _H1="Cookie: $csrftoken; $sessionid"
|
||||
export _H2="Referer: https://1984.hosting/accounts/login/"
|
||||
csrf_header=$(echo "$csrftoken" | sed 's/csrftoken=//' | _head_n 1)
|
||||
export _H3="X-CSRFToken: $csrf_header"
|
||||
|
||||
response="$(_post "username=$username&password=$password&otpkey=" $url)"
|
||||
response="$(echo "$response" | _normalizeJson)"
|
||||
@ -149,6 +149,8 @@ _1984hosting_login() {
|
||||
One984HOSTING_CSRFTOKEN_COOKIE="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _egrep_o 'csrftoken=[^;]*;' | tr -d ';')"
|
||||
export One984HOSTING_SESSIONID_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
|
||||
@ -157,9 +159,13 @@ _1984hosting_login() {
|
||||
}
|
||||
|
||||
_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
|
||||
One984HOSTING_Username=""
|
||||
One984HOSTING_Password=""
|
||||
_clearaccountconf_mutable One984HOSTING_Username
|
||||
_clearaccountconf_mutable One984HOSTING_Password
|
||||
_err "You haven't specified 1984Hosting username or password yet."
|
||||
_err "Please export as One984HOSTING_Username / One984HOSTING_Password and try again."
|
||||
return 1
|
||||
@ -171,42 +177,43 @@ _check_cookies() {
|
||||
One984HOSTING_SESSIONID_COOKIE="${One984HOSTING_SESSIONID_COOKIE:-$(_readaccountconf_mutable One984HOSTING_SESSIONID_COOKIE)}"
|
||||
One984HOSTING_CSRFTOKEN_COOKIE="${One984HOSTING_CSRFTOKEN_COOKIE:-$(_readaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE)}"
|
||||
if [ -z "$One984HOSTING_SESSIONID_COOKIE" ] || [ -z "$One984HOSTING_CSRFTOKEN_COOKIE" ]; then
|
||||
_debug "No cached cookie(s) found"
|
||||
_debug "No cached cookie(s) found."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_authget "https://management.1984hosting.com/accounts/loginstatus/"
|
||||
if _contains "$response" '"ok": true'; then
|
||||
_debug "Cached cookies still valid"
|
||||
_authget "https://1984.hosting/api/auth/"
|
||||
if _contains "$_response" '"ok": true'; then
|
||||
_debug "Cached cookies still valid."
|
||||
return 0
|
||||
fi
|
||||
_debug "Cached cookies no longer valid"
|
||||
|
||||
_debug "Cached cookies no longer valid. Clearing cookies."
|
||||
One984HOSTING_SESSIONID_COOKIE=""
|
||||
One984HOSTING_CSRFTOKEN_COOKIE=""
|
||||
_saveaccountconf_mutable One984HOSTING_SESSIONID_COOKIE "$One984HOSTING_SESSIONID_COOKIE"
|
||||
_saveaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE "$One984HOSTING_CSRFTOKEN_COOKIE"
|
||||
_clearaccountconf_mutable One984HOSTING_SESSIONID_COOKIE
|
||||
_clearaccountconf_mutable One984HOSTING_CSRFTOKEN_COOKIE
|
||||
return 1
|
||||
}
|
||||
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _acme-challenge.www.domain.com
|
||||
# Returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain="$1"
|
||||
i=1
|
||||
p=1
|
||||
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
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
_authget "https://management.1984hosting.com/domains/soacheck/?zone=$h&nameserver=ns0.1984.is."
|
||||
if _contains "$_response" "serial" && ! _contains "$_response" "null"; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_authget "https://1984.hosting/domains/zonestatus/$h/?cached=no"
|
||||
if _contains "$_response" '"ok": true'; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
@ -216,46 +223,46 @@ _get_root() {
|
||||
return 1
|
||||
}
|
||||
|
||||
#usage: _get_zone_id url domain.com
|
||||
#returns zone id for domain.com
|
||||
# Usage: _get_zone_id url domain.com
|
||||
# Returns zone id for domain.com
|
||||
_get_zone_id() {
|
||||
url=$1
|
||||
domain=$2
|
||||
_htmlget "$url" "$domain"
|
||||
_debug2 _response "$_response"
|
||||
_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"
|
||||
_err "Error getting _zone_id for $2."
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# add extra headers to request
|
||||
# Add extra headers to request
|
||||
_authget() {
|
||||
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE;$One984HOSTING_SESSIONID_COOKIE"
|
||||
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE; $One984HOSTING_SESSIONID_COOKIE"
|
||||
_response=$(_get "$1" | _normalizeJson)
|
||||
_debug2 _response "$_response"
|
||||
}
|
||||
|
||||
# truncate huge HTML response
|
||||
# echo: Argument list too long
|
||||
# Truncate huge HTML response
|
||||
_htmlget() {
|
||||
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE;$One984HOSTING_SESSIONID_COOKIE"
|
||||
export _H1="Cookie: $One984HOSTING_CSRFTOKEN_COOKIE; $One984HOSTING_SESSIONID_COOKIE"
|
||||
_response=$(_get "$1" | grep "$2")
|
||||
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() {
|
||||
url="https://management.1984hosting.com/domains"
|
||||
url="https://1984.hosting/domains"
|
||||
_get_zone_id "$url" "$_domain"
|
||||
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://management.1984hosting.com/domains/$_zone_id"
|
||||
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")
|
||||
_response="$(_post "$1" "$2" | _normalizeJson)"
|
||||
_debug2 _response "$_response"
|
||||
}
|
||||
|
@ -1,18 +1,18 @@
|
||||
#!/usr/bin/env sh
|
||||
#
|
||||
#Author: Wolfgang Ebner
|
||||
#Author: Sven Neubuaer
|
||||
#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>"
|
||||
#
|
||||
# shellcheck disable=SC2034
|
||||
dns_acmedns_info='acme-dns Server API
|
||||
The acme-dns is a limited DNS server with RESTful API to handle ACME DNS challenges.
|
||||
Site: github.com/joohoi/acme-dns
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_acmedns
|
||||
Options:
|
||||
ACMEDNS_USERNAME Username. Optional.
|
||||
ACMEDNS_PASSWORD Password. Optional.
|
||||
ACMEDNS_SUBDOMAIN Subdomain. Optional.
|
||||
ACMEDNS_BASE_URL API endpoint. Default: "https://auth.acme-dns.io".
|
||||
Issues: github.com/dampfklon/acme.sh
|
||||
Author: Wolfgang Ebner, Sven Neubuaer
|
||||
'
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_acmedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
|
18
dnsapi/dns_acmeproxy.sh
Normal file → Executable file
18
dnsapi/dns_acmeproxy.sh
Normal file → Executable file
@ -1,9 +1,17 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
## Acmeproxy DNS provider to be used with acmeproxy (http://github.com/mdbraber/acmeproxy)
|
||||
## API integration by Maarten den Braber
|
||||
##
|
||||
## Report any bugs via https://github.com/mdbraber/acme.sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_acmeproxy_info='AcmeProxy Server API
|
||||
AcmeProxy can be used to as a single host in your network to request certificates through a DNS API.
|
||||
Clients can connect with the one AcmeProxy host so you do not need to store DNS API credentials on every single host.
|
||||
Site: github.com/mdbraber/acmeproxy
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_acmeproxy
|
||||
Options:
|
||||
ACMEPROXY_ENDPOINT API Endpoint
|
||||
ACMEPROXY_USERNAME Username
|
||||
ACMEPROXY_PASSWORD Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2251
|
||||
Author: Maarten den Braber
|
||||
'
|
||||
|
||||
dns_acmeproxy_add() {
|
||||
fulldomain="${1}"
|
||||
|
@ -1,6 +1,13 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#ACTIVE24_Token="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
# shellcheck disable=SC2034
|
||||
dns_active24_info='Active24.com
|
||||
Site: Active24.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_active24
|
||||
Options:
|
||||
ACTIVE24_Token API Token
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2059
|
||||
Author: Milan Pála
|
||||
'
|
||||
|
||||
ACTIVE24_Api="https://api.active24.com"
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#AD_API_KEY="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
|
||||
#This is the Alwaysdata api wrapper for acme.sh
|
||||
#
|
||||
#Author: Paul Koppen
|
||||
#Report Bugs here: https://github.com/wpk-/acme.sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_ad_info='AlwaysData.com
|
||||
Site: AlwaysData.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_ad
|
||||
Options:
|
||||
AD_API_KEY API Key
|
||||
Issues: github.com/acmesh-official/acme.sh/pull/503
|
||||
Author: Paul Koppen
|
||||
'
|
||||
|
||||
AD_API_URL="https://$AD_API_KEY:@api.alwaysdata.com/v1"
|
||||
|
||||
|
@ -1,10 +1,16 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_ali_info='AlibabaCloud.com
|
||||
Domains: Aliyun.com
|
||||
Site: AlibabaCloud.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_ali
|
||||
Options:
|
||||
Ali_Key API Key
|
||||
Ali_Secret API Secret
|
||||
'
|
||||
|
||||
Ali_API="https://alidns.aliyuncs.com/"
|
||||
|
||||
#Ali_Key="LTqIA87hOKdjevsf5"
|
||||
#Ali_Secret="0p5EYueFNq501xnCPzKNbx6K51qPH2"
|
||||
|
||||
#Usage: dns_ali_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_ali_add() {
|
||||
fulldomain=$1
|
||||
@ -117,7 +123,7 @@ _ali_urlencode() {
|
||||
_ali_nonce() {
|
||||
#_head_n 1 </dev/urandom | _digest "sha256" hex | cut -c 1-31
|
||||
#Not so good...
|
||||
date +"%s%N"
|
||||
date +"%s%N" | sed 's/%N//g'
|
||||
}
|
||||
|
||||
_check_exist_query() {
|
||||
|
@ -1,9 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Anexia CloudDNS acme.sh hook
|
||||
# Author: MA
|
||||
|
||||
#ANX_Token="xxxx"
|
||||
# shellcheck disable=SC2034
|
||||
dns_anx_info='Anexia.com CloudDNS
|
||||
Site: Anexia.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_anx
|
||||
Options:
|
||||
ANX_Token API Token
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/3238
|
||||
'
|
||||
|
||||
ANX_API='https://engine.anexia-it.com/api/clouddns/v1'
|
||||
|
||||
|
177
dnsapi/dns_artfiles.sh
Normal file
177
dnsapi/dns_artfiles.sh
Normal file
@ -0,0 +1,177 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_artfiles_info='ArtFiles.de
|
||||
Site: ArtFiles.de
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_artfiles
|
||||
Options:
|
||||
AF_API_USERNAME API Username
|
||||
AF_API_PASSWORD API Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/4718
|
||||
Author: Martin Arndt <https://troublezone.net/>
|
||||
'
|
||||
|
||||
########## API configuration ###################################################
|
||||
|
||||
AF_API_SUCCESS='status":"OK'
|
||||
AF_URL_DCP='https://dcp.c.artfiles.de/api/'
|
||||
AF_URL_DNS=${AF_URL_DCP}'dns/{*}_dns.html?domain='
|
||||
AF_URL_DOMAINS=${AF_URL_DCP}'domain/get_domains.html'
|
||||
|
||||
########## Public functions ####################################################
|
||||
|
||||
# Adds a new TXT record for given ACME challenge value & domain.
|
||||
# Usage: dns_artfiles_add _acme-challenge.www.example.com "ACME challenge value"
|
||||
dns_artfiles_add() {
|
||||
domain="$1"
|
||||
txtValue="$2"
|
||||
_info 'Using ArtFiles.de DNS addition API…'
|
||||
_debug 'Domain' "$domain"
|
||||
_debug 'txtValue' "$txtValue"
|
||||
|
||||
_set_credentials
|
||||
_saveaccountconf_mutable 'AF_API_USERNAME' "$AF_API_USERNAME"
|
||||
_saveaccountconf_mutable 'AF_API_PASSWORD' "$AF_API_PASSWORD"
|
||||
|
||||
_set_headers
|
||||
_get_zone "$domain"
|
||||
_dns 'GET'
|
||||
if ! _contains "$response" 'TXT'; then
|
||||
_err 'Retrieving TXT records failed.'
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
_clean_records
|
||||
_dns 'SET' "$(printf -- '%s\n_acme-challenge "%s"' "$response" "$txtValue")"
|
||||
if ! _contains "$response" "$AF_API_SUCCESS"; then
|
||||
_err 'Adding ACME challenge value failed.'
|
||||
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Removes the existing TXT record for given ACME challenge value & domain.
|
||||
# Usage: dns_artfiles_rm _acme-challenge.www.example.com "ACME challenge value"
|
||||
dns_artfiles_rm() {
|
||||
domain="$1"
|
||||
txtValue="$2"
|
||||
_info 'Using ArtFiles.de DNS removal API…'
|
||||
_debug 'Domain' "$domain"
|
||||
_debug 'txtValue' "$txtValue"
|
||||
|
||||
_set_credentials
|
||||
_set_headers
|
||||
_get_zone "$domain"
|
||||
if ! _dns 'GET'; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "$txtValue"; then
|
||||
_err 'Retrieved TXT records are missing given ACME challenge value.'
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
_clean_records
|
||||
response="$(printf -- '%s' "$response" | sed '/_acme-challenge "'"$txtValue"'"/d')"
|
||||
_dns 'SET' "$response"
|
||||
if ! _contains "$response" "$AF_API_SUCCESS"; then
|
||||
_err 'Removing ACME challenge value failed.'
|
||||
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
########## Private functions ###################################################
|
||||
|
||||
# Cleans awful TXT records response of ArtFiles's API & pretty prints it.
|
||||
# Usage: _clean_records
|
||||
_clean_records() {
|
||||
_info 'Cleaning TXT records…'
|
||||
# Extract TXT part, strip trailing quote sign (ACME.sh API guidelines forbid
|
||||
# usage of SED's GNU extensions, hence couldn't omit it via regex), strip '\'
|
||||
# from '\"' & turn '\n' into real LF characters.
|
||||
# Yup, awful API to use - but that's all we got to get this working, so… ;)
|
||||
_debug2 'Raw ' "$response"
|
||||
response="$(printf -- '%s' "$response" | sed 's/^.*TXT":"\([^}]*\).*$/\1/;s/,".*$//;s/.$//;s/\\"/"/g;s/\\n/\n/g')"
|
||||
_debug2 'Clean' "$response"
|
||||
}
|
||||
|
||||
# Executes an HTTP GET or POST request for getting or setting DNS records,
|
||||
# containing given payload upon POST.
|
||||
# Usage: _dns [GET | SET] [payload]
|
||||
_dns() {
|
||||
_info 'Executing HTTP request…'
|
||||
action="$1"
|
||||
payload="$(printf -- '%s' "$2" | _url_encode)"
|
||||
url="$(printf -- '%s%s' "$AF_URL_DNS" "$domain" | sed 's/{\*}/'"$(printf -- '%s' "$action" | _lower_case)"'/')"
|
||||
|
||||
if [ "$action" = 'SET' ]; then
|
||||
_debug2 'Payload' "$payload"
|
||||
response="$(_post '' "$url&TXT=$payload" '' 'POST' 'application/x-www-form-urlencoded')"
|
||||
else
|
||||
response="$(_get "$url" '' 10)"
|
||||
fi
|
||||
|
||||
if ! _contains "$response" "$AF_API_SUCCESS"; then
|
||||
_err "DNS API error: $response"
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug 'Response' "$response"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Gets the root domain zone for given domain.
|
||||
# Usage: _get_zone _acme-challenge.www.example.com
|
||||
_get_zone() {
|
||||
fqdn="$1"
|
||||
domains="$(_get "$AF_URL_DOMAINS" '' 10)"
|
||||
_info 'Getting domain zone…'
|
||||
_debug2 'FQDN' "$fqdn"
|
||||
_debug2 'Domains' "$domains"
|
||||
|
||||
while _contains "$fqdn" "."; do
|
||||
if _contains "$domains" "$fqdn"; then
|
||||
domain="$fqdn"
|
||||
_info "Found root domain zone: $domain"
|
||||
break
|
||||
else
|
||||
fqdn="${fqdn#*.}"
|
||||
_debug2 'FQDN' "$fqdn"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$domain" = "$fqdn" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
_err 'Couldn'\''t find root domain zone.'
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Sets the credentials for accessing ArtFiles's API
|
||||
# Usage: _set_credentials
|
||||
_set_credentials() {
|
||||
_info 'Setting credentials…'
|
||||
AF_API_USERNAME="${AF_API_USERNAME:-$(_readaccountconf_mutable AF_API_USERNAME)}"
|
||||
AF_API_PASSWORD="${AF_API_PASSWORD:-$(_readaccountconf_mutable AF_API_PASSWORD)}"
|
||||
if [ -z "$AF_API_USERNAME" ] || [ -z "$AF_API_PASSWORD" ]; then
|
||||
_err 'Missing ArtFiles.de username and/or password.'
|
||||
_err 'Please ensure both are set via export command & try again.'
|
||||
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Adds the HTTP Authorization & Content-Type headers to a follow-up request.
|
||||
# Usage: _set_headers
|
||||
_set_headers() {
|
||||
_info 'Setting headers…'
|
||||
encoded="$(printf -- '%s:%s' "$AF_API_USERNAME" "$AF_API_PASSWORD" | _base64)"
|
||||
export _H1="Authorization: Basic $encoded"
|
||||
export _H2='Content-Type: application/json'
|
||||
}
|
@ -1,11 +1,16 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_arvan_info='ArvanCloud.ir
|
||||
Site: ArvanCloud.ir
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_arvan
|
||||
Options:
|
||||
Arvan_Token API Token
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2796
|
||||
Author: Vahid Fardi
|
||||
'
|
||||
|
||||
#Arvan_Token="Apikey xxxx"
|
||||
ARVAN_API_URL="https://napi.arvancloud.ir/cdn/4.0/domains"
|
||||
|
||||
ARVAN_API_URL="https://napi.arvancloud.com/cdn/4.0/domains"
|
||||
#Author: Vahid Fardi
|
||||
#Report Bugs here: https://github.com/Neilpang/acme.sh
|
||||
#
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_arvan_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
@ -18,7 +23,7 @@ dns_arvan_add() {
|
||||
|
||||
if [ -z "$Arvan_Token" ]; then
|
||||
_err "You didn't specify \"Arvan_Token\" token yet."
|
||||
_err "You can get yours from here https://npanel.arvancloud.com/profile/api-keys"
|
||||
_err "You can get yours from here https://npanel.arvancloud.ir/profile/api-keys"
|
||||
return 1
|
||||
fi
|
||||
#save the api token to the account conf file.
|
||||
@ -40,7 +45,7 @@ dns_arvan_add() {
|
||||
_info "response id is $response"
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
elif _contains "$response" "Record Data is Duplicated"; then
|
||||
elif _contains "$response" "Record Data is duplicate"; then
|
||||
_info "Already exists, OK"
|
||||
return 0
|
||||
else
|
||||
@ -141,6 +146,7 @@ _arvan_rest() {
|
||||
response="$(_post "$data" "$ARVAN_API_URL/$ep" "" "$mtd")"
|
||||
elif [ "$mtd" = "POST" ]; then
|
||||
export _H2="Content-Type: application/json"
|
||||
export _H3="Accept: application/json"
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$ARVAN_API_URL/$ep" "" "$mtd")"
|
||||
else
|
||||
|
@ -1,9 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#AURORA_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
#
|
||||
#AURORA_Secret="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
# shellcheck disable=SC2034
|
||||
dns_aurora_info='versio.nl AuroraDNS
|
||||
Domains: pcextreme.nl
|
||||
Site: versio.nl
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_aurora
|
||||
Options:
|
||||
AURORA_Key API Key
|
||||
AURORA_Secret API Secret
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/3459
|
||||
Author: Jasper Zonneveld
|
||||
'
|
||||
|
||||
AURORA_Api="https://api.auroradns.eu"
|
||||
|
||||
|
@ -1,16 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*-
|
||||
|
||||
# This is the InternetX autoDNS xml api wrapper for acme.sh
|
||||
# Author: auerswald@gmail.com
|
||||
# Created: 2018-01-14
|
||||
#
|
||||
# export AUTODNS_USER="username"
|
||||
# export AUTODNS_PASSWORD="password"
|
||||
# export AUTODNS_CONTEXT="context"
|
||||
#
|
||||
# Usage:
|
||||
# acme.sh --issue --dns dns_autodns -d example.com
|
||||
# shellcheck disable=SC2034
|
||||
dns_autodns_info='InternetX autoDNS
|
||||
InternetX autoDNS XML API
|
||||
Site: InternetX.com/autodns/
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_autodns
|
||||
Options:
|
||||
AUTODNS_USER Username
|
||||
AUTODNS_PASSWORD Password
|
||||
AUTODNS_CONTEXT Context
|
||||
Author: <auerswald@gmail.com>
|
||||
'
|
||||
|
||||
AUTODNS_API="https://gateway.autodns.com"
|
||||
|
||||
|
@ -1,13 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_aws_info='Amazon AWS Route53 domain API
|
||||
Site: docs.aws.amazon.com/route53/
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_aws
|
||||
Options:
|
||||
AWS_ACCESS_KEY_ID API Key ID
|
||||
AWS_SECRET_ACCESS_KEY API Secret
|
||||
'
|
||||
|
||||
#
|
||||
#AWS_ACCESS_KEY_ID="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
#
|
||||
#AWS_SECRET_ACCESS_KEY="xxxxxxx"
|
||||
|
||||
#This is the Amazon Route53 api wrapper for acme.sh
|
||||
#All `_sleep` commands are included to avoid Route53 throttling, see
|
||||
#https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/DNSLimitations.html#limits-api-requests
|
||||
# All `_sleep` commands are included to avoid Route53 throttling, see
|
||||
# https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/DNSLimitations.html#limits-api-requests
|
||||
|
||||
AWS_HOST="route53.amazonaws.com"
|
||||
AWS_URL="https://$AWS_HOST"
|
||||
@ -145,41 +147,29 @@ dns_aws_rm() {
|
||||
fi
|
||||
_sleep 1
|
||||
return 1
|
||||
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
i=1
|
||||
p=1
|
||||
|
||||
if aws_rest GET "2013-04-01/hostedzone"; then
|
||||
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
|
||||
# iterate over names (a.b.c.d -> b.c.d -> c.d -> d)
|
||||
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
|
||||
if _contains "$response" "<Name>$h.</Name>"; then
|
||||
hostedzone="$(echo "$response" | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<PrivateZone>false<.PrivateZone>.*<.HostedZone>")"
|
||||
hostedzone="$(echo "$response" | tr -d '\n' | sed 's/<HostedZone>/#&/g' | tr '#' '\n' | _egrep_o "<HostedZone><Id>[^<]*<.Id><Name>$h.<.Name>.*<PrivateZone>false<.PrivateZone>.*<.HostedZone>")"
|
||||
_debug hostedzone "$hostedzone"
|
||||
if [ "$hostedzone" ]; then
|
||||
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "<Id>.*<.Id>" | head -n 1 | _egrep_o ">.*<" | tr -d "<>")
|
||||
@ -192,10 +182,19 @@ _get_root() {
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
if _contains "$response" "<IsTruncated>true</IsTruncated>" && _contains "$response" "<NextMarker>"; then
|
||||
_debug "IsTruncated"
|
||||
_nextMarker="$(echo "$response" | _egrep_o "<NextMarker>.*</NextMarker>" | cut -d '>' -f 2 | cut -d '<' -f 1)"
|
||||
_debug "NextMarker" "$_nextMarker"
|
||||
else
|
||||
break
|
||||
fi
|
||||
_debug "Checking domain: $h - Next Page "
|
||||
aws_rest GET "2013-04-01/hostedzone" "marker=$_nextMarker"
|
||||
done
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
@ -209,24 +208,40 @@ _use_container_role() {
|
||||
}
|
||||
|
||||
_use_instance_role() {
|
||||
_url="http://169.254.169.254/latest/meta-data/iam/security-credentials/"
|
||||
_debug "_url" "$_url"
|
||||
if ! _get "$_url" true 1 | _head_n 1 | grep -Fq 200; then
|
||||
_instance_role_name_url="http://169.254.169.254/latest/meta-data/iam/security-credentials/"
|
||||
|
||||
if _get "$_instance_role_name_url" true 1 | _head_n 1 | grep -Fq 401; then
|
||||
_debug "Using IMDSv2"
|
||||
_token_url="http://169.254.169.254/latest/api/token"
|
||||
export _H1="X-aws-ec2-metadata-token-ttl-seconds: 21600"
|
||||
_token="$(_post "" "$_token_url" "" "PUT")"
|
||||
_secure_debug3 "_token" "$_token"
|
||||
if [ -z "$_token" ]; then
|
||||
_debug "Unable to fetch IMDSv2 token from instance metadata"
|
||||
return 1
|
||||
fi
|
||||
export _H1="X-aws-ec2-metadata-token: $_token"
|
||||
fi
|
||||
|
||||
if ! _get "$_instance_role_name_url" true 1 | _head_n 1 | grep -Fq 200; then
|
||||
_debug "Unable to fetch IAM role from instance metadata"
|
||||
return 1
|
||||
fi
|
||||
_aws_role=$(_get "$_url" "" 1)
|
||||
_debug "_aws_role" "$_aws_role"
|
||||
_use_metadata "$_url$_aws_role"
|
||||
|
||||
_instance_role_name=$(_get "$_instance_role_name_url" "" 1)
|
||||
_debug "_instance_role_name" "$_instance_role_name"
|
||||
_use_metadata "$_instance_role_name_url$_instance_role_name" "$_token"
|
||||
|
||||
}
|
||||
|
||||
_use_metadata() {
|
||||
export _H1="X-aws-ec2-metadata-token: $2"
|
||||
_aws_creds="$(
|
||||
_get "$1" "" 1 |
|
||||
_normalizeJson |
|
||||
tr '{,}' '\n' |
|
||||
while read -r _line; do
|
||||
_key="$(echo "${_line%%:*}" | tr -d '"')"
|
||||
_key="$(echo "${_line%%:*}" | tr -d '\"')"
|
||||
_value="${_line#*:}"
|
||||
_debug3 "_key" "$_key"
|
||||
_secure_debug3 "_value" "$_value"
|
||||
|
@ -1,9 +1,13 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#AZION_Email=""
|
||||
#AZION_Password=""
|
||||
#
|
||||
# shellcheck disable=SC2034
|
||||
dns_azion_info='Azion.om
|
||||
Site: Azion.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_azion
|
||||
Options:
|
||||
AZION_Email Email
|
||||
AZION_Password Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/3555
|
||||
'
|
||||
|
||||
AZION_Api="https://api.azionapi.net"
|
||||
|
||||
|
@ -1,6 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
WIKI="https://github.com/acmesh-official/acme.sh/wiki/How-to-use-Azure-DNS"
|
||||
# shellcheck disable=SC2034
|
||||
dns_azure_info='Azure
|
||||
Site: Azure.microsoft.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_azure
|
||||
Options:
|
||||
AZUREDNS_SUBSCRIPTIONID Subscription ID
|
||||
AZUREDNS_TENANTID Tenant ID
|
||||
AZUREDNS_APPID App ID. App ID of the service principal
|
||||
AZUREDNS_CLIENTSECRET Client Secret. Secret from creating the service principal
|
||||
AZUREDNS_MANAGEDIDENTITY Use Managed Identity. Use Managed Identity assigned to a resource instead of a service principal. "true"/"false"
|
||||
'
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
@ -9,57 +18,72 @@ 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
|
||||
#
|
||||
|
||||
dns_azure_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
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
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
AZUREDNS_TENANTID=""
|
||||
AZUREDNS_APPID=""
|
||||
AZUREDNS_CLIENTSECRET=""
|
||||
_err "You didn't specify the Azure Subscription ID "
|
||||
_err "You didn't specify the Azure Subscription ID"
|
||||
return 1
|
||||
fi
|
||||
|
||||
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.
|
||||
#save subscription id 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")
|
||||
AZUREDNS_MANAGEDIDENTITY="${AZUREDNS_MANAGEDIDENTITY:-$(_readaccountconf_mutable AZUREDNS_MANAGEDIDENTITY)}"
|
||||
if [ "$AZUREDNS_MANAGEDIDENTITY" = true ]; then
|
||||
_info "Using Azure managed identity"
|
||||
#save managed identity as preferred authentication method, clear service principal credentials from conf file.
|
||||
_saveaccountconf_mutable AZUREDNS_MANAGEDIDENTITY "$AZUREDNS_MANAGEDIDENTITY"
|
||||
_saveaccountconf_mutable AZUREDNS_TENANTID ""
|
||||
_saveaccountconf_mutable AZUREDNS_APPID ""
|
||||
_saveaccountconf_mutable AZUREDNS_CLIENTSECRET ""
|
||||
else
|
||||
_info "You didn't ask to use Azure managed identity, checking service principal credentials"
|
||||
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
|
||||
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
|
||||
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
|
||||
|
||||
if [ -z "$AZUREDNS_TENANTID" ]; then
|
||||
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
|
||||
|
||||
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
|
||||
|
||||
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
|
||||
_err "invalid domain"
|
||||
@ -116,10 +140,6 @@ dns_azure_rm() {
|
||||
txtvalue=$2
|
||||
|
||||
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
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
AZUREDNS_TENANTID=""
|
||||
@ -129,34 +149,44 @@ dns_azure_rm() {
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -z "$AZUREDNS_TENANTID" ]; then
|
||||
AZUREDNS_SUBSCRIPTIONID=""
|
||||
AZUREDNS_TENANTID=""
|
||||
AZUREDNS_APPID=""
|
||||
AZUREDNS_CLIENTSECRET=""
|
||||
_err "You didn't specify the Azure Tenant ID "
|
||||
return 1
|
||||
AZUREDNS_MANAGEDIDENTITY="${AZUREDNS_MANAGEDIDENTITY:-$(_readaccountconf_mutable AZUREDNS_MANAGEDIDENTITY)}"
|
||||
if [ "$AZUREDNS_MANAGEDIDENTITY" = true ]; then
|
||||
_info "Using Azure managed identity"
|
||||
else
|
||||
_info "You didn't ask to use Azure managed identity, checking service principal credentials"
|
||||
AZUREDNS_TENANTID="${AZUREDNS_TENANTID:-$(_readaccountconf_mutable AZUREDNS_TENANTID)}"
|
||||
AZUREDNS_APPID="${AZUREDNS_APPID:-$(_readaccountconf_mutable AZUREDNS_APPID)}"
|
||||
AZUREDNS_CLIENTSECRET="${AZUREDNS_CLIENTSECRET:-$(_readaccountconf_mutable AZUREDNS_CLIENTSECRET)}"
|
||||
|
||||
if [ -z "$AZUREDNS_TENANTID" ]; then
|
||||
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
|
||||
|
||||
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")
|
||||
accesstoken=$(_azure_getaccess_token "$AZUREDNS_MANAGEDIDENTITY" "$AZUREDNS_TENANTID" "$AZUREDNS_APPID" "$AZUREDNS_CLIENTSECRET")
|
||||
|
||||
if ! _get_root "$fulldomain" "$AZUREDNS_SUBSCRIPTIONID" "$accesstoken"; then
|
||||
_err "invalid domain"
|
||||
@ -258,9 +288,10 @@ _azure_rest() {
|
||||
|
||||
## Ref: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-service-to-service#request-an-access-token
|
||||
_azure_getaccess_token() {
|
||||
tenantID=$1
|
||||
clientID=$2
|
||||
clientSecret=$3
|
||||
managedIdentity=$1
|
||||
tenantID=$2
|
||||
clientID=$3
|
||||
clientSecret=$4
|
||||
|
||||
accesstoken="${AZUREDNS_BEARERTOKEN:-$(_readaccountconf_mutable AZUREDNS_BEARERTOKEN)}"
|
||||
expires_on="${AZUREDNS_TOKENVALIDTO:-$(_readaccountconf_mutable AZUREDNS_TOKENVALIDTO)}"
|
||||
@ -278,17 +309,25 @@ _azure_getaccess_token() {
|
||||
fi
|
||||
_debug "getting new bearer token"
|
||||
|
||||
export _H1="accept: application/json"
|
||||
export _H2="Content-Type: application/x-www-form-urlencoded"
|
||||
|
||||
body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials"
|
||||
_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 \")
|
||||
if [ "$managedIdentity" = true ]; then
|
||||
# https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token#get-a-token-using-http
|
||||
export _H1="Metadata: true"
|
||||
response="$(_get http://169.254.169.254/metadata/identity/oauth2/token\?api-version=2018-02-01\&resource=https://management.azure.com/)"
|
||||
response="$(echo "$response" | _normalizeJson)"
|
||||
accesstoken=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
expires_on=$(echo "$response" | _egrep_o "\"expires_on\":\"[^\"]*\"" | _head_n 1 | cut -d : -f 2 | tr -d \")
|
||||
else
|
||||
export _H1="accept: application/json"
|
||||
export _H2="Content-Type: application/x-www-form-urlencoded"
|
||||
body="resource=$(printf "%s" 'https://management.core.windows.net/' | _url_encode)&client_id=$(printf "%s" "$clientID" | _url_encode)&client_secret=$(printf "%s" "$clientSecret" | _url_encode)&grant_type=client_credentials"
|
||||
_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
|
||||
_err "no acccess token received. Check your Azure settings see $WIKI"
|
||||
|
88
dnsapi/dns_bookmyname.sh
Normal file
88
dnsapi/dns_bookmyname.sh
Normal file
@ -0,0 +1,88 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_bookmyname_info='BookMyName.com
|
||||
Site: BookMyName.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_bookmyname
|
||||
Options:
|
||||
BOOKMYNAME_USERNAME Username
|
||||
BOOKMYNAME_PASSWORD Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/3209
|
||||
Author: Neilpang
|
||||
'
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
# BookMyName urls:
|
||||
# https://BOOKMYNAME_USERNAME:BOOKMYNAME_PASSWORD@www.bookmyname.com/dyndns/?hostname=_acme-challenge.domain.tld&type=txt&ttl=300&do=add&value="XXXXXXXX"'
|
||||
# https://BOOKMYNAME_USERNAME:BOOKMYNAME_PASSWORD@www.bookmyname.com/dyndns/?hostname=_acme-challenge.domain.tld&type=txt&ttl=300&do=remove&value="XXXXXXXX"'
|
||||
|
||||
# Output:
|
||||
#good: update done, cid 123456, domain id 456789, type txt, ip XXXXXXXX
|
||||
#good: remove done 1, cid 123456, domain id 456789, ttl 300, type txt, ip XXXXXXXX
|
||||
|
||||
# Be careful, BMN DNS servers can be slow to pick up changes; using dnssleep is thus advised.
|
||||
|
||||
# Usage:
|
||||
# export BOOKMYNAME_USERNAME="ABCDE-FREE"
|
||||
# export BOOKMYNAME_PASSWORD="MyPassword"
|
||||
# /usr/local/ssl/acme.sh/acme.sh --dns dns_bookmyname --dnssleep 600 --issue -d domain.tld
|
||||
|
||||
#Usage: dns_bookmyname_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_bookmyname_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using bookmyname"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
BOOKMYNAME_USERNAME="${BOOKMYNAME_USERNAME:-$(_readaccountconf_mutable BOOKMYNAME_USERNAME)}"
|
||||
BOOKMYNAME_PASSWORD="${BOOKMYNAME_PASSWORD:-$(_readaccountconf_mutable BOOKMYNAME_PASSWORD)}"
|
||||
|
||||
if [ -z "$BOOKMYNAME_USERNAME" ] || [ -z "$BOOKMYNAME_PASSWORD" ]; then
|
||||
BOOKMYNAME_USERNAME=""
|
||||
BOOKMYNAME_PASSWORD=""
|
||||
_err "You didn't specify BookMyName username and password yet."
|
||||
_err "Please specify them and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the credentials to the account conf file.
|
||||
_saveaccountconf_mutable BOOKMYNAME_USERNAME "$BOOKMYNAME_USERNAME"
|
||||
_saveaccountconf_mutable BOOKMYNAME_PASSWORD "$BOOKMYNAME_PASSWORD"
|
||||
|
||||
uri="https://${BOOKMYNAME_USERNAME}:${BOOKMYNAME_PASSWORD}@www.bookmyname.com/dyndns/"
|
||||
data="?hostname=${fulldomain}&type=TXT&ttl=300&do=add&value=${txtvalue}"
|
||||
result="$(_get "${uri}${data}")"
|
||||
_debug "Result: $result"
|
||||
|
||||
if ! _startswith "$result" 'good: update done, cid '; then
|
||||
_err "Can't add $fulldomain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_bookmyname_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using bookmyname"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
BOOKMYNAME_USERNAME="${BOOKMYNAME_USERNAME:-$(_readaccountconf_mutable BOOKMYNAME_USERNAME)}"
|
||||
BOOKMYNAME_PASSWORD="${BOOKMYNAME_PASSWORD:-$(_readaccountconf_mutable BOOKMYNAME_PASSWORD)}"
|
||||
|
||||
uri="https://${BOOKMYNAME_USERNAME}:${BOOKMYNAME_PASSWORD}@www.bookmyname.com/dyndns/"
|
||||
data="?hostname=${fulldomain}&type=TXT&ttl=300&do=remove&value=${txtvalue}"
|
||||
result="$(_get "${uri}${data}")"
|
||||
_debug "Result: $result"
|
||||
|
||||
if ! _startswith "$result" 'good: remove done 1, cid '; then
|
||||
_info "Can't remove $fulldomain"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
245
dnsapi/dns_bunny.sh
Normal file
245
dnsapi/dns_bunny.sh
Normal file
@ -0,0 +1,245 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_bunny_info='Bunny.net
|
||||
Site: Bunny.net/dns/
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_bunny
|
||||
Options:
|
||||
BUNNY_API_KEY API Key
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/4296
|
||||
Author: <nosilver4u@ewww.io>
|
||||
'
|
||||
|
||||
##################### Public functions #####################
|
||||
|
||||
## Create the text record for validation.
|
||||
## Usage: fulldomain txtvalue
|
||||
## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
|
||||
dns_bunny_add() {
|
||||
fulldomain="$(echo "$1" | _lower_case)"
|
||||
txtvalue=$2
|
||||
|
||||
BUNNY_API_KEY="${BUNNY_API_KEY:-$(_readaccountconf_mutable BUNNY_API_KEY)}"
|
||||
# Check if API Key is set
|
||||
if [ -z "$BUNNY_API_KEY" ]; then
|
||||
BUNNY_API_KEY=""
|
||||
_err "You did not specify Bunny.net API key."
|
||||
_err "Please export BUNNY_API_KEY and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Using Bunny.net dns validation - add record"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
## save the env vars (key and domain split location) for later automated use
|
||||
_saveaccountconf_mutable BUNNY_API_KEY "$BUNNY_API_KEY"
|
||||
|
||||
## split the domain for Bunny API
|
||||
if ! _get_base_domain "$fulldomain"; then
|
||||
_err "domain not found in your account for addition"
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
_debug _domain_id "$_domain_id"
|
||||
|
||||
## Set the header with our post type and auth key
|
||||
export _H1="Accept: application/json"
|
||||
export _H2="AccessKey: $BUNNY_API_KEY"
|
||||
export _H3="Content-Type: application/json"
|
||||
PURL="https://api.bunny.net/dnszone/$_domain_id/records"
|
||||
PBODY='{"Id":'$_domain_id',"Type":3,"Name":"'$_sub_domain'","Value":"'$txtvalue'","ttl":120}'
|
||||
|
||||
_debug PURL "$PURL"
|
||||
_debug PBODY "$PBODY"
|
||||
|
||||
## the create request - POST
|
||||
## args: BODY, URL, [need64, httpmethod]
|
||||
response="$(_post "$PBODY" "$PURL" "" "PUT")"
|
||||
|
||||
## check response
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error in response: $response"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
|
||||
## finished correctly
|
||||
return 0
|
||||
}
|
||||
|
||||
## Remove the txt record after validation.
|
||||
## Usage: fulldomain txtvalue
|
||||
## EG: "_acme-challenge.www.other.domain.com" "XKrxpRBosdq0HG9i01zxXp5CPBs"
|
||||
dns_bunny_rm() {
|
||||
fulldomain="$(echo "$1" | _lower_case)"
|
||||
txtvalue=$2
|
||||
|
||||
BUNNY_API_KEY="${BUNNY_API_KEY:-$(_readaccountconf_mutable BUNNY_API_KEY)}"
|
||||
# Check if API Key Exists
|
||||
if [ -z "$BUNNY_API_KEY" ]; then
|
||||
BUNNY_API_KEY=""
|
||||
_err "You did not specify Bunny.net API key."
|
||||
_err "Please export BUNNY_API_KEY and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Using Bunny.net dns validation - remove record"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
## split the domain for Bunny API
|
||||
if ! _get_base_domain "$fulldomain"; then
|
||||
_err "Domain not found in your account for TXT record removal"
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
_debug _domain_id "$_domain_id"
|
||||
|
||||
## Set the header with our post type and key auth key
|
||||
export _H1="Accept: application/json"
|
||||
export _H2="AccessKey: $BUNNY_API_KEY"
|
||||
## get URL for the list of DNS records
|
||||
GURL="https://api.bunny.net/dnszone/$_domain_id"
|
||||
|
||||
## 1) Get the domain/zone records
|
||||
## the fetch request - GET
|
||||
## args: URL, [onlyheader, timeout]
|
||||
domain_list="$(_get "$GURL")"
|
||||
|
||||
## check response
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error in domain_list response: $domain_list"
|
||||
return 1
|
||||
fi
|
||||
_debug2 domain_list "$domain_list"
|
||||
|
||||
## 2) search through records
|
||||
## check for what we are looking for: "Type":3,"Value":"$txtvalue","Name":"$_sub_domain"
|
||||
record="$(echo "$domain_list" | _egrep_o "\"Id\"\s*\:\s*\"*[0-9]+\"*,\s*\"Type\"[^}]*\"Value\"\s*\:\s*\"$txtvalue\"[^}]*\"Name\"\s*\:\s*\"$_sub_domain\"")"
|
||||
|
||||
if [ -n "$record" ]; then
|
||||
|
||||
## We found records
|
||||
rec_ids="$(echo "$record" | _egrep_o "Id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
|
||||
_debug rec_ids "$rec_ids"
|
||||
if [ -n "$rec_ids" ]; then
|
||||
echo "$rec_ids" | while IFS= read -r rec_id; do
|
||||
## delete the record
|
||||
## delete URL for removing the one we dont want
|
||||
DURL="https://api.bunny.net/dnszone/$_domain_id/records/$rec_id"
|
||||
|
||||
## the removal request - DELETE
|
||||
## args: BODY, URL, [need64, httpmethod]
|
||||
response="$(_post "" "$DURL" "" "DELETE")"
|
||||
|
||||
## check response (sort of)
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error in remove response: $response"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
|
||||
done
|
||||
fi
|
||||
fi
|
||||
|
||||
## finished correctly
|
||||
return 0
|
||||
}
|
||||
|
||||
##################### Private functions below #####################
|
||||
|
||||
## Split the domain provided into the "base domain" and the "start prefix".
|
||||
## This function searches for the longest subdomain in your account
|
||||
## for the full domain given and splits it into the base domain (zone)
|
||||
## and the prefix/record to be added/removed
|
||||
## USAGE: fulldomain
|
||||
## EG: "_acme-challenge.two.three.four.domain.com"
|
||||
## returns
|
||||
## _sub_domain="_acme-challenge.two"
|
||||
## _domain="three.four.domain.com" *IF* zone "three.four.domain.com" exists
|
||||
## _domain_id=234
|
||||
## if only "domain.com" exists it will return
|
||||
## _sub_domain="_acme-challenge.two.three.four"
|
||||
## _domain="domain.com"
|
||||
## _domain_id=234
|
||||
_get_base_domain() {
|
||||
# args
|
||||
fulldomain="$(echo "$1" | _lower_case)"
|
||||
_debug fulldomain "$fulldomain"
|
||||
|
||||
# domain max legal length = 253
|
||||
MAX_DOM=255
|
||||
page=1
|
||||
|
||||
## get a list of domains for the account to check thru
|
||||
## Set the headers
|
||||
export _H1="Accept: application/json"
|
||||
export _H2="AccessKey: $BUNNY_API_KEY"
|
||||
_debug BUNNY_API_KEY "$BUNNY_API_KEY"
|
||||
## get URL for the list of domains
|
||||
## may get: "links":{"pages":{"last":".../v2/domains/DOM/records?page=2","next":".../v2/domains/DOM/records?page=2"}}
|
||||
DOMURL="https://api.bunny.net/dnszone"
|
||||
|
||||
## while we dont have a matching domain we keep going
|
||||
while [ -z "$found" ]; do
|
||||
## get the domain list (current page)
|
||||
domain_list="$(_get "$DOMURL")"
|
||||
|
||||
## check response
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error in domain_list response: $domain_list"
|
||||
return 1
|
||||
fi
|
||||
_debug2 domain_list "$domain_list"
|
||||
|
||||
i=1
|
||||
while [ $i -gt 0 ]; do
|
||||
## get next longest domain
|
||||
_domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
|
||||
## check we got something back from our cut (or are we at the end)
|
||||
if [ -z "$_domain" ]; then
|
||||
break
|
||||
fi
|
||||
## we got part of a domain back - grep it out
|
||||
found="$(echo "$domain_list" | _egrep_o "\"Id\"\s*:\s*\"*[0-9]+\"*,\s*\"Domain\"\s*\:\s*\"$_domain\"")"
|
||||
## check if it exists
|
||||
if [ -n "$found" ]; then
|
||||
## exists - exit loop returning the parts
|
||||
sub_point=$(_math $i - 1)
|
||||
_sub_domain=$(printf "%s" "$fulldomain" | cut -d . -f 1-"$sub_point")
|
||||
_domain_id="$(echo "$found" | _egrep_o "Id\"\s*\:\s*\"*[0-9]+" | _egrep_o "[0-9]+")"
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _domain "$_domain"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
found=""
|
||||
return 0
|
||||
fi
|
||||
## increment cut point $i
|
||||
i=$(_math $i + 1)
|
||||
done
|
||||
|
||||
if [ -z "$found" ]; then
|
||||
page=$(_math $page + 1)
|
||||
nextpage="https://api.bunny.net/dnszone?page=$page"
|
||||
## Find the next page if we don't have a match.
|
||||
hasnextpage="$(echo "$domain_list" | _egrep_o "\"HasMoreItems\"\s*:\s*true")"
|
||||
if [ -z "$hasnextpage" ]; then
|
||||
_err "No record and no nextpage in Bunny.net domain search."
|
||||
found=""
|
||||
return 1
|
||||
fi
|
||||
_debug2 nextpage "$nextpage"
|
||||
DOMURL="$nextpage"
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
## We went through the entire domain zone list and didn't find one that matched.
|
||||
## If we ever get here, something is broken in the code...
|
||||
_err "Domain not found in Bunny.net account, but we should never get here!"
|
||||
found=""
|
||||
return 1
|
||||
}
|
@ -1,13 +1,16 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#CF_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
#
|
||||
#CF_Email="xxxx@sss.com"
|
||||
|
||||
#CF_Token="xxxx"
|
||||
#CF_Account_ID="xxxx"
|
||||
#CF_Zone_ID="xxxx"
|
||||
# shellcheck disable=SC2034
|
||||
dns_cf_info='CloudFlare
|
||||
Site: CloudFlare.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cf
|
||||
Options:
|
||||
CF_Key API Key
|
||||
CF_Email Your account email
|
||||
OptionsAlt:
|
||||
CF_Token API Token
|
||||
CF_Account_ID Account ID
|
||||
CF_Zone_ID Zone ID. Optional.
|
||||
'
|
||||
|
||||
CF_Api="https://api.cloudflare.com/client/v4"
|
||||
|
||||
@ -25,9 +28,16 @@ dns_cf_add() {
|
||||
CF_Email="${CF_Email:-$(_readaccountconf_mutable CF_Email)}"
|
||||
|
||||
if [ "$CF_Token" ]; then
|
||||
_saveaccountconf_mutable CF_Token "$CF_Token"
|
||||
_saveaccountconf_mutable CF_Account_ID "$CF_Account_ID"
|
||||
_saveaccountconf_mutable CF_Zone_ID "$CF_Zone_ID"
|
||||
if [ "$CF_Zone_ID" ]; then
|
||||
_savedomainconf CF_Token "$CF_Token"
|
||||
_savedomainconf CF_Account_ID "$CF_Account_ID"
|
||||
_savedomainconf CF_Zone_ID "$CF_Zone_ID"
|
||||
else
|
||||
_saveaccountconf_mutable CF_Token "$CF_Token"
|
||||
_saveaccountconf_mutable CF_Account_ID "$CF_Account_ID"
|
||||
_clearaccountconf_mutable CF_Zone_ID
|
||||
_clearaccountconf CF_Zone_ID
|
||||
fi
|
||||
else
|
||||
if [ -z "$CF_Key" ] || [ -z "$CF_Email" ]; then
|
||||
CF_Key=""
|
||||
@ -45,6 +55,14 @@ dns_cf_add() {
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf_mutable CF_Key "$CF_Key"
|
||||
_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
|
||||
|
||||
_debug "First detect the root zone"
|
||||
|
@ -1,10 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Author: Radek Sprta <sprta@vshosting.cz>
|
||||
|
||||
#CLOUDDNS_EMAIL=XXXXX
|
||||
#CLOUDDNS_PASSWORD="YYYYYYYYY"
|
||||
#CLOUDDNS_CLIENT_ID=XXXXX
|
||||
# shellcheck disable=SC2034
|
||||
dns_clouddns_info='vshosting.cz CloudDNS
|
||||
Site: github.com/vshosting/clouddns
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_clouddns
|
||||
Options:
|
||||
CLOUDDNS_EMAIL Email
|
||||
CLOUDDNS_PASSWORD Password
|
||||
CLOUDDNS_CLIENT_ID Client ID
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2699
|
||||
Author: Radek Sprta <sprta@vshosting.cz>
|
||||
'
|
||||
|
||||
CLOUDDNS_API='https://admin.vshosting.cloud/clouddns'
|
||||
CLOUDDNS_LOGIN_API='https://admin.vshosting.cloud/api/public/auth/login'
|
||||
|
@ -1,12 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_cloudns_info='ClouDNS.net
|
||||
Site: ClouDNS.net
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cloudns
|
||||
Options:
|
||||
CLOUDNS_AUTH_ID Regular auth ID
|
||||
CLOUDNS_SUB_AUTH_ID Sub auth ID
|
||||
CLOUDNS_AUTH_PASSWORD Auth Password
|
||||
Author: Boyan Peychev <boyan@cloudns.net>
|
||||
'
|
||||
|
||||
# Author: Boyan Peychev <boyan at cloudns dot net>
|
||||
# Repository: https://github.com/ClouDNS/acme.sh/
|
||||
# Editor: I Komang Suryadana
|
||||
|
||||
#CLOUDNS_AUTH_ID=XXXXX
|
||||
#CLOUDNS_SUB_AUTH_ID=XXXXX
|
||||
#CLOUDNS_AUTH_PASSWORD="YYYYYYYYY"
|
||||
CLOUDNS_API="https://api.cloudns.net"
|
||||
DOMAIN_TYPE=
|
||||
DOMAIN_MASTER=
|
||||
@ -78,7 +81,7 @@ dns_cloudns_rm() {
|
||||
return 1
|
||||
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')
|
||||
|
||||
if [ -n "$record_id" ]; then
|
||||
|
@ -1,7 +1,14 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# DNS API for acme.sh for Core-Networks (https://beta.api.core-networks.de/doc/).
|
||||
# created by 5ll and francis
|
||||
# shellcheck disable=SC2034
|
||||
dns_cn_info='Core-Networks.de
|
||||
Site: beta.api.Core-Networks.de/doc/
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cn
|
||||
Options:
|
||||
CN_User User
|
||||
CN_Password Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2142
|
||||
Author: 5ll, francis
|
||||
'
|
||||
|
||||
CN_API="https://beta.api.core-networks.de"
|
||||
|
||||
|
@ -1,4 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_conoha_info='ConoHa.jp
|
||||
Domains: ConoHa.io
|
||||
Site: ConoHa.jp
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_conoha
|
||||
Options:
|
||||
CONOHA_Username Username
|
||||
CONOHA_Password Password
|
||||
CONOHA_TenantId TenantId
|
||||
CONOHA_IdentityServiceApi Identity Service API. E.g. "https://identity.xxxx.conoha.io/v2.0"
|
||||
'
|
||||
|
||||
CONOHA_DNS_EP_PREFIX_REGEXP="https://dns-service\."
|
||||
|
||||
|
@ -1,10 +1,16 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Author: Wout Decre <wout@canodus.be>
|
||||
# shellcheck disable=SC2034
|
||||
dns_constellix_info='Constellix.com
|
||||
Site: Constellix.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_constellix
|
||||
Options:
|
||||
CONSTELLIX_Key API Key
|
||||
CONSTELLIX_Secret API Secret
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2724
|
||||
Author: Wout Decre <wout@canodus.be>
|
||||
'
|
||||
|
||||
CONSTELLIX_Api="https://api.dns.constellix.com/v1"
|
||||
#CONSTELLIX_Key="XXX"
|
||||
#CONSTELLIX_Secret="XXX"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
|
@ -1,18 +1,19 @@
|
||||
#!/usr/bin/env sh
|
||||
#
|
||||
#Author: Bjarne Saltbaek
|
||||
#Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/3732
|
||||
#
|
||||
#
|
||||
# shellcheck disable=SC2034
|
||||
dns_cpanel_info='cPanel Server API
|
||||
Manage DNS via cPanel Dashboard.
|
||||
Site: cPanel.net
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_cpanel
|
||||
Options:
|
||||
cPanel_Username Username
|
||||
cPanel_Apitoken API Token
|
||||
cPanel_Hostname Server URL. E.g. "https://hostname:port"
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/3732
|
||||
Author: Bjarne Saltbaek
|
||||
'
|
||||
|
||||
######## Public functions #####################
|
||||
#
|
||||
# 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
|
||||
@ -120,7 +121,7 @@ _myget() {
|
||||
|
||||
_get_root() {
|
||||
_myget 'json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit&cpanel_jsonapi_func=fetchzones'
|
||||
_domains=$(echo "$_result" | sed 's/.*\(zones.*\[\).*/\1/' | cut -d':' -f2 | sed 's/"//g' | sed 's/{//g')
|
||||
_domains=$(echo "$_result" | _egrep_o '"[a-z0-9\.\-]*":\["; cPanel first' | cut -d':' -f1 | sed 's/"//g' | sed 's/{//g')
|
||||
_debug "_result is: $_result"
|
||||
_debug "_domains is: $_domains"
|
||||
if [ -z "$_domains" ]; then
|
||||
@ -138,15 +139,15 @@ _get_root() {
|
||||
}
|
||||
|
||||
_successful_update() {
|
||||
if (echo "$_result" | grep -q 'newserial'); then return 0; fi
|
||||
return 1
|
||||
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 "s/.*\(line.*$fulldomain.*$txtvalue\).*/\1/" | cut -d ':' -f 2 | cut -d ',' -f 1)
|
||||
_id=$(echo "$_result" | sed -e "s/},{/},\n{/g" | grep "$fulldomain" | grep "$txtvalue" | _egrep_o 'line":[0-9]+' | cut -d ':' -f 2)
|
||||
_debug "_result is: $_result"
|
||||
_debug "fulldomain. is $fulldomain."
|
||||
_debug "txtvalue is $txtvalue"
|
||||
|
165
dnsapi/dns_curanet.sh
Normal file
165
dnsapi/dns_curanet.sh
Normal file
@ -0,0 +1,165 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_curanet_info='Curanet.dk
|
||||
Domains: scannet.dk wannafind.dk dandomain.dk
|
||||
Site: Curanet.dk
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_curanet
|
||||
Options:
|
||||
CURANET_AUTHCLIENTID Auth ClientID. Requires scope dns
|
||||
CURANET_AUTHSECRET Auth Secret
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/3933
|
||||
Author: Peter L. Hansen <peter@r12.dk>
|
||||
'
|
||||
|
||||
CURANET_REST_URL="https://api.curanet.dk/dns/v1/Domains"
|
||||
CURANET_AUTH_URL="https://apiauth.dk.team.blue/auth/realms/Curanet/protocol/openid-connect/token"
|
||||
CURANET_ACCESS_TOKEN=""
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_curanet_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_curanet_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using curanet"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
CURANET_AUTHCLIENTID="${CURANET_AUTHCLIENTID:-$(_readaccountconf_mutable CURANET_AUTHCLIENTID)}"
|
||||
CURANET_AUTHSECRET="${CURANET_AUTHSECRET:-$(_readaccountconf_mutable CURANET_AUTHSECRET)}"
|
||||
if [ -z "$CURANET_AUTHCLIENTID" ] || [ -z "$CURANET_AUTHSECRET" ]; then
|
||||
CURANET_AUTHCLIENTID=""
|
||||
CURANET_AUTHSECRET=""
|
||||
_err "You don't specify curanet api client and secret."
|
||||
_err "Please create your auth info and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the credentials to the account conf file.
|
||||
_saveaccountconf_mutable CURANET_AUTHCLIENTID "$CURANET_AUTHCLIENTID"
|
||||
_saveaccountconf_mutable CURANET_AUTHSECRET "$CURANET_AUTHSECRET"
|
||||
|
||||
if ! _get_token; then
|
||||
_err "Unable to get token"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "Invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
export _H1="Content-Type: application/json-patch+json"
|
||||
export _H2="Accept: application/json"
|
||||
export _H3="Authorization: Bearer $CURANET_ACCESS_TOKEN"
|
||||
data="{\"name\": \"$fulldomain\",\"type\": \"TXT\",\"ttl\": 60,\"priority\": 0,\"data\": \"$txtvalue\"}"
|
||||
response="$(_post "$data" "$CURANET_REST_URL/${_domain}/Records" "" "")"
|
||||
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_debug "TXT record added OK"
|
||||
else
|
||||
_err "Unable to add TXT record"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_curanet_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using curanet"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
CURANET_AUTHCLIENTID="${CURANET_AUTHCLIENTID:-$(_readaccountconf_mutable CURANET_AUTHCLIENTID)}"
|
||||
CURANET_AUTHSECRET="${CURANET_AUTHSECRET:-$(_readaccountconf_mutable CURANET_AUTHSECRET)}"
|
||||
|
||||
if ! _get_token; then
|
||||
_err "Unable to get token"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "Invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Getting current record list to identify TXT to delete"
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
export _H2="Accept: application/json"
|
||||
export _H3="Authorization: Bearer $CURANET_ACCESS_TOKEN"
|
||||
|
||||
response="$(_get "$CURANET_REST_URL/${_domain}/Records" "" "")"
|
||||
|
||||
if ! _contains "$response" "$txtvalue"; then
|
||||
_err "Unable to delete record (does not contain $txtvalue )"
|
||||
return 1
|
||||
fi
|
||||
|
||||
recordid=$(echo "$response" | _egrep_o "{\"id\":[0-9]+,\"name\":\"$fulldomain\",\"type\":\"TXT\",\"ttl\":60,\"priority\":0,\"data\":\"..$txtvalue" | _egrep_o "id\":[0-9]+" | cut -c 5-)
|
||||
|
||||
if [ -z "$recordid" ]; then
|
||||
_err "Unable to get recordid"
|
||||
_debug "regex {\"id\":[0-9]+,\"name\":\"$fulldomain\",\"type\":\"TXT\",\"ttl\":60,\"priority\":0,\"data\":\"..$txtvalue"
|
||||
_debug "response $response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Deleting recordID $recordid"
|
||||
response="$(_post "" "$CURANET_REST_URL/${_domain}/Records/$recordid" "" "DELETE")"
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_get_token() {
|
||||
response="$(_post "grant_type=client_credentials&client_id=$CURANET_AUTHCLIENTID&client_secret=$CURANET_AUTHSECRET&scope=dns" "$CURANET_AUTH_URL" "" "")"
|
||||
if ! _contains "$response" "access_token"; then
|
||||
_err "Unable get access token"
|
||||
return 1
|
||||
fi
|
||||
CURANET_ACCESS_TOKEN=$(echo "$response" | _egrep_o "\"access_token\":\"[^\"]+" | cut -c 17-)
|
||||
|
||||
if [ -z "$CURANET_ACCESS_TOKEN" ]; then
|
||||
_err "Unable to get token"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _domain=domain.com
|
||||
# _domain_id=sdjkglgdfewsdfg
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=1
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
export _H2="Accept: application/json"
|
||||
export _H3="Authorization: Bearer $CURANET_ACCESS_TOKEN"
|
||||
response="$(_get "$CURANET_REST_URL/$h/Records" "" "")"
|
||||
|
||||
if [ ! "$(echo "$response" | _egrep_o "Entity not found")" ]; then
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
185
dnsapi/dns_cx.sh
185
dnsapi/dns_cx.sh
@ -1,185 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# CloudXNS Domain api
|
||||
#
|
||||
#CX_Key="1234"
|
||||
#
|
||||
#CX_Secret="sADDsdasdgdsf"
|
||||
|
||||
CX_Api="https://www.cloudxns.net/api2"
|
||||
|
||||
#REST_API
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_cx_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
CX_Key="${CX_Key:-$(_readaccountconf_mutable CX_Key)}"
|
||||
CX_Secret="${CX_Secret:-$(_readaccountconf_mutable CX_Secret)}"
|
||||
if [ -z "$CX_Key" ] || [ -z "$CX_Secret" ]; then
|
||||
CX_Key=""
|
||||
CX_Secret=""
|
||||
_err "You don't specify cloudxns.net api key or secret yet."
|
||||
_err "Please create you key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
REST_API="$CX_Api"
|
||||
|
||||
#save the api key and email to the account conf file.
|
||||
_saveaccountconf_mutable CX_Key "$CX_Key"
|
||||
_saveaccountconf_mutable CX_Secret "$CX_Secret"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
|
||||
add_record "$_domain" "$_sub_domain" "$txtvalue"
|
||||
}
|
||||
|
||||
#fulldomain txtvalue
|
||||
dns_cx_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
CX_Key="${CX_Key:-$(_readaccountconf_mutable CX_Key)}"
|
||||
CX_Secret="${CX_Secret:-$(_readaccountconf_mutable CX_Secret)}"
|
||||
REST_API="$CX_Api"
|
||||
if _get_root "$fulldomain"; then
|
||||
record_id=""
|
||||
existing_records "$_domain" "$_sub_domain" "$txtvalue"
|
||||
if [ "$record_id" ]; then
|
||||
_rest DELETE "record/$record_id/$_domain_id" "{}"
|
||||
_info "Deleted record ${fulldomain}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
#usage: root sub
|
||||
#return if the sub record already exists.
|
||||
#echos the existing records count.
|
||||
# '0' means doesn't exist
|
||||
existing_records() {
|
||||
_debug "Getting txt records"
|
||||
root=$1
|
||||
sub=$2
|
||||
if ! _rest GET "record/$_domain_id?:domain_id?host_id=0&offset=0&row_num=100"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
seg=$(printf "%s\n" "$response" | _egrep_o '"record_id":[^{]*host":"'"$_sub_domain"'"[^}]*\}')
|
||||
_debug seg "$seg"
|
||||
if [ -z "$seg" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if printf "%s" "$response" | grep '"type":"TXT"' >/dev/null; then
|
||||
record_id=$(printf "%s\n" "$seg" | _egrep_o '"record_id":"[^"]*"' | cut -d : -f 2 | tr -d \" | _head_n 1)
|
||||
_debug record_id "$record_id"
|
||||
return 0
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
#add the txt record.
|
||||
#usage: root sub txtvalue
|
||||
add_record() {
|
||||
root=$1
|
||||
sub=$2
|
||||
txtvalue=$3
|
||||
fulldomain="$sub.$root"
|
||||
|
||||
_info "Adding record"
|
||||
|
||||
if ! _rest POST "record" "{\"domain_id\": $_domain_id, \"host\":\"$_sub_domain\", \"value\":\"$txtvalue\", \"type\":\"TXT\",\"ttl\":600, \"line_id\":1}"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_id=sdjkglgdfewsdfg
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
|
||||
if ! _rest GET "domain"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "$h."; then
|
||||
seg=$(printf "%s\n" "$response" | _egrep_o '"id":[^{]*"'"$h"'."[^}]*}')
|
||||
_debug seg "$seg"
|
||||
_domain_id=$(printf "%s\n" "$seg" | _egrep_o "\"id\":\"[^\"]*\"" | cut -d : -f 2 | tr -d \")
|
||||
_debug _domain_id "$_domain_id"
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_domain="$h"
|
||||
_debug _domain "$_domain"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p="$i"
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
#Usage: method URI data
|
||||
_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
_debug ep "$ep"
|
||||
url="$REST_API/$ep"
|
||||
_debug url "$url"
|
||||
|
||||
cdate=$(date -u "+%Y-%m-%d %H:%M:%S UTC")
|
||||
_debug cdate "$cdate"
|
||||
|
||||
data="$3"
|
||||
_debug data "$data"
|
||||
|
||||
sec="$CX_Key$url$data$cdate$CX_Secret"
|
||||
_debug sec "$sec"
|
||||
hmac=$(printf "%s" "$sec" | _digest md5 hex)
|
||||
_debug hmac "$hmac"
|
||||
|
||||
export _H1="API-KEY: $CX_Key"
|
||||
export _H2="API-REQUEST-DATE: $cdate"
|
||||
export _H3="API-HMAC: $hmac"
|
||||
export _H4="Content-Type: application/json"
|
||||
|
||||
if [ "$data" ]; then
|
||||
response="$(_post "$data" "$url" "" "$m")"
|
||||
else
|
||||
response="$(_get "$url")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
|
||||
_contains "$response" '"code":1'
|
||||
|
||||
}
|
@ -1,21 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
########
|
||||
# Custom cyon.ch DNS API for use with [acme.sh](https://github.com/acmesh-official/acme.sh)
|
||||
#
|
||||
# Usage: acme.sh --issue --dns dns_cyon -d www.domain.com
|
||||
#
|
||||
# Dependencies:
|
||||
# -------------
|
||||
# - oathtool (When using 2 Factor Authentication)
|
||||
#
|
||||
# Issues:
|
||||
# -------
|
||||
# Any issues / questions / suggestions can be posted here:
|
||||
# https://github.com/noplanman/cyon-api/issues
|
||||
#
|
||||
# Author: Armando Lüscher <armando@noplanman.ch>
|
||||
########
|
||||
# shellcheck disable=SC2034
|
||||
dns_cyon_info='cyon.ch
|
||||
Site: cyon.ch
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_cyon
|
||||
Options:
|
||||
CY_Username Username
|
||||
CY_Password API Token
|
||||
CY_OTP_Secret OTP token. Only required if using 2FA
|
||||
Issues: github.com/noplanman/cyon-api/issues
|
||||
Author: Armando Lüscher <armando@noplanman.ch>
|
||||
'
|
||||
|
||||
dns_cyon_add() {
|
||||
_cyon_load_credentials &&
|
||||
@ -44,7 +38,7 @@ dns_cyon_rm() {
|
||||
_cyon_load_credentials() {
|
||||
# Convert loaded password to/from base64 as needed.
|
||||
if [ "${CY_Password_B64}" ]; then
|
||||
CY_Password="$(printf "%s" "${CY_Password_B64}" | _dbase64 "multiline")"
|
||||
CY_Password="$(printf "%s" "${CY_Password_B64}" | _dbase64)"
|
||||
elif [ "${CY_Password}" ]; then
|
||||
CY_Password_B64="$(printf "%s" "${CY_Password}" | _base64)"
|
||||
fi
|
||||
|
@ -1,31 +1,14 @@
|
||||
#!/usr/bin/env sh
|
||||
# -*- mode: sh; tab-width: 2; indent-tabs-mode: s; coding: utf-8 -*-
|
||||
# vim: et ts=2 sw=2
|
||||
#
|
||||
# DirectAdmin 1.41.0 API
|
||||
# The DirectAdmin interface has it's own Let's encrypt functionality, but this
|
||||
# script can be used to generate certificates for names which are not hosted on
|
||||
# DirectAdmin
|
||||
#
|
||||
# User must provide login data and URL to DirectAdmin incl. port.
|
||||
# You can create login key, by using the Login Keys function
|
||||
# ( https://da.example.com:8443/CMD_LOGIN_KEYS ), which only has access to
|
||||
# - CMD_API_DNS_CONTROL
|
||||
# - CMD_API_SHOW_DOMAINS
|
||||
#
|
||||
# See also https://www.directadmin.com/api.php and
|
||||
# https://www.directadmin.com/features.php?id=1298
|
||||
#
|
||||
# Report bugs to https://github.com/TigerP/acme.sh/issues
|
||||
#
|
||||
# Values to export:
|
||||
# export DA_Api="https://remoteUser:remotePassword@da.example.com:8443"
|
||||
# export DA_Api_Insecure=1
|
||||
#
|
||||
# Set DA_Api_Insecure to 1 for insecure and 0 for secure -> difference is
|
||||
# whether ssl cert is checked for validity (0) or whether it is just accepted
|
||||
# (1)
|
||||
#
|
||||
# shellcheck disable=SC2034
|
||||
dns_da_info='DirectAdmin Server API
|
||||
Site: DirectAdmin.com/api.php
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_da
|
||||
Options:
|
||||
DA_Api API Server URL. E.g. "https://remoteUser:remotePassword@da.domain.tld:8443"
|
||||
DA_Api_Insecure Insecure TLS. 0: check for cert validity, 1: always accept
|
||||
Issues: github.com/TigerP/acme.sh/issues
|
||||
'
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
# Usage: dns_myapi_add _acme-challenge.www.example.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
|
@ -1,18 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_ddnss_info='DDNSS.de
|
||||
Site: DDNSS.de
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_ddnss
|
||||
Options:
|
||||
DDNSS_Token API Token
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2230
|
||||
Author: RaidenII, helbgd, mod242
|
||||
'
|
||||
|
||||
#Created by RaidenII, to use DuckDNS's API to add/remove text records
|
||||
#modified by helbgd @ 03/13/2018 to support ddnss.de
|
||||
#modified by mod242 @ 04/24/2018 to support different ddnss domains
|
||||
#Please note: the Wildcard Feature must be turned on for the Host record
|
||||
#and the checkbox for TXT needs to be enabled
|
||||
|
||||
# Pass credentials before "acme.sh --issue --dns dns_ddnss ..."
|
||||
# --
|
||||
# export DDNSS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
||||
# --
|
||||
#
|
||||
|
||||
DDNSS_DNS_API="https://ip4.ddnss.de/upd.php"
|
||||
DDNSS_DNS_API="https://ddnss.de/upd.php"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
@ -77,7 +74,7 @@ dns_ddnss_rm() {
|
||||
|
||||
# Now remove the TXT record from DDNS DNS
|
||||
_info "Trying to remove TXT record"
|
||||
if _ddnss_rest GET "key=$DDNSS_Token&host=$_ddnss_domain&txtm=1&txt=."; then
|
||||
if _ddnss_rest GET "key=$DDNSS_Token&host=$_ddnss_domain&txtm=2"; then
|
||||
if [ "$response" = "Updated 1 hostname." ]; then
|
||||
_info "TXT record has been successfully removed from your DDNSS domain."
|
||||
return 0
|
||||
|
@ -1,11 +1,13 @@
|
||||
#!/usr/bin/env sh
|
||||
#
|
||||
# deSEC.io Domain API
|
||||
#
|
||||
# Author: Zheng Qian
|
||||
#
|
||||
# deSEC API doc
|
||||
# https://desec.readthedocs.io/en/latest/
|
||||
# shellcheck disable=SC2034
|
||||
dns_desec_info='deSEC.io
|
||||
Site: desec.readthedocs.io/en/latest/
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_desec
|
||||
Options:
|
||||
DDNSS_Token API Token
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2180
|
||||
Author: Zheng Qian
|
||||
'
|
||||
|
||||
REST_API="https://desec.io/api/v1/domains"
|
||||
|
||||
|
@ -1,18 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
########################################################################
|
||||
# https://dyndnsfree.de hook script for acme.sh
|
||||
#
|
||||
# Environment variables:
|
||||
#
|
||||
# - $DF_user (your dyndnsfree.de username)
|
||||
# - $DF_password (your dyndnsfree.de password)
|
||||
#
|
||||
# Author: Thilo Gass <thilo.gass@gmail.com>
|
||||
# Git repo: https://github.com/ThiloGa/acme.sh
|
||||
|
||||
#-- dns_df_add() - Add TXT record --------------------------------------
|
||||
# Usage: dns_df_add _acme-challenge.subdomain.domain.com "XyZ123..."
|
||||
# shellcheck disable=SC2034
|
||||
dns_df_info='DynDnsFree.de
|
||||
Domains: dynup.de
|
||||
Site: DynDnsFree.de
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_df
|
||||
Options:
|
||||
DF_user Username
|
||||
DF_password Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2897
|
||||
Author: Thilo Gass <thilo.gass@gmail.com>
|
||||
'
|
||||
|
||||
dyndnsfree_api="https://dynup.de/acme.php"
|
||||
|
||||
|
@ -1,16 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
## Will be called by acme.sh to add the txt record to your api system.
|
||||
## returns 0 means success, otherwise error.
|
||||
|
||||
## Author: thewer <github at thewer.com>
|
||||
## GitHub: https://github.com/gitwer/acme.sh
|
||||
|
||||
##
|
||||
## Environment Variables Required:
|
||||
##
|
||||
## DO_API_KEY="75310dc4ca779ac39a19f6355db573b49ce92ae126553ebd61ac3a3ae34834cc"
|
||||
##
|
||||
# shellcheck disable=SC2034
|
||||
dns_dgon_info='DigitalOcean.com
|
||||
Site: DigitalOcean.com/help/api/
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dgon
|
||||
Options:
|
||||
DO_API_KEY API Key
|
||||
Author: <github@thewer.com>
|
||||
'
|
||||
|
||||
##################### Public functions #####################
|
||||
|
||||
@ -192,6 +188,7 @@ _get_base_domain() {
|
||||
## 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.digitalocean.com/v2/domains"
|
||||
found=""
|
||||
|
||||
## while we dont have a matching domain we keep going
|
||||
while [ -z "$found" ]; do
|
||||
@ -205,9 +202,7 @@ _get_base_domain() {
|
||||
fi
|
||||
_debug2 domain_list "$domain_list"
|
||||
|
||||
## 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
|
||||
i=1
|
||||
while [ $i -gt 0 ]; do
|
||||
## get next longest domain
|
||||
_domain=$(printf "%s" "$fulldomain" | cut -d . -f "$i"-"$MAX_DOM")
|
||||
|
188
dnsapi/dns_dnsexit.sh
Normal file
188
dnsapi/dns_dnsexit.sh
Normal file
@ -0,0 +1,188 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_dnsexit_info='DNSExit.com
|
||||
Site: DNSExit.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dnsexit
|
||||
Options:
|
||||
DNSEXIT_API_KEY API Key
|
||||
DNSEXIT_AUTH_USER Username
|
||||
DNSEXIT_AUTH_PASS Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/4719
|
||||
Author: Samuel Jimenez
|
||||
'
|
||||
|
||||
DNSEXIT_API_URL="https://api.dnsexit.com/dns/"
|
||||
DNSEXIT_HOSTS_URL="https://update.dnsexit.com/ipupdate/hosts.jsp"
|
||||
|
||||
######## Public functions #####################
|
||||
#Usage: dns_dnsexit_add _acme-challenge.*.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_dnsexit_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using DNSExit.com"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_debug 'Load account auth'
|
||||
if ! get_account_info; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug 'First detect the root zone'
|
||||
if ! _get_root "$fulldomain"; then
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
if ! _dnsexit_rest "{\"domain\":\"$_domain\",\"add\":{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\",\"ttl\":0,\"overwrite\":false}}"; then
|
||||
_err "$response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 _response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_dnsexit_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using DNSExit.com"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_debug 'Load account auth'
|
||||
if ! get_account_info; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug 'First detect the root zone'
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "$response"
|
||||
return 1
|
||||
fi
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
if ! _dnsexit_rest "{\"domain\":\"$_domain\",\"delete\":{\"type\":\"TXT\",\"name\":\"$_sub_domain\",\"content\":\"$txtvalue\"}}"; then
|
||||
_err "$response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 _response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=1
|
||||
while true; do
|
||||
_domain=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$_domain"
|
||||
if [ -z "$_domain" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug login "$DNSEXIT_AUTH_USER"
|
||||
_debug password "$DNSEXIT_AUTH_PASS"
|
||||
_debug domain "$_domain"
|
||||
|
||||
_dnsexit_http "login=$DNSEXIT_AUTH_USER&password=$DNSEXIT_AUTH_PASS&domain=$_domain"
|
||||
|
||||
if _contains "$response" "0=$_domain"; then
|
||||
_sub_domain="$(echo "$fulldomain" | sed "s/\\.$_domain\$//")"
|
||||
return 0
|
||||
else
|
||||
_debug "Go to next level of $_domain"
|
||||
fi
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
_dnsexit_rest() {
|
||||
m=POST
|
||||
ep=""
|
||||
data="$1"
|
||||
_debug _dnsexit_rest "$ep"
|
||||
_debug data "$data"
|
||||
|
||||
api_key_trimmed=$(echo "$DNSEXIT_API_KEY" | tr -d '"')
|
||||
|
||||
export _H1="apikey: $api_key_trimmed"
|
||||
export _H2='Content-Type: application/json'
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$DNSEXIT_API_URL/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$DNSEXIT_API_URL/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Error $ep"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
_dnsexit_http() {
|
||||
m=GET
|
||||
param="$1"
|
||||
_debug param "$param"
|
||||
_debug get "$DNSEXIT_HOSTS_URL?$param"
|
||||
|
||||
response="$(_get "$DNSEXIT_HOSTS_URL?$param")"
|
||||
|
||||
_debug response "$response"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Error $param"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
get_account_info() {
|
||||
|
||||
DNSEXIT_API_KEY="${DNSEXIT_API_KEY:-$(_readaccountconf_mutable DNSEXIT_API_KEY)}"
|
||||
if test -z "$DNSEXIT_API_KEY"; then
|
||||
DNSEXIT_API_KEY=''
|
||||
_err 'DNSEXIT_API_KEY was not exported'
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable DNSEXIT_API_KEY "$DNSEXIT_API_KEY"
|
||||
|
||||
DNSEXIT_AUTH_USER="${DNSEXIT_AUTH_USER:-$(_readaccountconf_mutable DNSEXIT_AUTH_USER)}"
|
||||
if test -z "$DNSEXIT_AUTH_USER"; then
|
||||
DNSEXIT_AUTH_USER=""
|
||||
_err 'DNSEXIT_AUTH_USER was not exported'
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable DNSEXIT_AUTH_USER "$DNSEXIT_AUTH_USER"
|
||||
|
||||
DNSEXIT_AUTH_PASS="${DNSEXIT_AUTH_PASS:-$(_readaccountconf_mutable DNSEXIT_AUTH_PASS)}"
|
||||
if test -z "$DNSEXIT_AUTH_PASS"; then
|
||||
DNSEXIT_AUTH_PASS=""
|
||||
_err 'DNSEXIT_AUTH_PASS was not exported'
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable DNSEXIT_AUTH_PASS "$DNSEXIT_AUTH_PASS"
|
||||
|
||||
return 0
|
||||
}
|
@ -1,15 +1,14 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# 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=""
|
||||
# shellcheck disable=SC2034
|
||||
dns_dnshome_info='dnsHome.de
|
||||
Site: dnsHome.de
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dnshome
|
||||
Options:
|
||||
DNSHOME_Subdomain Subdomain
|
||||
DNSHOME_SubdomainPassword Subdomain Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/3819
|
||||
Author: dnsHome.de https://github.com/dnsHome-de
|
||||
'
|
||||
|
||||
# Usage: add subdomain.ddnsdomain.tld "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
# Used to add txt record
|
||||
|
@ -1,12 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# DNSimple domain api
|
||||
# https://github.com/pho3nixf1re/acme.sh/issues
|
||||
#
|
||||
# This is your oauth token which can be acquired on the account page. Please
|
||||
# note that this must be an _account_ token and not a _user_ token.
|
||||
# https://dnsimple.com/a/<your account id>/account/access_tokens
|
||||
# DNSimple_OAUTH_TOKEN="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
# shellcheck disable=SC2034
|
||||
dns_dnsimple_info='DNSimple.com
|
||||
Site: DNSimple.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dnsimple
|
||||
Options:
|
||||
DNSimple_OAUTH_TOKEN OAuth Token
|
||||
Issues: github.com/pho3nixf1re/acme.sh/issues
|
||||
'
|
||||
|
||||
DNSimple_API="https://api.dnsimple.com/v2"
|
||||
|
||||
|
251
dnsapi/dns_dnsservices.sh
Executable file
251
dnsapi/dns_dnsservices.sh
Executable file
@ -0,0 +1,251 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_dnsservices_info='DNS.Services
|
||||
Site: DNS.Services
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dnsservices
|
||||
Options:
|
||||
DnsServices_Username Username
|
||||
DnsServices_Password Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/4152
|
||||
Author: Bjarke Bruun <bbruun@gmail.com>
|
||||
'
|
||||
|
||||
DNSServices_API=https://dns.services/api
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_dnsservices_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_dnsservices_add() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
_info "Using dns.services to create ACME DNS challenge"
|
||||
_debug2 add_fulldomain "$fulldomain"
|
||||
_debug2 add_txtvalue "$txtvalue"
|
||||
|
||||
# Read username/password from environment or .acme.sh/accounts.conf
|
||||
DnsServices_Username="${DnsServices_Username:-$(_readaccountconf_mutable DnsServices_Username)}"
|
||||
DnsServices_Password="${DnsServices_Password:-$(_readaccountconf_mutable DnsServices_Password)}"
|
||||
if [ -z "$DnsServices_Username" ] || [ -z "$DnsServices_Password" ]; then
|
||||
DnsServices_Username=""
|
||||
DnsServices_Password=""
|
||||
_err "You didn't specify dns.services api username and password yet."
|
||||
_err "Set environment variables DnsServices_Username and DnsServices_Password"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Setup GET/POST/DELETE headers
|
||||
_setup_headers
|
||||
|
||||
#save the credentials to the account conf file.
|
||||
_saveaccountconf_mutable DnsServices_Username "$DnsServices_Username"
|
||||
_saveaccountconf_mutable DnsServices_Password "$DnsServices_Password"
|
||||
|
||||
if ! _contains "$DnsServices_Username" "@"; then
|
||||
_err "It seems that the username variable DnsServices_Username has not been set/left blank"
|
||||
_err "or is not a valid email. Please correct and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _get_root "${fulldomain}"; then
|
||||
_err "Invalid domain ${fulldomain}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! createRecord "$fulldomain" "${txtvalue}"; then
|
||||
_err "Error creating TXT record in domain $fulldomain in $rootZoneName"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 challenge-created "Created $fulldomain"
|
||||
return 0
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Description: Remove the txt record after validation.
|
||||
dns_dnsservices_rm() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
_info "Using dns.services to remove DNS record $fulldomain TXT $txtvalue"
|
||||
_debug rm_fulldomain "$fulldomain"
|
||||
_debug rm_txtvalue "$txtvalue"
|
||||
|
||||
# Read username/password from environment or .acme.sh/accounts.conf
|
||||
DnsServices_Username="${DnsServices_Username:-$(_readaccountconf_mutable DnsServices_Username)}"
|
||||
DnsServices_Password="${DnsServices_Password:-$(_readaccountconf_mutable DnsServices_Password)}"
|
||||
if [ -z "$DnsServices_Username" ] || [ -z "$DnsServices_Password" ]; then
|
||||
DnsServices_Username=""
|
||||
DnsServices_Password=""
|
||||
_err "You didn't specify dns.services api username and password yet."
|
||||
_err "Set environment variables DnsServices_Username and DnsServices_Password"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Setup GET/POST/DELETE headers
|
||||
_setup_headers
|
||||
|
||||
if ! _get_root "${fulldomain}"; then
|
||||
_err "Invalid domain ${fulldomain}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 rm_rootDomainInfo "found root domain $rootZoneName for $fulldomain"
|
||||
|
||||
if ! deleteRecord "${fulldomain}" "${txtvalue}"; then
|
||||
_err "Error removing record: $fulldomain TXT ${txtvalue}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_setup_headers() {
|
||||
# Set up API Headers for _get() and _post()
|
||||
# The <function>_add or <function>_rm must have been called before to work
|
||||
|
||||
if [ -z "$DnsServices_Username" ] || [ -z "$DnsServices_Password" ]; then
|
||||
_err "Could not setup BASIC authentication headers, they are missing"
|
||||
return 1
|
||||
fi
|
||||
|
||||
DnsServiceCredentials="$(printf "%s" "$DnsServices_Username:$DnsServices_Password" | _base64)"
|
||||
export _H1="Authorization: Basic $DnsServiceCredentials"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
# Just return if headers are set
|
||||
return 0
|
||||
}
|
||||
|
||||
_get_root() {
|
||||
domain="$1"
|
||||
_debug2 _get_root "Get the root domain of ${domain} for DNS API"
|
||||
|
||||
# Setup _get() and _post() headers
|
||||
#_setup_headers
|
||||
|
||||
result=$(_H1="$_H1" _H2="$_H2" _get "$DNSServices_API/dns")
|
||||
result2="$(printf "%s\n" "$result" | tr '[' '\n' | grep '"name"')"
|
||||
result3="$(printf "%s\n" "$result2" | tr '}' '\n' | grep '"name"' | sed "s,^\,,,g" | sed "s,$,},g")"
|
||||
useResult=""
|
||||
_debug2 _get_root "Got the following root domain(s) $result"
|
||||
_debug2 _get_root "- JSON: $result"
|
||||
|
||||
if [ "$(printf "%s\n" "$result" | tr '}' '\n' | grep -c '"name"')" -gt "1" ]; then
|
||||
checkMultiZones="true"
|
||||
_debug2 _get_root "- multiple zones found"
|
||||
else
|
||||
checkMultiZones="false"
|
||||
_debug2 _get_root "- single zone found"
|
||||
fi
|
||||
|
||||
# Find/isolate the root zone to work with in createRecord() and deleteRecord()
|
||||
rootZone=""
|
||||
if [ "$checkMultiZones" = "true" ]; then
|
||||
#rootZone=$(for x in $(printf "%s" "${result3}" | tr ',' '\n' | sed -n 's/.*"name":"\(.*\)",.*/\1/p'); do if [ "$(echo "$domain" | grep "$x")" != "" ]; then echo "$x"; fi; done)
|
||||
rootZone=$(for x in $(printf "%s\n" "${result3}" | tr ',' '\n' | grep name | cut -d'"' -f4); do if [ "$(echo "$domain" | grep "$x")" != "" ]; then echo "$x"; fi; done)
|
||||
if [ "$rootZone" != "" ]; then
|
||||
_debug2 _rootZone "- root zone for $domain is $rootZone"
|
||||
else
|
||||
_err "Could not find root zone for $domain, is it correctly typed?"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
rootZone=$(echo "$result" | tr '}' '\n' | _egrep_o '"name":"[^"]*' | cut -d'"' -f4)
|
||||
_debug2 _get_root "- only found 1 domain in API: $rootZone"
|
||||
fi
|
||||
|
||||
if [ -z "$rootZone" ]; then
|
||||
_err "Could not find root domain for $domain - is it correctly typed?"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Make sure we use the correct API zone data
|
||||
useResult="$(printf "%s\n" "${result3}" tr ',' '\n' | grep "$rootZone")"
|
||||
_debug2 _useResult "useResult=$useResult"
|
||||
|
||||
# Setup variables used by other functions to communicate with DNS.Services API
|
||||
#zoneInfo=$(printf "%s\n" "$useResult" | sed -E 's,.*(zones)(.*),\1\2,g' | sed -E 's,^(.*"name":")([^"]*)"(.*)$,\2,g')
|
||||
zoneInfo=$(printf "%s\n" "$useResult" | tr ',' '\n' | grep '"name"' | cut -d'"' -f4)
|
||||
rootZoneName="$rootZone"
|
||||
subDomainName="$(printf "%s\n" "$domain" | sed "s,\.$rootZone,,g")"
|
||||
subDomainNameClean="$(printf "%s\n" "$domain" | sed "s,_acme-challenge.,,g")"
|
||||
rootZoneDomainID=$(printf "%s\n" "$useResult" | tr ',' '\n' | grep domain_id | cut -d'"' -f4)
|
||||
rootZoneServiceID=$(printf "%s\n" "$useResult" | tr ',' '\n' | grep service_id | cut -d'"' -f4)
|
||||
|
||||
_debug2 _zoneInfo "Zone info from API : $zoneInfo"
|
||||
_debug2 _get_root "Root zone name : $rootZoneName"
|
||||
_debug2 _get_root "Root zone domain ID : $rootZoneDomainID"
|
||||
_debug2 _get_root "Root zone service ID: $rootZoneServiceID"
|
||||
_debug2 _get_root "Sub domain : $subDomainName"
|
||||
|
||||
_debug _get_root "Found valid root domain $rootZone for $subDomainNameClean"
|
||||
return 0
|
||||
}
|
||||
|
||||
createRecord() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
# Get root domain information - needed for DNS.Services API communication
|
||||
if [ -z "$rootZoneName" ] || [ -z "$rootZoneDomainID" ] || [ -z "$rootZoneServiceID" ]; then
|
||||
_get_root "$fulldomain"
|
||||
fi
|
||||
if [ -z "$rootZoneName" ] || [ -z "$rootZoneDomainID" ] || [ -z "$rootZoneServiceID" ]; then
|
||||
_err "Something happend - could not get the API zone information"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 createRecord "CNAME TXT value is: $txtvalue"
|
||||
|
||||
# Prepare data to send to API
|
||||
data="{\"name\":\"${fulldomain}\",\"type\":\"TXT\",\"content\":\"${txtvalue}\", \"ttl\":\"10\"}"
|
||||
|
||||
_debug2 createRecord "data to API: $data"
|
||||
result=$(_post "$data" "$DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID/records" "" "POST")
|
||||
_debug2 createRecord "result from API: $result"
|
||||
|
||||
if [ "$(echo "$result" | _egrep_o "\"success\":true")" = "" ]; then
|
||||
_err "Failed to create TXT record $fulldomain with content $txtvalue in zone $rootZoneName"
|
||||
_err "$result"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Record \"$fulldomain TXT $txtvalue\" has been created"
|
||||
return 0
|
||||
}
|
||||
|
||||
deleteRecord() {
|
||||
fulldomain="$1"
|
||||
txtvalue="$2"
|
||||
|
||||
_log deleteRecord "Deleting $fulldomain TXT $txtvalue record"
|
||||
|
||||
if [ -z "$rootZoneName" ] || [ -z "$rootZoneDomainID" ] || [ -z "$rootZoneServiceID" ]; then
|
||||
_get_root "$fulldomain"
|
||||
fi
|
||||
|
||||
result="$(_H1="$_H1" _H2="$_H2" _get "$DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID")"
|
||||
#recordInfo="$(echo "$result" | sed -e 's/:{/:{\n/g' -e 's/},/\n},\n/g' | grep "${txtvalue}")"
|
||||
#recordID="$(echo "$recordInfo" | sed -e 's/:{/:{\n/g' -e 's/},/\n},\n/g' | grep "${txtvalue}" | sed -E 's,.*(zones)(.*),\1\2,g' | sed -E 's,^(.*"id":")([^"]*)"(.*)$,\2,g')"
|
||||
recordID="$(printf "%s\n" "$result" | tr '}' '\n' | grep -- "$txtvalue" | tr ',' '\n' | grep '"id"' | cut -d'"' -f4)"
|
||||
_debug2 _recordID "recordID used for deletion of record: $recordID"
|
||||
|
||||
if [ -z "$recordID" ]; then
|
||||
_info "Record $fulldomain TXT $txtvalue not found or already deleted"
|
||||
return 0
|
||||
else
|
||||
_debug2 deleteRecord "Found recordID=$recordID"
|
||||
fi
|
||||
|
||||
_debug2 deleteRecord "DELETE request $DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID/records/$recordID"
|
||||
_log "curl DELETE request $DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID/records/$recordID"
|
||||
result="$(_H1="$_H1" _H2="$_H2" _post "" "$DNSServices_API/service/$rootZoneServiceID/dns/$rootZoneDomainID/records/$recordID" "" "DELETE")"
|
||||
_debug2 deleteRecord "API Delete result \"$result\""
|
||||
_log "curl API Delete result \"$result\""
|
||||
|
||||
# Return OK regardless
|
||||
return 0
|
||||
}
|
148
dnsapi/dns_do.sh
148
dnsapi/dns_do.sh
@ -1,148 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# DNS API for Domain-Offensive / Resellerinterface / Domainrobot
|
||||
|
||||
# Report bugs at https://github.com/seidler2547/acme.sh/issues
|
||||
|
||||
# set these environment variables to match your customer ID and password:
|
||||
# DO_PID="KD-1234567"
|
||||
# DO_PW="cdfkjl3n2"
|
||||
|
||||
DO_URL="https://soap.resellerinterface.de/"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_myapi_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_do_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
if _dns_do_authenticate; then
|
||||
_info "Adding TXT record to ${_domain} as ${fulldomain}"
|
||||
_dns_do_soap createRR origin "${_domain}" name "${fulldomain}" type TXT data "${txtvalue}" ttl 300
|
||||
if _contains "${response}" '>success<'; then
|
||||
return 0
|
||||
fi
|
||||
_err "Could not create resource record, check logs"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
#fulldomain
|
||||
dns_do_rm() {
|
||||
fulldomain=$1
|
||||
if _dns_do_authenticate; then
|
||||
if _dns_do_list_rrs; then
|
||||
_dns_do_had_error=0
|
||||
for _rrid in ${_rr_list}; do
|
||||
_info "Deleting resource record $_rrid for $_domain"
|
||||
_dns_do_soap deleteRR origin "${_domain}" rrid "${_rrid}"
|
||||
if ! _contains "${response}" '>success<'; then
|
||||
_dns_do_had_error=1
|
||||
_err "Could not delete resource record for ${_domain}, id ${_rrid}"
|
||||
fi
|
||||
done
|
||||
return $_dns_do_had_error
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
_dns_do_authenticate() {
|
||||
_info "Authenticating as ${DO_PID}"
|
||||
_dns_do_soap authPartner partner "${DO_PID}" password "${DO_PW}"
|
||||
if _contains "${response}" '>success<'; then
|
||||
_get_root "$fulldomain"
|
||||
_debug "_domain $_domain"
|
||||
return 0
|
||||
else
|
||||
_err "Authentication failed, are DO_PID and DO_PW set correctly?"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
_dns_do_list_rrs() {
|
||||
_dns_do_soap getRRList origin "${_domain}"
|
||||
if ! _contains "${response}" 'SOAP-ENC:Array'; then
|
||||
_err "getRRList origin ${_domain} failed"
|
||||
return 1
|
||||
fi
|
||||
_rr_list="$(echo "${response}" |
|
||||
tr -d "\n\r\t" |
|
||||
sed -e 's/<item xsi:type="ns2:Map">/\n/g' |
|
||||
grep ">$(_regexcape "$fulldomain")</value>" |
|
||||
sed -e 's/<\/item>/\n/g' |
|
||||
grep '>id</key><value' |
|
||||
_egrep_o '>[0-9]{1,16}<' |
|
||||
tr -d '><')"
|
||||
[ "${_rr_list}" ]
|
||||
}
|
||||
|
||||
_dns_do_soap() {
|
||||
func="$1"
|
||||
shift
|
||||
# put the parameters to xml
|
||||
body="<tns:${func} xmlns:tns=\"${DO_URL}\">"
|
||||
while [ "$1" ]; do
|
||||
_k="$1"
|
||||
shift
|
||||
_v="$1"
|
||||
shift
|
||||
body="$body<$_k>$_v</$_k>"
|
||||
done
|
||||
body="$body</tns:${func}>"
|
||||
_debug2 "SOAP request ${body}"
|
||||
|
||||
# build SOAP XML
|
||||
_xml='<?xml version="1.0" encoding="UTF-8"?>
|
||||
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
|
||||
<env:Body>'"$body"'</env:Body>
|
||||
</env:Envelope>'
|
||||
|
||||
# set SOAP headers
|
||||
export _H1="SOAPAction: ${DO_URL}#${func}"
|
||||
|
||||
if ! response="$(_post "${_xml}" "${DO_URL}")"; then
|
||||
_err "Error <$1>"
|
||||
return 1
|
||||
fi
|
||||
_debug2 "SOAP response $response"
|
||||
|
||||
# retrieve cookie header
|
||||
_H2="$(_egrep_o 'Cookie: [^;]+' <"$HTTP_HEADER" | _head_n 1)"
|
||||
export _H2
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=1
|
||||
|
||||
_dns_do_soap getDomainList
|
||||
_all_domains="$(echo "${response}" |
|
||||
tr -d "\n\r\t " |
|
||||
_egrep_o 'domain</key><value[^>]+>[^<]+' |
|
||||
sed -e 's/^domain<\/key><value[^>]*>//g')"
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
if [ -z "$h" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "${_all_domains}" "^$(_regexcape "$h")\$"; then
|
||||
_domain="$h"
|
||||
return 0
|
||||
fi
|
||||
|
||||
i=$(_math $i + 1)
|
||||
done
|
||||
_debug "$domain not found"
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
_regexcape() {
|
||||
echo "$1" | sed -e 's/\([]\.$*^[]\)/\\\1/g'
|
||||
}
|
@ -1,12 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Official Let's Encrypt API for do.de / Domain-Offensive
|
||||
#
|
||||
# This is different from the dns_do adapter, because dns_do is only usable for enterprise customers
|
||||
# This API is also available to private customers/individuals
|
||||
#
|
||||
# Provide the required LetsEncrypt token like this:
|
||||
# DO_LETOKEN="FmD408PdqT1E269gUK57"
|
||||
# shellcheck disable=SC2034
|
||||
dns_doapi_info='Domain-Offensive do.de
|
||||
Official LetsEncrypt API for do.de / Domain-Offensive.
|
||||
This is different from the dns_do adapter, because dns_do is only usable for enterprise customers.
|
||||
This API is also available to private customers/individuals.
|
||||
Site: do.de
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_doapi
|
||||
Options:
|
||||
DO_LETOKEN LetsEncrypt Token
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2057
|
||||
'
|
||||
|
||||
DO_API="https://www.do.de/api/letsencrypt"
|
||||
|
||||
|
@ -1,4 +1,13 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_domeneshop_info='DomeneShop.no
|
||||
Site: DomeneShop.no
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_domeneshop
|
||||
Options:
|
||||
DOMENESHOP_Token Token
|
||||
DOMENESHOP_Secret Secret
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2457
|
||||
'
|
||||
|
||||
DOMENESHOP_Api_Endpoint="https://api.domeneshop.no/v0"
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Dnspod.cn Domain api
|
||||
#
|
||||
#DP_Id="1234"
|
||||
#
|
||||
#DP_Key="sADDsdasdgdsf"
|
||||
# shellcheck disable=SC2034
|
||||
dns_dp_info='DNSPod.cn
|
||||
Site: DNSPod.cn
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dp
|
||||
Options:
|
||||
DP_Id Id
|
||||
DP_Key Key
|
||||
'
|
||||
|
||||
REST_API="https://dnsapi.cn"
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Dnspod.com Domain api
|
||||
#
|
||||
#DPI_Id="1234"
|
||||
#
|
||||
#DPI_Key="sADDsdasdgdsf"
|
||||
# shellcheck disable=SC2034
|
||||
dns_dpi_info='DNSPod.com
|
||||
Site: DNSPod.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dpi
|
||||
Options:
|
||||
DPI_Id Id
|
||||
DPI_Key Key
|
||||
'
|
||||
|
||||
REST_API="https://api.dnspod.com"
|
||||
|
||||
|
@ -1,10 +1,14 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_dreamhost_info='DreamHost.com
|
||||
Site: DreamHost.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dreamhost
|
||||
Options:
|
||||
DH_API_KEY API Key
|
||||
Issues: github.com/RhinoLance/acme.sh
|
||||
Author: RhinoLance
|
||||
'
|
||||
|
||||
#Author: RhinoLance
|
||||
#Report Bugs here: https://github.com/RhinoLance/acme.sh
|
||||
#
|
||||
|
||||
#define the api endpoint
|
||||
DH_API_ENDPOINT="https://api.dreamhost.com/"
|
||||
querystring=""
|
||||
|
||||
|
@ -1,14 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Created by RaidenII, to use DuckDNS's API to add/remove text records
|
||||
#06/27/2017
|
||||
|
||||
# Pass credentials before "acme.sh --issue --dns dns_duckdns ..."
|
||||
# --
|
||||
# export DuckDNS_Token="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
|
||||
# --
|
||||
#
|
||||
# Due to the fact that DuckDNS uses StartSSL as cert provider, --insecure may need to be used with acme.sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_duckdns_info='DuckDNS.org
|
||||
Site: www.DuckDNS.org
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_duckdns
|
||||
Options:
|
||||
DuckDNS_Token API Token
|
||||
Author: RaidenII
|
||||
'
|
||||
|
||||
DuckDNS_API="https://www.duckdns.org/update"
|
||||
|
||||
|
@ -1,7 +1,13 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#DD_API_User="xxxxx"
|
||||
#DD_API_Key="xxxxxx"
|
||||
# shellcheck disable=SC2034
|
||||
dns_durabledns_info='DurableDNS.com
|
||||
Site: DurableDNS.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_durabledns
|
||||
Options:
|
||||
DD_API_User API User
|
||||
DD_API_Key API Key
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2281
|
||||
'
|
||||
|
||||
_DD_BASE="https://durabledns.com/services/dns"
|
||||
|
||||
|
@ -1,10 +1,16 @@
|
||||
#!/usr/bin/env sh
|
||||
#
|
||||
# Dyn.com Domain API
|
||||
#
|
||||
# Author: Gerd Naschenweng
|
||||
# https://github.com/magicdude4eva
|
||||
#
|
||||
# shellcheck disable=SC2034
|
||||
dns_dyn_info='Dyn.com
|
||||
Domains: dynect.net
|
||||
Site: Dyn.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dyn
|
||||
Options:
|
||||
DYN_Customer Customer
|
||||
DYN_Username API Username
|
||||
DYN_Password Secret
|
||||
Author: Gerd Naschenweng <https://github.com/magicdude4eva>
|
||||
'
|
||||
|
||||
# Dyn Managed DNS API
|
||||
# https://help.dyn.com/dns-api-knowledge-base/
|
||||
#
|
||||
@ -20,13 +26,6 @@
|
||||
# ZoneRemoveNode
|
||||
# ZonePublish
|
||||
# --
|
||||
#
|
||||
# Pass credentials before "acme.sh --issue --dns dns_dyn ..."
|
||||
# --
|
||||
# export DYN_Customer="customer"
|
||||
# export DYN_Username="apiuser"
|
||||
# export DYN_Password="secret"
|
||||
# --
|
||||
|
||||
DYN_API="https://api.dynect.net/REST"
|
||||
|
||||
|
@ -1,20 +1,21 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_dynu_info='Dynu.com
|
||||
Site: Dynu.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_dynu
|
||||
Options:
|
||||
Dynu_ClientId Client ID
|
||||
Dynu_Secret Secret
|
||||
Issues: github.com/shar0119/acme.sh
|
||||
Author: Dynu Systems Inc
|
||||
'
|
||||
|
||||
#Client ID
|
||||
#Dynu_ClientId="0b71cae7-a099-4f6b-8ddf-94571cdb760d"
|
||||
#
|
||||
#Secret
|
||||
#Dynu_Secret="aCUEY4BDCV45KI8CSIC3sp2LKQ9"
|
||||
#
|
||||
#Token
|
||||
Dynu_Token=""
|
||||
#
|
||||
#Endpoint
|
||||
Dynu_EndPoint="https://api.dynu.com/v2"
|
||||
#
|
||||
#Author: Dynu Systems, Inc.
|
||||
#Report Bugs here: https://github.com/shar0119/acme.sh
|
||||
#
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
|
@ -1,8 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
#Author StefanAbl
|
||||
#Usage specify a private keyfile to use with dynv6 'export KEY="path/to/keyfile"'
|
||||
#or use the HTTP REST API by by specifying a token 'export DYNV6_TOKEN="value"
|
||||
#if no keyfile is specified, you will be asked if you want to create one in /home/$USER/.ssh/dynv6 and /home/$USER/.ssh/dynv6.pub
|
||||
# shellcheck disable=SC2034
|
||||
dns_dynv6_info='DynV6.com
|
||||
Site: DynV6.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_dynv6
|
||||
Options:
|
||||
DYNV6_TOKEN REST API token. Get from https://DynV6.com/keys
|
||||
OptionsAlt:
|
||||
KEY Path to SSH private key file. E.g. "/root/.ssh/dynv6"
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2702
|
||||
Author: StefanAbl
|
||||
'
|
||||
|
||||
dynv6_api="https://dynv6.com/api/v2"
|
||||
######## Public functions #####################
|
||||
@ -94,8 +101,8 @@ _get_domain() {
|
||||
_your_hosts="$(echo "$_your_hosts" | awk '/\./ {print $1}')"
|
||||
for l in $_your_hosts; do
|
||||
#echo "host: $l"
|
||||
if test "${_full_domain#*$l}" != "$_full_domain"; then
|
||||
_record="${_full_domain%.$l}"
|
||||
if test "${_full_domain#*"$l"}" != "$_full_domain"; then
|
||||
_record=${_full_domain%."$l"}
|
||||
_host=$l
|
||||
_debug "The host is $_host and the record $_record"
|
||||
return 0
|
||||
@ -143,7 +150,7 @@ _dns_dynv6_add_http() {
|
||||
return 1
|
||||
fi
|
||||
_get_zone_name "$_zone_id"
|
||||
record="${fulldomain%%.$_zone_name}"
|
||||
record=${fulldomain%%."$_zone_name"}
|
||||
_set_record TXT "$record" "$txtvalue"
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "Successfully added record"
|
||||
@ -161,7 +168,7 @@ _dns_dynv6_rm_http() {
|
||||
return 1
|
||||
fi
|
||||
_get_zone_name "$_zone_id"
|
||||
record="${fulldomain%%.$_zone_name}"
|
||||
record=${fulldomain%%."$_zone_name"}
|
||||
_get_record_id "$_zone_id" "$record" "$txtvalue"
|
||||
_del_record "$_zone_id" "$_record_id"
|
||||
if [ -z "$response" ]; then
|
||||
|
@ -1,14 +1,17 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_easydns_info='easyDNS.net
|
||||
Site: easyDNS.net
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_easydns
|
||||
Options:
|
||||
EASYDNS_Token API Token
|
||||
EASYDNS_Key API Key
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2647
|
||||
Author: Neilpang, wurzelpanzer <wurzelpanzer@maximolider.net>
|
||||
'
|
||||
|
||||
#######################################################
|
||||
#
|
||||
# easyDNS REST API for acme.sh by Neilpang based on dns_cf.sh
|
||||
#
|
||||
# API Documentation: https://sandbox.rest.easydns.net:3001/
|
||||
#
|
||||
# Author: wurzelpanzer [wurzelpanzer@maximolider.net]
|
||||
# Report Bugs here: https://github.com/acmesh-official/acme.sh/issues/2647
|
||||
#
|
||||
|
||||
#################### Public functions #################
|
||||
|
||||
#EASYDNS_Key="xxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
|
@ -1,4 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_edgedns_info='Akamai.com Edge DNS
|
||||
Site: techdocs.Akamai.com/edge-dns/reference/edge-dns-api
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_edgedns
|
||||
Options: Specify individual credentials
|
||||
AKAMAI_HOST Host
|
||||
AKAMAI_ACCESS_TOKEN Access token
|
||||
AKAMAI_CLIENT_TOKEN Client token
|
||||
AKAMAI_CLIENT_SECRET Client secret
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/3157
|
||||
'
|
||||
|
||||
# Akamai Edge DNS v2 API
|
||||
# User must provide Open Edgegrid API credentials to the EdgeDNS installation. The remote user in EdgeDNS must have CRUD access to
|
||||
@ -6,18 +17,10 @@
|
||||
|
||||
# Report bugs to https://control.akamai.com/apps/support-ui/#/contact-support
|
||||
|
||||
# Values to export:
|
||||
# --EITHER--
|
||||
# *** TBD. NOT IMPLEMENTED YET ***
|
||||
# specify Edgegrid credentials file and section
|
||||
# AKAMAI_EDGERC=<full file path>
|
||||
# AKAMAI_EDGERC_SECTION="default"
|
||||
## --OR--
|
||||
# specify indiviual credentials
|
||||
# export AKAMAI_HOST = <host>
|
||||
# export AKAMAI_ACCESS_TOKEN = <access token>
|
||||
# export AKAMAI_CLIENT_TOKEN = <client token>
|
||||
# export AKAMAI_CLIENT_SECRET = <client secret>
|
||||
# Specify Edgegrid credentials file and section.
|
||||
# AKAMAI_EDGERC Edge RC. Full file path
|
||||
# AKAMAI_EDGERC_SECTION Edge RC Section. E.g. "default"
|
||||
|
||||
ACME_EDGEDNS_VERSION="0.1.0"
|
||||
|
||||
@ -176,6 +179,7 @@ _EDGEDNS_credentials() {
|
||||
_debug "GettingEdge DNS credentials"
|
||||
_log "$(printf "ACME DNSAPI Edge DNS version %s" ${ACME_EDGEDNS_VERSION})"
|
||||
args_missing=0
|
||||
AKAMAI_ACCESS_TOKEN="${AKAMAI_ACCESS_TOKEN:-$(_readaccountconf_mutable AKAMAI_ACCESS_TOKEN)}"
|
||||
if [ -z "$AKAMAI_ACCESS_TOKEN" ]; then
|
||||
AKAMAI_ACCESS_TOKEN=""
|
||||
AKAMAI_CLIENT_TOKEN=""
|
||||
@ -184,6 +188,7 @@ _EDGEDNS_credentials() {
|
||||
_err "AKAMAI_ACCESS_TOKEN is missing"
|
||||
args_missing=1
|
||||
fi
|
||||
AKAMAI_CLIENT_TOKEN="${AKAMAI_CLIENT_TOKEN:-$(_readaccountconf_mutable AKAMAI_CLIENT_TOKEN)}"
|
||||
if [ -z "$AKAMAI_CLIENT_TOKEN" ]; then
|
||||
AKAMAI_ACCESS_TOKEN=""
|
||||
AKAMAI_CLIENT_TOKEN=""
|
||||
@ -192,6 +197,7 @@ _EDGEDNS_credentials() {
|
||||
_err "AKAMAI_CLIENT_TOKEN is missing"
|
||||
args_missing=1
|
||||
fi
|
||||
AKAMAI_HOST="${AKAMAI_HOST:-$(_readaccountconf_mutable AKAMAI_HOST)}"
|
||||
if [ -z "$AKAMAI_HOST" ]; then
|
||||
AKAMAI_ACCESS_TOKEN=""
|
||||
AKAMAI_CLIENT_TOKEN=""
|
||||
@ -200,6 +206,7 @@ _EDGEDNS_credentials() {
|
||||
_err "AKAMAI_HOST is missing"
|
||||
args_missing=1
|
||||
fi
|
||||
AKAMAI_CLIENT_SECRET="${AKAMAI_CLIENT_SECRET:-$(_readaccountconf_mutable AKAMAI_CLIENT_SECRET)}"
|
||||
if [ -z "$AKAMAI_CLIENT_SECRET" ]; then
|
||||
AKAMAI_ACCESS_TOKEN=""
|
||||
AKAMAI_CLIENT_TOKEN=""
|
||||
@ -414,7 +421,7 @@ _edgedns_make_data_to_sign() {
|
||||
_secure_debug2 "hdr" "$hdr"
|
||||
_edgedns_make_content_hash
|
||||
path="$(echo "$_request_url_path" | tr -d "\n\r" | sed 's/https\?:\/\///')"
|
||||
path="${path#*$AKAMAI_HOST}"
|
||||
path=${path#*"$AKAMAI_HOST"}
|
||||
_debug "hier path" "$path"
|
||||
# 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")"
|
||||
|
@ -1,18 +1,14 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#This is the euserv.eu api wrapper for acme.sh
|
||||
#
|
||||
#Author: Michael Brueckner
|
||||
#Report Bugs: https://www.github.com/initit/acme.sh or mbr@initit.de
|
||||
|
||||
#
|
||||
#EUSERV_Username="username"
|
||||
#
|
||||
#EUSERV_Password="password"
|
||||
#
|
||||
# Dependencies:
|
||||
# -------------
|
||||
# - none -
|
||||
# shellcheck disable=SC2034
|
||||
dns_euserv_info='EUserv.com
|
||||
Domains: EUserv.eu
|
||||
Site: EUserv.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_euserv
|
||||
Options:
|
||||
EUSERV_Username Username
|
||||
EUSERV_Password Password
|
||||
Author: Michael Brueckner
|
||||
'
|
||||
|
||||
EUSERV_Api="https://api.euserv.net"
|
||||
|
||||
|
@ -1,4 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_exoscale_info='Exoscale.com
|
||||
Site: Exoscale.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_exoscale
|
||||
Options:
|
||||
EXOSCALE_API_KEY API Key
|
||||
EXOSCALE_SECRET_KEY API Secret key
|
||||
'
|
||||
|
||||
EXOSCALE_API=https://api.exoscale.com/dns/v1
|
||||
|
||||
|
153
dnsapi/dns_fornex.sh
Normal file
153
dnsapi/dns_fornex.sh
Normal file
@ -0,0 +1,153 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_fornex_info='Fornex.com
|
||||
Site: Fornex.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_fornex
|
||||
Options:
|
||||
FORNEX_API_KEY API Key
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/3998
|
||||
Author: Timur Umarov <inbox@tumarov.com>
|
||||
'
|
||||
|
||||
FORNEX_API_URL="https://fornex.com/api/dns/v0.1"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_fornex_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_fornex_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if ! _Fornex_API; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "Unable to determine root domain"
|
||||
return 1
|
||||
else
|
||||
_debug _domain "$_domain"
|
||||
fi
|
||||
|
||||
_info "Adding record"
|
||||
if _rest POST "$_domain/entry_set/add/" "host=$fulldomain&type=TXT&value=$txtvalue&apikey=$FORNEX_API_KEY"; then
|
||||
_debug _response "$response"
|
||||
if _contains "$response" '"ok": true' || _contains "$response" 'Такая запись уже существует.'; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
}
|
||||
|
||||
#Usage: dns_fornex_rm _acme-challenge.www.domain.com
|
||||
dns_fornex_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if ! _Fornex_API; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "Unable to determine root domain"
|
||||
return 1
|
||||
else
|
||||
_debug _domain "$_domain"
|
||||
fi
|
||||
|
||||
_debug "Getting txt records"
|
||||
_rest GET "$_domain/entry_set.json?apikey=$FORNEX_API_KEY"
|
||||
|
||||
if ! _contains "$response" "$txtvalue"; then
|
||||
_err "Txt record not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_record_id="$(echo "$response" | _egrep_o "{[^{]*\"value\"*:*\"$txtvalue\"[^}]*}" | sed -n -e 's#.*"id": \([0-9]*\).*#\1#p')"
|
||||
_debug "_record_id" "$_record_id"
|
||||
if [ -z "$_record_id" ]; then
|
||||
_err "can not find _record_id"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _rest POST "$_domain/entry_set/$_record_id/delete/" "apikey=$FORNEX_API_KEY"; then
|
||||
_err "Delete record error."
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
_get_root() {
|
||||
domain=$1
|
||||
|
||||
i=1
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _rest GET "domain_list.json?q=$h&apikey=$FORNEX_API_KEY"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"$h\"" >/dev/null; then
|
||||
_domain=$h
|
||||
return 0
|
||||
else
|
||||
_debug "$h not found"
|
||||
fi
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
_Fornex_API() {
|
||||
FORNEX_API_KEY="${FORNEX_API_KEY:-$(_readaccountconf_mutable FORNEX_API_KEY)}"
|
||||
if [ -z "$FORNEX_API_KEY" ]; then
|
||||
FORNEX_API_KEY=""
|
||||
|
||||
_err "You didn't specify the Fornex API key yet."
|
||||
_err "Please create your key and try again."
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf_mutable FORNEX_API_KEY "$FORNEX_API_KEY"
|
||||
}
|
||||
|
||||
#method method action data
|
||||
_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
export _H1="Accept: application/json"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$FORNEX_API_URL/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$FORNEX_API_URL/$ep" | _normalizeJson)"
|
||||
fi
|
||||
|
||||
_ret="$?"
|
||||
if [ "$_ret" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
@ -1,14 +1,15 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_freedns_info='FreeDNS
|
||||
Site: FreeDNS.afraid.org
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_freedns
|
||||
Options:
|
||||
FREEDNS_User Username
|
||||
FREEDNS_Password Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2305
|
||||
Author: David Kerr <https://github.com/dkerr64>
|
||||
'
|
||||
|
||||
#This file name is "dns_freedns.sh"
|
||||
#So, here must be a method dns_freedns_add()
|
||||
#Which will be called by acme.sh to add the txt record to your api system.
|
||||
#returns 0 means success, otherwise error.
|
||||
#
|
||||
#Author: David Kerr
|
||||
#Report Bugs here: https://github.com/dkerr64/acme.sh
|
||||
#or here... https://github.com/acmesh-official/acme.sh/issues/2305
|
||||
#
|
||||
######## Public functions #####################
|
||||
|
||||
# Export FreeDNS userid and password in following variables...
|
||||
|
@ -1,31 +1,42 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_gandi_livedns_info='Gandi.net LiveDNS
|
||||
Site: Gandi.net/domain/dns
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gandi_livedns
|
||||
Options:
|
||||
GANDI_LIVEDNS_KEY API Key
|
||||
Issues: github.com/fcrozat/acme.sh
|
||||
Author: Frédéric Crozat <fcrozat@suse.com>, Dominik Röttsches <drott@google.com>
|
||||
'
|
||||
|
||||
# Gandi LiveDNS v5 API
|
||||
# http://doc.livedns.gandi.net/
|
||||
# https://api.gandi.net/docs/livedns/
|
||||
# https://api.gandi.net/docs/authentication/ for token + apikey (deprecated) authentication
|
||||
# currently under beta
|
||||
#
|
||||
# Requires GANDI API KEY set in GANDI_LIVEDNS_KEY set as environment variable
|
||||
#
|
||||
#Author: Frédéric Crozat <fcrozat@suse.com>
|
||||
# Dominik Röttsches <drott@google.com>
|
||||
#Report Bugs here: https://github.com/fcrozat/acme.sh
|
||||
#
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
GANDI_LIVEDNS_API="https://dns.api.gandi.net/api/v5"
|
||||
GANDI_LIVEDNS_API="https://api.gandi.net/v5/livedns"
|
||||
|
||||
#Usage: dns_gandi_livedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_gandi_livedns_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
if [ -z "$GANDI_LIVEDNS_KEY" ]; then
|
||||
_err "No API key specified for Gandi LiveDNS."
|
||||
_err "Create your key and export it as GANDI_LIVEDNS_KEY"
|
||||
if [ -z "$GANDI_LIVEDNS_KEY" ] && [ -z "$GANDI_LIVEDNS_TOKEN" ]; then
|
||||
_err "No Token or API key (deprecated) specified for Gandi LiveDNS."
|
||||
_err "Create your token or key and export it as GANDI_LIVEDNS_KEY or GANDI_LIVEDNS_TOKEN respectively"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY"
|
||||
# Keep only one secret in configuration
|
||||
if [ -n "$GANDI_LIVEDNS_TOKEN" ]; then
|
||||
_saveaccountconf GANDI_LIVEDNS_TOKEN "$GANDI_LIVEDNS_TOKEN"
|
||||
_clearaccountconf GANDI_LIVEDNS_KEY
|
||||
elif [ -n "$GANDI_LIVEDNS_KEY" ]; then
|
||||
_saveaccountconf GANDI_LIVEDNS_KEY "$GANDI_LIVEDNS_KEY"
|
||||
_clearaccountconf GANDI_LIVEDNS_TOKEN
|
||||
fi
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
@ -70,7 +81,7 @@ dns_gandi_livedns_rm() {
|
||||
_gandi_livedns_rest PUT \
|
||||
"domains/$_domain/records/$_sub_domain/TXT" \
|
||||
"{\"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")"
|
||||
}
|
||||
|
||||
@ -126,7 +137,7 @@ _dns_gandi_append_record() {
|
||||
_debug new_rrset_values "$_rrset_values"
|
||||
_gandi_livedns_rest PUT "domains/$_domain/records/$sub_domain/TXT" \
|
||||
"{\"rrset_ttl\": 300, \"rrset_values\": $_rrset_values}" &&
|
||||
_contains "$response" '{"message": "DNS Record Created"}' &&
|
||||
_contains "$response" '{"message":"DNS Record Created"}' &&
|
||||
_info "Adding record $(__green "success")"
|
||||
}
|
||||
|
||||
@ -136,11 +147,11 @@ _dns_gandi_existing_rrset_values() {
|
||||
if ! _gandi_livedns_rest GET "domains/$domain/records/$sub_domain"; then
|
||||
return 1
|
||||
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."
|
||||
return 1
|
||||
fi
|
||||
if _contains "$response" '"rrset_values": \[\]'; then
|
||||
if _contains "$response" '"rrset_values":\[\]'; then
|
||||
_debug "Empty rrset_values for TXT record, no previous TXT record."
|
||||
return 1
|
||||
fi
|
||||
@ -157,7 +168,12 @@ _gandi_livedns_rest() {
|
||||
_debug "$ep"
|
||||
|
||||
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
|
||||
response="$(_get "$GANDI_LIVEDNS_API/$ep")"
|
||||
|
@ -1,6 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# Author: Janos Lenart <janos@lenart.io>
|
||||
# shellcheck disable=SC2034
|
||||
dns_gcloud_info='Google Cloud DNS
|
||||
Site: Cloud.Google.com/dns
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gcloud
|
||||
Options:
|
||||
CLOUDSDK_ACTIVE_CONFIG_NAME Active config name. E.g. "default"
|
||||
Author: Janos Lenart <janos@lenart.io>
|
||||
'
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
@ -39,10 +45,10 @@ dns_gcloud_rm() {
|
||||
_dns_gcloud_start_tr || return $?
|
||||
_dns_gcloud_get_rrdatas || 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 $?
|
||||
|
||||
_info "$fulldomain record added"
|
||||
_info "$fulldomain record removed"
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
@ -98,7 +104,7 @@ _dns_gcloud_remove_rrs() {
|
||||
--ttl="$ttl" \
|
||||
--type=TXT \
|
||||
--zone="$managedZone" \
|
||||
--transaction-file="$tr"; then
|
||||
--transaction-file="$tr" --; then
|
||||
_debug tr "$(cat "$tr")"
|
||||
rm -r "$trd"
|
||||
_err "_dns_gcloud_remove_rrs: failed to remove RRs"
|
||||
@ -113,7 +119,7 @@ _dns_gcloud_add_rrs() {
|
||||
--ttl="$ttl" \
|
||||
--type=TXT \
|
||||
--zone="$managedZone" \
|
||||
--transaction-file="$tr"; then
|
||||
--transaction-file="$tr" --; then
|
||||
_debug tr "$(cat "$tr")"
|
||||
rm -r "$trd"
|
||||
_err "_dns_gcloud_add_rrs: failed to add RRs"
|
||||
|
191
dnsapi/dns_gcore.sh
Executable file
191
dnsapi/dns_gcore.sh
Executable file
@ -0,0 +1,191 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_gcore_info='Gcore.com
|
||||
Site: Gcore.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gcore
|
||||
Options:
|
||||
GCORE_Key API Key
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/4460
|
||||
'
|
||||
|
||||
GCORE_Api="https://api.gcore.com/dns/v2"
|
||||
GCORE_Doc="https://api.gcore.com/docs/dns"
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_gcore_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
GCORE_Key="${GCORE_Key:-$(_readaccountconf_mutable GCORE_Key)}"
|
||||
|
||||
if [ -z "$GCORE_Key" ]; then
|
||||
GCORE_Key=""
|
||||
_err "You didn't specify a Gcore api key yet."
|
||||
_err "You can get yours from here $GCORE_Doc"
|
||||
return 1
|
||||
fi
|
||||
|
||||
#save the api key to the account conf file.
|
||||
_saveaccountconf_mutable GCORE_Key "$GCORE_Key"
|
||||
|
||||
_debug "First detect the zone name"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _zone_name "$_zone_name"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_gcore_rest GET "zones/$_zone_name/$fulldomain/TXT"
|
||||
payload=""
|
||||
|
||||
if echo "$response" | grep "record is not found" >/dev/null; then
|
||||
_info "Record doesn't exists"
|
||||
payload="{\"resource_records\":[{\"content\":[\"$txtvalue\"],\"enabled\":true}],\"ttl\":120}"
|
||||
elif echo "$response" | grep "$txtvalue" >/dev/null; then
|
||||
_info "Already exists, OK"
|
||||
return 0
|
||||
elif echo "$response" | tr -d " " | grep \"name\":\""$fulldomain"\",\"type\":\"TXT\" >/dev/null; then
|
||||
_info "Record with mismatch txtvalue, try update it"
|
||||
payload=$(echo "$response" | tr -d " " | sed 's/"updated_at":[0-9]\+,//g' | sed 's/"meta":{}}]}/"meta":{}},{"content":['\""$txtvalue"\"'],"enabled":true}]}/')
|
||||
fi
|
||||
|
||||
# For wildcard cert, the main root domain and the wildcard domain have the same txt subdomain name, so
|
||||
# we can not use updating anymore.
|
||||
# count=$(printf "%s\n" "$response" | _egrep_o "\"count\":[^,]*" | cut -d : -f 2)
|
||||
# _debug count "$count"
|
||||
# if [ "$count" = "0" ]; then
|
||||
_info "Adding record"
|
||||
if _gcore_rest PUT "zones/$_zone_name/$fulldomain/TXT" "$payload"; then
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "Added, OK"
|
||||
return 0
|
||||
elif _contains "$response" "rrset is already exists"; then
|
||||
_info "Already exists, OK"
|
||||
return 0
|
||||
else
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
}
|
||||
|
||||
#fulldomain txtvalue
|
||||
dns_gcore_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
GCORE_Key="${GCORE_Key:-$(_readaccountconf_mutable GCORE_Key)}"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "invalid domain"
|
||||
return 1
|
||||
fi
|
||||
_debug _zone_name "$_zone_name"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_debug "Getting txt records"
|
||||
_gcore_rest GET "zones/$_zone_name/$fulldomain/TXT"
|
||||
|
||||
if echo "$response" | grep "record is not found" >/dev/null; then
|
||||
_info "No such txt recrod"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! echo "$response" | tr -d " " | grep \"name\":\""$fulldomain"\",\"type\":\"TXT\" >/dev/null; then
|
||||
_err "Error: $response"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! echo "$response" | tr -d " " | grep \""$txtvalue"\" >/dev/null; then
|
||||
_info "No such txt recrod"
|
||||
return 0
|
||||
fi
|
||||
|
||||
count="$(echo "$response" | grep -o "content" | wc -l)"
|
||||
|
||||
if [ "$count" = "1" ]; then
|
||||
if ! _gcore_rest DELETE "zones/$_zone_name/$fulldomain/TXT"; then
|
||||
_err "Delete record error. $response"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
payload="$(echo "$response" | tr -d " " | sed 's/"updated_at":[0-9]\+,//g' | sed 's/{"id":[0-9]\+,"content":\["'"$txtvalue"'"\],"enabled":true,"meta":{}}//' | sed 's/\[,/\[/' | sed 's/,,/,/' | sed 's/,\]/\]/')"
|
||||
if ! _gcore_rest PUT "zones/$_zone_name/$fulldomain/TXT" "$payload"; then
|
||||
_err "Delete record error. $response"
|
||||
fi
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.sub.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.sub or _acme-challenge
|
||||
# _domain=domain.com
|
||||
# _zone_name=domain.com or sub.domain.com
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=1
|
||||
p=1
|
||||
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! _gcore_rest GET "zones/$h"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"name\":\"$h\""; then
|
||||
_zone_name=$h
|
||||
if [ "$_zone_name" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-$p)
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_gcore_rest() {
|
||||
m=$1
|
||||
ep="$2"
|
||||
data="$3"
|
||||
_debug "$ep"
|
||||
|
||||
key_trimmed=$(echo "$GCORE_Key" | tr -d '"')
|
||||
|
||||
export _H1="Content-Type: application/json"
|
||||
export _H2="Authorization: APIKey $key_trimmed"
|
||||
|
||||
if [ "$m" != "GET" ]; then
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$GCORE_Api/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$GCORE_Api/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#Godaddy domain api
|
||||
#
|
||||
#GD_Key="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
#
|
||||
#GD_Secret="asdfsdfsfsdfsdfdfsdf"
|
||||
# shellcheck disable=SC2034
|
||||
dns_gd_info='GoDaddy.com
|
||||
Site: GoDaddy.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_gd
|
||||
Options:
|
||||
GD_Key API Key
|
||||
GD_Secret API Secret
|
||||
'
|
||||
|
||||
GD_Api="https://api.godaddy.com/v1"
|
||||
|
||||
@ -20,8 +22,8 @@ dns_gd_add() {
|
||||
if [ -z "$GD_Key" ] || [ -z "$GD_Secret" ]; then
|
||||
GD_Key=""
|
||||
GD_Secret=""
|
||||
_err "You don't specify godaddy api key and secret yet."
|
||||
_err "Please create you key and try again."
|
||||
_err "You didn't specify godaddy api key and secret yet."
|
||||
_err "Please create your key and try again."
|
||||
return 1
|
||||
fi
|
||||
|
||||
@ -44,14 +46,15 @@ dns_gd_add() {
|
||||
fi
|
||||
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "The record is existing, skip"
|
||||
_info "This record already exists, skipping"
|
||||
return 0
|
||||
fi
|
||||
|
||||
_add_data="{\"data\":\"$txtvalue\"}"
|
||||
for t in $(echo "$response" | tr '{' "\n" | grep "\"name\":\"$_sub_domain\"" | tr ',' "\n" | grep '"data"' | cut -d : -f 2); do
|
||||
_debug2 t "$t"
|
||||
if [ "$t" ]; then
|
||||
# ignore empty (previously removed) records, to prevent useless _acme-challenge TXT entries
|
||||
if [ "$t" ] && [ "$t" != '""' ]; then
|
||||
_add_data="$_add_data,{\"data\":$t}"
|
||||
fi
|
||||
done
|
||||
@ -59,13 +62,25 @@ dns_gd_add() {
|
||||
|
||||
_info "Adding record"
|
||||
if _gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"; then
|
||||
_info "Added, sleeping 10 seconds"
|
||||
_sleep 10
|
||||
#todo: check if the record takes effect
|
||||
return 0
|
||||
_debug "Checking updated records of '${fulldomain}'"
|
||||
|
||||
if ! _gd_rest GET "domains/$_domain/records/TXT/$_sub_domain"; then
|
||||
_err "Validating TXT record for '${fulldomain}' with rest error [$?]." "$response"
|
||||
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
|
||||
_err "Add txt record error."
|
||||
return 1
|
||||
|
||||
_sleep 10
|
||||
_info "Added TXT record '${txtvalue}' for '${fulldomain}'."
|
||||
return 0
|
||||
}
|
||||
|
||||
#fulldomain
|
||||
@ -107,11 +122,20 @@ dns_gd_rm() {
|
||||
fi
|
||||
done
|
||||
if [ -z "$_add_data" ]; then
|
||||
_add_data="{\"data\":\"\"}"
|
||||
# delete empty record
|
||||
_debug "Delete last record for '${fulldomain}'"
|
||||
if ! _gd_rest DELETE "domains/$_domain/records/TXT/$_sub_domain"; then
|
||||
_err "Cannot delete empty TXT record for '$fulldomain'"
|
||||
return 1
|
||||
fi
|
||||
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
|
||||
_debug2 _add_data "$_add_data"
|
||||
|
||||
_gd_rest PUT "domains/$_domain/records/TXT/$_sub_domain" "[$_add_data]"
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
@ -156,15 +180,15 @@ _gd_rest() {
|
||||
export _H1="Authorization: sso-key $GD_Key:$GD_Secret"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
if [ "$data" ]; then
|
||||
_debug data "$data"
|
||||
if [ "$data" ] || [ "$m" = "DELETE" ]; then
|
||||
_debug "data ($m): " "$data"
|
||||
response="$(_post "$data" "$GD_Api/$ep" "" "$m")"
|
||||
else
|
||||
response="$(_get "$GD_Api/$ep")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
_err "error on rest call ($m): $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
|
@ -1,177 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
#Author: Herman Sletteng
|
||||
#Report Bugs here: https://github.com/loial/acme.sh
|
||||
#
|
||||
#
|
||||
# Note, gratisdns requires a login first, so the script needs to handle
|
||||
# temporary cookies. Since acme.sh _get/_post currently don't directly support
|
||||
# cookies, I've defined wrapper functions _myget/_mypost to set the headers
|
||||
|
||||
GDNSDK_API="https://admin.gratisdns.com"
|
||||
######## Public functions #####################
|
||||
#Usage: dns_gdnsdk_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_gdnsdk_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using gratisdns.dk"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
if ! _gratisdns_login; then
|
||||
_err "Login failed!"
|
||||
return 1
|
||||
fi
|
||||
#finding domain zone
|
||||
if ! _get_domain; then
|
||||
_err "No matching root domain for $fulldomain found"
|
||||
return 1
|
||||
fi
|
||||
# adding entry
|
||||
_info "Adding the entry"
|
||||
_mypost "action=dns_primary_record_added_txt&user_domain=$_domain&name=$fulldomain&txtdata=$txtvalue&ttl=1"
|
||||
if _successful_update; then return 0; fi
|
||||
_err "Couldn't create entry!"
|
||||
return 1
|
||||
}
|
||||
|
||||
#Usage: fulldomain txtvalue
|
||||
#Remove the txt record after validation.
|
||||
dns_gdnsdk_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
_info "Using gratisdns.dk"
|
||||
_debug fulldomain "$fulldomain"
|
||||
_debug txtvalue "$txtvalue"
|
||||
if ! _gratisdns_login; then
|
||||
_err "Login failed!"
|
||||
return 1
|
||||
fi
|
||||
if ! _get_domain; then
|
||||
_err "No matching root domain for $fulldomain found"
|
||||
return 1
|
||||
fi
|
||||
_findentry "$fulldomain" "$txtvalue"
|
||||
if [ -z "$_id" ]; then
|
||||
_info "Entry doesn't exist, nothing to delete"
|
||||
return 0
|
||||
fi
|
||||
_debug "Deleting record..."
|
||||
_mypost "action=dns_primary_delete_txt&user_domain=$_domain&id=$_id"
|
||||
# removing entry
|
||||
|
||||
if _successful_update; then return 0; fi
|
||||
_err "Couldn't delete entry!"
|
||||
return 1
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_checkcredentials() {
|
||||
GDNSDK_Username="${GDNSDK_Username:-$(_readaccountconf_mutable GDNSDK_Username)}"
|
||||
GDNSDK_Password="${GDNSDK_Password:-$(_readaccountconf_mutable GDNSDK_Password)}"
|
||||
|
||||
if [ -z "$GDNSDK_Username" ] || [ -z "$GDNSDK_Password" ]; then
|
||||
GDNSDK_Username=""
|
||||
GDNSDK_Password=""
|
||||
_err "You haven't specified gratisdns.dk username and password yet."
|
||||
_err "Please add credentials and try again."
|
||||
return 1
|
||||
fi
|
||||
#save the credentials to the account conf file.
|
||||
_saveaccountconf_mutable GDNSDK_Username "$GDNSDK_Username"
|
||||
_saveaccountconf_mutable GDNSDK_Password "$GDNSDK_Password"
|
||||
return 0
|
||||
}
|
||||
|
||||
_checkcookie() {
|
||||
GDNSDK_Cookie="${GDNSDK_Cookie:-$(_readaccountconf_mutable GDNSDK_Cookie)}"
|
||||
if [ -z "$GDNSDK_Cookie" ]; then
|
||||
_debug "No cached cookie found"
|
||||
return 1
|
||||
fi
|
||||
_myget "action="
|
||||
if (echo "$_result" | grep -q "logmeout"); then
|
||||
_debug "Cached cookie still valid"
|
||||
return 0
|
||||
fi
|
||||
_debug "Cached cookie no longer valid"
|
||||
GDNSDK_Cookie=""
|
||||
_saveaccountconf_mutable GDNSDK_Cookie "$GDNSDK_Cookie"
|
||||
return 1
|
||||
}
|
||||
|
||||
_gratisdns_login() {
|
||||
if ! _checkcredentials; then return 1; fi
|
||||
|
||||
if _checkcookie; then
|
||||
_debug "Already logged in"
|
||||
return 0
|
||||
fi
|
||||
_debug "Logging into GratisDNS with user $GDNSDK_Username"
|
||||
|
||||
if ! _mypost "login=$GDNSDK_Username&password=$GDNSDK_Password&action=logmein"; then
|
||||
_err "GratisDNS login failed for user $GDNSDK_Username bad RC from _post"
|
||||
return 1
|
||||
fi
|
||||
|
||||
GDNSDK_Cookie="$(grep -A 15 '302 Found' "$HTTP_HEADER" | _egrep_o 'Cookie: [^;]*' | _head_n 1 | cut -d ' ' -f2)"
|
||||
|
||||
if [ -z "$GDNSDK_Cookie" ]; then
|
||||
_err "GratisDNS login failed for user $GDNSDK_Username. Check $HTTP_HEADER file"
|
||||
return 1
|
||||
fi
|
||||
export GDNSDK_Cookie
|
||||
_saveaccountconf_mutable GDNSDK_Cookie "$GDNSDK_Cookie"
|
||||
return 0
|
||||
}
|
||||
|
||||
_myget() {
|
||||
#Adds cookie to request
|
||||
export _H1="Cookie: $GDNSDK_Cookie"
|
||||
_result=$(_get "$GDNSDK_API?$1")
|
||||
}
|
||||
_mypost() {
|
||||
#Adds cookie to request
|
||||
export _H1="Cookie: $GDNSDK_Cookie"
|
||||
_result=$(_post "$1" "$GDNSDK_API")
|
||||
}
|
||||
|
||||
_get_domain() {
|
||||
_myget 'action=dns_primarydns'
|
||||
_domains=$(echo "$_result" | _egrep_o ' domain="[[:alnum:]._-]+' | sed 's/^.*"//')
|
||||
if [ -z "$_domains" ]; then
|
||||
_err "Primary domain list not found!"
|
||||
return 1
|
||||
fi
|
||||
for _domain in $_domains; do
|
||||
if (_endswith "$fulldomain" "$_domain"); then
|
||||
_debug "Root domain: $_domain"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
_successful_update() {
|
||||
if (echo "$_result" | grep -q 'table-success'); then return 0; fi
|
||||
return 1
|
||||
}
|
||||
|
||||
_findentry() {
|
||||
#args $1: fulldomain, $2: txtvalue
|
||||
#returns id of dns entry, if it exists
|
||||
_myget "action=dns_primary_changeDNSsetup&user_domain=$_domain"
|
||||
_debug3 "_result: $_result"
|
||||
|
||||
_tmp_result=$(echo "$_result" | tr -d '\n\r' | _egrep_o "<td>$1</td>\s*<td>$2</td>[^?]*[^&]*&id=[^&]*")
|
||||
_debug _tmp_result "$_tmp_result"
|
||||
if [ -z "${_tmp_result:-}" ]; then
|
||||
_debug "The variable is _tmp_result is not supposed to be empty, there may be something wrong with the script"
|
||||
fi
|
||||
|
||||
_id=$(echo "$_tmp_result" | sed 's/^.*=//')
|
||||
if [ -n "$_id" ]; then
|
||||
_debug "Entry found with _id=$_id"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
232
dnsapi/dns_geoscaling.sh
Executable file
232
dnsapi/dns_geoscaling.sh
Executable file
@ -0,0 +1,232 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_geoscaling_info='GeoScaling.com
|
||||
Site: GeoScaling.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_geoscaling
|
||||
Options:
|
||||
GEOSCALING_Username Username. This is usually NOT an email address
|
||||
GEOSCALING_Password Password
|
||||
'
|
||||
|
||||
#-- dns_geoscaling_add() - Add TXT record --------------------------------------
|
||||
# Usage: dns_geoscaling_add _acme-challenge.subdomain.domain.com "XyZ123..."
|
||||
|
||||
dns_geoscaling_add() {
|
||||
full_domain=$1
|
||||
txt_value=$2
|
||||
_info "Using DNS-01 Geoscaling DNS2 hook"
|
||||
|
||||
GEOSCALING_Username="${GEOSCALING_Username:-$(_readaccountconf_mutable GEOSCALING_Username)}"
|
||||
GEOSCALING_Password="${GEOSCALING_Password:-$(_readaccountconf_mutable GEOSCALING_Password)}"
|
||||
if [ -z "$GEOSCALING_Username" ] || [ -z "$GEOSCALING_Password" ]; then
|
||||
GEOSCALING_Username=
|
||||
GEOSCALING_Password=
|
||||
_err "No auth details provided. Please set user credentials using the \$GEOSCALING_Username and \$GEOSCALING_Password environment variables."
|
||||
return 1
|
||||
fi
|
||||
_saveaccountconf_mutable GEOSCALING_Username "${GEOSCALING_Username}"
|
||||
_saveaccountconf_mutable GEOSCALING_Password "${GEOSCALING_Password}"
|
||||
|
||||
# Fills in the $zone_id and $zone_name
|
||||
find_zone "${full_domain}" || return 1
|
||||
_debug "Zone id '${zone_id}' will be used."
|
||||
|
||||
# We're logged in here
|
||||
|
||||
# we should add ${full_domain} minus the trailing ${zone_name}
|
||||
|
||||
prefix=$(echo "${full_domain}" | sed "s|\\.${zone_name}\$||")
|
||||
|
||||
body="id=${zone_id}&name=${prefix}&type=TXT&content=${txt_value}&ttl=300&prio=0"
|
||||
|
||||
do_post "$body" "https://www.geoscaling.com/dns2/ajax/add_record.php"
|
||||
exit_code="$?"
|
||||
if [ "${exit_code}" -eq 0 ]; then
|
||||
_info "TXT record added successfully."
|
||||
else
|
||||
_err "Couldn't add the TXT record."
|
||||
fi
|
||||
do_logout
|
||||
return "${exit_code}"
|
||||
}
|
||||
|
||||
#-- dns_geoscaling_rm() - Remove TXT record ------------------------------------
|
||||
# Usage: dns_geoscaling_rm _acme-challenge.subdomain.domain.com "XyZ123..."
|
||||
|
||||
dns_geoscaling_rm() {
|
||||
full_domain=$1
|
||||
txt_value=$2
|
||||
_info "Cleaning up after DNS-01 Geoscaling DNS2 hook"
|
||||
|
||||
GEOSCALING_Username="${GEOSCALING_Username:-$(_readaccountconf_mutable GEOSCALING_Username)}"
|
||||
GEOSCALING_Password="${GEOSCALING_Password:-$(_readaccountconf_mutable GEOSCALING_Password)}"
|
||||
if [ -z "$GEOSCALING_Username" ] || [ -z "$GEOSCALING_Password" ]; then
|
||||
GEOSCALING_Username=
|
||||
GEOSCALING_Password=
|
||||
_err "No auth details provided. Please set user credentials using the \$GEOSCALING_Username and \$GEOSCALING_Password environment variables."
|
||||
return 1
|
||||
fi
|
||||
_saveaccountconf_mutable GEOSCALING_Username "${GEOSCALING_Username}"
|
||||
_saveaccountconf_mutable GEOSCALING_Password "${GEOSCALING_Password}"
|
||||
|
||||
# fills in the $zone_id
|
||||
find_zone "${full_domain}" || return 1
|
||||
_debug "Zone id '${zone_id}' will be used."
|
||||
|
||||
# Here we're logged in
|
||||
# Find the record id to clean
|
||||
|
||||
# get the domain
|
||||
response=$(do_get "https://www.geoscaling.com/dns2/index.php?module=domain&id=${zone_id}")
|
||||
_debug2 "response" "$response"
|
||||
|
||||
table="$(echo "${response}" | tr -d '\n' | sed 's|.*<div class="box"><div class="boxtitle">Basic Records</div><div class="boxtext"><table|<table|; s|</table>.*|</table>|')"
|
||||
_debug2 table "${table}"
|
||||
names=$(echo "${table}" | _egrep_o 'id="[0-9]+\.name">[^<]*</td>' | sed 's|</td>||; s|.*>||')
|
||||
ids=$(echo "${table}" | _egrep_o 'id="[0-9]+\.name">[^<]*</td>' | sed 's|\.name">.*||; s|id="||')
|
||||
types=$(echo "${table}" | _egrep_o 'id="[0-9]+\.type">[^<]*</td>' | sed 's|</td>||; s|.*>||')
|
||||
values=$(echo "${table}" | _egrep_o 'id="[0-9]+\.content">[^<]*</td>' | sed 's|</td>||; s|.*>||')
|
||||
|
||||
_debug2 names "${names}"
|
||||
_debug2 ids "${ids}"
|
||||
_debug2 types "${types}"
|
||||
_debug2 values "${values}"
|
||||
|
||||
# look for line whose name is ${full_domain}, whose type is TXT, and whose value is ${txt_value}
|
||||
line_num="$(echo "${values}" | grep -F -n -- "${txt_value}" | _head_n 1 | cut -d ':' -f 1)"
|
||||
_debug2 line_num "${line_num}"
|
||||
found_id=
|
||||
if [ -n "$line_num" ]; then
|
||||
type=$(echo "${types}" | sed -n "${line_num}p")
|
||||
name=$(echo "${names}" | sed -n "${line_num}p")
|
||||
id=$(echo "${ids}" | sed -n "${line_num}p")
|
||||
|
||||
_debug2 type "$type"
|
||||
_debug2 name "$name"
|
||||
_debug2 id "$id"
|
||||
_debug2 full_domain "$full_domain"
|
||||
|
||||
if [ "${type}" = "TXT" ] && [ "${name}" = "${full_domain}" ]; then
|
||||
found_id=${id}
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "${found_id}" = "" ]; then
|
||||
_err "Can not find record id."
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Remove the record
|
||||
body="id=${zone_id}&record_id=${found_id}"
|
||||
response=$(do_post "$body" "https://www.geoscaling.com/dns2/ajax/delete_record.php")
|
||||
exit_code="$?"
|
||||
if [ "$exit_code" -eq 0 ]; then
|
||||
_info "Record removed successfully."
|
||||
else
|
||||
_err "Could not clean (remove) up the record. Please go to Geoscaling administration interface and clean it by hand."
|
||||
fi
|
||||
do_logout
|
||||
return "${exit_code}"
|
||||
}
|
||||
|
||||
########################## PRIVATE FUNCTIONS ###########################
|
||||
|
||||
do_get() {
|
||||
_url=$1
|
||||
export _H1="Cookie: $geoscaling_phpsessid_cookie"
|
||||
_get "${_url}"
|
||||
}
|
||||
|
||||
do_post() {
|
||||
_body=$1
|
||||
_url=$2
|
||||
export _H1="Cookie: $geoscaling_phpsessid_cookie"
|
||||
_post "${_body}" "${_url}"
|
||||
}
|
||||
|
||||
do_login() {
|
||||
|
||||
_info "Logging in..."
|
||||
|
||||
username_encoded="$(printf "%s" "${GEOSCALING_Username}" | _url_encode)"
|
||||
password_encoded="$(printf "%s" "${GEOSCALING_Password}" | _url_encode)"
|
||||
body="username=${username_encoded}&password=${password_encoded}"
|
||||
|
||||
response=$(_post "$body" "https://www.geoscaling.com/dns2/index.php?module=auth")
|
||||
_debug2 response "${response}"
|
||||
|
||||
#retcode=$(grep '^HTTP[^ ]*' "${HTTP_HEADER}" | _head_n 1 | _egrep_o '[0-9]+$')
|
||||
retcode=$(grep '^HTTP[^ ]*' "${HTTP_HEADER}" | _head_n 1 | cut -d ' ' -f 2)
|
||||
|
||||
if [ "$retcode" != "302" ]; then
|
||||
_err "Geoscaling login failed for user ${GEOSCALING_Username}. Check ${HTTP_HEADER} file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
geoscaling_phpsessid_cookie="$(grep -i '^set-cookie:' "${HTTP_HEADER}" | _egrep_o 'PHPSESSID=[^;]*;' | tr -d ';')"
|
||||
return 0
|
||||
|
||||
}
|
||||
|
||||
do_logout() {
|
||||
_info "Logging out."
|
||||
response="$(do_get "https://www.geoscaling.com/dns2/index.php?module=auth")"
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
|
||||
find_zone() {
|
||||
domain="$1"
|
||||
|
||||
# do login
|
||||
do_login || return 1
|
||||
|
||||
# get zones
|
||||
response="$(do_get "https://www.geoscaling.com/dns2/index.php?module=domains")"
|
||||
|
||||
table="$(echo "${response}" | tr -d '\n' | sed 's|.*<div class="box"><div class="boxtitle">Your domains</div><div class="boxtext"><table|<table|; s|</table>.*|</table>|')"
|
||||
_debug2 table "${table}"
|
||||
zone_names="$(echo "${table}" | _egrep_o '<b>[^<]*</b>' | sed 's|<b>||;s|</b>||')"
|
||||
_debug2 _matches "${zone_names}"
|
||||
# Zone names and zone IDs are in same order
|
||||
zone_ids=$(echo "${table}" | _egrep_o '<a href=.index\.php\?module=domain&id=[0-9]+. onclick="javascript:show_loader\(\);">' | sed 's|.*id=||;s|. .*||')
|
||||
|
||||
_debug2 "These are the zones on this Geoscaling account:"
|
||||
_debug2 "zone_names" "${zone_names}"
|
||||
_debug2 "And these are their respective IDs:"
|
||||
_debug2 "zone_ids" "${zone_ids}"
|
||||
if [ -z "${zone_names}" ] || [ -z "${zone_ids}" ]; then
|
||||
_err "Can not get zone names or IDs."
|
||||
return 1
|
||||
fi
|
||||
# Walk through all possible zone names
|
||||
strip_counter=1
|
||||
while true; do
|
||||
attempted_zone=$(echo "${domain}" | cut -d . -f ${strip_counter}-)
|
||||
|
||||
# All possible zone names have been tried
|
||||
if [ -z "${attempted_zone}" ]; then
|
||||
_err "No zone for domain '${domain}' found."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug "Looking for zone '${attempted_zone}'"
|
||||
|
||||
line_num="$(echo "${zone_names}" | grep -n "^${attempted_zone}\$" | _head_n 1 | cut -d : -f 1)"
|
||||
_debug2 line_num "${line_num}"
|
||||
if [ "$line_num" ]; then
|
||||
zone_id=$(echo "${zone_ids}" | sed -n "${line_num}p")
|
||||
zone_name=$(echo "${zone_names}" | sed -n "${line_num}p")
|
||||
if [ -z "${zone_id}" ]; then
|
||||
_err "Can not find zone id."
|
||||
return 1
|
||||
fi
|
||||
_debug "Found relevant zone '${attempted_zone}' with id '${zone_id}' - will be used for domain '${domain}'."
|
||||
return 0
|
||||
fi
|
||||
|
||||
_debug "Zone '${attempted_zone}' doesn't exist, let's try a less specific zone."
|
||||
strip_counter=$(_math "${strip_counter}" + 1)
|
||||
done
|
||||
}
|
||||
# vim: et:ts=2:sw=2:
|
178
dnsapi/dns_googledomains.sh
Executable file
178
dnsapi/dns_googledomains.sh
Executable file
@ -0,0 +1,178 @@
|
||||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_googledomains_info='Google Domains
|
||||
Site: Domains.Google.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_googledomains
|
||||
Options:
|
||||
GOOGLEDOMAINS_ACCESS_TOKEN API Access Token
|
||||
GOOGLEDOMAINS_ZONE Zone
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/4545
|
||||
Author: Alex Leigh <leigh@alexleigh.me>
|
||||
'
|
||||
|
||||
GOOGLEDOMAINS_API="https://acmedns.googleapis.com/v1/acmeChallengeSets"
|
||||
|
||||
######## Public functions ########
|
||||
|
||||
#Usage: dns_googledomains_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_googledomains_add() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_info "Invoking Google Domains ACME DNS API."
|
||||
|
||||
if ! _dns_googledomains_setup; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
zone="$(_dns_googledomains_get_zone "$fulldomain")"
|
||||
if [ -z "$zone" ]; then
|
||||
_err "Could not find a Google Domains-managed zone containing the requested domain."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug zone "$zone"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_info "Adding TXT record for $fulldomain."
|
||||
if _dns_googledomains_api "$zone" ":rotateChallenges" "{\"accessToken\":\"$GOOGLEDOMAINS_ACCESS_TOKEN\",\"recordsToAdd\":[{\"fqdn\":\"$fulldomain\",\"digest\":\"$txtvalue\"}],\"keepExpiredRecords\":true}"; then
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_info "TXT record added."
|
||||
return 0
|
||||
else
|
||||
_err "Error adding TXT record."
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
_err "Error adding TXT record."
|
||||
return 1
|
||||
}
|
||||
|
||||
#Usage: dns_googledomains_rm _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_googledomains_rm() {
|
||||
fulldomain=$1
|
||||
txtvalue=$2
|
||||
|
||||
_info "Invoking Google Domains ACME DNS API."
|
||||
|
||||
if ! _dns_googledomains_setup; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
zone="$(_dns_googledomains_get_zone "$fulldomain")"
|
||||
if [ -z "$zone" ]; then
|
||||
_err "Could not find a Google Domains-managed domain based on request."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug zone "$zone"
|
||||
_debug txtvalue "$txtvalue"
|
||||
|
||||
_info "Removing TXT record for $fulldomain."
|
||||
if _dns_googledomains_api "$zone" ":rotateChallenges" "{\"accessToken\":\"$GOOGLEDOMAINS_ACCESS_TOKEN\",\"recordsToRemove\":[{\"fqdn\":\"$fulldomain\",\"digest\":\"$txtvalue\"}],\"keepExpiredRecords\":true}"; then
|
||||
if _contains "$response" "$txtvalue"; then
|
||||
_err "Error removing TXT record."
|
||||
return 1
|
||||
else
|
||||
_info "TXT record removed."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
_err "Error removing TXT record."
|
||||
return 1
|
||||
}
|
||||
|
||||
######## Private functions ########
|
||||
|
||||
_dns_googledomains_setup() {
|
||||
if [ -n "$GOOGLEDOMAINS_SETUP_COMPLETED" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
GOOGLEDOMAINS_ACCESS_TOKEN="${GOOGLEDOMAINS_ACCESS_TOKEN:-$(_readaccountconf_mutable GOOGLEDOMAINS_ACCESS_TOKEN)}"
|
||||
GOOGLEDOMAINS_ZONE="${GOOGLEDOMAINS_ZONE:-$(_readaccountconf_mutable GOOGLEDOMAINS_ZONE)}"
|
||||
|
||||
if [ -z "$GOOGLEDOMAINS_ACCESS_TOKEN" ]; then
|
||||
GOOGLEDOMAINS_ACCESS_TOKEN=""
|
||||
_err "Google Domains access token was not specified."
|
||||
_err "Please visit Google Domains Security settings to provision an ACME DNS API access token."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$GOOGLEDOMAINS_ZONE" ]; then
|
||||
_savedomainconf GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
|
||||
_savedomainconf GOOGLEDOMAINS_ZONE "$GOOGLEDOMAINS_ZONE"
|
||||
else
|
||||
_saveaccountconf_mutable GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
|
||||
_clearaccountconf_mutable GOOGLEDOMAINS_ZONE
|
||||
_clearaccountconf GOOGLEDOMAINS_ZONE
|
||||
fi
|
||||
|
||||
_debug GOOGLEDOMAINS_ACCESS_TOKEN "$GOOGLEDOMAINS_ACCESS_TOKEN"
|
||||
_debug GOOGLEDOMAINS_ZONE "$GOOGLEDOMAINS_ZONE"
|
||||
|
||||
GOOGLEDOMAINS_SETUP_COMPLETED=1
|
||||
return 0
|
||||
}
|
||||
|
||||
_dns_googledomains_get_zone() {
|
||||
domain=$1
|
||||
|
||||
# Use zone directly if provided
|
||||
if [ "$GOOGLEDOMAINS_ZONE" ]; then
|
||||
if ! _dns_googledomains_api "$GOOGLEDOMAINS_ZONE"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$GOOGLEDOMAINS_ZONE"
|
||||
return 0
|
||||
fi
|
||||
|
||||
i=2
|
||||
while true; do
|
||||
curr=$(printf "%s" "$domain" | cut -d . -f $i-100)
|
||||
_debug curr "$curr"
|
||||
|
||||
if [ -z "$curr" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _dns_googledomains_api "$curr"; then
|
||||
echo "$curr"
|
||||
return 0
|
||||
fi
|
||||
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
_dns_googledomains_api() {
|
||||
zone=$1
|
||||
apimethod=$2
|
||||
data="$3"
|
||||
|
||||
if [ -z "$data" ]; then
|
||||
response="$(_get "$GOOGLEDOMAINS_API/$zone$apimethod")"
|
||||
else
|
||||
_debug data "$data"
|
||||
export _H1="Content-Type: application/json"
|
||||
response="$(_post "$data" "$GOOGLEDOMAINS_API/$zone$apimethod")"
|
||||
fi
|
||||
|
||||
_debug response "$response"
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "Error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if _contains "$response" "\"error\": {"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
@ -1,15 +1,14 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
########################################################################
|
||||
# Hurricane Electric hook script for acme.sh
|
||||
#
|
||||
# Environment variables:
|
||||
#
|
||||
# - $HE_Username (your dns.he.net username)
|
||||
# - $HE_Password (your dns.he.net password)
|
||||
#
|
||||
# Author: Ondrej Simek <me@ondrejsimek.com>
|
||||
# Git repo: https://github.com/angel333/acme.sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_he_info='Hurricane Electric HE.net
|
||||
Site: dns.he.net
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_he
|
||||
Options:
|
||||
HE_Username Username
|
||||
HE_Password Password
|
||||
Issues: github.com/angel333/acme.sh/issues/
|
||||
Author: Ondrej Simek <me@ondrejsimek.com>
|
||||
'
|
||||
|
||||
#-- dns_he_add() - Add TXT record --------------------------------------
|
||||
# Usage: dns_he_add _acme-challenge.subdomain.domain.com "XyZ123..."
|
||||
|
@ -1,8 +1,12 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
#HETZNER_Token="sdfsdfsdfljlbjkljlkjsdfoiwje"
|
||||
#
|
||||
# shellcheck disable=SC2034
|
||||
dns_hetzner_info='Hetzner.com
|
||||
Site: Hetzner.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_hetzner
|
||||
Options:
|
||||
HETZNER_Token API Token
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2943
|
||||
'
|
||||
|
||||
HETZNER_Api="https://dns.hetzner.com/api/v1"
|
||||
|
||||
|
@ -1,9 +1,13 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
#
|
||||
# Hexonet_Login="username!roleId"
|
||||
#
|
||||
# Hexonet_Password="rolePassword"
|
||||
# shellcheck disable=SC2034
|
||||
dns_hexonet_info='Hexonet.com
|
||||
Site: Hexonet.com
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi2#dns_hexonet
|
||||
Options:
|
||||
Hexonet_Login Login. E.g. "username!roleId"
|
||||
Hexonet_Password Role Password
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2389
|
||||
'
|
||||
|
||||
Hexonet_Api="https://coreapi.1api.net/api/call.cgi"
|
||||
|
||||
|
@ -1,10 +1,13 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
# hosting.de API
|
||||
|
||||
# Values to export:
|
||||
# export HOSTINGDE_ENDPOINT='https://secure.hosting.de'
|
||||
# export HOSTINGDE_APIKEY='xxxxx'
|
||||
# shellcheck disable=SC2034
|
||||
dns_hostingde_info='Hosting.de
|
||||
Site: Hosting.de
|
||||
Docs: github.com/acmesh-official/acme.sh/wiki/dnsapi#dns_hostingde
|
||||
Options:
|
||||
HOSTINGDE_ENDPOINT Endpoint. E.g. "https://secure.hosting.de"
|
||||
HOSTINGDE_APIKEY API Key
|
||||
Issues: github.com/acmesh-official/acme.sh/issues/2058
|
||||
'
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user