Browse Source

Merge branch 'master' of https://github.com/srvrco/getssl

Local changes (to be pushed upstream):

add standard -v and --version options
dns_godaddy - correct fix for a godaddy API change
export AUTH_DNS_SERVER, PUBLIC_DNS_SERVER, LANG for hooks
apply $DNS_CHECK_OPTIONS to all dns lookups (for binding to an IP or
                                             applying a TSIG file)
When making combined cert/key files, force 077 permissions
In Makefile, handle *_scripts directories with install to get proper permissions.
Update template with advice on split views.
In dns_*_nsupdate, fix indent, prevent malformed commands
pull/660/head
Timothe Litt 5 years ago
parent
commit
b028cb7291
Failed to extract signature
150 changed files with 9438 additions and 1238 deletions
  1. +3
    -0
      .editorconfig
  2. +8
    -0
      .gitattributes
  3. +30
    -0
      .github/ISSUE_TEMPLATE/bug_report.md
  4. +20
    -0
      .github/ISSUE_TEMPLATE/feature_request.md
  5. +97
    -0
      .github/workflows/run-tests-pebble.yml
  6. +25
    -0
      .github/workflows/run-tests-staging-duckdns.yml
  7. +25
    -0
      .github/workflows/run-tests-staging-dynu.yml
  8. +17
    -0
      .github/workflows/shellcheck.yml
  9. +31
    -0
      .github/workflows/stale2.yml
  10. +0
    -17
      .travis.yml
  11. +16
    -9
      CONTRIBUTING.md
  12. +219
    -66
      README.md
  13. +52
    -0
      dns_scripts/Cloudflare-README.md
  14. +10
    -0
      dns_scripts/DNS_ROUTE53.md
  15. +60
    -0
      dns_scripts/GoDaddy-README.txt
  16. +7
    -0
      dns_scripts/dns_add_challtestsrv
  17. +103
    -0
      dns_scripts/dns_add_clouddns
  18. +79
    -69
      dns_scripts/dns_add_cloudflare
  19. +76
    -0
      dns_scripts/dns_add_cpanel
  20. +185
    -0
      dns_scripts/dns_add_del_aliyun.sh
  21. +28
    -0
      dns_scripts/dns_add_duckdns
  22. +72
    -0
      dns_scripts/dns_add_dynu
  23. +44
    -0
      dns_scripts/dns_add_joker
  24. +15
    -12
      dns_scripts/dns_add_nsupdate
  25. +33
    -33
      dns_scripts/dns_add_ovh
  26. +6
    -0
      dns_scripts/dns_del_challtestsrv
  27. +110
    -0
      dns_scripts/dns_del_clouddns
  28. +80
    -70
      dns_scripts/dns_del_cloudflare
  29. +69
    -0
      dns_scripts/dns_del_cpanel
  30. +21
    -0
      dns_scripts/dns_del_duckdns
  31. +71
    -0
      dns_scripts/dns_del_dynu
  32. +44
    -0
      dns_scripts/dns_del_joker
  33. +14
    -11
      dns_scripts/dns_del_nsupdate
  34. +35
    -35
      dns_scripts/dns_del_ovh
  35. +702
    -0
      dns_scripts/dns_freedns.sh
  36. +87
    -0
      dns_scripts/dns_route53.py
  37. +33
    -0
      docker-compose.yml
  38. +1880
    -910
      getssl
  39. +6
    -6
      other_scripts/cpanel_cert_upload
  40. +40
    -0
      test/1-simple-http01-dig.bats
  41. +40
    -0
      test/1-simple-http01-nslookup.bats
  42. +26
    -0
      test/1-simple-http01-two-acl.bats
  43. +35
    -0
      test/1-simple-http01.bats
  44. +41
    -0
      test/10-mixed-case.bats
  45. +63
    -0
      test/11-test--install.bats
  46. +20
    -0
      test/11-test-no-domain-storage.bats
  47. +75
    -0
      test/12-auto-upgrade-v1.bats
  48. +45
    -0
      test/13-notify-valid.bats
  49. +44
    -0
      test/14-test-revoke.bats
  50. +50
    -0
      test/15-test-revoke-no-suffix.bats
  51. +23
    -0
      test/16-test-bad-acl.bats
  52. +87
    -0
      test/17-test-spaces-in-sans-dns01.bats
  53. +87
    -0
      test/17-test-spaces-in-sans-http01.bats
  54. +38
    -0
      test/18-retry-dns-add.bats
  55. +64
    -0
      test/19-test-add-to-sans.bats
  56. +49
    -0
      test/2-simple-dns01-dig.bats
  57. +41
    -0
      test/2-simple-dns01-nslookup.bats
  58. +64
    -0
      test/20-wildcard-simple.bats
  59. +74
    -0
      test/21-wildcard-dual-rsa.bats
  60. +61
    -0
      test/22-wildcard-dual-rsa-ecdsa-copy-2-locations.bats
  61. +46
    -0
      test/23-wildcard-check-globbing.bats
  62. +64
    -0
      test/24-wildcard-sans.bats
  63. +42
    -0
      test/25-wildcard-all.bats
  64. +41
    -0
      test/26-wildcard-revoke.bats
  65. +45
    -0
      test/27-wildcard-existing-cert.bats
  66. +31
    -0
      test/28-wildcard-error-http01-validation.bats
  67. +47
    -0
      test/29-check-mktemp-failure.bats
  68. +96
    -0
      test/3-dual-rsa-ecdsa.bats
  69. +44
    -0
      test/30-handle-dig-failure.bats
  70. +25
    -0
      test/31-test-posix-error.bats
  71. +111
    -0
      test/32-test-upgrade.bats
  72. +71
    -0
      test/33-ftp.bats
  73. +71
    -0
      test/34-ftp-passive.bats
  74. +111
    -0
      test/35-preferred-chain.bats
  75. +94
    -0
      test/36-full-chain-inc-root.bats
  76. +45
    -0
      test/4-more-than-10-hosts.bats
  77. +57
    -0
      test/5-secp384-http01.bats
  78. +81
    -0
      test/6-dual-rsa-ecdsa-copy-2-locations.bats
  79. +62
    -0
      test/8-staging-ecdsa.bats
  80. +60
    -0
      test/9-multiple-domains-dns01.bats
  81. +32
    -0
      test/9-test--all.bats
  82. +33
    -0
      test/Dockerfile-alpine
  83. +34
    -0
      test/Dockerfile-bash4-0
  84. +34
    -0
      test/Dockerfile-bash4-2
  85. +34
    -0
      test/Dockerfile-bash5-0
  86. +47
    -0
      test/Dockerfile-centos6
  87. +32
    -0
      test/Dockerfile-centos7
  88. +28
    -0
      test/Dockerfile-centos7-duckdns
  89. +29
    -0
      test/Dockerfile-centos7-dynu
  90. +34
    -0
      test/Dockerfile-centos8
  91. +32
    -0
      test/Dockerfile-debian
  92. +38
    -0
      test/Dockerfile-ubuntu
  93. +30
    -0
      test/Dockerfile-ubuntu-duckdns
  94. +30
    -0
      test/Dockerfile-ubuntu-dynu
  95. +36
    -0
      test/Dockerfile-ubuntu16
  96. +41
    -0
      test/Dockerfile-ubuntu18
  97. +35
    -0
      test/README-Testing.md
  98. +30
    -0
      test/debug-test.sh
  99. +6
    -0
      test/dns_add_fail
  100. +9
    -0
      test/restart-ftpd

+ 3
- 0
.editorconfig View File

@ -7,3 +7,6 @@ end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
[Makefile]
indent_style = tab

+ 8
- 0
.gitattributes View File

@ -1,3 +1,11 @@
# Files not to include in .zip/.tar.gz archives
#
.git* export-ignore
# Handle line endings automatically for files detected as text
# and leave all files detected as binary untouched.
* text=auto
# Make all text files lf formatted
* text eol=lf

+ 30
- 0
.github/ISSUE_TEMPLATE/bug_report.md View File

@ -0,0 +1,30 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Operating system (please complete the following information):**
- OS: [e.g. Debian 9, Ubuntu 18.04, freeBSD ]
- Bash Version [e.g. GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)]
**Additional context**
Add any other context about the problem here.

+ 20
- 0
.github/ISSUE_TEMPLATE/feature_request.md View File

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

+ 97
- 0
.github/workflows/run-tests-pebble.yml View File

@ -0,0 +1,97 @@
name: Run all tests on pebble
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
test-alpine:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Build the docker-compose stack
run: docker-compose up -d --build
- name: Run test suite on Alpine
run: test/run-test.sh alpine
test-bash-4-0:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Build the docker-compose stack
run: docker-compose up -d --build
- name: Run test suite on Alpine using Bash 4.0
run: test/run-test.sh bash4-0
test-bash-4-2:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Build the docker-compose stack
run: docker-compose up -d --build
- name: Run test suite on Alpine using Bash 4.2
run: test/run-test.sh bash4-2
test-bash-5-0:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Build the docker-compose stack
run: docker-compose up -d --build
- name: Run test suite on Alpine using Bash 5
run: test/run-test.sh bash5-0
test-centos6:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Build the docker-compose stack
run: docker-compose up -d --build
- name: Run test suite on CentOS6
run: test/run-test.sh centos6
test-centos7:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Build the docker-compose stack
run: docker-compose up -d --build
- name: Run test suite on CentOS7
run: test/run-test.sh centos7
test-centos8:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Build the docker-compose stack
run: docker-compose up -d --build
- name: Run test suite on CentOS8
run: test/run-test.sh centos8
test-debian:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Build the docker-compose stack
run: docker-compose up -d --build
- name: Run test suite on Debian
run: test/run-test.sh debian
test-ubuntu:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Build the docker-compose stack
run: docker-compose up -d --build
- name: Run test suite on Ubuntu
run: test/run-test.sh ubuntu
test-ubuntu16:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Build the docker-compose stack
run: docker-compose up -d --build
- name: Run test suite on Ubuntu16
run: test/run-test.sh ubuntu16
test-ubuntu18:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Build the docker-compose stack
run: docker-compose up -d --build
- name: Run test suite on Ubuntu18
run: test/run-test.sh ubuntu18

+ 25
- 0
.github/workflows/run-tests-staging-duckdns.yml View File

@ -0,0 +1,25 @@
name: Run all tests using DuckDNS
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
test-centos7-duckdns:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Build the docker-compose stack
run: docker-compose up -d --build
- name: Run test suite on CentOS7 against Staging using DuckDNS
run: test/run-test.sh centos7-duckdns
test-ubuntu-duckdns:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Build the docker-compose stack
run: docker-compose up -d --build
- name: Run test suite on Ubuntu against Staging using DuckDNS
run: test/run-test.sh ubuntu-duckdns

+ 25
- 0
.github/workflows/run-tests-staging-dynu.yml View File

@ -0,0 +1,25 @@
name: Run all tests using Dynu
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
test-centos7-dynu:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Build the docker-compose stack
run: docker-compose up -d --build
- name: Run test suite on CentOS7 against Staging using Dynu
run: test/run-test.sh centos7-dynu
test-ubuntu-dynu:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Build the docker-compose stack
run: docker-compose up -d --build
- name: Run test suite on Ubuntu against Staging using Dynu
run: test/run-test.sh ubuntu-dynu

+ 17
- 0
.github/workflows/shellcheck.yml View File

@ -0,0 +1,17 @@
name: shellcheck
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Lint check
uses: azohra/shell-linter@v0.3.0
with:
path: "getssl"

+ 31
- 0
.github/workflows/stale2.yml View File

@ -0,0 +1,31 @@
on:
schedule:
- cron: "0 0 * * *"
name: Run Stale Bot on Issue Comments
jobs:
build:
name: stale
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: stale
uses: gatsbyjs/stale@master
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DRY_RUN: true
DAYS_BEFORE_STALE: 60
DAYS_BEFORE_CLOSE: 30
STALE_ISSUE_LABEL: 'stale'
STALE_PR_LABEL: 'stale'
OPERATIONS_PER_RUN: 30
STALE_ISSUE_MESSAGE: 'This issue will be closed as no updates for 60 days'
CLOSE_MESSAGE: 'Closing stale issue after 90 days of inactivity'
EXEMPT_ISSUE_LABELS: |
bug
documentation
enhancement
feature
help wanted
rfc

+ 0
- 17
.travis.yml View File

@ -1,17 +0,0 @@
language: bash
# Use container-based infrastructure for quicker build start-up
sudo: false
addons:
apt:
sources:
- debian-sid # Grab shellcheck from the Debian repo (o_O)
packages:
- shellcheck
script:
- bash -c 'shopt -s globstar; shellcheck getssl'
matrix:
fast_finish: true

+ 16
- 9
CONTRIBUTING.md View File

@ -1,24 +1,31 @@
# How to contribute
If you are happy writing in bash, please create a PR for any changes you'd like to see included (or bug fixes).
If you are happy writing in bash, please create a PR for any changes
you'd like to see included (or bug fixes).
If you aren't happy writing in bash, please open an issue with as much detail as possible about the issue or what you'd like to see added / improved.
If you aren't happy writing in bash, please open an issue with as much
detail as possible about the issue or what you'd like to see added /
improved.
## Submitting changes
Please update the 'revision history' and version number at the top of the code (without this I can't easily do a merge)
Please update the 'revision history' and version number at the top of
the code (without this I can't easily do a merge)
Please update just one issue per PR. If there are multiple issues, please provide separate PR's one per issue.
Please update just one issue per PR. If there are multiple issues,
please provide separate PR's one per issue.
## Coding conventions
Please see the guidelines at https://github.com/srvrco/getssl/wiki/Bash-Style-guide
Please see the guidelines at <https://github.com/srvrco/getssl/wiki/Bash-Style-guide>
## Testing
Please test with [shellcheck](https://github.com/koalaman/shellcheck), although this will also be tested on github ( via travis) on all PRs.
Please test with [shellcheck](https://github.com/koalaman/shellcheck),
although this will also be tested on github (via travis) on all PRs.
Please remember that the system is used across a wide range of platforms, so if you have access to multiple operating systems, please test on all.
Please remember that the system is used across a wide range of
platforms, so if you have access to multiple operating systems, please
test on all.
Thanks :)
Thanks :)

+ 219
- 66
README.md View File

@ -1,93 +1,155 @@
# getssl
Obtain SSL certificates from the letsencrypt.org ACME server. Suitable for automating the process on remote servers.
# getssl <!-- omit in toc -->
![Run all tests](https://github.com/srvrco/getssl/workflows/Run%20all%20tests/badge.svg) ![shellcheck](https://github.com/srvrco/getssl/workflows/shellcheck/badge.svg)
Obtain SSL certificates from the letsencrypt.org ACME server. Suitable
for automating the process on remote servers.
## Table of Contents <!-- omit in toc -->
- [Features](#features)
- [Installation](#installation)
- [Overview](#overview)
- [Getting started](#getting-started)
- [Detailed guide to getting started with more examples](#detailed-guide-to-getting-started-with-more-examples)
- [Wildcard certificates](#wildcard-certificates)
- [Automating updates](#automating-updates)
- [Structure](#structure)
- [Server-Types](#server-types)
- [Revoke a certificate](#revoke-a-certificate)
- [Elliptic curve keys](#elliptic-curve-keys)
- [Preferred Chain](#preferred-chain)
- [Include Root certificate in full chain](#include-root-certificate-in-full-chain)
- [Issues / problems / help](#issues--problems--help)
## Features
* **Bash** - It runs on virtually all unix machines, including BSD, most Linux distributions, MAC OSX.
* **Get certificates for remote servers** - The tokens used to provide validation of domain ownership, and the certificates themselves can be automatically copied to remote servers (via ssh, sftp or ftp for tokens). The script doesn't need to run on the server itself. This can be useful if you don't have access to run such scripts on the server itself, e.g. if it's a shared server.
* **Runs as a daily cron** - so certificates will be automatically renewed when required.
* **Bash** - It runs on virtually all unix machines, including BSD, most
Linux distributions, macOS.
* **Get certificates for remote servers** - The tokens used to provide
validation of domain ownership, and the certificates themselves can be
automatically copied to remote servers (via ssh, sftp or ftp for
tokens). The script doesn't need to run on the server itself. This can
be useful if you don't have access to run such scripts on the server
itself, e.g. if it's a shared server.
* **Runs as a daily cron** - so certificates will be automatically
renewed when required.
* **Automatic certificate renewals**
* **Checks certificates are correctly loaded**. After installation of a new certificate it will test the port specified ( see [Server-Types](#server-types) for options ) that the certificate is actually being used correctly.
* **Automatically updates** - The script can automatically update itself with bug fixes etc if required.
* **Extensively configurable** - With a simple configuration file for each certificate it is possible to configure it exactly for your needs, whether a simple single domain or multiple domains across multiple servers on the same certificate.
* **Checks certificates are correctly loaded** - After installation of a
new certificate it will test the port specified ( see
[Server-Types](#server-types) for options ) that the certificate is
actually being used correctly.
* **Automatically updates** - The script can automatically update itself
with bug fixes etc if required.
* **Extensively configurable** - With a simple configuration file for
each certificate it is possible to configure it exactly for your
needs, whether a simple single domain or multiple domains across
multiple servers on the same certificate.
* **Supports http and dns challenges** - Full ACME implementation
* **Simple and easy to use**
* **Detailed debug info** - Whilst it shouldn't be needed, detailed debug information is available.
* **Reload services** - After a new certificate is obtained then the relevant services (e.g. apache/nginx/postfix) can be reloaded.
* **Detailed debug info** - Whilst it shouldn't be needed, detailed
debug information is available.
* **Reload services** - After a new certificate is obtained then the
relevant services (e.g. apache/nginx/postfix) can be reloaded.
* **ACME v1 and V2** - Supports both ACME versions 1 and 2 (note ACMEv1 is deprecated and clients will automatically use v2)
## Installation
Since the script is only one file, you can use the following command for a quick installation of GetSSL only:
```
Since the script is only one file, you can use the following command for
a quick installation of GetSSL only:
```sh
curl --silent https://raw.githubusercontent.com/srvrco/getssl/master/getssl > getssl ; chmod 700 getssl
```
This will copy the getssl Bash script to the current location and change the permissions to make it executable for you.
For a more comprehensive installation (e.g. install also helper scripts) use the provided Makefile with each release tarball. Use the `install` target.
This will copy the getssl Bash script to the current location and change
the permissions to make it executable for you.
For a more comprehensive installation (e.g. install also helper scripts)
use the provided Makefile with each release tarball. Use the `install`
target.
You'll find the latest version in the git repository:
```
```sh
git clone https://github.com/srvrco/getssl.git
```
For Arch Linux there are packages in the AUR, see [here](https://aur.archlinux.org/packages/getssl/) and [there](https://aur.archlinux.org/packages/getssl-git/).
For Arch Linux there are packages in the AUR, see
[here](https://aur.archlinux.org/packages/getssl/) and
[there](https://aur.archlinux.org/packages/getssl-git/).
If you use puppet, there is a [GetSSL Puppet module](https://github.com/dthielking/puppet_getssl) by dthielking
If you use puppet, there is a [GetSSL Puppet
module](https://github.com/dthielking/puppet_getssl) by dthielking
## Overview
GetSSL was written in standard bash ( so it can be run on a server, a desktop computer, or even a virtualbox) and add the checks, and certificates to a remote server ( providing you have a ssh with key, sftp or ftp access to the remote server).
GetSSL was written in standard bash ( so it can be run on a server, a
desktop computer, or even a virtualbox) and add the checks, and
certificates to a remote server ( providing you have a ssh with key,
sftp or ftp access to the remote server).
```
getssl ver. 2.02
```getssl -h
getssl ver. 2.35
Obtain SSL certificates from the letsencrypt.org ACME server
Usage: getssl [-h|--help] [-d|--debug] [-c|--create] [-f|--force] [-a|--all] [-q|--quiet] [-Q|--mute] [-u|--upgrade] [-k|--keep #] [-U|--nocheck] [-r|--revoke cert key] [-w working_dir] domain
Usage: getssl [-h|--help] [-d|--debug] [-c|--create] [-f|--force] [-a|--all] [-q|--quiet] [-Q|--mute] [-u|--upgrade] [-k|--keep #] [-U|--nocheck] [-r|--revoke cert key] [-w working_dir] [--preferred-chain chain] domain
Options:
-a, --all Check all certificates
-d, --debug Outputs debug information
-d, --debug Output debug information
-c, --create Create default config files
-f, --force Force renewal of cert (overrides expiry checks)
-h, --help Display this help message and exit
-i, --install Install certificates and reload service
-q, --quiet Quiet mode (only outputs on error, success of new cert, or getssl was upgraded)
-Q, --mute Like -q, but mutes notification about successful upgrade
-Q, --mute Like -q, but also mute notification about successful upgrade
-r, --revoke "cert" "key" [CA_server] Revoke a certificate (the cert and key are required)
-u, --upgrade Upgrade getssl if a more recent version is available
-k, --keep "#" Maximum amount of old getssl versions to keep when upgrading
-u, --upgrade Upgrade getssl if a more recent version is available - can be used with or without domain(s)
-k, --keep "#" Maximum number of old getssl versions to keep when upgrading
-U, --nocheck Do not check if a more recent version is available
-w working_dir "Working directory"
--preferred-chain "chain" Use an alternate chain for the certificate
```
## Getting started
Once you have obtained the script (see Installation above), the next step is to use
```./getssl -c yourdomain.com```
```sh
./getssl -c yourdomain.com
```
where yourdomain.com is the primary domain name that you want to create a certificate for. This will create the following folders and files.
where yourdomain.com is the primary domain name that you want to create
a certificate for. This will create the following folders and files.
```
```sh
~/.getssl
~/.getssl/getssl.cfg
~/.getssl/yourdomain.com
~/.getssl/yourdomain.com/getssl.cfg
```
You can then edit ~/.getssl/getssl.cfg to set the values you want as the default for the majority of your certificates.
You can then edit `~/.getssl/getssl.cfg` to set the values you want as the
default for the majority of your certificates.
Then edit ~/.getssl/yourdomain.com/getssl.cfg to have the values you want for this specific domain (make sure to uncomment and specify correct `ACL` option, since it is required).
Then edit `~/.getssl/yourdomain.com/getssl.cfg` to have the values you
want for this specific domain (make sure to uncomment and specify
correct `ACL` option, since it is required).
You can then just run;
You can then just run:
```getssl yourdomain.com ```
and it should run, providing output like;
```sh
getssl yourdomain.com
```
and it should run, providing output like:
```sh
Registering account
Verify each domain
Verifing yourdomain.com
Verifying yourdomain.com
Verified yourdomain.com
Verifing www.yourdomain.com
Verifying www.yourdomain.com
Verified www.yourdomain.com
Verification completed, obtaining certificate.
Certificate saved in /home/user/.getssl/yourdomain.com/yourdomain.com.crt
@ -97,35 +159,76 @@ copying private key to ssh:server5:/home/yourdomain/ssl/domain.key
copying CA certificate to ssh:server5:/home/yourdomain/ssl/chain.crt
reloading SSL services
```
**This will (by default) use the staging server, so should give you a certificate that isn't trusted ( Fake Let's Encrypt).**
**This will (by default) use the staging server, so should give you a
certificate that isn't trusted ( Fake Let's Encrypt).**
Change the server in your config file to get a fully valid certificate.
**Note:** Verification is done via port 80 (http), port 443 (https) or dns. The certificate can be used (and checked with getssl) on alternate ports.
**Note:** Verification is done via port 80 (http), port 443 (https) or
dns. The certificate can be used (and checked with getssl) on alternate
ports.
## Automating updates
## Detailed guide to getting started with more examples
[Guide to getting a certificate for example.com and www.example.com](https://github.com/srvrco/getssl/wiki/Guide-to-getting-a-certificate-for-example.com-and-www.example.com)
## Wildcard certificates
`getssl` supports creating wildcard certificates, i.e. _*.example.com_ which allows a single certificate to be used for any domain under *example.com*, e.g. *www.example.com*, *mail.example.com*. These must be validated using the dns-01 method.
A *partial* example `getssl.cfg` file is:
I use the following cron
```sh
VALIDATE_VIA_DNS=true
export CPANEL_USERNAME=''
export CPANEL_URL='https://www.cpanel.host:2083'
export CPANEL_APITOKEN='1ABC2DEF3GHI4JKL5MNO6PQR7STU8VWX9YZA'
DNS_ADD_COMMAND=/home/root/getssl/dns_scripts/dns_add_cpanel
DNS_DEL_COMMAND=/home/root/getssl/dns_scripts/dns_del_cpanel
```
Create the wildcard certificate (need to use quotes to prevent globbing):
```sh
getssl "*.example.domain"
```
You can renew the certificate using `getssl -a` to renew all configured certificates.
You can also specify additional domains in the `SANS` line, e.g. `SANS="www.test.example.com"`.
This cannot contain any of the domains which would be covered by the wildcard certificate.
## Automating updates
I use the following **cron** job
```cron
23 5 * * * /root/scripts/getssl -u -a -q
```
The cron will automatically update getssl and renew any certificates, only giving output if there are issues / errors.
The cron will automatically update getssl and renew any certificates,
only giving output if there are issues / errors.
* The -u flag updates getssl if there is a more recent version available.
* The -a flag automatically renews any certificates that are due for renewal.
* The -q flag is "quiet" so that it only outputs and emails me if there was an error / issue.
* The -q flag is "quiet" so that it only outputs and emails me if there
was an error / issue.
## Structure
The design aim was to provide flexibility in running the code. The default working directory is ~/.getssl ( which can be modified via the command line)
The design aim was to provide flexibility in running the code. The
default working directory is `~/.getssl` (which can be modified via the
command line).
Within the **working directory** is a config file, getssl.cfg which is a simple bash file containing variables, an example of which is
Within the **working directory** is a config file `getssl.cfg` which is a
simple bash file containing variables, an example of which is:
```
```sh
# Uncomment and modify any variables you need
# The staging server is best for testing (hence set as default)
CA="https://acme-staging.api.letsencrypt.org"
CA="https://acme-staging-v02.api.letsencrypt.org"
# This server issues full certificates, however has rate limits
#CA="https://acme-v01.api.letsencrypt.org"
#CA="https://acme-v02.api.letsencrypt.org"
AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.0.1-July-27-2015.pdf"
@ -142,17 +245,19 @@ RENEW_ALLOW="30"
SSLCONF="/usr/lib/ssl/openssl.cnf"
```
then, within the **working directory** there will be a folder for each certificate (based on its domain name). Within that folder will be a config file (again called getssl.cfg). An example of which is;
then, within the **working directory** there will be a folder for each
certificate (based on its domain name). Within that folder will be a
config file (again called `getssl.cfg`). An example of which is:
```
```sh
# Uncomment and modify any variables you need
# see https://github.com/srvrco/getssl/wiki/Config-variables for details
# see https://github.com/srvrco/getssl/wiki/Example-config-files for example configs
#
# The staging server is best for testing
#CA="https://acme-staging.api.letsencrypt.org"
#CA="https://acme-staging-v02.api.letsencrypt.org"
# This server issues full certificates, however has rate limits
#CA="https://acme-v01.api.letsencrypt.org"
#CA="https://acme-v02.api.letsencrypt.org"
#AGREEMENT="https://letsencrypt.org/documents/LE-SA-v1.1.1-August-1-2016.pdf"
@ -183,7 +288,9 @@ DOMAIN_KEY_LOCATION="ssh:server5:/etc/ssl/domain.key"
#DOMAIN_PEM_LOCATION="" this is the domain_key. domain cert and CA cert
# The command needed to reload apache / nginx or whatever you use
# The command needed to reload apache / nginx or whatever you use.
# Several (ssh) commands may be given using a bash array:
# RELOAD_CMD=('ssh:sshuserid@server5:systemctl reload httpd' 'logger getssl for server5 efficient.')
RELOAD_CMD="service apache2 reload"
# Define the server type. This can be https, ftp, ftpi, imap, imaps, pop3, pop3s, smtp,
@ -194,24 +301,32 @@ RELOAD_CMD="service apache2 reload"
#CHECK_REMOTE="true"
```
If a location for a file starts with ssh: it is assumed the next part of the file is the hostname, followed by a colon, and then the path.
Files will be securely copied using scp, and it assumes that you have a key on the server ( for passwordless access). You can set the user, port etc for the server in your .ssh/config file
If a location for a file starts with `ssh:` it is assumed the next part
of the file is the hostname, followed by a colon, and then the path.
Files will be securely copied using scp, and it assumes that you have a
key on the server (for passwordless access). You can set the user,
port etc for the server in your `.ssh/config` file.
If an ACL starts with ftp: or sftp: it as assumed that the line is in the format "ftp:UserID:Password:servername:/path/to/acme-challenge". sftp requires sshpass.
Note: FTP can be used for copying tokens only and can **not** be used for uploading private key or certificates as it's not a secure method of transfer.
If an ACL starts with `ftp:` or `sftp:` it as assumed that the line is
in the format "ftp:UserID:Password:servername:/path/to/acme-challenge".
sftp requires sshpass.
Note: FTP can be used for copying tokens only
and can **not** be used for uploading private key or certificates as
it's not a secure method of transfer.
ssh can also be used for the reload command if using on remote servers.
Multiple locations can be defined for a file by separating the locations with a semi-colon.
A typical config file for `example.com` and `www.example.com` on the
same server would be:
A typical config file for example.com and www.example.com on the same server would be
```
```sh
# uncomment and modify any variables you need
# The staging server is best for testing
CA="https://acme-staging.api.letsencrypt.org"
CA="https://acme-staging-v02.api.letsencrypt.org"
# This server issues full certificates, however has rate limits
#CA="https://acme-v01.api.letsencrypt.org"
#CA="https://acme-v02.api.letsencrypt.org"
# additional domains - this could be multiple domains / subdomains in a comma separated list
SANS="www.example.com"
@ -230,6 +345,7 @@ RELOAD_CMD="service apache2 reload"
```
## Server-Types
OpenSSL has built-in support for getting the certificate from a number of SSL services
these are available in getssl to check if the certificate is installed correctly
@ -251,23 +367,60 @@ these are available in getssl to check if the certificate is installed correctly
| ldaps | 636 | |
| port number | | |
## Revoke a certificate
In general revoking a certificate is not required.
Usage: `getssl -r path/to/cert path/to/key [CA_server]`
You need to specify both the certificate you want to revoke, and the account or private domain key which was used to sign / obtain the original certificate. The CA_server is an optional parameter and defaults to Let's Encrypt ( "https://acme-v01.api.letsencrypt.org" ) as that is currently the only Certificate Authority using the ACME protocol.
You need to specify both the certificate you want to revoke, and the
account or private domain key which was used to sign / obtain the
original certificate. The `CA_server` is an optional parameter and
defaults to Let's Encrypt ("<https://acme-v01.api.letsencrypt.org>") as
that is currently the only Certificate Authority using the ACME
protocol.
## Elliptic curve keys
You can use Elliptic curve keys for both the account key and the domain key (different of course, don't use the same key for both). prime256v1 (NIST P-256) and secp384r1 (NIST P-384) are both fully supported. secp521r1 (NIST P-521) is included in the code, but not currently supported by Let's Encrypt).
You can use Elliptic curve keys for both the account key and the domain
key (different of course, don't use the same key for both). prime256v1
(NIST P-256) and secp384r1 (NIST P-384) are both fully supported.
secp521r1 (NIST P-521) is included in the code, but not currently
supported by Let's Encrypt).
## Preferred Chain
If a CA offers multiple chains then it is possible to select which chain
is used by using the `PREFERRED_CHAIN` variable in `getssl.cfg` or specifying
`--preferred-chain` in the call to `getssl`
This uses wildcard matching so requesting "X1" returns the first certificate
returned by the CA which contains the text "X1", Note you may need to escape
any characters which special characters, e.g.
` PREFERRED_CHAIN="\(STAGING\) Doctored Durian Root CA X3"`
* Staging options are: "(STAGING) Doctored Durian Root CA X3" and "(STAGING) Pretend Pear X1"
* Production options are: "ISRG Root X1" and "ISRG Root X2"
## Include Root certificate in full chain
Some servers, including those that use Java keystores, will not accept a server certificate if it cannot valid the full chain of signers.
Specifically, Nutanix Prism (Element and Central) will not accept the `fullchain.crt` until the root CA's certificate has been appended to it manually.
If your application requires the full chain, i.e. including the
root certificate of the CA, then this can be included in the `fullchain.crt` file by
adding the following line to `getssl.cfg`
```sh
FULL_CHAIN_INCLUDE_ROOT="true"
```
## Issues / problems / help
If you have any issues, please log them at https://github.com/srvrco/getssl/issues
If you have any issues, please log them at <https://github.com/srvrco/getssl/issues>
There are additional help pages on the [wiki](https://github.com/srvrco/getssl/wiki)
If you have any suggestions for improvements then pull requests are welcomed, or raise an issue.
If you have any suggestions for improvements then pull requests are
welcomed, or raise an issue.

+ 52
- 0
dns_scripts/Cloudflare-README.md View File

@ -0,0 +1,52 @@
## Using Cloudflare DNS for LetsEncrypt domain validation
### Enabling the scripts
Set the following options in `getssl.cfg` (either global or domain-specific):
```
VALIDATE_VIA_DNS="true"
DNS_ADD_COMMAND="/usr/share/getssl/dns_scripts/dns_add_cloudflare"
DNS_DEL_COMMAND="/usr/share/getssl/dns_scripts/dns_del_cloudflare"
```
### Authentication
There are 2 methods of authenticating with Cloudflare:
1. API Keys - Account level, all-purpose tokens
2. API Tokens - Scoped and permissioned access to resources
Both are configured from your profile in the [Cloudflare dashboard][1]
[1]: https://dash.cloudflare.com/profile/api-tokens
#### API Keys
The **Zone ID** for the domain will be searched for programmatically.
Set the following options in `getssl.cfg`:
```
export CF_EMAIL="..." # Cloudflare account email address
export CF_KEY="..." # Global API Key
```
#### API Tokens
Cloudflare provides a template for creating an API Token with access to edit
zone records. Tokens must be created with at least '**DNS:Edit** permissions
for the domain to add/delete records.
The API requires higher privileges to be able to list zones, therefore this
method also requires the **Zone ID** from the Overview tab in the Cloudflare
Dashboard.
Set the following options in the domain-specific `getssl.cfg`
```
export CF_API_TOKEN="..."
export CF_ZONE_ID="..."
```
__Note__: API Keys will be used instead if also configured

+ 10
- 0
dns_scripts/DNS_ROUTE53.md View File

@ -0,0 +1,10 @@
# Do DNS-01 verification using Route53
I was not about to implement this in BASH, sorry guys. I'd like you to have it, however.
It's pretty simple to use.
1. pip install boto3 dnspython
2. ln -s dns_route53.py dns_add_route53
3. ln -s dns_route53.py dns_del_route53
4. Use it just like the other scripts

+ 60
- 0
dns_scripts/GoDaddy-README.txt View File

@ -0,0 +1,60 @@
Using GoDaddy DNS for LetsEncrypt domain validation.
Quick guide to setting up getssl for domain validation of
GoDaddy DNS domains.
There are two prerequisites to using getssl with GoDaddy DNS:
1) Obtain an API access key from developer.godaddy.com
At first sign-up, you will be required to take a "test" key.
This is NOT what you need. Accept it, then get a "Production"
key. At this writing, there is no charge - but you must have
a GoDaddy customer account.
You must get the API key for the account which owns the domain
that you want to get certificates for. If the domains that you
manage are owned by more than one account, get a key for each.
The access key consists of a "Key" and a "Secret". You need
both.
2) Obtain JSON.sh - https://github.com/dominictarr/JSON.sh
With those in hand, the installation procedure is:
1) Put JSON.sh in the getssl DNS scripts directory
Default: /usr/share/getssl/dns_scripts
2) Open your config file (the global file in ~/.getssl/getssl.cfg
or the per-account file in ~/.getssl/example.net/getssl.cfg
3) Set the following options:
VALIDATE_VIA_DNS="true"
DNS_ADD_COMMAND="/usr/share/getssl/dns_scripts/dns_add_godaddy"
DNS_DEL_COMMAND="/usr/share/getssl/dns_scripts/dns_del_godaddy"
# The API key for your account/this domain
export GODADDY_KEY="..." GODADDY_SECRET="..."
4) Set any other options that you wish (per the standard
directions.) Use the test CA to make sure that
everything is setup correctly.
That's it. getssl example.net will now validate with DNS.
To trace record additions and removals, run getssl as
GODADDY_TRACE=Y getssl example.net
There are additional options, which are documented in the
*godaddy" files and dns_godaddy -h.
Copyright (2017) Timothe Litt litt at acm _dot org
This sofware may be freely used providing this notice is included with
all copies. The name of the author may not be used to endorse
any other product or derivative work. No warranty is provided
and the user assumes all responsibility for use of this software.
Report any issues to https://github.com/tlhackque/getssl/issues.
Enjoy.

+ 7
- 0
dns_scripts/dns_add_challtestsrv View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
# Simple script to update the challtestserv mock DNS server when testing DNS responses
fulldomain="${1}"
token="${2}"
curl --silent -X POST -d "{\"host\":\"_acme-challenge.${fulldomain}.\", \"value\": \"${token}\"}" http://10.30.50.3:8055/set-txt

+ 103
- 0
dns_scripts/dns_add_clouddns View File

@ -0,0 +1,103 @@
#!/usr/bin/env bash
# Need to add your email address and API key to clouddns below or set as env variables
email=${CLOUDDNS_EMAIL:-''}
password=${CLOUDDNS_PASSWORD:-''}
client=${CLOUDDNS_CLIENT:-''}
# This script adds a token to clouddns DNS for the ACME challenge
# usage dns_add_clouddns "domain name" "token"
# return codes are;
# 0 - success
# 1 - error in input
# 2 - error within internal processing
# 3 - error in result ( domain not found in clouddns etc)
fulldomain="${1}"
token="${2}"
API='https://admin.vshosting.cloud/clouddns'
LOGIN_API='https://admin.vshosting.cloud/api/public/auth/login'
# Check initial parameters
if [[ -z "$fulldomain" ]]; then
echo "DNS script requires full domain name as first parameter"
exit 1
fi
if [[ -z "$token" ]]; then
echo "DNS script requires challenge token as second parameter"
exit 1
fi
if [[ -z "$email" ]]; then
echo "CLOUDDNS_EMAIL (email) parameter not set"
exit 1
fi
if [[ -z "$password" ]]; then
echo "CLOUDDNS_PASSWORD (password) parameter not set"
exit 1
fi
if [[ -z "$client" ]]; then
echo "CLOUDDNS_CLIENT (id) parameter not set"
exit 1
fi
# Login to clouddns to get accessToken
resp=$(curl --silent -X POST -H 'Content-Type: application/json' "$LOGIN_API" \
--data "{\"email\": \"$email\", \"password\": \"$password\"}")
re='"accessToken":"([^,]*)",' # Match access token
if [[ "${resp// }" =~ $re ]]; then
access_token="${BASH_REMATCH[1]}"
fi
if [[ -z "$access_token" ]]; then
echo 'Could not get access token; check your credentials'
exit 3
fi
curl_params=( -H "Authorization: Bearer $access_token" -H 'Content-Type: application/json' )
# Get main domain
resp=$(curl --silent "${curl_params[@]}" -X POST "$API/domain/search" \
--data "{\"search\": [{\"name\": \"clientId\", \"operator\": \"eq\", \"value\": \"$client\"}]}")
domain_slice="$fulldomain"
while [[ -z "$domain_root" ]]; do
if [[ "${resp// }" =~ domainName\":\"$domain_slice ]]; then
domain_root="$domain_slice"
_debug domain_root "$domain_root"
fi
domain_slice="${domain_slice#[^\.]*.}"
done
# Get domain id
resp=$(curl --silent "${curl_params[@]}" -X POST "$API/domain/search" \
--data "{\"search\": [{\"name\": \"clientId\", \"operator\": \"eq\", \"value\": \"$client\"}, {\"name\": \"domainName\", \"operator\": \"eq\", \"value\": \"$domain_root.\"}]}")
re='domainType":"[^"]*","id":"([^,]*)",' # Match domain id
if [[ "${resp//[$'\t\r\n ']}" =~ $re ]]; then
domain_id="${BASH_REMATCH[1]}"
fi
if [[ -z "$domain_id" ]]; then
echo 'Domain name not found on your CloudDNS account'
exit 3
fi
# Add challenge record
txt_record="_acme-challenge.$fulldomain."
resp=$(curl --silent "${curl_params[@]}" -X POST "$API/record-txt" \
--data "{\"type\":\"TXT\",\"name\":\"$txt_record\",\"value\":\"$token\",\"domainId\":\"$domain_id\"}")
# If adding record failed (error:) then print error message
if [[ "${resp// }" == *'"error"'* ]]; then
if [[ "${resp// }" == *'"code":4136'* ]]; then
echo "DNS challenge token already exists"
exit
fi
re='"message":"([^"]+)"'
if [[ "$resp" =~ $re ]]; then
echo "Error: DNS challenge not added: ${BASH_REMATCH[1]}"
exit 3
else
echo "Error: DNS challenge not added: unknown error - ${resp}"
exit 3
fi
fi
# Publish challenge record
resp=$(curl --silent "${curl_params[@]}" -X PUT "$API/domain/$domain_id/publish" \
--data "{\"soaTtl\":300}")

+ 79
- 69
dns_scripts/dns_add_cloudflare View File

@ -1,9 +1,11 @@
#!/usr/bin/env bash
# need to add your email address and API key to cloudflare below or set as env variables
# either configure here or export environment variables in getssl.cfg
email=${CF_EMAIL:-''}
key=${CF_KEY:-''}
api_token=${CF_API_TOKEN:-''}
zone_id=${CF_ZONE_ID:-''}
# This script adds a token to cloudflare DNS for the ACME challenge
# This script adds a TXT record to cloudflare DNS for the ACME challenge
# usage dns_add_cloudflare "domain name" "token"
# return codes are;
# 0 - success
@ -14,7 +16,11 @@ key=${CF_KEY:-''}
fulldomain="${1}"
token="${2}"
API='https://api.cloudflare.com/client/v4/zones'
curl_params=( -H "X-Auth-Email: $email" -H "X-Auth-Key: $key" -H 'Content-Type: application/json' )
if [[ -z "$api_token" ]]; then
curl_params=( -H "X-Auth-Email: $email" -H "X-Auth-Key: $key" -H 'Content-Type: application/json' )
else
curl_params=( -H "Authorization: Bearer $api_token" -H 'Content-Type: application/json' )
fi
# check initial parameters
@ -28,84 +34,88 @@ if [[ -z "$token" ]]; then
exit 1
fi
if [[ -z "$email" ]]; then
echo "CF_EMAIL (email) parameter not set"
exit 1
fi
if [[ -z "$api_token" ]]; then
if [[ -z "$email" ]]; then
echo "CF_EMAIL (email) parameter not set"
exit 1
fi
if [[ -z "$key" ]]; then
echo "CF_KEY (key) parameter not set"
exit 1
if [[ -z "$key" ]]; then
echo "CF_KEY (key) parameter not set"
exit 1
fi
fi
# get a list of all domain names from cloudflare
# If you have a lot, you may need add "&page=1&per_page=1000" and/or "&status=active"
resp=$(curl --silent "${curl_params[@]}" -X GET "$API")
re='"result":\[(([^][]*\[[^][]*])*[^][]*)]' # find result section
if [[ "${resp// }" =~ $re ]]; then
resp="${BASH_REMATCH[1]}"
fi
# iterate through all sections to obtain a list of domains
while [[ "$resp" ]]; do
re='[^}{]*\{(([^}{]*\{[^}{]*})*[^}{]*)}(.*)'
if [[ "$resp" =~ $re ]]; then
first="${BASH_REMATCH[1]}"
resp="${BASH_REMATCH[3]}"
if [[ -z "$zone_id" ]]; then
# get a list of all domain names from cloudflare
# If you have a lot, you may need add "&page=1&per_page=1000" and/or "&status=active"
resp=$(curl --silent "${curl_params[@]}" -X GET "$API")
re='"result":\[(([^][]*\[[^][]*])*[^][]*)]' # find result section
if [[ "${resp// }" =~ $re ]]; then
resp="${BASH_REMATCH[1]}"
fi
# remove subsections - leave only domain level
while [[ "$first" =~ (.*)[\[\{][^]\{\}[]*[\]\}](.*) ]]; do
first="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
done
re='"name":"([^"]*)"'
if [[ "$first" =~ $re ]]; then
domains=( "${domains[@]}" "${BASH_REMATCH[1]}" )
else
echo "Error getting domain name"
exit 2
fi
re='"id":"([^"]*)"'
if [[ "$first" =~ $re ]]; then
ids=( "${ids[@]}" "${BASH_REMATCH[1]}" )
else
echo "Error getting domain id"
exit 2
fi
done
# split required domain name into an array
dnarray=(${fulldomain//./ })
# get number of parts in required domain name
NumParts=${#dnarray[@]}
# build a test domain name, starting with the largest, and reduce it
# until a match is found, set domain = first ( longest) match.
domain=""
i=1
while [ $i -lt "$NumParts" ]; do
testdomain="${dnarray[i-1]}"
for ((j=i; j<NumParts; j++)); do
testdomain+=".${dnarray[j]}"
done
# loop through domains at cloudflare
for k in "${!domains[@]}"; do
# if match found, then set domain and domain_id
if [[ "$testdomain" == "${domains[k]}" ]]; then
domain="$testdomain"
domain_id=${ids[k]}
i="$NumParts"
# iterate through all sections to obtain a list of domains
while [[ "$resp" ]]; do
re='[^}{]*\{(([^}{]*\{[^}{]*})*[^}{]*)}(.*)'
if [[ "$resp" =~ $re ]]; then
first="${BASH_REMATCH[1]}"
resp="${BASH_REMATCH[3]}"
fi
# remove subsections - leave only domain level
while [[ "$first" =~ (.*)[\[\{][^]\{\}[]*[\]\}](.*) ]]; do
first="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
done
re='"name":"([^"]*)"'
if [[ "$first" =~ $re ]]; then
domains=( "${domains[@]}" "${BASH_REMATCH[1]}" )
else
echo "Error getting domain name"
exit 2
fi
re='"id":"([^"]*)"'
if [[ "$first" =~ $re ]]; then
ids=( "${ids[@]}" "${BASH_REMATCH[1]}" )
else
echo "Error getting domain id"
exit 2
fi
done
# split required domain name into an array
dnarray=(${fulldomain//./ })
# get number of parts in required domain name
NumParts=${#dnarray[@]}
# build a test domain name, starting with the largest, and reduce it
# until a match is found, set domain = first ( longest) match.
domain=""
i=1
while [ $i -lt "$NumParts" ]; do
testdomain="${dnarray[i-1]}"
for ((j=i; j<NumParts; j++)); do
testdomain+=".${dnarray[j]}"
done
# loop through domains at cloudflare
for k in "${!domains[@]}"; do
# if match found, then set domain and zone_id
if [[ "$testdomain" == "${domains[k]}" ]]; then
domain="$testdomain"
zone_id=${ids[k]}
i="$NumParts"
fi
done
((i++))
done
((i++))
done
if [[ -z "$domain" ]]; then
echo 'domain name not found on your cloudflare account'
exit 3
if [[ -z "$domain" ]]; then
echo 'domain name not found on your cloudflare account'
exit 3
fi
fi
txt_record="_acme-challenge.${fulldomain%.$domain}"
resp=$(curl --silent "${curl_params[@]}" -X POST "$API/$domain_id/dns_records" \
resp=$(curl --silent "${curl_params[@]}" -X POST "$API/$zone_id/dns_records" \
--data "{\"type\":\"TXT\",\"name\":\"${txt_record}\",\"content\":\"$token\",\"ttl\":300}")
# if it failed (success:false) then give error message


+ 76
- 0
dns_scripts/dns_add_cpanel View File

@ -0,0 +1,76 @@
#!/usr/bin/env bash
# Need to add your email address and API key to cpanel below or set as env variables
user=${CPANEL_USERNAME:-''}
password=${CPANEL_PASSWORD:-''}
url=${CPANEL_URL:-''} # e.g. https://www.cpanel-host.test:2083
apitoken=${CPANEL_APITOKEN:-''}
fulldomain="${1}"
token="${2}"
# Check initial parameters
if [[ -z "$fulldomain" ]]; then
echo "DNS script requires full domain name as first parameter"
exit 1
fi
if [[ -z "$token" ]]; then
echo "DNS script requires challenge token as second parameter"
exit 1
fi
if [[ -z "$user" ]]; then
echo "CPANEL_USERNAME (username) parameter not set"
exit 1
fi
if [[ -z "$apitoken" ]] && [[ -z "$password" ]]; then
echo "Must set either CPANEL_APITOKEN or CPANEL_PASSWORD in dns script, environment variable or getssl.cfg"
exit 1
fi
if [[ -z "$url" ]]; then
echo "CPANEL_URL (url) parameter not set"
exit 1
fi
# Setup
request_func="${url}/json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit"
if [[ -n $apitoken ]]; then
curl_params=( -H "Authorization: cpanel $user:$apitoken" )
else
auth_string=$(echo -ne "$user:$password" | base64 --wrap 0)
curl_params=( -H "Authorization: Basic $auth_string" )
fi
# Check if domain is a CNAME
res=$(dig CNAME "$fulldomain")
domain=$(echo "$res"| awk '$4 ~ "CNAME" {print $5}' |sed 's/\.$//g')
if [[ -n "$domain" ]]; then
name=".${fulldomain%.$domain}"
else
domain=$fulldomain
name=""
fi
# Check to see if challenge dns entry already exists (update or delete?)
request_params="&cpanel_jsonapi_func=fetchzone_records&domain=${domain}&type=TXT&name=_acme-challenge.${fulldomain}."
resp=$(curl --silent "${curl_params[@]}" "$request_func$request_params")
if [[ "$resp" = *\"error\":* ]]; then
echo -n "cpanel fetchzone records failed: "
echo "$resp" | awk -F"error" '{ print $2 }' | awk -F\" '{ print $3 }'
exit 1
fi
# If no existing record, create a new TXT record, otherwise edit the existing record
if [[ "$resp" == *\"data\":[]* ]]; then
request_params="&cpanel_jsonapi_func=add_zone_record&domain=$domain&type=TXT&name=_acme-challenge$name&txtdata=$token"
else
# shellcheck disable=SC2001
line=$(echo "$resp" | sed -e 's/.*line":\([0-9]*\),.*/\1/')
request_params="&cpanel_jsonapi_func=edit_zone_record&domain=$domain&type=TXT&name=_acme-challenge$name&txtdata=${token}&line=${line}"
fi
resp=$(curl --silent "${curl_params[@]}" "$request_func$request_params")
if [[ "$resp" = *\"status\":0* ]]; then
echo -n "cpanel edit zone record failed: "
echo "$resp" | awk -F"statusmsg" '{ print $2 }' | awk -F\" '{ print $3 }'
exit 1
fi

+ 185
- 0
dns_scripts/dns_add_del_aliyun.sh View File

@ -0,0 +1,185 @@
#!/bin/bash
#https://blog.aymar.cn
#https://protocol.aymar.cn
PROGNAME=${0##*/}
VERSION="2021年3月22日 16:07:05"
Ali_API="https://dns.aliyuncs.com/"
_timestamp=$(date -u +"%Y-%m-%dT%H%%3A%M%%3A%SZ")
__debug="0"
__delete="0"
#Wildcard certificates
#A partial example getssl.cfg file is:
#VALIDATE_VIA_DNS=true
#DNS_ADD_COMMAND=/root/.getssl/dns_add_del_aliyun.sh
#DNS_DEL_COMMAND=/root/.getssl/dns_add_del_aliyun.sh
# either configure KeyId & KeySecret here or export environment variables in getssl.cfg
AccessKeyId=${ALI_KeyId:-''}
AccessKeySecret=${ALI_KeySecret:-''}
usage() { # print out the program usage
echo "Usage: $PROGNAME [-a|--add <Domain Name> <RecordValue>] [-d|--delete <Full.DomainName.com>] [-s|--search <Full.DomainName.com> ] [-h|--help] [-t|--type] "\
"[-q|--quiet] [-c|--check] [-S|--status] [-l|--lock #] [-T|--ttl] [-u|--update] [-w|--weight] [-L|--Line]"
}
help_message() { # print out the help message
cat <<- _EOF_
$PROGNAME Version. $VERSION
$(usage)
Options:
-a, --add Add Domain Record 域名 ip (默认类型TXT)
-d, --delete Delete Domain Record 域名 (默认类型TXT)
-s, --search Search Domain Record 域名
-t, --type Record Type 类型(A、MX、CNAME、TXT、REDIRECT_URL、FORWORD_URL、NS、AAAA、SRV)
_EOF_
}
_arg_check(){
[ -z "$1" ] || _arg_count=$1
shift
[ ${#} -lt $_arg_count ] && help_message && exit 1 || (echo $2 | grep "^-") && help_message && exit 1
#If the number of arguments <$_ARG_COUNT print help and exit, and if the second argument begins with “-” print help and exit
return 0
}
#[ ${#} -lt 2 ] && help_message && exit 1 #Same as below
#[ -z "$2" ] && help_message && exit 1 #Same as below
_arg_check 2 $@
_debug (){
if [ "$__debug" -eq 1 ]; then
echo -e "\033[1;31m # debug: $(date "+%m %d %T") | Func: ${FUNCNAME[@]} | Line:${BASH_LINENO[@]} \033[0m" "\n $@ " #"Current FUNCNAME ${FUNCNAME} #$LINENO " #"$(($RANDOM%10))"
fi
return 0
}
_requires() {
_cmds='' # Check if the commands exists
if [[ "$#" -gt 0 ]]; then
for i in "$@"; do
if eval type type >/dev/null 2>&1; then
eval type "$i" >/dev/null 2>&1
elif command >/dev/null 2>&1; then
command -v "$i" >/dev/null 2>&1
else
which "$i" >/dev/null 2>&1
fi
#[ "$?" -eq 0 ] && _debug "checking for $i exists = ok" || _cmds=$_cmds"$i: "
#shellcheck disable=SC2181
if [ "$?" -eq 0 ]; then
#_debug "checking for $i exists = ok"
continue
else
_cmds=$_cmds"$i: "
fi
done
else
echo "Usage: _requires [command] "
return 1
fi
[ -n "$_cmds" ] && { echo -e "\033[1;31m $_cmds command not found \033[0m" && return 1 ;} || return 0
}
_requires openssl
#shellcheck disable=SC2120
_hex_dump() { #ascii hex
local _str=''
[ $# -gt 0 ] && _str=$@ || read _str
local _str_len=${#_str}
local i=1
while [ "$i" -le "$_str_len" ]; do
local _str_c="$(printf "%s" "$_str" | cut -c "$i")"
printf " %02x" "'$_str_c"
i=$(($i + 1))
done
#printf "%s" " 0a"
}
_urlencode() {
local length="${#1}"
local i=''
for i in $(awk "BEGIN { for ( i=0; i<$length; i++ ) print i }")
do
#local _strc="$(printf "%s" "$1" | cut -c "$i")" #i=1; i<=$length; i++
local _strc="${1:$i:1}"
case $_strc in [a-zA-Z0-9.~_-]) printf "%s" "$_strc" ;; *) printf "%%%02X" "'$_strc" ;;
esac
done
}
_signature(){
signature=''
_hexkey=$(printf "%s" "$AccessKeySecret&" | _hex_dump |sed 's/ //g')
#signature=$(printf "%s" "GET&%2F&$(_urlencode "$query")" | openssl dgst -sha1 -hmac $(printf "%s" "$AccessKeySecret&" | _hex_dump |sed 's/ //g'| xxd -r -p ) -binary | openssl base64 -e)
signature=$(printf "%s" "GET&%2F&$(_urlencode "$query")" | openssl dgst -sha1 -mac HMAC -macopt "hexkey:$_hexkey" -binary | openssl base64 -e)
signature=$(_urlencode "$signature")
}
_query() {
[ -n "$__type" ] && { [[ "$_Action" = "AddDomainRecord" ]] && _Type="$__type" || { [ "$_Action" = "DescribeDomainRecords" ] && _TypeKeyWord="$__type"; } ; }
query=''
[ -n $AccessKeyId ] && query=$query'AccessKeyId='$AccessKeyId
query=$query'&Action='"$1"
[ -z $_DomainNames ] || query=$query'&DomainName='$_DomainNames
query=$query'&Format=json'
[ -z $_RR ] || query=$query'&RR='$_RR
[ -z $_RRKeyWord ] || query=$query'&RRKeyWord='$_RRKeyWord
[ -z $_RecordId ] || query=$query'&RecordId='$_RecordId
query=$query'&SignatureMethod=HMAC-SHA1'
query=$query"&SignatureNonce=$(date +"%s%N")"
query=$query'&SignatureVersion=1.0'
query=$query'&Timestamp='$_timestamp
[ -z $_Type ] || query=$query'&Type='$_Type
[ -z $_TypeKeyWord ] || query=$query'&TypeKeyWord='$_TypeKeyWord
[ -z $_Value ] || query=$query'&Value='$_Value
[ -z $_ValueKeyWord ] || query=$query'&ValueKeyWord='$_ValueKeyWord
query=$query'&Version=2015-01-09'
#_debug "$query"
_signature
return 0
}
_Get_RecordIds(){
_Action="DescribeDomainRecords"
_query $_Action $_DomainNames
url="${Ali_API}?${query}&Signature=${signature}"
_debug $url
_RecordIds=$(curl -k -s $url | grep -Po 'RecordId[": "]+\K[^"]+') && __delete="1" #RecordId requisite
_debug $_RecordIds
return 0
}
__type='TXT'
_DomainNames=$(printf "%s" $1| awk -F"." '{if(NF>=2){print $(NF-1)"."$NF}}') #awk -F\. '{print $(NF-1) FS $NF}') #requisite
_RRKeyWord="_acme-challenge"
_Get_RecordIds
_RRKeyWord=''
_TypeKeyWord=''
_ValueKeyWord=''
if [ "$__delete" = "1" ];then
_Action="DeleteDomainRecord" #Action requisite
_DomainNames=''
for _RecordId in ${_RecordIds[@]} #Delete multiple txt domain record
do
_debug "_RecordId" $_RecordId
_query $_Action $_RecordId
url="${Ali_API}?${query}&Signature=${signature}"
_debug $url
curl -k -s $url && ( echo -e "\n\033[1;32m Aliyun DNS record _acme-challenge.$1 has been deleted \033[0m")
done
else
_Action="AddDomainRecord" #requisite
_RR=$(printf "_acme-challenge.%s" $1| awk -F'.' '{if(NF>2){gsub("."$(NF-1)"."$NF,"");print}}') #requisite
_Value=$2 #requisite
_query $_Action $_DomainNames
url="${Ali_API}?${query}&Signature=${signature}"
_debug $url
curl -k -s $url && (echo -e "\n\033[1;32m Start Checking aliyun DNS record _acme-challenge.$1 \033[0m")
exit 0
fi

+ 28
- 0
dns_scripts/dns_add_duckdns View File

@ -0,0 +1,28 @@
#!/bin/bash
# need to add your Token for duckdns below
token=${DUCKDNS_TOKEN:-}
if [ -z "$token" ]; then
echo "DUCKDNS_TOKEN not set"
exit 1
fi
domain="$1"
txtvalue="$2"
i=1
response=$(curl --retry 5 --silent "https://www.duckdns.org/update?domains=${domain}&token=${token}&txt=${txtvalue}")
while [[ "${response}" == *"502 Bad Gateway"* ]] && [ $i -le 5 ]; do
echo "Retrying Bad Gateway response (attempt $i of 5)"
sleep 5
i=$((i+1))
response=$(curl --retry 5 --silent "https://www.duckdns.org/update?domains=${domain}&token=${token}&txt=${txtvalue}")
done
if [ "$response" != "OK" ]; then
echo "Failed to update TXT record for ${domain} at duckdns.org (is the TOKEN valid?)"
echo "Response: $response"
exit 1
fi

+ 72
- 0
dns_scripts/dns_add_dynu View File

@ -0,0 +1,72 @@
#!/usr/bin/env bash
# Need to add your API key below or set as env variable
apikey=${DYNU_API_KEY:-''}
# This script adds a token to dynu.com DNS for the ACME challenge
# usage dns_add_dynu "domain name" "token"
# return codes are;
# 0 - success
# 1 - error in input
# 2 - error within internal processing
# 3 - error in result ( domain not found in dynu.com etc)
fulldomain="${1}"
token="${2}"
API='https://api.dynu.com/v2/dns'
# Check initial parameters
if [[ -z "$fulldomain" ]]; then
echo "DNS script requires full domain name as first parameter"
exit 1
fi
if [[ -z "$token" ]]; then
echo "DNS script requires challenge token as second parameter"
exit 1
fi
curl_params=( -H "accept: application/json" -H "API-Key: $apikey" -H 'Content-Type: application/json' )
# Get domain id
# curl -X GET https://api.dynu.com/v2/dns/getroot/ubuntu-getssl.freeddns.org
resp=$(curl --silent "${curl_params[@]}" -X GET "$API/getroot/${fulldomain}")
# Match domain id
re="\"id\":([^,]*),\"domainName\":\"${fulldomain}\""
if [[ "$resp" =~ $re ]]; then
domain_id="${BASH_REMATCH[1]}"
fi
if [[ -z "$domain_id" ]]; then
echo 'Domain name not found on your Dynu account'
exit 3
fi
# Check for existing _acme-challenge TXT record
# curl -X GET "https://api.dynu.com/v2/dns/record/_acme-challenge.ubuntu-getssl.freeddns.org?recordType=TXT"
resp=$(curl --silent "${curl_params[@]}" -X GET "${API}/record/_acme-challenge.${fulldomain}?recordType=TXT")
re="\"id\":([^,]*)"
if [[ "$resp" =~ $re ]]; then
record_id="${BASH_REMATCH[1]}"
fi
if [[ -z "$record_id" ]]; then
# Add new TXT challenge record
resp=$(curl --silent \
"${curl_params[@]}" \
-X POST "${API}/${domain_id}/record" \
--data "{\"nodeName\":\"_acme-challenge\",\"recordType\":\"TXT\",\"state\":\"true\",\"textData\":\"$token\"}")
else
# Update existing record
# curl -X POST https://api.dynu.com/v2/dns/9329328/record/7082063 -d "{\"nodeName\":\"_acme-challenge\",\"recordType\":\"TXT\",\"state\":\"true\",\"textData\":\"Test2\"}"
resp=$(curl --silent \
"${curl_params[@]}" \
-X POST "${API}/${domain_id}/record/${record_id}" \
--data "{\"nodeName\":\"_acme-challenge\",\"recordType\":\"TXT\",\"state\":\"true\",\"textData\":\"$token\"}")
fi
# If adding record failed (exception:) then print error message
if [[ "$resp" != *"\"statusCode\":200"* ]]; then
echo "Error: DNS challenge not added: unknown error - ${resp}"
exit 3
fi

+ 44
- 0
dns_scripts/dns_add_joker View File

@ -0,0 +1,44 @@
#!/bin/bash
FULLDOMAIN=$1
TOKEN=$2
TMPFILE=$(mktemp /tmp/dns_add_joker.XXXXXXX)
USERNAME="youruser"
PASSWORD="yourpassword"
# Verify that required parameters are set
if [[ -z "${FULLDOMAIN}" ]]; then
echo "DNS script requires full domain name as first parameter"
exit 1
fi
if [[ -z "${TOKEN}" ]]; then
echo "DNS script requires challenge token as second parameter"
exit 1
fi
DOMAIN_ROOT=$(echo "${FULLDOMAIN}" | awk -F\. '{print $(NF-1) FS $NF}')
SID=$(curl --silent -X POST https://dmapi.joker.com/request/login \
-H "Accept: application/json" -H "User-Agent: getssl/0.1" \
-H "application/x-www-form-urlencoded" -d "username=${USERNAME}&password=${PASSWORD}" \
-i -k 2>/dev/null | grep Auth-Sid | awk '{ print $2 }')
## put zone data in tempfile
curl --silent -X POST https://dmapi.joker.com/request/dns-zone-get \
-H "Accept: application/json" -H "User-Agent: getssl/0.1" \
-H "application/x-www-form-urlencoded" -d "domain=${DOMAIN_ROOT}&auth-sid=${SID}" | \
tail -n +7 >"${TMPFILE}"
## add txt record
printf "_acme-challenge.%s. TXT 0 \"%s \" 300\n\n" "${FULLDOMAIN}" "${TOKEN}" >>"${TMPFILE}"
## generate encoded url data
URLDATA=$(cat "${TMPFILE}" | sed 's/ /%20/g' | sed 's/"/%22/g' | sed ':a;N;$!ba;s/\n/%0A/g')
## write new zonefile to joker
curl --silent --output /dev/null "https://dmapi.joker.com/request/dns-zone-put?domain=${DOMAIN_ROOT}&zone=${URLDATA}&auth-sid=${SID}" 2>&1
## remove tempfile
rm -f "${TMPFILE}"

+ 15
- 12
dns_scripts/dns_add_nsupdate View File

@ -14,26 +14,29 @@ token="$2"
if [ -n "${DNS_NSUPDATE_KEYFILE}" ]; then
if [ -n "${DNS_NSUPDATE_KEY_HOOK}" ] && ! ${DNS_NSUPDATE_KEY_HOOK} 'add' 'open' ${fulldomain} ; then
exit $(( $? + 128 ))
fi
if [ -n "${DNS_NSUPDATE_KEY_HOOK}" ] && ! ${DNS_NSUPDATE_KEY_HOOK} 'add' 'open' "${fulldomain}" ; then
exit $(( $? + 128 ))
fi
options="-k ${DNS_NSUPDATE_KEYFILE}"
options="-k ${DNS_NSUPDATE_KEYFILE}"
fi
# Note that blank line is a "send" command to nsupdate
cmd=
if [ -n "${DNS_SERVER}" ]; then
cmd+="server ${DNS_SERVER}\n"
fi
nsupdate ${options} -v <<EOF
update add _acme-challenge.${fulldomain}. 300 in TXT "${token}"
cmd+="update add ${DNS_ZONE:-"_acme-challenge.${fulldomain}."} 300 in TXT \"${token}\"\n"
cmd+="\n" # blank line is a "send" command to nsupdate
EOF
printf "$cmd" | nsupdate ${options} -v
sts=$?
if [ -n "${DNS_NSUPDATE_KEYFILE}" ]; then
if [ -n "${DNS_NSUPDATE_KEY_HOOK}" ] && ! ${DNS_NSUPDATE_KEY_HOOK} 'add' 'close' ${fulldomain}; then
exit $(( ${sts} + ( $? * 10 ) ))
fi
if [ -n "${DNS_NSUPDATE_KEY_HOOK}" ] && ! ${DNS_NSUPDATE_KEY_HOOK} 'add' 'close' "${fulldomain}"; then
exit $(( sts + ( $? * 10 ) ))
fi
fi
exit ${sts}
exit ${sts}

+ 33
- 33
dns_scripts/dns_add_ovh View File

@ -1,33 +1,33 @@
#!/bin/bash
domains=($(echo "$1"|sed -e 's/^\(\([a-zA-Z0-9.-]*\?\)\.\)*\([a-zA-Z0-9-]\+\.[a-zA-Z-]\+\)$/"\1" _acme-challenge.\2 \3/g'))
challenge="$2"
# Please, do not forget to ask for your credentials at https://eu.api.ovh.com/createToken/
# permissions needed are /domain/zone/* in GET,POST,DELETE
applicationKey="YourAK"
applicationSecret="YourAS"
consumerKey="YourCK"
topDomain=${domains[2]}
subDomain=${domains[1]%%.}
function send
{
method=$1
url=$2
body=$3
ts=$(date +%s)
sign=\$1\$$(echo -n "${applicationSecret}+${consumerKey}+${method}+https://eu.api.ovh.com/1.0${url}+${body}+${ts}"|sha1sum|cut -d" " -f1)
curl -X ${method} -H "Content-Type: application/json" -H "X-Ovh-Application: ${applicationKey}" -H "X-Ovh-Timestamp: ${ts}" -H "X-Ovh-Signature: ${sign}" -H "X-Ovh-Consumer: ${consumerKey}" -d "${body}" https://eu.api.ovh.com/1.0${url}
}
# Creation request
send POST /domain/zone/${topDomain}/record "{\"fieldType\":\"TXT\",\"subDomain\":\"$subDomain\",\"ttl\":60,\"target\":\"$challenge\"}"
# Refresh request
send POST /domain/zone/${topDomain}/refresh ""
# Pause for 10 seconds, for DNS propagation
sleep 10
#!/bin/bash
domains=($(echo "$1"|sed -e 's/^\(\([a-zA-Z0-9.-]*\?\)\.\)*\([a-zA-Z0-9-]\+\.[a-zA-Z-]\+\)$/"\1" _acme-challenge.\2 \3/g'))
challenge="$2"
# Please, do not forget to ask for your credentials at https://eu.api.ovh.com/createToken/
# permissions needed are /domain/zone/* in GET,POST,DELETE
applicationKey="YourAK"
applicationSecret="YourAS"
consumerKey="YourCK"
topDomain=${domains[2]}
subDomain=${domains[1]%%.}
function send
{
method=$1
url=$2
body=$3
ts=$(date +%s)
sign=\$1\$$(echo -n "${applicationSecret}+${consumerKey}+${method}+https://eu.api.ovh.com/1.0${url}+${body}+${ts}"|sha1sum|cut -d" " -f1)
curl -X "${method}" -H "Content-Type: application/json" -H "X-Ovh-Application: ${applicationKey}" -H "X-Ovh-Timestamp: ${ts}" -H "X-Ovh-Signature: ${sign}" -H "X-Ovh-Consumer: ${consumerKey}" -d "${body}" "https://eu.api.ovh.com/1.0${url}"
}
# Creation request
send POST "/domain/zone/${topDomain}/record" "{\"fieldType\":\"TXT\",\"subDomain\":\"$subDomain\",\"ttl\":60,\"target\":\"$challenge\"}"
# Refresh request
send POST "/domain/zone/${topDomain}/refresh" ""
# Pause for 10 seconds, for DNS propagation
sleep 10

+ 6
- 0
dns_scripts/dns_del_challtestsrv View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
# Simple script to update the challtestserv mock DNS server when testing DNS responses
fulldomain="${1}"
curl -X POST -d "{\"host\":\"_acme-challenge.${fulldomain}.\"}" http://10.30.50.3:8055/clear-txt

+ 110
- 0
dns_scripts/dns_del_clouddns View File

@ -0,0 +1,110 @@
#!/usr/bin/env bash
# Need to add your email address and API key to clouddns below or set as env variables
email=${CLOUDDNS_EMAIL:-''}
password=${CLOUDDNS_PASSWORD:-''}
client=${CLOUDDNS_CLIENT:-''}
# This script adds a token to clouddns DNS for the ACME challenge
# usage dns_add_clouddns "domain name" "token"
# return codes are;
# 0 - success
# 1 - error in input
# 2 - error within internal processing
# 3 - error in result ( domain not found in clouddns etc)
fulldomain="${1}"
token="${2}"
API='https://admin.vshosting.cloud/clouddns'
LOGIN_API='https://admin.vshosting.cloud/api/public/auth/login'
# Check initial parameters
if [[ -z "$fulldomain" ]]; then
echo "DNS script requires full domain name as first parameter"
exit 1
fi
if [[ -z "$token" ]]; then
echo "DNS script requires challenge token as second parameter"
exit 1
fi
if [[ -z "$email" ]]; then
echo "CLOUDDNS_EMAIL (email) parameter not set"
exit 1
fi
if [[ -z "$password" ]]; then
echo "CLOUDDNS_PASSWORD (password) parameter not set"
exit 1
fi
if [[ -z "$client" ]]; then
echo "CLOUDDNS_CLIENT (id) parameter not set"
exit 1
fi
# Login to clouddns to get accessToken
resp=$(curl --silent -X POST -H 'Content-Type: application/json' "$LOGIN_API" \
--data "{\"email\": \"$email\", \"password\": \"$password\"}")
re='"accessToken":"([^,]*)",' # Match access token
if [[ "${resp// }" =~ $re ]]; then
access_token="${BASH_REMATCH[1]}"
fi
if [[ -z "$access_token" ]]; then
echo 'Could not get access token; check your credentials'
exit 3
fi
curl_params=( -H "Authorization: Bearer $access_token" -H 'Content-Type: application/json' )
# Get main domain and challenge record
resp=$(curl --silent "${curl_params[@]}" -X POST "$API/domain/search" \
--data "{\"search\": [{\"name\": \"clientId\", \"operator\": \"eq\", \"value\": \"$client\"}]}")
domain_slice="$fulldomain"
while [[ -z "$domain_root" ]]; do
if [[ "${resp// }" =~ domainName\":\"$domain_slice ]]; then
domain_root="$domain_slice"
_debug domain_root "$domain_root"
fi
domain_slice="${domain_slice#[^\.]*.}"
done
txt_record="_acme-challenge.$fulldomain."
# Get domain id
curl_domainid_body="{\"search\": [{\"name\": \"clientId\", \"operator\": \"eq\", \"value\": \"$client\"}, {\"name\": \"domainName\", \"operator\": \"eq\", \"value\": \"$domain_root.\"}]}"
resp=$(curl --silent "${curl_params[@]}" -X POST -d "$curl_domainid_body" "$API/domain/search")
re='domainType":"[^"]*","id":"([^,]*)",' # Find result section
if [[ "${resp//[$'\t\r\n ']}" =~ $re ]]; then
domain_id="${BASH_REMATCH[1]}"
fi
if [[ -z "$domain_id" ]]; then
echo 'Domain name not found on your CloudDNS account'
exit 3
fi
# Get challenge record ID
resp=$(curl --silent "${curl_params[@]}" -X GET "$API/domain/$domain_id" )
re="\"lastDomainRecordList\".*\"id\":\"([^,]*)\"[^}]*\"name\":\"$txt_record\"," # Match domain id
if [[ "${resp//[$'\t\r\n ']}" =~ $re ]]; then
record_id="${BASH_REMATCH[1]}"
fi
if [[ -z "$record_id" ]]; then
echo 'Challenge record does not exist'
exit 3
fi
# Remove challenge record
resp=$(curl --silent "${curl_params[@]}" -X DELETE "$API/record/$record_id")
# If removing record failed (error:) then print error message
if [[ "${resp// }" == *'"error"'* ]]; then
re='"message":"([^"]+)"'
if [[ "$resp" =~ $re ]]; then
echo "Error: DNS challenge not removed: ${BASH_REMATCH[1]}"
exit 3
else
echo "Error: DNS challenge not removed: unknown error - ${resp}"
exit 3
fi
fi
# Publish challenge record deletion
resp=$(curl --silent "${curl_params[@]}" -X PUT "$API/domain/$domain_id/publish" \
--data "{\"soaTtl\":300}")

+ 80
- 70
dns_scripts/dns_del_cloudflare View File

@ -1,9 +1,11 @@
#!/usr/bin/env bash
# need to add your email address and API key to cloudflare below or set as env variables
# either configure here or export environment variables in getssl.cfg
email=${CF_EMAIL:-''}
key=${CF_KEY:-''}
api_token=${CF_API_TOKEN:-''}
zone_id=${CF_ZONE_ID:-''}
# This script removes a token from cloudflare DNS for the ACME challenge
# This script removes a TXT record from cloudflare DNS for the ACME challenge
# usage dns_del_cloudflare "domain name" "token (optional)"
# if token is not specified, then all tokens are removed.
# return codes are;
@ -15,7 +17,11 @@ key=${CF_KEY:-''}
fulldomain="${1}"
token="${2}"
API='https://api.cloudflare.com/client/v4/zones'
curl_params=( -H "X-Auth-Email: $email" -H "X-Auth-Key: $key" -H 'Content-Type: application/json' )
if [[ -z "$api_token" ]]; then
curl_params=( -H "X-Auth-Email: $email" -H "X-Auth-Key: $key" -H 'Content-Type: application/json' )
else
curl_params=( -H "Authorization: Bearer $api_token" -H 'Content-Type: application/json' )
fi
# check initial parameters
@ -24,83 +30,87 @@ if [[ -z "$fulldomain" ]]; then
exit 1
fi
if [[ -z "$email" ]]; then
echo "CF_EMAIL (email) parameter not set"
exit 1
fi
if [[ -z "$api_token" ]]; then
if [[ -z "$email" ]]; then
echo "CF_EMAIL (email) parameter not set"
exit 1
fi
if [[ -z "$key" ]]; then
echo "CF_KEY (key) parameter not set"
exit 1
if [[ -z "$key" ]]; then
echo "CF_KEY (key) parameter not set"
exit 1
fi
fi
# get a list of all domain names from cloudflare
# If you have a lot, you may need add "&page=1&per_page=1000" and/or "&status=active"
resp=$(curl --silent "${curl_params[@]}" -X GET "$API")
re='"result":\[(([^][]*\[[^][]*])*[^][]*)]' # find result section
if [[ "${resp// }" =~ $re ]]; then
resp="${BASH_REMATCH[1]}"
fi
# iterate through all sections to obtain a list of domains
while [[ "$resp" ]]; do
re='[^}{]*\{(([^}{]*\{[^}{]*})*[^}{]*)}(.*)'
if [[ "$resp" =~ $re ]]; then
first="${BASH_REMATCH[1]}"
resp="${BASH_REMATCH[3]}"
fi
# remove subsections - leave only domain level
while [[ "$first" =~ (.*)[\[\{][^]\{\}[]*[\]\}](.*) ]]; do
first="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
done
re='"name":"([^"]*)"'
if [[ "$first" =~ $re ]]; then
domains=( "${domains[@]}" "${BASH_REMATCH[1]}" )
else
echo "Error getting domain name"
exit 2
if [[ -z "$zone_id" ]]; then
# get a list of all domain names from cloudflare
# If you have a lot, you may need add "&page=1&per_page=1000" and/or "&status=active"
resp=$(curl --silent "${curl_params[@]}" -X GET "$API")
re='"result":\[(([^][]*\[[^][]*])*[^][]*)]' # find result section
if [[ "${resp// }" =~ $re ]]; then
resp="${BASH_REMATCH[1]}"
fi
re='"id":"([^"]*)"'
if [[ "$first" =~ $re ]]; then
ids=( "${ids[@]}" "${BASH_REMATCH[1]}" )
else
echo "Error getting domain id"
exit 2
fi
done
# split required domain name into an array
dnarray=(${fulldomain//./ })
# get number of parts in required domain name
NumParts=${#dnarray[@]}
# build a test domain name, starting with the largest, and reduce it
# until a match is found, set domain = first ( longest) match.
domain=""
i=1
while [ $i -lt "$NumParts" ]; do
testdomain="${dnarray[i-1]}"
for ((j=i; j<NumParts; j++)); do
testdomain+=".${dnarray[j]}"
done
# loop through domains at cloudflare
for k in "${!domains[@]}"; do
# if match found, then set domain and domain_id
if [[ "$testdomain" == "${domains[k]}" ]]; then
domain="$testdomain"
domain_id=${ids[k]}
i="$NumParts"
# iterate through all sections to obtain a list of domains
while [[ "$resp" ]]; do
re='[^}{]*\{(([^}{]*\{[^}{]*})*[^}{]*)}(.*)'
if [[ "$resp" =~ $re ]]; then
first="${BASH_REMATCH[1]}"
resp="${BASH_REMATCH[3]}"
fi
# remove subsections - leave only domain level
while [[ "$first" =~ (.*)[\[\{][^]\{\}[]*[\]\}](.*) ]]; do
first="${BASH_REMATCH[1]}${BASH_REMATCH[2]}"
done
re='"name":"([^"]*)"'
if [[ "$first" =~ $re ]]; then
domains=( "${domains[@]}" "${BASH_REMATCH[1]}" )
else
echo "Error getting domain name"
exit 2
fi
re='"id":"([^"]*)"'
if [[ "$first" =~ $re ]]; then
ids=( "${ids[@]}" "${BASH_REMATCH[1]}" )
else
echo "Error getting domain id"
exit 2
fi
done
((i++))
done
if [[ -z "$domain" ]]; then
echo 'domain name not found on your cloudflare account'
exit 3
# split required domain name into an array
dnarray=(${fulldomain//./ })
# get number of parts in required domain name
NumParts=${#dnarray[@]}
# build a test domain name, starting with the largest, and reduce it
# until a match is found, set domain = first ( longest) match.
domain=""
i=1
while [ $i -lt "$NumParts" ]; do
testdomain="${dnarray[i-1]}"
for ((j=i; j<NumParts; j++)); do
testdomain+=".${dnarray[j]}"
done
# loop through domains at cloudflare
for k in "${!domains[@]}"; do
# if match found, then set domain and zone_id
if [[ "$testdomain" == "${domains[k]}" ]]; then
domain="$testdomain"
zone_id=${ids[k]}
i="$NumParts"
fi
done
((i++))
done
if [[ -z "$domain" ]]; then
echo 'domain name not found on your cloudflare account'
exit 3
fi
fi
curl_request="$API/$domain_id/dns_records?type=TXT&name=_acme-challenge.$fulldomain"
curl_request="$API/$zone_id/dns_records?type=TXT&name=_acme-challenge.$fulldomain"
if [[ ! -z "$token" ]]; then # if token specified, then use it
curl_request+="&content=$token"
fi
@ -131,7 +141,7 @@ while [[ "$resp" ]]; do # iterate through records returned
echo "Error: domain ID not found"
exit 2
fi
respd=$(curl --silent "${curl_params[@]}" -X DELETE "$API/$domain_id/dns_records/$id")
respd=$(curl --silent "${curl_params[@]}" -X DELETE "$API/$zone_id/dns_records/$id")
if [[ "${respd// }" == *'"success":false'* ]]; then
re='"message":"([^"]+)"'
if [[ "$respd" =~ $re ]]; then


+ 69
- 0
dns_scripts/dns_del_cpanel View File

@ -0,0 +1,69 @@
#!/usr/bin/env bash
# Need to add your email address and API key to cpanel below or set as env variables
user=${CPANEL_USERNAME:-''}
password=${CPANEL_PASSWORD:-''}
url=${CPANEL_URL:-''} # e.g. https://www.cpanel-host.test:2083
apitoken=${CPANEL_APITOKEN:-''}
fulldomain="${1}"
# Check initial parameters
if [[ -z "$fulldomain" ]]; then
echo "DNS script requires full domain name as first parameter"
exit 1
fi
if [[ -z "$user" ]]; then
echo "CPANEL_USERNAME (username) parameter not set"
exit 1
fi
if [[ -z "$apitoken" ]] && [[ -z "$password" ]]; then
echo "Must set either CPANEL_APITOKEN or CPANEL_PASSWORD in dns script, environment variable or getssl.cfg"
exit 1
fi
if [[ -z "$url" ]]; then
echo "CPANEL_URL (url) parameter not set"
exit 1
fi
# Setup
request_func="${url}/json-api/cpanel?cpanel_jsonapi_apiversion=2&cpanel_jsonapi_module=ZoneEdit"
if [[ -n $apitoken ]]; then
curl_params=( -H "Authorization: cpanel $user:$apitoken" )
else
auth_string=$(echo -ne "$user:$password" | base64 --wrap 0)
curl_params=( -H "Authorization: Basic $auth_string" )
fi
# Check if domain is a CNAME
res=$(dig CNAME "$fulldomain")
domain=$(echo "$res"| awk '$4 ~ "CNAME" {print $5}' |sed 's/\.$//g')
if [[ -n "$domain" ]]; then
name=".${fulldomain%.$domain}"
else
domain=$fulldomain
name=""
fi
# Find line number of existing record
request_params="&cpanel_jsonapi_func=fetchzone_records&domain=${domain}&type=TXT&name=_acme-challenge.${fulldomain}."
resp=$(curl --silent "${curl_params[@]}" "$request_func$request_params")
if [[ "$resp" = *\"error\":* ]]; then
echo -n "cpanel fetchzone records failed: "
echo "$resp" | awk -F"error" '{ print $2 }' | awk -F\" '{ print $3 }'
exit 1
fi
# shellcheck disable=SC2001
line=$(echo "$resp" | sed -e 's/.*line":\([0-9]*\),.*/\1/')
if [[ "$line" != "" ]]; then
# Delete the challenge token
request_params="&cpanel_jsonapi_func=remove_zone_record&domain=$domain&type=TXT&name=_acme-challenge$name&line=$line"
resp=$(curl --silent "${curl_params[@]}" "$request_func$request_params")
fi
if [[ "$resp" = *\"status\":0* ]]; then
echo -n "cpanel remove zone record failed: "
echo "$resp" | awk -F"statusmsg" '{ print $2 }' | awk -F\" '{ print $3 }'
exit 1
fi

+ 21
- 0
dns_scripts/dns_del_duckdns View File

@ -0,0 +1,21 @@
#!/bin/bash
# need to add your Token for duckdns below
token=${DUCKDNS_TOKEN:-}
domain="$1"
i=1
response=$(curl --retry 5 --silent "https://www.duckdns.org/update?domains=${domain}&token=${token}&txt=&clear=true")
while [[ "${response}" == *"502 Bad Gateway"* ]] && [ $i -le 5 ]; do
echo "Retrying Bad Gateway response (attempt $i of 5)"
sleep 5
i=$((i+1))
response=$(curl --retry 5 --silent "https://www.duckdns.org/update?domains=${domain}&token=${token}&txt=&clear=true")
done
if [ "$response" != "OK" ]; then
echo "Failed to update TXT record for ${domain} at duckdns.org (is the TOKEN valid?)"
echo "$response"
exit 1
fi

+ 71
- 0
dns_scripts/dns_del_dynu View File

@ -0,0 +1,71 @@
#!/usr/bin/env bash
# Need to add your API key below or set as env variable
apikey=${DYNU_API_KEY:-''}
# This script deletes the _acme-challenge TXT record from the dynu.com DNS entry for the domain
# usage dns_del_dynu "domain name"
# return codes are;
# 0 - success
# 1 - error in input
# 2 - error within internal processing
# 3 - error in result ( domain not found in dynu.com etc)
# After deleting the TXT record from Dynu.com it takes over 30 minutes to add a new TXT record!
# This doesn't happen when updating the TXT record, just for delete then add
# As this is used for testing, changed the delete to a no-op.
exit 0
fulldomain="${1}"
API='https://api.dynu.com/v2/dns'
# Check initial parameters
if [[ -z "$fulldomain" ]]; then
echo "DNS script requires full domain name as first parameter"
exit 1
fi
if [[ -z "$apikey" ]]; then
echo "DNS script requires apikey environment variable to be set"
exit 1
fi
curl_params=( -H "accept: application/json" -H "API-Key: $apikey" -H 'Content-Type: application/json' )
# Get domain id
# curl -X GET https://api.dynu.com/v2/dns/getroot/ubuntu-getssl.freeddns.org
resp=$(curl --silent "${curl_params[@]}" -X GET "$API/getroot/${fulldomain}")
# Match domain id
re="\"id\":([^,]*),\"domainName\":\"${fulldomain}\""
if [[ "$resp" =~ $re ]]; then
domain_id="${BASH_REMATCH[1]}"
fi
if [[ -z "$domain_id" ]]; then
echo 'Domain name not found on your Dynu account'
exit 3
fi
# Check for existing _acme-challenge TXT record
# curl -X GET "https://api.dynu.com/v2/dns/record/_acme-challenge.ubuntu-getssl.freeddns.org?recordType=TXT"
resp=$(curl --silent "${curl_params[@]}" -X GET "${API}/record/_acme-challenge.${fulldomain}?recordType=TXT")
re="\"id\":([^,]*)"
if [[ "$resp" =~ $re ]]; then
record_id="${BASH_REMATCH[1]}"
fi
if [[ -z "$record_id" ]]; then
echo "No _acme-challenge.${fulldomain} TXT record found"
exit 0
fi
resp=$(curl --silent \
"${curl_params[@]}" \
-X DELETE "${API}/${domain_id}/record/${record_id}")
# If adding record failed (exception:) then print error message
if [[ "$resp" != *"\"statusCode\":200"* ]]; then
echo "Error: DNS challenge not added: unknown error - ${resp}"
exit 3
fi

+ 44
- 0
dns_scripts/dns_del_joker View File

@ -0,0 +1,44 @@
#!/bin/bash
FULLDOMAIN=$1
TOKEN=$2
TMPFILE=$(mktemp /tmp/dns_add_joker.XXXXXXX)
USERNAME="youruser"
PASSWORD="yourpassword"
# Verify that required parameters are set
if [[ -z "${FULLDOMAIN}" ]]; then
echo "DNS script requires full domain name as first parameter"
exit 1
fi
if [[ -z "${TOKEN}" ]]; then
echo "DNS script requires challenge token as second parameter"
exit 1
fi
DOMAIN_ROOT=$(echo "${FULLDOMAIN}" | awk -F\. '{print $(NF-1) FS $NF}')
SID=$(curl --silent -X POST https://dmapi.joker.com/request/login \
-H "Accept: application/json" -H "User-Agent: getssl/0.1" \
-H "application/x-www-form-urlencoded" -d "username=${USERNAME}&password=${PASSWORD}" \
-i -k 2>/dev/null | grep Auth-Sid | awk '{ print $2 }')
## put zone data in tempfile
curl --silent -X POST https://dmapi.joker.com/request/dns-zone-get \
-H "Accept: application/json" -H "User-Agent: getssl/0.1" \
-H "application/x-www-form-urlencoded" -d "domain=${DOMAIN_ROOT}&auth-sid=${SID}" | \
tail -n +7 >"${TMPFILE}"
## remove txt record
sed -i "/_acme-challenge.${FULLDOMAIN}.*${TOKEN}.*/d" "${TMPFILE}"
## generate encoded url data
URLDATA=$(cat "${TMPFILE}" | sed 's/ /%20/g' | sed 's/"/%22/g' | sed ':a;N;$!ba;s/\n/%0A/g')
## write new zonefile to joker
curl --silent --output /dev/null "https://dmapi.joker.com/request/dns-zone-put?domain=${DOMAIN_ROOT}&zone=${URLDATA}&auth-sid=${SID}" 2>&1
## remove tempfile
rm -f "${TMPFILE}"

+ 14
- 11
dns_scripts/dns_del_nsupdate View File

@ -14,26 +14,29 @@ token="$2"
# 'open" / 'close'
if [ -n "${DNS_NSUPDATE_KEYFILE}" ]; then
if [ -n "${DNS_NSUPDATE_KEY_HOOK}" ] && ! ${DNS_NSUPDATE_KEY_HOOK} 'del' 'open' ${fulldomain} ; then
exit $(( $? + 128 ))
fi
if [ -n "${DNS_NSUPDATE_KEY_HOOK}" ] && ! "${DNS_NSUPDATE_KEY_HOOK}" 'del' 'open' "${fulldomain}" ; then
exit $(( $? + 128 ))
fi
options="-k ${DNS_NSUPDATE_KEYFILE}"
options="-k ${DNS_NSUPDATE_KEYFILE}"
fi
# Note that blank line is a "send" command to nsupdate
cmd=
if [ -n "${DNS_SERVER}" ]; then
cmd+="server ${DNS_SERVER}\n"
fi
nsupdate ${options} -v <<EOF
update delete _acme-challenge.${fulldomain}. 300 in TXT "${token}"
cmd+="update delete ${DNS_ZONE:-"_acme-challenge.${fulldomain}."} 300 in TXT \"${token}\"\n"
cmd+="\n" # blank line is a "send" command to nsupdate
EOF
printf "$cmd" | nsupdate ${options} -v
sts=$?
if [ -n "${DNS_NSUPDATE_KEYFILE}" ]; then
if [ -n "${DNS_NSUPDATE_KEY_HOOK}" ] && ! ${DNS_NSUPDATE_KEY_HOOK} 'del' 'close' ${fulldomain} ; then
exit $(( ${sts} + ( $? * 10 ) ))
fi
if [ -n "${DNS_NSUPDATE_KEY_HOOK}" ] && ! "${DNS_NSUPDATE_KEY_HOOK}" 'del' 'close' "${fulldomain}" ; then
exit $(( sts + ( $? * 10 ) ))
fi
fi
exit ${sts}

+ 35
- 35
dns_scripts/dns_del_ovh View File

@ -1,35 +1,35 @@
#!/bin/bash
domains=($(echo "$1"|sed -e 's/^\(\([a-zA-Z0-9.-]*\?\)\.\)*\([a-zA-Z0-9-]\+\.[a-zA-Z-]\+\)$/"\1" _acme-challenge.\2 \3/g'))
challenge="$2"
# Please, do not forget to ask for your credentials at https://eu.api.ovh.com/createToken/
# permissions needed are /domain/zone/* in GET,POST,DELETE
applicationKey="YourAK"
applicationSecret="YourAS"
consumerKey="YourCK"
topDomain=${domains[2]}
subDomain=${domains[1]%%.}
function send
{
method=$1
url=$2
body=$3
ts=$(date +%s)
sign=\$1\$$(echo -n "${applicationSecret}+${consumerKey}+${method}+https://eu.api.ovh.com/1.0${url}+${body}+${ts}"|sha1sum|cut -d" " -f1)
curl -X ${method} -H "Content-Type: application/json" -H "X-Ovh-Application: ${applicationKey}" -H "X-Ovh-Timestamp: ${ts}" -H "X-Ovh-Signature: ${sign}" -H "X-Ovh-Consumer: ${consumerKey}" -d "${body}" https://eu.api.ovh.com/1.0${url}
}
# Creation request
oldResult=$(send GET "/domain/zone/${topDomain}/record?fieldType=TXT&subDomain=${subDomain}" ""|sed -e 's/\[//' -e 's/\]//')
for num in ${oldResult//,/ }
do
send DELETE "/domain/zone/${topDomain}/record/${num}" ""
done
# Refresh request
send POST /domain/zone/${topDomain}/refresh ""
#!/bin/bash
domains=($(echo "$1"|sed -e 's/^\(\([a-zA-Z0-9.-]*\?\)\.\)*\([a-zA-Z0-9-]\+\.[a-zA-Z-]\+\)$/"\1" _acme-challenge.\2 \3/g'))
#challenge="$2"
# Please, do not forget to ask for your credentials at https://eu.api.ovh.com/createToken/
# permissions needed are /domain/zone/* in GET,POST,DELETE
applicationKey="YourAK"
applicationSecret="YourAS"
consumerKey="YourCK"
topDomain=${domains[2]}
subDomain=${domains[1]%%.}
function send
{
method=$1
url=$2
body=$3
ts=$(date +%s)
sign=\$1\$$(echo -n "${applicationSecret}+${consumerKey}+${method}+https://eu.api.ovh.com/1.0${url}+${body}+${ts}"|sha1sum|cut -d" " -f1)
curl -X "${method}" -H "Content-Type: application/json" -H "X-Ovh-Application: ${applicationKey}" -H "X-Ovh-Timestamp: ${ts}" -H "X-Ovh-Signature: ${sign}" -H "X-Ovh-Consumer: ${consumerKey}" -d "${body}" "https://eu.api.ovh.com/1.0${url}"
}
# Creation request
oldResult=$(send GET "/domain/zone/${topDomain}/record?fieldType=TXT&subDomain=${subDomain}" ""|sed -e 's/\[//' -e 's/\]//')
for num in ${oldResult//,/ }
do
send DELETE "/domain/zone/${topDomain}/record/${num}" ""
done
# Refresh request
send POST "/domain/zone/${topDomain}/refresh" ""

+ 702
- 0
dns_scripts/dns_freedns.sh View File

@ -0,0 +1,702 @@
#!/usr/bin/env sh
#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/Neilpang/acme.sh/issues/2305
#
######## Public functions #####################
# Export FreeDNS userid and password in following variables...
# FREEDNS_User=username
# FREEDNS_Password=password
# login cookie is saved in acme account config file so userid / pw
# need to be set only when changed.
#Usage: dns_freedns_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
dns_freedns_add() {
fulldomain="_acme-challenge.$1"
txtvalue="$2"
FREEDNS_COOKIE="$(cat $(dirname "$(readlink -f "$0")")/freednscookie.dat)"
echo "Info: Add TXT record using FreeDNS"
#echo "Debug: fulldomain: $fulldomain"
#echo "Debug: txtvalue: $txtvalue"
if [ -z "$FREEDNS_User" ] || [ -z "$FREEDNS_Password" ]; then
FREEDNS_User=""
FREEDNS_Password=""
if [ -z "$FREEDNS_COOKIE" ]; then
echo "ERROR: You did not specify the FreeDNS username and password yet."
echo "ERROR: Please export as FREEDNS_User / FREEDNS_Password and try again."
return 1
fi
using_cached_cookies="true"
else
FREEDNS_COOKIE="$(_freedns_login "$FREEDNS_User" "$FREEDNS_Password")"
if [ -z "$FREEDNS_COOKIE" ]; then
return 1
fi
using_cached_cookies="false"
fi
#echo "Debug: FreeDNS login cookies: $FREEDNS_COOKIE (cached = $using_cached_cookies)"
echo "$FREEDNS_COOKIE">$(dirname "$(readlink -f "$0")")/freednscookie.dat
# We may have to cycle through the domain name to find the
# TLD that we own...
i=1
wmax="$(echo "$fulldomain" | tr '.' ' ' | wc -w)"
while [ "$i" -lt "$wmax" ]; do
# split our full domain name into two parts...
sub_domain="$(echo "$fulldomain" | cut -d. -f -"$i")"
i="$(_math "$i" + 1)"
top_domain="$(echo "$fulldomain" | cut -d. -f "$i"-100)"
#echo "Debug: sub_domain: $sub_domain"
#echo "Debug: top_domain: $top_domain"
DNSdomainid="$(_freedns_domain_id "$top_domain")"
if [ "$?" = "0" ]; then
echo "Info:Domain $top_domain found at FreeDNS, domain_id $DNSdomainid"
break
else
echo "Info:Domain $top_domain not found at FreeDNS, try with next level of TLD"
fi
done
if [ -z "$DNSdomainid" ]; then
# If domain ID is empty then something went wrong (top level
# domain not found at FreeDNS).
echo "ERROR: Domain $top_domain not found at FreeDNS"
return 1
fi
# Add in new TXT record with the value provided
#echo "Debug: Adding TXT record for $fulldomain, $txtvalue"
_freedns_add_txt_record "$FREEDNS_COOKIE" "$DNSdomainid" "$sub_domain" "$txtvalue"
return $?
}
#Usage: fulldomain txtvalue
#Remove the txt record after validation.
dns_freedns_rm() {
fulldomain="_acme-challenge.$1"
txtvalue="$2"
echo "Info:Delete TXT record using FreeDNS"
#echo "Debug: fulldomain: $fulldomain"
#echo "Debug: txtvalue: $txtvalue"
# Need to read cookie from conf file again in case new value set
# during login to FreeDNS when TXT record was created.
FREEDNS_COOKIE="$(cat $(dirname "$(readlink -f "$0")")/freednscookie.dat)"
#echo "Debug: FreeDNS login cookies: $FREEDNS_COOKIE"
TXTdataid="$(_freedns_data_id "$fulldomain" "TXT")"
if [ "$?" != "0" ]; then
echo "Info:Cannot delete TXT record for $fulldomain, record does not exist at FreeDNS"
return 1
fi
#echo "Debug: Data ID's found, $TXTdataid"
# now we have one (or more) TXT record data ID's. Load the page
# for that record and search for the record txt value. If match
# then we can delete it.
lines="$(echo "$TXTdataid" | wc -l)"
#echo "Debug: Found $lines TXT data records for $fulldomain"
i=0
while [ "$i" -lt "$lines" ]; do
i="$(_math "$i" + 1)"
dataid="$(echo "$TXTdataid" | sed -n "${i}p")"
#echo "Debug: $dataid"
htmlpage="$(_freedns_retrieve_data_page "$FREEDNS_COOKIE" "$dataid")"
if [ "$?" != "0" ]; then
if [ "$using_cached_cookies" = "true" ]; then
echo "ERROR: Has your FreeDNS username and password changed? If so..."
echo "ERROR: Please export as FREEDNS_User / FREEDNS_Password and try again."
fi
return 1
fi
echo "$htmlpage" | grep "value=\"&quot;$txtvalue&quot;\"" >/dev/null
if [ "$?" = "0" ]; then
# Found a match... delete the record and return
echo "Info:Deleting TXT record for $fulldomain, $txtvalue"
_freedns_delete_txt_record "$FREEDNS_COOKIE" "$dataid"
return $?
fi
done
# If we get this far we did not find a match
# Not necessarily an error, but log anyway.
echo "Info:Cannot delete TXT record for $fulldomain, $txtvalue. Does not exist at FreeDNS"
return 0
}
#################### Private functions below ##################################
# usage: _freedns_login username password
# print string "cookie=value" etc.
# returns 0 success
_freedns_login() {
export _H1="Accept-Language:en-US"
username="$1"
password="$2"
url="https://freedns.afraid.org/zc.php?step=2"
#echo "Debug: Login to FreeDNS as user $username"
data="username=$(printf '%s' "$username" | _url_encode)&password=$(printf '%s' "$password" | _url_encode)&submit=Login&action=auth"
#echo "$data"
if [ -z "$HTTP_HEADER" ] || ! touch "$HTTP_HEADER"; then
HTTP_HEADER="$(_mktemp)"
fi
htmlpage="$(curl -L --silent --dump-header $HTTP_HEADER -X POST -H "$_H1" -H "$_H2" --data "$data" "$url")"
if [ "$?" != "0" ]; then
echo "ERROR: FreeDNS login failed for user $username bad RC from _post"
return 1
fi
cookies="$(grep -i '^Set-Cookie.*dns_cookie.*$' "$HTTP_HEADER" | _head_n 1 | tr -d "\r\n" | cut -d " " -f 2)"
# if cookies is not empty then logon successful
if [ -z "$cookies" ]; then
#echo "Debug3: htmlpage: $htmlpage"
echo "ERROR: FreeDNS login failed for user $username. Check $HTTP_HEADER file"
return 1
fi
printf "%s" "$cookies"
return 0
}
# usage _freedns_retrieve_subdomain_page login_cookies
# echo page retrieved (html)
# returns 0 success
_freedns_retrieve_subdomain_page() {
export _H1="Cookie:$1"
export _H2="Accept-Language:en-US"
url="https://freedns.afraid.org/subdomain/"
#echo "Debug: Retrieve subdomain page from FreeDNS"
htmlpage="$(curl -L --silent -H "$_H1" -H "$_H2" "$url")"
if [ "$?" != "0" ]; then
echo "ERROR: FreeDNS retrieve subdomains failed bad RC from _get"
return 1
elif [ -z "$htmlpage" ]; then
echo "ERROR: FreeDNS returned empty subdomain page"
return 1
fi
#echo "Debug3: htmlpage: $htmlpage"
printf "%s" "$htmlpage"
return 0
}
# usage _freedns_retrieve_data_page login_cookies data_id
# echo page retrieved (html)
# returns 0 success
_freedns_retrieve_data_page() {
export _H1="Cookie:$1"
export _H2="Accept-Language:en-US"
data_id="$2"
url="https://freedns.afraid.org/subdomain/edit.php?data_id=$2"
#echo "Debug: Retrieve data page for ID $data_id from FreeDNS"
htmlpage="$(curl -L --silent -H "$_H1" -H "$_H2" "$url")"
if [ "$?" != "0" ]; then
echo "ERROR: FreeDNS retrieve data page failed bad RC from _get"
return 1
elif [ -z "$htmlpage" ]; then
echo "ERROR: FreeDNS returned empty data page"
return 1
fi
#echo "Debug3: htmlpage: $htmlpage"
printf "%s" "$htmlpage"
return 0
}
# usage _freedns_add_txt_record login_cookies domain_id subdomain value
# returns 0 success
_freedns_add_txt_record() {
export _H1="Cookie:$1"
export _H2="Accept-Language:en-US"
domain_id="$2"
subdomain="$3"
value="$(printf '%s' "$4" | _url_encode)"
url="https://freedns.afraid.org/subdomain/save.php?step=2"
if [ -z "$HTTP_HEADER" ] || ! touch "$HTTP_HEADER"; then
HTTP_HEADER="$(_mktemp)"
fi
htmlpage="$(curl -L --silent --dump-header $HTTP_HEADER -X POST -H "$_H1" -H "$_H2" --data "type=TXT&domain_id=$domain_id&subdomain=$subdomain&address=%22$value%22&send=Save%21" "$url")"
if [ "$?" != "0" ]; then
echo "ERROR: FreeDNS failed to add TXT record for $subdomain bad RC from _post"
return 1
elif ! grep "200 OK" "$HTTP_HEADER" >/dev/null; then
#echo "Debug3: htmlpage: $(cat $HTTP_HEADER)"
echo "ERROR: FreeDNS failed to add TXT record for $subdomain. Check $HTTP_HEADER file"
return 1
elif _contains "$htmlpage" "security code was incorrect"; then
#echo "Debug3: htmlpage: $htmlpage"
echo "ERROR: FreeDNS failed to add TXT record for $subdomain as FreeDNS requested security code"
echo "ERROR: Note that you cannot use automatic DNS validation for FreeDNS public domains"
return 1
fi
#echo "Debug3: htmlpage: $htmlpage"
echo "Info:Added acme challenge TXT record for $fulldomain at FreeDNS"
return 0
}
# usage _freedns_delete_txt_record login_cookies data_id
# returns 0 success
_freedns_delete_txt_record() {
export _H1="Cookie:$1"
export _H2="Accept-Language:en-US"
data_id="$2"
url="https://freedns.afraid.org/subdomain/delete2.php"
htmlheader="$(curl -L --silent -I -H "$_H1" -H "$_H2" "$url?data_id%5B%5D=$data_id&submit=delete+selected")"
if [ "$?" != "0" ]; then
echo "ERROR: FreeDNS failed to delete TXT record for $data_id bad RC from _get"
return 1
elif ! _contains "$htmlheader" "200 OK"; then
#echo "Debug2: htmlheader: $htmlheader"
echo "ERROR: FreeDNS failed to delete TXT record $data_id"
return 1
fi
echo "Info:Deleted acme challenge TXT record for $fulldomain at FreeDNS"
return 0
}
# usage _freedns_domain_id domain_name
# echo the domain_id if found
# return 0 success
_freedns_domain_id() {
# Start by escaping the dots in the domain name
search_domain="$(echo "$1" | sed 's/\./\\./g')"
# Sometimes FreeDNS does not return the subdomain page but rather
# returns a page regarding becoming a premium member. This usually
# happens after a period of inactivity. Immediately trying again
# returns the correct subdomain page. So, we will try twice to
# load the page and obtain our domain ID
attempts=2
while [ "$attempts" -gt "0" ]; do
attempts="$(_math "$attempts" - 1)"
htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")"
if [ "$?" != "0" ]; then
if [ "$using_cached_cookies" = "true" ]; then
echo "ERROR: Has your FreeDNS username and password changed? If so..."
echo "ERROR: Please export as FREEDNS_User / FREEDNS_Password and try again."
fi
return 1
fi
domain_id="$(echo "$htmlpage" | tr -d " \t\r\n\v\f" | sed 's/<tr>/@<tr>/g' | tr '@' '\n' \
| grep "<td>$search_domain</td>\|<td>$search_domain(.*)</td>" \
| sed -n 's/.*\(edit\.php?edit_domain_id=[0-9a-zA-Z]*\).*/\1/p' \
| cut -d = -f 2)"
# The above beauty extracts domain ID from the html page...
# strip out all blank space and new lines. Then insert newlines
# before each table row <tr>
# search for the domain within each row (which may or may not have
# a text string in brackets (.*) after it.
# And finally extract the domain ID.
if [ -n "$domain_id" ]; then
printf "%s" "$domain_id"
return 0
fi
#echo "Debug:Domain $search_domain not found. Retry loading subdomain page ($attempts attempts remaining)"
done
#echo "Debug:Domain $search_domain not found after retry"
return 1
}
# usage _freedns_data_id domain_name record_type
# echo the data_id(s) if found
# return 0 success
_freedns_data_id() {
# Start by escaping the dots in the domain name
search_domain="$(echo "$1" | sed 's/\./\\./g')"
record_type="$2"
# Sometimes FreeDNS does not return the subdomain page but rather
# returns a page regarding becoming a premium member. This usually
# happens after a period of inactivity. Immediately trying again
# returns the correct subdomain page. So, we will try twice to
# load the page and obtain our domain ID
attempts=2
while [ "$attempts" -gt "0" ]; do
attempts="$(_math "$attempts" - 1)"
htmlpage="$(_freedns_retrieve_subdomain_page "$FREEDNS_COOKIE")"
if [ "$?" != "0" ]; then
if [ "$using_cached_cookies" = "true" ]; then
echo "ERROR: Has your FreeDNS username and password changed? If so..."
echo "ERROR: Please export as FREEDNS_User / FREEDNS_Password and try again."
fi
return 1
fi
data_id="$(echo "$htmlpage" | tr -d " \t\r\n\v\f" | sed 's/<tr>/@<tr>/g' | tr '@' '\n' \
| grep "<td[a-zA-Z=#]*>$record_type</td>" \
| grep "<ahref.*>$search_domain</a>" \
| sed -n 's/.*\(edit\.php?data_id=[0-9a-zA-Z]*\).*/\1/p' \
| cut -d = -f 2)"
# The above beauty extracts data ID from the html page...
# strip out all blank space and new lines. Then insert newlines
# before each table row <tr>
# search for the record type withing each row (e.g. TXT)
# search for the domain within each row (which is within a <a..>
# </a> anchor. And finally extract the domain ID.
if [ -n "$data_id" ]; then
printf "%s" "$data_id"
return 0
fi
#echo "Debug:Domain $search_domain not found. Retry loading subdomain page ($attempts attempts remaining)"
done
#echo "Debug:Domain $search_domain not found after retry"
return 1
}
#### BEGIN things shamefully ripped from https://github.com/Neilpang/acme.sh/blob/master/acme.sh
#_ascii_hex str
#this can only process ascii chars, should only be used when od command is missing as a backup way.
_ascii_hex() {
_debug2 "Using _ascii_hex"
_str="$1"
_str_len=${#_str}
_h_i=1
while [ "$_h_i" -le "$_str_len" ]; do
_str_c="$(printf "%s" "$_str" | cut -c "$_h_i")"
printf " %02x" "'$_str_c"
_h_i="$(_math "$_h_i" + 1)"
done
}
#stdin output hexstr splited by one space
#input:"abc"
#output: " 61 62 63"
_hex_dump() {
if _exists od; then
od -A n -v -t x1 | tr -s " " | sed 's/ $//' | tr -d "\r\t\n"
elif _exists hexdump; then
hexdump -v -e '/1 ""' -e '/1 " %02x" ""'
elif _exists xxd; then
xxd -ps -c 20 -i | sed "s/ 0x/ /g" | tr -d ",\n" | tr -s " "
else
str=$(cat)
_ascii_hex "$str"
fi
}
#url encode, no-preserved chars
#A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
#41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a
#a b c d e f g h i j k l m n o p q r s t u v w x y z
#61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a
#0 1 2 3 4 5 6 7 8 9 - _ . ~
#30 31 32 33 34 35 36 37 38 39 2d 5f 2e 7e
#stdin stdout
_url_encode() {
_hex_str=$(_hex_dump)
for _hex_code in $_hex_str; do
#upper case
case "${_hex_code}" in
"41")
printf "%s" "A"
;;
"42")
printf "%s" "B"
;;
"43")
printf "%s" "C"
;;
"44")
printf "%s" "D"
;;
"45")
printf "%s" "E"
;;
"46")
printf "%s" "F"
;;
"47")
printf "%s" "G"
;;
"48")
printf "%s" "H"
;;
"49")
printf "%s" "I"
;;
"4a")
printf "%s" "J"
;;
"4b")
printf "%s" "K"
;;
"4c")
printf "%s" "L"
;;
"4d")
printf "%s" "M"
;;
"4e")
printf "%s" "N"
;;
"4f")
printf "%s" "O"
;;
"50")
printf "%s" "P"
;;
"51")
printf "%s" "Q"
;;
"52")
printf "%s" "R"
;;
"53")
printf "%s" "S"
;;
"54")
printf "%s" "T"
;;
"55")
printf "%s" "U"
;;
"56")
printf "%s" "V"
;;
"57")
printf "%s" "W"
;;
"58")
printf "%s" "X"
;;
"59")
printf "%s" "Y"
;;
"5a")
printf "%s" "Z"
;;
#lower case
"61")
printf "%s" "a"
;;
"62")
printf "%s" "b"
;;
"63")
printf "%s" "c"
;;
"64")
printf "%s" "d"
;;
"65")
printf "%s" "e"
;;
"66")
printf "%s" "f"
;;
"67")
printf "%s" "g"
;;
"68")
printf "%s" "h"
;;
"69")
printf "%s" "i"
;;
"6a")
printf "%s" "j"
;;
"6b")
printf "%s" "k"
;;
"6c")
printf "%s" "l"
;;
"6d")
printf "%s" "m"
;;
"6e")
printf "%s" "n"
;;
"6f")
printf "%s" "o"
;;
"70")
printf "%s" "p"
;;
"71")
printf "%s" "q"
;;
"72")
printf "%s" "r"
;;
"73")
printf "%s" "s"
;;
"74")
printf "%s" "t"
;;
"75")
printf "%s" "u"
;;
"76")
printf "%s" "v"
;;
"77")
printf "%s" "w"
;;
"78")
printf "%s" "x"
;;
"79")
printf "%s" "y"
;;
"7a")
printf "%s" "z"
;;
#numbers
"30")
printf "%s" "0"
;;
"31")
printf "%s" "1"
;;
"32")
printf "%s" "2"
;;
"33")
printf "%s" "3"
;;
"34")
printf "%s" "4"
;;
"35")
printf "%s" "5"
;;
"36")
printf "%s" "6"
;;
"37")
printf "%s" "7"
;;
"38")
printf "%s" "8"
;;
"39")
printf "%s" "9"
;;
"2d")
printf "%s" "-"
;;
"5f")
printf "%s" "_"
;;
"2e")
printf "%s" "."
;;
"7e")
printf "%s" "~"
;;
#other hex
*)
printf '%%%s' "$_hex_code"
;;
esac
done
}
_exists() {
cmd="$1"
if [ -z "$cmd" ]; then
_usage "Usage: _exists cmd"
return 1
fi
if eval type type >/dev/null 2>&1; then
eval type "$cmd" >/dev/null 2>&1
elif command >/dev/null 2>&1; then
command -v "$cmd" >/dev/null 2>&1
else
which "$cmd" >/dev/null 2>&1
fi
ret="$?"
#echo "Debug3: $cmd exists=$ret"
return $ret
}
_head_n() {
head -n "$1"
}
_mktemp() {
if _exists mktemp; then
if mktemp 2>/dev/null; then
return 0
elif _contains "$(mktemp 2>&1)" "-t prefix" && mktemp -t "$PROJECT_NAME" 2>/dev/null; then
#for Mac osx
return 0
fi
fi
if [ -d "/tmp" ]; then
echo "/tmp/${PROJECT_NAME}wefADf24sf.$(_time).tmp"
return 0
elif [ "$LE_TEMP_DIR" ] && mkdir -p "$LE_TEMP_DIR"; then
echo "/$LE_TEMP_DIR/wefADf24sf.$(_time).tmp"
return 0
fi
_err "Can not create temp file."
}
#a + b
_math() {
_m_opts="$@"
printf "%s" "$(($_m_opts))"
}
_contains() {
_str="$1"
_sub="$2"
echo "$_str" | grep -- "$_sub" >/dev/null 2>&1
}
##Now actually do something with that function
case "$1" in
add)
dns_freedns_add $2 $3
;;
rm)
dns_freedns_rm $2 $3
;;
esac

+ 87
- 0
dns_scripts/dns_route53.py View File

@ -0,0 +1,87 @@
#!/usr/bin/env python
import boto3, sys, time
from os.path import basename
import dns.resolver
client = boto3.client('route53')
name = sys.argv[0]
fqdn = sys.argv[1]
challenge = sys.argv[2]
bname = basename(name)
if bname == 'dns_add_route53':
action = 'UPSERT'
elif bname == 'dns_del_route53':
action = 'DELETE'
else:
print("No such action: {a}".format(a=bname))
sys.exit(1)
try:
response = client.list_hosted_zones()
except Exception as e:
print("Oops: {e!r}".format(e=e))
sys.exit(1)
zone_id = ""
zone_list = dict()
for zone in response['HostedZones']:
if not zone['Config']['PrivateZone']:
zone_list[zone['Name']] = zone['Id']
for key in sorted(zone_list.keys(), key=len, reverse=True):
if ".{z}".format(z=key) in ".{z}.".format(z=fqdn):
zone_id = zone_list[key]
if zone_id == "":
print("We didn't find the zone")
sys.exit(1)
challenge_fqdn = "_acme-challenge.{f}".format(f=fqdn)
try:
response = client.change_resource_record_sets(
HostedZoneId=zone_id,
ChangeBatch={
'Comment': 'getssl/Letsencrypt verification',
'Changes': [
{
'Action': action,
'ResourceRecordSet': {
'Name': challenge_fqdn,
'Type': 'TXT',
'TTL': 300,
'ResourceRecords': [{'Value': "\"{c}\"".format(c=challenge)}]
}
},
]
}
)
except Exception as e:
print("Oops: {e!r}".format(e=e))
sys.exit(1)
waiting = 0
if action == 'UPSERT':
# Wait until we see the record before returning. The ACME server's timeout is too short.
# But only if we're adding the record. Don't care how long it takes to delete.
while (True):
try:
my_resolver = dns.resolver.Resolver(configure=False)
my_resolver.nameservers = ['8.8.8.8', '8.8.4.4']
results = my_resolver.resolve(challenge_fqdn, 'TXT')
data = str(results.response.answer[0][0]).strip('\"')
if data == challenge:
print("found {f} entry".format(f=challenge_fqdn))
else:
print("found {f} entry but it has bad data: {d}".format(f=challenge_fqdn,
d=data))
break
except dns.resolver.NXDOMAIN:
waiting += 10
print("Didn't find {f} entry yet, sleeping... ({w}s)".format(f=challenge_fqdn,
w=waiting))
time.sleep(10)
pass

+ 33
- 0
docker-compose.yml View File

@ -0,0 +1,33 @@
version: '3'
services:
pebble:
image: letsencrypt/pebble:latest
# TODO enable -strict
command: pebble -config /test/config/pebble-config.json -dnsserver 10.30.50.3:53
environment:
# with Go 1.13.x which defaults TLS 1.3 to on
GODEBUG: "tls13=1"
PEBBLE_ALTERNATE_ROOTS: 2
ports:
- 14000:14000 # HTTPS ACME API
- 15000:15000 # HTTPS Management API
networks:
acmenet:
ipv4_address: 10.30.50.2
challtestsrv:
image: letsencrypt/pebble-challtestsrv:latest
command: pebble-challtestsrv -defaultIPv6 "" -defaultIPv4 10.30.50.3 -dns01 ":53"
ports:
- 8055:8055 # HTTP Management API
networks:
acmenet:
ipv4_address: 10.30.50.3
networks:
acmenet:
driver: bridge
ipam:
driver: default
config:
- subnet: 10.30.50.0/24

+ 1880
- 910
getssl
File diff suppressed because it is too large
View File


+ 6
- 6
other_scripts/cpanel_cert_upload View File

@ -14,12 +14,12 @@ rawurlencode() {
local pos c o
for (( pos=0 ; pos<strlen ; pos++ )); do
c=${string:$pos:1}
case "$c" in
[-_.~a-zA-Z0-9] ) o="${c}" ;;
* ) printf -v o '%%%02x' "'$c"
esac
encoded+="${o}"
c=${string:$pos:1}
case "$c" in
[-_.~a-zA-Z0-9] ) o="${c}" ;;
* ) printf -v o '%%%02x' "'$c"
esac
encoded+="${o}"
done
echo "${encoded}"
}


+ 40
- 0
test/1-simple-http01-dig.bats View File

@ -0,0 +1,40 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
if [ -f /usr/bin/host ]; then
mv /usr/bin/host /usr/bin/host.getssl.bak
fi
if [ -f /usr/bin/nslookup ]; then
mv /usr/bin/nslookup /usr/bin/nslookup.getssl.bak
fi
}
teardown() {
if [ -f /usr/bin/host.getssl.bak ]; then
mv /usr/bin/host.getssl.bak /usr/bin/host
fi
if [ -f /usr/bin/nslookup.getssl.bak ]; then
mv /usr/bin/nslookup.getssl.bak /usr/bin/nslookup
fi
}
@test "Create new certificate using HTTP-01 verification (dig)" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-http01.cfg"
setup_environment
init_getssl
create_certificate
assert_success
check_output_for_errors
}

+ 40
- 0
test/1-simple-http01-nslookup.bats View File

@ -0,0 +1,40 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
if [ -f /usr/bin/dig ]; then
mv /usr/bin/dig /usr/bin/dig.getssl.bak
fi
if [ -f /usr/bin/host ]; then
mv /usr/bin/host /usr/bin/host.getssl.bak
fi
}
teardown() {
if [ -f /usr/bin/dig.getssl.bak ]; then
mv /usr/bin/dig.getssl.bak /usr/bin/dig
fi
if [ -f /usr/bin/host.getssl.bak ]; then
mv /usr/bin/host.getssl.bak /usr/bin/host
fi
}
@test "Create new certificate using HTTP-01 verification (nslookup)" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-http01.cfg"
setup_environment
init_getssl
create_certificate
assert_success
check_output_for_errors
}

+ 26
- 0
test/1-simple-http01-two-acl.bats View File

@ -0,0 +1,26 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
}
@test "Check that can install challenge token to multiple locations when using HTTP-01 verification" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-http01-two-acl.cfg"
setup_environment
init_getssl
create_certificate -d
assert_success
assert_output --partial "to /var/www/html/.well-known/acme-challenge"
assert_output --partial "to /var/webroot/html/.well-known/acme-challenge"
check_output_for_errors "debug"
}

+ 35
- 0
test/1-simple-http01.bats View File

@ -0,0 +1,35 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
}
@test "Create new certificate using HTTP-01 verification (any dns tool)" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-http01.cfg"
setup_environment
init_getssl
create_certificate
assert_success
check_output_for_errors
}
@test "Force renewal of certificate using HTTP-01 (any dns tool)" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
run ${CODE_DIR}/getssl -f $GETSSL_HOST
assert_success
check_output_for_errors
cleanup_environment
}

+ 41
- 0
test/10-mixed-case.bats View File

@ -0,0 +1,41 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
}
@test "Check that HTTP-01 verification works if the domain is not lowercase" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-http01.cfg"
GETSSL_CMD_HOST=$(echo $GETSSL_HOST | tr a-z A-Z)
setup_environment
init_getssl
create_certificate
assert_success
check_output_for_errors
}
@test "Check that DNS-01 verification works if the domain is not lowercase" {
CONFIG_FILE="getssl-dns01.cfg"
GETSSL_CMD_HOST=$(echo $GETSSL_HOST | tr a-z A-Z)
setup_environment
init_getssl
create_certificate
assert_success
check_output_for_errors
}

+ 63
- 0
test/11-test--install.bats View File

@ -0,0 +1,63 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
}
@test "Check that config files in /etc/getssl works" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-http01.cfg"
setup_environment
# Fail if not running in docker and /etc/getssl already exists
refute [ -d /etc/getssl ]
# Create /etc/getssl/$DOMAIN
mkdir -p /etc/getssl/${GETSSL_CMD_HOST}
# Copy the config file to /etc/getssl
cp "${CODE_DIR}/test/test-config/${CONFIG_FILE}" "/etc/getssl/${GETSSL_CMD_HOST}/getssl.cfg"
cp "${CODE_DIR}/test/test-config/getssl-etc-template.cfg" "/etc/getssl/getssl.cfg"
# Run getssl
run ${CODE_DIR}/getssl "$GETSSL_CMD_HOST"
assert_success
check_output_for_errors
assert_line 'Verification completed, obtaining certificate.'
assert_line 'Requesting certificate'
refute [ -d '$HOME/.getssl' ]
}
@test "Check that --install doesn't call the ACME server" {
# NOTE that this test depends on the previous test!
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-http01.cfg"
# Run getssl
run ${CODE_DIR}/getssl --install "$GETSSL_CMD_HOST"
assert_success
check_output_for_errors
refute_line 'Verification completed, obtaining certificate.'
refute_line 'Requesting certificate'
assert_line --partial 'copying domain certificate to'
assert_line --partial 'copying private key to'
assert_line --partial 'copying CA certificate to'
# Cleanup previous test
rm -rf /etc/getssl
}

+ 20
- 0
test/11-test-no-domain-storage.bats View File

@ -0,0 +1,20 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
@test "Check that if domain storage isn't set getssl doesn't try to delete /tmp" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-http01-no-domain-storage.cfg"
setup_environment
mkdir ${INSTALL_DIR}/.getssl
cp "${CODE_DIR}/test/test-config/${CONFIG_FILE}" "${INSTALL_DIR}/.getssl/getssl.cfg"
run ${CODE_DIR}/getssl -a
assert_success
check_output_for_errors
assert_line 'Not going to delete TEMP_DIR ///tmp as it appears to be /tmp'
}

+ 75
- 0
test/12-auto-upgrade-v1.bats View File

@ -0,0 +1,75 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
@test "Check that auto upgrade to v2 doesn't change pebble url" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-upgrade-test-pebble.cfg"
setup_environment
mkdir ${INSTALL_DIR}/.getssl
cp "${CODE_DIR}/test/test-config/${CONFIG_FILE}" "${INSTALL_DIR}/.getssl/getssl.cfg"
run ${CODE_DIR}/getssl -d --check-config "$GETSSL_CMD_HOST"
assert_success
assert_line 'Using certificate issuer: https://pebble:14000/dir'
}
@test "Check that auto upgrade to v2 doesn't change v2 staging url" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-upgrade-test-v2-staging.cfg"
setup_environment
mkdir ${INSTALL_DIR}/.getssl
cp "${CODE_DIR}/test/test-config/${CONFIG_FILE}" "${INSTALL_DIR}/.getssl/getssl.cfg"
run ${CODE_DIR}/getssl -d --check-config "$GETSSL_CMD_HOST"
assert_success
assert_line 'Using certificate issuer: https://acme-staging-v02.api.letsencrypt.org/directory'
}
@test "Check that auto upgrade to v2 doesn't change v2 prod url" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-upgrade-test-v2-prod.cfg"
setup_environment
mkdir ${INSTALL_DIR}/.getssl
cp "${CODE_DIR}/test/test-config/${CONFIG_FILE}" "${INSTALL_DIR}/.getssl/getssl.cfg"
run ${CODE_DIR}/getssl -d --check-config "$GETSSL_CMD_HOST"
assert_success
assert_line 'Using certificate issuer: https://acme-v02.api.letsencrypt.org/directory'
}
@test "Check that auto upgrade to v2 changes v1 staging to v2 staging url" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-upgrade-test-v1-staging.cfg"
setup_environment
mkdir ${INSTALL_DIR}/.getssl
cp "${CODE_DIR}/test/test-config/${CONFIG_FILE}" "${INSTALL_DIR}/.getssl/getssl.cfg"
run ${CODE_DIR}/getssl -d --check-config "$GETSSL_CMD_HOST"
assert_success
assert_line 'Using certificate issuer: https://acme-staging-v02.api.letsencrypt.org/directory'
}
@test "Check that auto upgrade to v2 changes v1 prod to v2 prod url" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-upgrade-test-v1-prod.cfg"
setup_environment
mkdir ${INSTALL_DIR}/.getssl
cp "${CODE_DIR}/test/test-config/${CONFIG_FILE}" "${INSTALL_DIR}/.getssl/getssl.cfg"
run ${CODE_DIR}/getssl -d --check-config "$GETSSL_CMD_HOST"
assert_success
assert_line 'Using certificate issuer: https://acme-v02.api.letsencrypt.org/directory'
}

+ 45
- 0
test/13-notify-valid.bats View File

@ -0,0 +1,45 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
}
@test "Create certificate to check valid exit code" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-http01.cfg"
setup_environment
init_getssl
create_certificate
assert_success
check_output_for_errors
}
@test "Check no-renewal needed exits with normal exit code" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
run ${CODE_DIR}/getssl $GETSSL_HOST
assert_success
check_output_for_errors
}
@test "Check no-renewal needed returns 2 if requested" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
run ${CODE_DIR}/getssl --notify-valid $GETSSL_HOST
assert [ $status == 2 ]
check_output_for_errors
cleanup_environment
}

+ 44
- 0
test/14-test-revoke.bats View File

@ -0,0 +1,44 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
}
@test "Create certificate to check revoke" {
if [ -n "$STAGING" ]; then
CONFIG_FILE="getssl-dns01.cfg"
else
CONFIG_FILE="getssl-http01.cfg"
fi
. "${CODE_DIR}/test/test-config/${CONFIG_FILE}"
setup_environment
init_getssl
create_certificate
assert_success
check_output_for_errors
}
@test "Check we can revoke a certificate" {
if [ -n "$STAGING" ]; then
CONFIG_FILE="getssl-dns01.cfg"
else
CONFIG_FILE="getssl-http01.cfg"
fi
. "${CODE_DIR}/test/test-config/${CONFIG_FILE}"
CERT=${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.crt
KEY=${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.key
run ${CODE_DIR}/getssl -d --revoke $CERT $KEY $CA
assert_success
check_output_for_errors "debug"
}

+ 50
- 0
test/15-test-revoke-no-suffix.bats View File

@ -0,0 +1,50 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
}
@test "Create certificate to check revoke (no suffix)" {
if [ -n "$STAGING" ]; then
CONFIG_FILE="getssl-dns01.cfg"
else
CONFIG_FILE="getssl-http01-no-suffix.cfg"
fi
. "${CODE_DIR}/test/test-config/${CONFIG_FILE}"
setup_environment
init_getssl
echo 'CA="https://acme-staging-v02.api.letsencrypt.org"' > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
create_certificate
assert_success
check_output_for_errors
}
@test "Check we can revoke a certificate (no suffix)" {
if [ -n "$STAGING" ]; then
CONFIG_FILE="getssl-dns01.cfg"
else
CONFIG_FILE="getssl-http01.cfg"
fi
echo 'CA="https://acme-staging-v02.api.letsencrypt.org"' > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
. "${CODE_DIR}/test/test-config/${CONFIG_FILE}"
CERT=${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.crt
KEY=${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.key
run ${CODE_DIR}/getssl -d --revoke $CERT $KEY $CA
assert_success
check_output_for_errors "debug"
}

+ 23
- 0
test/16-test-bad-acl.bats View File

@ -0,0 +1,23 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
}
@test "Test behaviour if ACL= line has a space" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-http01-bad-acl.cfg"
setup_environment
init_getssl
create_certificate
assert_failure
}

+ 87
- 0
test/17-test-spaces-in-sans-dns01.bats View File

@ -0,0 +1,87 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
}
@test "Test behaviour if SANS line is space separated instead of comma separated (dns01)" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-dns01-spaces-sans.cfg"
setup_environment
# Add hosts to DNS (also need to be added as aliases in docker-compose.yml)
for prefix in a b c; do
curl --silent -X POST -d '{"host":"'$prefix.$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a
done
init_getssl
create_certificate
assert_success
check_output_for_errors
}
@test "Test renewal if SANS line is space separated instead of comma separated (dns01)" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
run ${CODE_DIR}/getssl -f $GETSSL_HOST
assert_success
check_output_for_errors
cleanup_environment
}
@test "Test behaviour if SANS line is space separated and IGNORE_DIRECTORY_DOMAIN (dns01)" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-dns01-spaces-sans-and-ignore-dir-domain.cfg"
setup_environment
init_getssl
create_certificate
assert_success
check_output_for_errors
}
@test "Test renewal if SANS line is space separated and IGNORE_DIRECTORY_DOMAIN (dns01)" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
run ${CODE_DIR}/getssl -f $GETSSL_HOST
assert_success
check_output_for_errors
cleanup_environment
}
@test "Test behaviour if SANS line is comma and space separated (dns01)" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-dns01-spaces-and-commas-sans.cfg"
setup_environment
init_getssl
create_certificate
assert_success
check_output_for_errors
cleanup_environment
for prefix in a b c; do
curl --silent -X POST -d '{"host":"'$prefix.$GETSSL_HOST'"}' http://10.30.50.3:8055/clear-a
done
}

+ 87
- 0
test/17-test-spaces-in-sans-http01.bats View File

@ -0,0 +1,87 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
}
@test "Test behaviour if SANS line is space separated instead of comma separated (http01)" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-http01-spaces-sans.cfg"
setup_environment
# Add hosts to DNS (also need to be added as aliases in docker-compose.yml)
for prefix in a b c; do
curl --silent -X POST -d '{"host":"'$prefix.$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a
done
init_getssl
create_certificate
assert_success
check_output_for_errors
}
@test "Test renewal if SANS line is space separated instead of comma separated (http01)" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
run ${CODE_DIR}/getssl -f $GETSSL_HOST
assert_success
check_output_for_errors
cleanup_environment
}
@test "Test behaviour if SANS line is space separated and IGNORE_DIRECTORY_DOMAIN (http01)" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-http01-spaces-sans-and-ignore-dir-domain.cfg"
setup_environment
init_getssl
create_certificate
assert_success
check_output_for_errors
}
@test "Test renewal if SANS line is space separated and IGNORE_DIRECTORY_DOMAIN (http01)" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
run ${CODE_DIR}/getssl -f $GETSSL_HOST
assert_success
check_output_for_errors
cleanup_environment
}
@test "Test behaviour if SANS line is comma and space separated (http01)" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-http01-spaces-and-commas-sans.cfg"
setup_environment
init_getssl
create_certificate
assert_success
check_output_for_errors
cleanup_environment
for prefix in a b c; do
curl --silent -X POST -d '{"host":"'$prefix.$GETSSL_HOST'"}' http://10.30.50.3:8055/clear-a
done
}

+ 38
- 0
test/18-retry-dns-add.bats View File

@ -0,0 +1,38 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
}
@test "Check retry add dns command if dns isn't updated" {
if [ -n "$STAGING" ]; then
skip "Running internal tests, skipping external test"
fi
CONFIG_FILE="getssl-dns01.cfg"
setup_environment
init_getssl
cat <<- EOF > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
DNS_ADD_COMMAND="/getssl/test/dns_add_fail"
# Speed up the test by reducing the number or retries and the wait between retries.
DNS_WAIT=2
DNS_WAIT_COUNT=11
DNS_EXTRA_WAIT=0
CHECK_ALL_AUTH_DNS="false"
CHECK_PUBLIC_DNS_SERVER="false"
DNS_WAIT_RETRY_ADD="true"
_RUNNING_TEST=1
EOF
create_certificate
assert_failure
assert_line --partial "Retrying adding DNS via command"
}

+ 64
- 0
test/19-test-add-to-sans.bats View File

@ -0,0 +1,64 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
curl --silent -X POST -d '{"host":"a.'$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a
curl --silent -X POST -d '{"host":"b.'$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a
fi
}
teardown() {
if [ -z "$STAGING" ]; then
curl --silent -X POST -d '{"host":"a.'$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/clear-a
curl --silent -X POST -d '{"host":"b.'$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/clear-a
fi
}
@test "Create certificate to check can add to SANS" {
skip "FIXME: Certificate is not recreated when SANS is updated"
if [ -n "$STAGING" ]; then
skip "Not trying on staging server yet"
CONFIG_FILE="getssl-dns01.cfg"
else
CONFIG_FILE="getssl-dns01-add-to-sans-1.cfg"
fi
. "${CODE_DIR}/test/test-config/${CONFIG_FILE}"
setup_environment
init_getssl
create_certificate
assert_success
check_output_for_errors
}
@test "Check we can add a new domain to SANS" {
skip "FIXME: Certificate is not recreated when SANS is updated"
if [ -n "$STAGING" ]; then
skip "Not trying on staging server yet"
CONFIG_FILE="getssl-dns01.cfg"
else
CONFIG_FILE="getssl-dns01-add-to-sans-2.cfg"
fi
# . "${CODE_DIR}/test/test-config/${CONFIG_FILE}"
# CERT=${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.crt
# KEY=${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.key
# cp "${CODE_DIR}/test/test-config/${CONFIG_FILE}" "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl.cfg"
create_certificate
assert_success
check_output_for_errors
# As the SANS list changed, a new certificate is needed
assert_line --partial "certificate installed OK on server"
refute_line --partial 'certificate is valid for more than'
}

+ 49
- 0
test/2-simple-dns01-dig.bats View File

@ -0,0 +1,49 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
if [ -f /usr/bin/host ]; then
mv /usr/bin/host /usr/bin/host.getssl.bak
fi
if [ -f /usr/bin/nslookup ]; then
mv /usr/bin/nslookup /usr/bin/nslookup.getssl.bak
fi
}
teardown() {
if [ -f /usr/bin/host.getssl.bak ]; then
mv /usr/bin/host.getssl.bak /usr/bin/host
fi
if [ -f /usr/bin/nslookup.getssl.bak ]; then
mv /usr/bin/nslookup.getssl.bak /usr/bin/nslookup
fi
}
@test "Create new certificate using DNS-01 verification (dig)" {
CONFIG_FILE="getssl-dns01.cfg"
setup_environment
init_getssl
create_certificate -d
assert_success
assert_output --partial "dig"
check_output_for_errors "debug"
}
@test "Force renewal of certificate using DNS-01 (dig)" {
run ${CODE_DIR}/getssl -d -f $GETSSL_HOST
assert_success
assert_output --partial "dig"
check_output_for_errors "debug"
cleanup_environment
}

+ 41
- 0
test/2-simple-dns01-nslookup.bats View File

@ -0,0 +1,41 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
if [ -f /usr/bin/dig ]; then
mv /usr/bin/dig /usr/bin/dig.getssl.bak
fi
if [ -f /usr/bin/host ]; then
mv /usr/bin/host /usr/bin/host.getssl.bak
fi
}
teardown() {
if [ -f /usr/bin/dig.getssl.bak ]; then
mv /usr/bin/dig.getssl.bak /usr/bin/dig
fi
if [ -f /usr/bin/host.getssl.bak ]; then
mv /usr/bin/host.getssl.bak /usr/bin/host
fi
}
@test "Create new certificate using DNS-01 verification (nslookup)" {
CONFIG_FILE="getssl-dns01.cfg"
setup_environment
init_getssl
create_certificate -d
assert_success
assert_output --partial "nslookup"
check_output_for_errors "debug"
}

+ 64
- 0
test/20-wildcard-simple.bats View File

@ -0,0 +1,64 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
}
@test "Create wildcard certificate" {
CONFIG_FILE="getssl-dns01.cfg"
GETSSL_CMD_HOST="*.${GETSSL_HOST}"
setup_environment
init_getssl
create_certificate
assert_success
check_output_for_errors
}
@test "Check CHECK_REMOTE works for wildcard certificates" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
run ${CODE_DIR}/getssl "*.$GETSSL_HOST"
assert_success
assert_line --partial "certificate is valid for more than"
check_output_for_errors
}
@test "Force renewal of wildcard certificate" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
run ${CODE_DIR}/getssl -f "*.$GETSSL_HOST"
assert_success
refute_line --partial "certificate is valid for more than"
check_output_for_errors
}
@test "Check renewal of near-expiration wildcard certificate" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
echo "RENEW_ALLOW=2000" >> "${INSTALL_DIR}/.getssl/*.${GETSSL_HOST}/getssl.cfg"
run ${CODE_DIR}/getssl "*.$GETSSL_HOST"
assert_success
refute_line --partial "certificate is valid for more than"
check_output_for_errors
cleanup_environment
}

+ 74
- 0
test/21-wildcard-dual-rsa.bats View File

@ -0,0 +1,74 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
}
@test "Create secp384r1 wildcard certificate" {
CONFIG_FILE="getssl-dns01.cfg"
GETSSL_CMD_HOST="*.${GETSSL_HOST}"
setup_environment
init_getssl
cat <<- EOF > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
ACCOUNT_KEY_TYPE="secp384r1"
PRIVATE_KEY_ALG="secp384r1"
EOF
create_certificate
assert_success
check_output_for_errors
run openssl x509 -noout -text -in "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.crt"
assert_line --partial "Public Key Algorithm: id-ecPublicKey"
cleanup_environment
}
@test "Create dual certificates using DNS-01 verification" {
CONFIG_FILE="getssl-dns01.cfg"
GETSSL_CMD_HOST="*.${GETSSL_HOST}"
setup_environment
init_getssl
cat <<- EOF > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
DUAL_RSA_ECDSA="true"
ACCOUNT_KEY_TYPE="prime256v1"
PRIVATE_KEY_ALG="prime256v1"
EOF
check_nginx
if [ "$OLD_NGINX" = "false" ]; then
echo 'RELOAD_CMD="cp /getssl/test/test-config/nginx-ubuntu-dual-certs ${NGINX_CONFIG} && /getssl/test/restart-nginx"' >> ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
else
echo 'CHECK_REMOTE="false"' >> ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
fi
create_certificate
assert_success
check_output_for_errors
check_certificates
assert [ -e "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/chain.ec.crt" ]
assert [ -e "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.ec.crt" ]
assert [ -e "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.ec.crt" ]
run openssl x509 -noout -text -in "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.crt"
assert_line --partial "Public Key Algorithm: rsaEncryption"
run openssl x509 -noout -text -in "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.ec.crt"
assert_line --partial "Public Key Algorithm: id-ecPublicKey"
cleanup_environment
}

+ 61
- 0
test/22-wildcard-dual-rsa-ecdsa-copy-2-locations.bats View File

@ -0,0 +1,61 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# These are run for every test, not once per file
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
}
@test "Create dual certificates (one wildcard) and copy RSA and ECDSA chain and key to two locations" {
CONFIG_FILE="getssl-dns01.cfg"
GETSSL_CMD_HOST="*.${GETSSL_HOST}"
setup_environment
init_getssl
cat <<- 'EOF' > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
DUAL_RSA_ECDSA="true"
ACCOUNT_KEY_TYPE="prime256v1"
PRIVATE_KEY_ALG="prime256v1"
DOMAIN_KEY_LOCATION="/etc/nginx/pki/private/server.key;/root/a.${GETSSL_HOST}/server.key"
DOMAIN_CHAIN_LOCATION="/etc/nginx/pki/domain-chain.crt;/root/a.${GETSSL_HOST}/domain-chain.crt" # this is the domain cert and CA cert
EOF
check_nginx
if [ "$OLD_NGINX" = "false" ]; then
echo 'RELOAD_CMD="cp /getssl/test/test-config/nginx-ubuntu-dual-certs ${NGINX_CONFIG} && /getssl/test/restart-nginx"' >> ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
else
echo 'CHECK_REMOTE="false"' >> ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
fi
create_certificate
assert_success
check_output_for_errors
if [ "$OLD_NGINX" = "false" ]; then
assert_line --partial "rsa certificate installed OK on server"
assert_line --partial "prime256v1 certificate installed OK on server"
fi
# Check that the RSA chain and key have been copied to both locations
assert [ -e "/etc/nginx/pki/domain-chain.crt" ]
assert [ -e "/root/a.${GETSSL_HOST}/domain-chain.crt" ]
assert [ -e "/etc/nginx/pki/private/server.key" ]
assert [ -e "/root/a.${GETSSL_HOST}/server.key" ]
# Check that the ECDSA chain and key have been copied to both locations
assert [ -e "/etc/nginx/pki/domain-chain.ec.crt" ]
assert [ -e "/root/a.${GETSSL_HOST}/domain-chain.ec.crt" ]
assert [ -e "/etc/nginx/pki/private/server.ec.key" ]
assert [ -e "/root/a.${GETSSL_HOST}/server.ec.key" ]
cleanup_environment
}

+ 46
- 0
test/23-wildcard-check-globbing.bats View File

@ -0,0 +1,46 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
}
@test "Check for globbing for wildcard domains" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
else
CONFIG_FILE="getssl-dns01.cfg"
fi
GETSSL_CMD_HOST="*.${GETSSL_HOST}"
setup_environment
init_getssl
# Create a directory in /root which looks like a domain so that if glob expansion is performed a certificate for the wrong domain will be created
mkdir -p "${INSTALL_DIR}/a.${GETSSL_HOST}"
create_certificate
assert_success
check_output_for_errors
}
@test "Force renewal of wildcard certificate" {
if [ -n "$STAGING" ]; then
skip "Not trying on staging server yet"
fi
run ${CODE_DIR}/getssl -f "*.$GETSSL_HOST"
assert_success
refute_line --partial "certificate is valid for more than"
check_output_for_errors
}

+ 64
- 0
test/24-wildcard-sans.bats View File

@ -0,0 +1,64 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
curl --silent -X POST -d '{"host":"wild-'$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a
fi
}
teardown() {
if [ -z "$STAGING" ]; then
curl --silent -X POST -d '{"host":"wild-'$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/clear-a
fi
}
@test "Check can create certificate for wildcard domain as arg and non-wildcard in SANS" {
CONFIG_FILE="getssl-dns01.cfg"
# Staging server generates an error if try to create a certificate for *.domain and a.domain
# so create for *.wild-domain and a.domain instead
GETSSL_CMD_HOST="*.wild-${GETSSL_HOST}"
setup_environment
init_getssl
echo 'SANS="${GETSSL_HOST}"' > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
if [ -n "$STAGING" ]; then
echo 'CHECK_REMOTE="false"' >> ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
fi
create_certificate
assert_success
check_output_for_errors
run openssl x509 -noout -text -in "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.crt"
# verify certificate is for wildcard domain with non-wildcard domain in the Subject Alternative Name list
assert_output --regexp "Subject: CN[ ]?=[ ]?\*.wild-${GETSSL_HOST}"
assert_output --partial "DNS:${GETSSL_HOST}"
}
@test "Check can create certificate for non-wildcard domain as arg and wildcard in SANS" {
CONFIG_FILE="getssl-dns01.cfg"
GETSSL_CMD_HOST="${GETSSL_HOST}"
setup_environment
init_getssl
echo 'SANS="*.wild-${GETSSL_HOST}"' > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
create_certificate
assert_success
check_output_for_errors
run openssl x509 -noout -text -in "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.crt"
# verify certificate is for non-wildcard domain with wildcard domain in the Subject Alternative Name list
assert_output --regexp "Subject: CN[ ]?=[ ]?${GETSSL_HOST}"
assert_output --partial "DNS:*.wild-${GETSSL_HOST}"
}

+ 42
- 0
test/25-wildcard-all.bats View File

@ -0,0 +1,42 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
}
@test "Check can create certificate for wildcard domain using --all" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
else
CONFIG_FILE="getssl-dns01.cfg"
fi
GETSSL_CMD_HOST="*.${GETSSL_HOST}"
setup_environment
# Create .getssl directory and .getssl/*.{host} directory
init_getssl
cp "${CODE_DIR}/test/test-config/${CONFIG_FILE}" "${INSTALL_DIR}/.getssl/*.${GETSSL_HOST}/getssl.cfg"
# create another domain in the .getssl directory
run ${CODE_DIR}/getssl -c "a.${GETSSL_HOST}"
cp "${CODE_DIR}/test/test-config/${CONFIG_FILE}" "${INSTALL_DIR}/.getssl/a.${GETSSL_HOST}/getssl.cfg"
# Create a directory in /root which looks like a domain so that if glob expansion is performed the wildcard certificate won't be created
mkdir -p "${INSTALL_DIR}/a.${GETSSL_HOST}"
run ${CODE_DIR}/getssl --all
assert_success
assert_line --partial "Certificate saved in /root/.getssl/*.${GETSSL_HOST}/*.${GETSSL_HOST}"
assert_line --partial "Certificate saved in /root/.getssl/a.${GETSSL_HOST}/a.${GETSSL_HOST}"
check_output_for_errors
}

+ 41
- 0
test/26-wildcard-revoke.bats View File

@ -0,0 +1,41 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
}
@test "Create certificate to check wildcard revoke" {
CONFIG_FILE="getssl-dns01.cfg"
GETSSL_CMD_HOST="*.${GETSSL_HOST}"
setup_environment
init_getssl
create_certificate
assert_success
check_output_for_errors
}
@test "Check we can revoke a wildcard certificate" {
CONFIG_FILE="getssl-dns01.cfg"
. "${CODE_DIR}/test/test-config/${CONFIG_FILE}"
GETSSL_CMD_HOST="*.${GETSSL_HOST}"
CERT=${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.crt
KEY=${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.key
run ${CODE_DIR}/getssl -d --revoke $CERT $KEY $CA
assert_line "certificate revoked"
assert_success
check_output_for_errors "debug"
}

+ 45
- 0
test/27-wildcard-existing-cert.bats View File

@ -0,0 +1,45 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
}
@test "Check that new creating a new configuration files uses details from existing certificate" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
else
CONFIG_FILE="getssl-dns01.cfg"
fi
# Create and install certificate for wildcard + another domain
GETSSL_CMD_HOST="*.${GETSSL_HOST}"
setup_environment
init_getssl
echo 'SANS="a.${GETSSL_HOST}"' > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
create_certificate
assert_success
check_output_for_errors
# Delete configuration
rm -r ${INSTALL_DIR}/.getssl
# Create configuration
run ${CODE_DIR}/getssl -c "${GETSSL_CMD_HOST}"
# Assert that the newly created configuration contains the additional domain in SANS
# if this fails then error in tests will be "grep failed" - this means SANS did not hold the expected value
# eg SANS="a.centos7.getssl.test"
grep -q "SANS=\"a.${GETSSL_HOST}\"" ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl.cfg
assert_success
}

+ 31
- 0
test/28-wildcard-error-http01-validation.bats View File

@ -0,0 +1,31 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
}
@test "Check that trying to create a wildcard certificate using http-01 validation shows an error message" {
if [ -n "$STAGING" ]; then
skip "Internal test, no need to test on staging server"
else
CONFIG_FILE="getssl-http01.cfg"
fi
# Try and create a wildcard certificate using http-01 validation
GETSSL_CMD_HOST="*.${GETSSL_HOST}"
setup_environment
init_getssl
create_certificate
assert_failure
assert_line --partial "cannot use http-01 validation for wildcard domains"
}

+ 47
- 0
test/29-check-mktemp-failure.bats View File

@ -0,0 +1,47 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
}
@test "Check that getssl -c fails with an error message if mktemp fails" {
if [ -n "$STAGING" ]; then
skip "Internal test, no need to test on staging server"
else
CONFIG_FILE="getssl-http01.cfg"
fi
# set TMPDIR to an invalid directory and check for failure
export TMPDIR=/getssl.invalid.directory
setup_environment
run ${CODE_DIR}/getssl -c "$GETSSL_CMD_HOST"
assert_failure
assert_line --partial "mktemp failed"
}
@test "Check that getssl fails with an error message if mktemp fails" {
if [ -n "$STAGING" ]; then
skip "Internal test, no need to test on staging server"
else
CONFIG_FILE="getssl-http01.cfg"
fi
setup_environment
init_getssl
# set TMPDIR to an invalid directory and check for failure
export TMPDIR=/getssl.invalid.directory
create_certificate
assert_failure
assert_line --partial "mktemp failed"
}

+ 96
- 0
test/3-dual-rsa-ecdsa.bats View File

@ -0,0 +1,96 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
}
@test "Create dual certificates using HTTP-01 verification" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
check_nginx
if [ "$OLD_NGINX" = "false" ]; then
CONFIG_FILE="getssl-http01-dual-rsa-ecdsa.cfg"
else
CONFIG_FILE="getssl-http01-dual-rsa-ecdsa-old-nginx.cfg"
fi
setup_environment
init_getssl
create_certificate
assert_success
check_output_for_errors
check_certificates
assert [ -e "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/chain.ec.crt" ]
assert [ -e "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.ec.crt" ]
assert [ -e "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.ec.crt" ]
}
@test "Check renewal test works for dual certificates using HTTP-01" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
check_nginx
run ${CODE_DIR}/getssl -d $GETSSL_HOST
if [ "$OLD_NGINX" = "false" ]; then
assert_line "certificate on server is same as the local cert"
else
assert_line --partial "certificate is valid for more than 30 days"
fi
assert_success
}
@test "Force renewal of dual certificates using HTTP-01" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
run ${CODE_DIR}/getssl -f $GETSSL_HOST
assert_success
check_output_for_errors
}
@test "Create dual certificates using DNS-01 verification" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
check_nginx
if [ "$OLD_NGINX" = "false" ]; then
CONFIG_FILE="getssl-dns01-dual-rsa-ecdsa.cfg"
else
CONFIG_FILE="getssl-dns01-dual-rsa-ecdsa-old-nginx.cfg"
fi
setup_environment
init_getssl
create_certificate
assert_success
check_output_for_errors
check_certificates
assert [ -e "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/chain.ec.crt" ]
assert [ -e "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.ec.crt" ]
assert [ -e "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.ec.crt" ]
}
@test "Force renewal of dual certificates using DNS-01" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
run ${CODE_DIR}/getssl -f $GETSSL_HOST
assert_success
check_output_for_errors
cleanup_environment
}

+ 44
- 0
test/30-handle-dig-failure.bats View File

@ -0,0 +1,44 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
if [ -f /usr/bin/drill ]; then
mv /usr/bin/drill /usr/bin/drill.getssl.bak
fi
if [ -f /usr/bin/dig ]; then
chmod -x /usr/bin/dig
fi
}
teardown() {
if [ -f /usr/bin/drill.getssl.bak ]; then
mv /usr/bin/drill.getssl.bak /usr/bin/drill
fi
if [ -f /usr/bin/dig ]; then
chmod +x /usr/bin/dig
fi
}
@test "Test that if dig exists but errors HAS_DIG is not set" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
if [ ! -f /usr/bin/dig ]; then
skip "dig not installed, skipping dig test"
fi
CONFIG_FILE="getssl-http01.cfg"
setup_environment
init_getssl
create_certificate -d
assert_success
refute_line --partial "HAS DIG_OR_DRILL=dig"
check_output_for_errors "debug"
}

+ 25
- 0
test/31-test-posix-error.bats View File

@ -0,0 +1,25 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
}
@test "Test that running in POSIX mode shows an error" {
# v2.31 uses read to create an array in the get_auth_dns function which causes a parse error in posix mode
# Could be re-written to not use this functionality if it causes for required.
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
run bash --posix "${CODE_DIR}/getssl"
assert_failure
assert_line "getssl: Running with POSIX mode enabled is not supported"
check_output_for_errors
}

+ 111
- 0
test/32-test-upgrade.bats View File

@ -0,0 +1,111 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
# Turn off warning about detached head
git config --global advice.detachedHead false
run git clone https://github.com/srvrco/getssl.git "$INSTALL_DIR/upgrade-getssl"
# Don't do version arithmetics any longer, look what was the previous version by getting the last
# line (starting with v) and the one before that from the list of tags.
cd "$INSTALL_DIR/upgrade-getssl"
# This sets CURRENT_TAG and PREVIOUS_TAG bash variables
eval $(git tag -l | awk 'BEGIN {cur="?.??"};/^v/{prv=cur;cur=substr($1,2)};END{ printf("CURRENT_TAG=\"%s\";PREVIOUS_TAG=\"%s\"\n",cur,prv)}')
# The version in the file, which we will overwrite
FILE_VERSION=$(awk -F'"' '/^VERSION=/{print $2}' "$CODE_DIR/getssl")
# If FILE_VERSION > CURRENT_TAG then either we are testing a push to master or the last version wasn't released
}
teardown() {
rm -r "$INSTALL_DIR/upgrade-getssl"
}
@test "Test that we are told that a newer version is available" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
cd "$INSTALL_DIR/upgrade-getssl"
git checkout tags/v${PREVIOUS_TAG}
CONFIG_FILE="getssl-http01.cfg"
setup_environment
init_getssl
cp "${CODE_DIR}/test/test-config/${CONFIG_FILE}" "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl.cfg"
# Overwrite checked out getssl-script with copy of new one, but write the previous version into the copy
# Note that this way we mock downgrading getssl and are testing the upgrading of the version in development
cp "$CODE_DIR/getssl" "$INSTALL_DIR/upgrade-getssl/"
sed -i -e "s/VERSION=\"${FILE_VERSION}\"/VERSION=\"${PREVIOUS_TAG}\"/" "$INSTALL_DIR/upgrade-getssl/getssl"
run "$INSTALL_DIR/upgrade-getssl/getssl" --check-config ${GETSSL_CMD_HOST}
assert_success
# Check for current tag or file version otherwise push to master fails on a new version (or if the tag hasn't been updated)
assert_line --regexp "A more recent version \(v(${CURRENT_TAG}|${FILE_VERSION})\) of getssl is available, please update"
check_output_for_errors
}
@test "Test that we can upgrade to the newer version" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
cd "$INSTALL_DIR/upgrade-getssl"
git checkout tags/v${CURRENT_TAG}
CONFIG_FILE="getssl-http01.cfg"
setup_environment
init_getssl
cp "${CODE_DIR}/test/test-config/${CONFIG_FILE}" "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl.cfg"
# Overwrite checked out getssl-script with copy of new one, but write the previous version into the copy
# Note that this way we mock downgrading getssl and are testing the upgrading of the version in development
cp "$CODE_DIR/getssl" "$INSTALL_DIR/upgrade-getssl/"
sed -i -e "s/VERSION=\"${FILE_VERSION}\"/VERSION=\"${PREVIOUS_TAG}\"/" "$INSTALL_DIR/upgrade-getssl/getssl"
run "$INSTALL_DIR/upgrade-getssl/getssl" --check-config --upgrade ${GETSSL_CMD_HOST}
assert_success
# Check for current tag or file version otherwise push to master fails on a new version (or if the tag hasn't been updated)
assert_line --regexp "Updated getssl from v${PREVIOUS_TAG} to v(${CURRENT_TAG}|${FILE_VERSION})"
}
@test "Test that we can upgrade to the newer version when invoking as \"bash ./getssl\"" {
# Note that `bash getssl` will fail if the CWD isn't in the PATH and an upgrade occurs
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
cd "$INSTALL_DIR/upgrade-getssl"
git checkout tags/v${PREVIOUS_TAG}
CONFIG_FILE="getssl-http01.cfg"
setup_environment
init_getssl
cp "${CODE_DIR}/test/test-config/${CONFIG_FILE}" "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl.cfg"
# Overwrite checked out getssl-script with copy of new one, but write the previous version into the copy
# Note that this way we mock downgrading getssl and are testing the upgrading of the version in development
cp "$CODE_DIR/getssl" "$INSTALL_DIR/upgrade-getssl/"
sed -i -e "s/VERSION=\"${FILE_VERSION}\"/VERSION=\"${PREVIOUS_TAG}\"/" "$INSTALL_DIR/upgrade-getssl/getssl"
run bash ./getssl --check-config --upgrade ${GETSSL_CMD_HOST}
assert_success
# Check for current tag or file version otherwise push to master fails on a new version (or if the tag hasn't been updated)
assert_line --regexp "Updated getssl from v${PREVIOUS_TAG} to v(${CURRENT_TAG}|${FILE_VERSION})"
}

+ 71
- 0
test/33-ftp.bats View File

@ -0,0 +1,71 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
if [ -n "${VSFTPD_CONF}" ]; then
cp $VSFTPD_CONF ${VSFTPD_CONF}.getssl
# enable passive and disable active mode
# https://www.pixelstech.net/article/1364817664-FTP-active-mode-and-passive-mode
cat <<- _FTP >> $VSFTPD_CONF
pasv_enable=NO
_FTP
${CODE_DIR}/test/restart-ftpd
fi
}
teardown() {
if [ -n "${VSFTPD_CONF}" ]; then
cp ${VSFTPD_CONF}.getssl $VSFTPD_CONF
${CODE_DIR}/test/restart-ftpd
fi
}
@test "Use FTP to create challenge file" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
if [[ ! -d /var/www/html/.well-known/acme-challenge ]]; then
mkdir -p /var/www/html/.well-known/acme-challenge
fi
# Always change ownership and permissions in case previous tests created the directories as root
chgrp -R www-data /var/www/html/.well-known
chmod -R g+w /var/www/html/.well-known
CONFIG_FILE="getssl-http01.cfg"
setup_environment
init_getssl
cat <<- EOF > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
ACL="ftp:ftpuser:ftpuser:${GETSSL_CMD_HOST}:/var/www/html/.well-known/acme-challenge"
EOF
if [[ "$GETSSL_OS" = "alpine" ]]; then
cat <<- EOF2 >> ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
FTP_OPTIONS="set ftp:passive-mode off"
EOF2
elif [[ "$FTP_PASSIVE_DEFAULT" == "true" ]]; then
cat <<- EOF3 >> ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
FTP_OPTIONS="passive"
EOF3
fi
create_certificate
assert_success
assert_line --partial "ftp:ftpuser:ftpuser:"
if [[ "$GETSSL_OS" != "alpine" ]] && [[ "$FTP_PASSIVE_DEFAULT" == "true" ]]; then
assert_line --partial "Passive mode off"
fi
check_output_for_errors
}

+ 71
- 0
test/34-ftp-passive.bats View File

@ -0,0 +1,71 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
if [ -n "${VSFTPD_CONF}" ]; then
cp $VSFTPD_CONF ${VSFTPD_CONF}.getssl
# enable passive and disable active mode
# https://www.pixelstech.net/article/1364817664-FTP-active-mode-and-passive-mode
cat <<- _FTP >> $VSFTPD_CONF
pasv_enable=YES
pasv_max_port=10100
pasv_min_port=10090
connect_from_port_20=NO
_FTP
${CODE_DIR}/test/restart-ftpd
fi
}
teardown() {
if [ -n "${VSFTPD_CONF}" ]; then
cp ${VSFTPD_CONF}.getssl $VSFTPD_CONF
${CODE_DIR}/test/restart-ftpd
fi
}
@test "Use Passive FTP to create challenge file" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
if [[ ! -d /var/www/html/.well-known/acme-challenge ]]; then
mkdir -p /var/www/html/.well-known/acme-challenge
fi
# Always change ownership and permissions in case previous tests created the directories as root
chgrp -R www-data /var/www/html/.well-known
chmod -R g+w /var/www/html/.well-known
CONFIG_FILE="getssl-http01.cfg"
setup_environment
init_getssl
cat <<- EOF > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
ACL="ftp:ftpuser:ftpuser:${GETSSL_CMD_HOST}:/var/www/html/.well-known/acme-challenge"
EOF
if [[ "$FTP_PASSIVE_DEFAULT" == "false" ]]; then
cat <<- EOF3 >> ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
FTP_OPTIONS="passive"
EOF3
fi
create_certificate
assert_success
assert_line --partial "ftp:ftpuser:ftpuser:"
if [[ "$FTP_PASSIVE_DEFAULT" == "false" ]]; then
assert_line --partial "Passive mode on"
else
refute_line --partial "Passive mode off"
fi
check_output_for_errors
}

+ 111
- 0
test/35-preferred-chain.bats View File

@ -0,0 +1,111 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
}
@test "Use PREFERRED_CHAIN to select an alternate root" {
if [ -n "$STAGING" ]; then
PREFERRED_CHAIN="\(STAGING\) Pretend Pear X1"
CHECK_CHAIN="(STAGING) Pretend Pear X1"
else
PREFERRED_CHAIN=$(curl --silent https://pebble:15000/roots/2 | openssl x509 -text -noout | grep "Issuer:" | awk -F"CN *= *" '{ print $2 }')
PREFERRED_CHAIN="${PREFERRED_CHAIN# }" # remove leading whitespace
CHECK_CHAIN=$PREFERRED_CHAIN
fi
CONFIG_FILE="getssl-dns01.cfg"
setup_environment
init_getssl
cat <<- EOF > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
PREFERRED_CHAIN="${PREFERRED_CHAIN}"
EOF
create_certificate
assert_success
check_output_for_errors
issuer=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.crt" | openssl pkcs7 -print_certs -text -noout | grep Issuer: | tail -1 | awk -F"CN=" '{ print $2 }')
# verify certificate is issued by preferred chain root
if [[ "${CHECK_CHAIN}" != "$issuer" ]]; then
echo "# PREFERRED_CHAIN=$PREFERRED_CHAIN"
echo "# issuer=$issuer"
fi
[ "${CHECK_CHAIN}" = "$issuer" ]
}
@test "Use PREFERRED_CHAIN to select the default root" {
if [ -n "$STAGING" ]; then
PREFERRED_CHAIN="\(STAGING\) Doctored Durian Root CA X3"
CHECK_CHAIN="(STAGING) Doctored Durian Root CA X3"
else
PREFERRED_CHAIN=$(curl --silent https://pebble:15000/roots/0 | openssl x509 -text -noout | grep Issuer: | awk -F"CN *= *" '{ print $2 }')
PREFERRED_CHAIN="${PREFERRED_CHAIN# }" # remove leading whitespace
CHECK_CHAIN=$PREFERRED_CHAIN
fi
CONFIG_FILE="getssl-dns01.cfg"
setup_environment
init_getssl
cat <<- EOF > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
PREFERRED_CHAIN="${PREFERRED_CHAIN}"
EOF
create_certificate
assert_success
check_output_for_errors
issuer=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.crt" | openssl pkcs7 -print_certs -text -noout | grep Issuer: | tail -1 | awk -F"CN=" '{ print $2 }')
# verify certificate is issued by preferred chain root
if [[ "${CHECK_CHAIN}" != "$issuer" ]]; then
echo "# PREFERRED_CHAIN=$PREFERRED_CHAIN"
echo "# issuer=$issuer"
fi
[ "${CHECK_CHAIN}" = "$issuer" ]
}
@test "Use PREFERRED_CHAIN to select an alternate root by suffix" {
if [ -n "$STAGING" ]; then
FULL_PREFERRED_CHAIN="(STAGING) Pretend Pear X1"
else
FULL_PREFERRED_CHAIN=$(curl --silent https://pebble:15000/roots/2 | openssl x509 -text -noout | grep "Issuer:" | awk -F"CN *= *" '{ print $2 }')
FULL_PREFERRED_CHAIN="${FULL_PREFERRED_CHAIN# }" # remove leading whitespace
fi
# Take the last word from FULL_PREFERRED_CHAIN as the chain to use
PREFERRED_CHAIN="${FULL_PREFERRED_CHAIN##* }"
CONFIG_FILE="getssl-dns01.cfg"
setup_environment
init_getssl
cat <<- EOF > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
PREFERRED_CHAIN="${PREFERRED_CHAIN}"
EOF
create_certificate
assert_success
check_output_for_errors
issuer=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.crt" | openssl pkcs7 -print_certs -text -noout | grep Issuer: | tail -1 | awk -F"CN=" '{ print $2 }')
# verify certificate is issued by preferred chain root
if [[ "${FULL_PREFERRED_CHAIN}" != "$issuer" ]]; then
echo "# PREFERRED_CHAIN=$PREFERRED_CHAIN"
echo "# FULL_PREFERRED_CHAIN=$FULL_PREFERRED_CHAIN"
echo "# issuer=$issuer"
fi
[ "${FULL_PREFERRED_CHAIN}" = "$issuer" ]
}

+ 94
- 0
test/36-full-chain-inc-root.bats View File

@ -0,0 +1,94 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
}
@test "Use FULL_CHAIN_INCLUDE_ROOT to include the root certificate in the fullchain" {
CONFIG_FILE="getssl-dns01.cfg"
setup_environment
init_getssl
cat <<- EOF > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
FULL_CHAIN_INCLUDE_ROOT="true"
EOF
create_certificate
assert_success
check_output_for_errors
if [ -n "$STAGING" ]; then
PREFERRED_CHAIN="(STAGING) Doctored Durian Root CA X3"
else
# pebble doesn't support CA Issuers so the fullchain.crt will just contain the certificate (code path means it won't contain the intermediate cert in this case)
# This is testing that requesting FULL_CHAIN_INCLUDE_ROOT doesn't fail if there is no CA Issuers in the certificate
PREFERRED_CHAIN=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.crt" | openssl pkcs7 -print_certs -text -noout | grep Subject: | tail -1 | awk -F"CN=" '{ print $2 }')
fi
final_issuer=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.crt" | openssl pkcs7 -print_certs -text -noout | grep Subject: | tail -1 | awk -F"CN=" '{ print $2 }')
# verify certificate includes the chain root
if [[ "${PREFERRED_CHAIN}" != "$final_issuer" ]]; then
echo "# PREFERRED_CHAIN=$PREFERRED_CHAIN"
echo "# final_issuer=$final_issuer"
fi
[ "${PREFERRED_CHAIN}" = "$final_issuer" ]
}
@test "Use FULL_CHAIN_INCLUDE_ROOT with dual certificates" {
if [ -n "$STAGING" ]; then
PREFERRED_CHAIN="(STAGING) Doctored Durian Root CA X3"
fi
CONFIG_FILE="getssl-dns01.cfg"
setup_environment
init_getssl
cat <<- EOF > ${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/getssl_test_specific.cfg
FULL_CHAIN_INCLUDE_ROOT="true"
DUAL_RSA_ECDSA="true"
ACCOUNT_KEY_TYPE="prime256v1"
PRIVATE_KEY_ALG="prime256v1"
CHECK_REMOTE="false"
EOF
create_certificate
assert_success
check_output_for_errors
check_certificates
assert [ -e "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/chain.ec.crt" ]
assert [ -e "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.ec.crt" ]
assert [ -e "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.ec.crt" ]
if [ -n "$STAGING" ]; then
PREFERRED_CHAIN="(STAGING) Doctored Durian Root CA X3"
else
# pebble doesn't support CA Issuers so the fullchain.crt will just contain the certificate (code path means it won't contain the intermediate cert in this case)
# This is testing that requesting FULL_CHAIN_INCLUDE_ROOT doesn't fail if there is no CA Issuers in the certificate
PREFERRED_CHAIN=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/${GETSSL_CMD_HOST}.crt" | openssl pkcs7 -print_certs -text -noout | grep Subject: | tail -1 | awk -F"CN=" '{ print $2 }')
fi
# verify both rsa and ecdsa certificates include the chain root
final_issuer=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.crt" | openssl pkcs7 -print_certs -text -noout | grep Subject: | tail -1 | awk -F"CN=" '{ print $2 }')
if [[ "${PREFERRED_CHAIN}" != "$final_issuer" ]]; then
echo "# PREFERRED_CHAIN=$PREFERRED_CHAIN"
echo "# final_issuer=$final_issuer"
fi
[ "${PREFERRED_CHAIN}" = "$final_issuer" ]
ecdsa_final_issuer=$(openssl crl2pkcs7 -nocrl -certfile "${INSTALL_DIR}/.getssl/${GETSSL_CMD_HOST}/fullchain.ec.crt" | openssl pkcs7 -print_certs -text -noout | grep Subject: | tail -1 | awk -F"CN=" '{ print $2 }')
if [[ "$PREFERRED_CHAIN" != "$ecdsa_final_issuer" ]]; then
echo "# PREFERRED_CHAIN=$PREFERRED_CHAIN"
echo "# ecdsa_final_issuer=$ecdsa_final_issuer"
fi
[ "${PREFERRED_CHAIN}" = "$ecdsa_final_issuer" ]
}

+ 45
- 0
test/4-more-than-10-hosts.bats View File

@ -0,0 +1,45 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
}
@test "Create certificates for more than 10 hosts using HTTP-01 verification" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-http01-10-hosts.cfg"
setup_environment
# Add 11 hosts to DNS (also need to be added as aliases in docker-compose.yml)
for prefix in a b c d e f g h i j k; do
curl --silent -X POST -d '{"host":"'$prefix.$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a
done
init_getssl
create_certificate
assert_success
check_output_for_errors
}
@test "Force renewal of more than 10 certificates using HTTP-01" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
run ${CODE_DIR}/getssl -f $GETSSL_HOST
assert_success
check_output_for_errors
# Remove all the dns aliases
cleanup_environment
for prefix in a b c d e f g h i j k; do
curl --silent -X POST -d '{"host":"'$prefix.$GETSSL_HOST'"}' http://10.30.50.3:8055/clear-a
done
}

+ 57
- 0
test/5-secp384-http01.bats View File

@ -0,0 +1,57 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
}
@test "Create new secp384r1 certificate using HTTP-01 verification" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-http01-secp384.cfg"
setup_environment
init_getssl
create_certificate
assert_success
check_output_for_errors
}
@test "Force renewal of secp384r1 certificate using HTTP-01" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
run ${CODE_DIR}/getssl -f $GETSSL_HOST
assert_success
check_output_for_errors
}
@test "Create new secp521r1 certificate using HTTP-01 verification" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-http01-secp521.cfg"
setup_environment
init_getssl
create_certificate
assert_success
check_output_for_errors
}
@test "Force renewal of secp521r1 certificate using HTTP-01" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
run ${CODE_DIR}/getssl -f $GETSSL_HOST
assert_success
check_output_for_errors
}

+ 81
- 0
test/6-dual-rsa-ecdsa-copy-2-locations.bats View File

@ -0,0 +1,81 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# These are run for every test, not once per file
setup() {
if [ -z "$STAGING" ]; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
curl --silent -X POST -d '{"host":"'a.$GETSSL_HOST'", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a
fi
}
teardown() {
if [ -z "$STAGING" ]; then
curl --silent -X POST -d '{"host":"'a.$GETSSL_HOST'"}' http://10.30.50.3:8055/clear-a
fi
}
@test "Create dual certificates and copy RSA and ECDSA chain and key to two locations" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
check_nginx
if [ "$OLD_NGINX" = "false" ]; then
CONFIG_FILE="getssl-http01-dual-rsa-ecdsa-2-locations.cfg"
else
CONFIG_FILE="getssl-http01-dual-rsa-ecdsa-2-locations-old-nginx.cfg"
fi
setup_environment
mkdir -p /root/a.${GETSSL_HOST}
init_getssl
create_certificate
assert_success
check_output_for_errors
if [ "$OLD_NGINX" = "false" ]; then
assert_line --partial "rsa certificate installed OK on server"
assert_line --partial "prime256v1 certificate installed OK on server"
fi
# Check that the RSA chain and key have been copied to both locations
assert [ -e "/etc/nginx/pki/domain-chain.crt" ]
assert [ -e "/root/a.${GETSSL_HOST}/domain-chain.crt" ]
assert [ -e "/etc/nginx/pki/private/server.key" ]
assert [ -e "/root/a.${GETSSL_HOST}/server.key" ]
# Check that the ECDSA chain and key have been copied to both locations
assert [ -e "/etc/nginx/pki/domain-chain.ec.crt" ]
assert [ -e "/root/a.${GETSSL_HOST}/domain-chain.ec.crt" ]
assert [ -e "/etc/nginx/pki/private/server.ec.key" ]
assert [ -e "/root/a.${GETSSL_HOST}/server.ec.key" ]
}
@test "Create dual certificates and copy to two locations but not returned by server" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
check_nginx
if [ "$OLD_NGINX" = "false" ]; then
CONFIG_FILE="getssl-http01-dual-rsa-ecdsa-2-locations-wrong-nginx.cfg"
else
skip "Skipping as old nginx servers cannot return both certificates"
fi
setup_environment
mkdir -p /root/a.${GETSSL_HOST}
init_getssl
create_certificate
assert_failure
assert_line --partial "prime256v1 certificate obtained but not installed on server"
}

+ 62
- 0
test/8-staging-ecdsa.bats View File

@ -0,0 +1,62 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
@test "Create new certificate using staging server and prime256v1" {
if [ -z "$STAGING" ]; then
skip "Running external tests, skipping internal testing"
fi
CONFIG_FILE="getssl-dns01.cfg"
setup_environment
init_getssl
sed -e 's/rsa/prime256v1/g' < "${CODE_DIR}/test/test-config/${CONFIG_FILE}" > "${INSTALL_DIR}/.getssl/${GETSSL_HOST}/getssl.cfg"
run ${CODE_DIR}/getssl -d "$GETSSL_HOST"
assert_success
check_output_for_errors "debug"
}
@test "Force renewal of certificate using staging server and prime256v1" {
if [ -z "$STAGING" ]; then
skip "Running internal tests, skipping external test"
fi
run ${CODE_DIR}/getssl -d -f $GETSSL_HOST
assert_success
check_output_for_errors "debug"
cleanup_environment
}
@test "Create new certificate using staging server and secp384r1" {
if [ -z "$STAGING" ]; then
skip "Running external tests, skipping internal testing"
fi
CONFIG_FILE="getssl-dns01.cfg"
setup_environment
init_getssl
sed -e 's/rsa/secp384r1/g' < "${CODE_DIR}/test/test-config/${CONFIG_FILE}" > "${INSTALL_DIR}/.getssl/${GETSSL_HOST}/getssl.cfg"
run ${CODE_DIR}/getssl -d "$GETSSL_HOST"
assert_success
check_output_for_errors "debug"
}
@test "Force renewal of certificate using staging server and secp384r1" {
if [ -z "$STAGING" ]; then
skip "Running internal tests, skipping external test"
fi
run ${CODE_DIR}/getssl -d -f $GETSSL_HOST
assert_success
check_output_for_errors "debug"
cleanup_environment
}
# Note letsencrypt doesn't support ECDSA curve P-521 as it's being deprecated

+ 60
- 0
test/9-multiple-domains-dns01.bats View File

@ -0,0 +1,60 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
}
@test "Create certificates for multi-level domains using DNS-01 verification" {
# This tests we can create a certificate for <os>.getssl.test and getssl.test (in SANS)
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-dns01-multiple-domains.cfg"
setup_environment
# Add top level domain from SANS to DNS
curl --silent -X POST -d '{"host":"getssl.test", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a
init_getssl
create_certificate
assert_success
check_output_for_errors
}
@test "Force renewal of multi-level domains using DNS-01" {
# This tests we can renew a certificate for <os>.getssl.test and getssl.test (in SANS)
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
run ${CODE_DIR}/getssl -f $GETSSL_HOST
assert_success
check_output_for_errors
# Remove all the dns aliases
cleanup_environment
curl --silent -X POST -d '{"host":"getssl.tst"}' http://10.30.50.3:8055/clear-a
}
@test "Test IGNORE_DIRECTORY_DOMAIN using DNS-01 verification" {
# This tests we can create a certificate for getssl.test and <os>.getssl.test (*both* in SANS)
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
CONFIG_FILE="getssl-dns01-ignore-directory-domain.cfg"
setup_environment
# Add top level domain from SANS to DNS
curl --silent -X POST -d '{"host":"getssl.test", "addresses":["'$GETSSL_IP'"]}' http://10.30.50.3:8055/add-a
init_getssl
create_certificate
assert_success
check_output_for_errors
}

+ 32
- 0
test/9-test--all.bats View File

@ -0,0 +1,32 @@
#! /usr/bin/env bats
load '/bats-support/load.bash'
load '/bats-assert/load.bash'
load '/getssl/test/test_helper.bash'
# This is run for every test
setup() {
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
export PATH=$PATH:/getssl
}
@test "Create new certificate using --all" {
if [ -n "$STAGING" ]; then
skip "Using staging server, skipping internal test"
fi
# Setup
CONFIG_FILE="getssl-http01.cfg"
setup_environment
init_getssl
cp "${CODE_DIR}/test/test-config/${CONFIG_FILE}" "${INSTALL_DIR}/.getssl/${GETSSL_HOST}/getssl.cfg"
# Run test
run ${CODE_DIR}/getssl --all
# Check success conditions
assert_success
check_output_for_errors
}

+ 33
- 0
test/Dockerfile-alpine View File

@ -0,0 +1,33 @@
FROM alpine:latest
# Note this image uses busybox awk instead of gawk
RUN apk --no-cache add supervisor openssl git curl bind-tools drill wget nginx bash lftp vsftpd openssh-server
WORKDIR /root
# Create nginx directories in standard places
RUN mkdir /run/nginx
RUN mkdir -p /etc/nginx/pki/private
# Setup ftp
ENV VSFTPD_CONF=/etc/vsftpd.conf
ENV FTP_PASSIVE_DEFAULT=true
COPY ./test/test-config/vsftpd.conf /etc/vsftpd.conf
RUN echo "seccomp_sandbox=NO" >> /etc/vsftpd.conf
RUN adduser -D ftpuser
RUN echo 'ftpuser:ftpuser' | chpasswd
RUN adduser ftpuser www-data
RUN adduser root www-data
RUN chown -R ftpuser.www-data /var/www
RUN chmod g+w -R /var/www
# BATS (Bash Automated Testings)
RUN git clone --depth 1 https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1
RUN git clone --depth 1 https://github.com/bats-core/bats-support /bats-support
RUN git clone --depth 1 https://github.com/bats-core/bats-assert /bats-assert
RUN /bats-core/install.sh /usr/local
# Use supervisord to run nginx in the background
COPY ./test/test-config/alpine-supervisord.conf /etc/supervisord.conf
CMD [ "tail", "-f", "/dev/null" ]

+ 34
- 0
test/Dockerfile-bash4-0 View File

@ -0,0 +1,34 @@
FROM bash:4.0
# https://hub.docker.com/_/bash
RUN apk --no-cache add supervisor openssl git curl bind-tools drill wget nginx lftp vsftpd openssh-server
WORKDIR /root
# Create nginx directories in standard places
RUN mkdir /run/nginx
RUN mkdir /etc/nginx/pki
RUN mkdir /etc/nginx/pki/private
# Setup ftp
ENV VSFTPD_CONF=/etc/vsftpd.conf
ENV FTP_PASSIVE_DEFAULT=true
COPY ./test/test-config/vsftpd.conf /etc/vsftpd.conf
RUN echo "seccomp_sandbox=NO" >> /etc/vsftpd.conf
RUN adduser -D ftpuser
RUN echo 'ftpuser:ftpuser' | chpasswd
RUN adduser ftpuser www-data
RUN adduser root www-data
RUN chown -R ftpuser.www-data /var/www
RUN chmod g+w -R /var/www
# BATS (Bash Automated Testings)
RUN git clone https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1
RUN git clone https://github.com/bats-core/bats-support /bats-support
RUN git clone https://github.com/bats-core/bats-assert /bats-assert
RUN /bats-core/install.sh /usr/local
# Use supervisord to run nginx in the background
COPY ./test/test-config/alpine-supervisord.conf /etc/supervisord.conf
CMD tail -f /dev/null

+ 34
- 0
test/Dockerfile-bash4-2 View File

@ -0,0 +1,34 @@
FROM bash:4.2
# https://hub.docker.com/_/bash
RUN apk --no-cache add supervisor openssl git curl bind-tools drill wget nginx lftp vsftpd openssh-server
WORKDIR /root
# Create nginx directories in standard places
RUN mkdir /run/nginx
RUN mkdir /etc/nginx/pki
RUN mkdir /etc/nginx/pki/private
# Setup ftp
ENV VSFTPD_CONF=/etc/vsftpd.conf
ENV FTP_PASSIVE_DEFAULT=true
COPY ./test/test-config/vsftpd.conf /etc/vsftpd.conf
RUN echo "seccomp_sandbox=NO" >> /etc/vsftpd.conf
RUN adduser -D ftpuser
RUN echo 'ftpuser:ftpuser' | chpasswd
RUN adduser ftpuser www-data
RUN adduser root www-data
RUN chown -R ftpuser.www-data /var/www
RUN chmod g+w -R /var/www
# BATS (Bash Automated Testings)
RUN git clone https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1
RUN git clone https://github.com/bats-core/bats-support /bats-support
RUN git clone https://github.com/bats-core/bats-assert /bats-assert
RUN /bats-core/install.sh /usr/local
# Use supervisord to run nginx in the background
COPY ./test/test-config/alpine-supervisord.conf /etc/supervisord.conf
CMD tail -f /dev/null

+ 34
- 0
test/Dockerfile-bash5-0 View File

@ -0,0 +1,34 @@
FROM bash:5.0
# https://hub.docker.com/_/bash
RUN apk --no-cache add supervisor openssl git curl bind-tools drill wget nginx lftp vsftpd openssh-server
WORKDIR /root
# Create nginx directories in standard places
RUN mkdir /run/nginx
RUN mkdir /etc/nginx/pki
RUN mkdir /etc/nginx/pki/private
# Setup ftp
ENV VSFTPD_CONF=/etc/vsftpd.conf
ENV FTP_PASSIVE_DEFAULT=true
COPY ./test/test-config/vsftpd.conf /etc/vsftpd.conf
RUN echo "seccomp_sandbox=NO" >> /etc/vsftpd.conf
RUN adduser -D ftpuser
RUN echo 'ftpuser:ftpuser' | chpasswd
RUN adduser ftpuser www-data
RUN adduser root www-data
RUN chown -R ftpuser.www-data /var/www
RUN chmod g+w -R /var/www
# BATS (Bash Automated Testings)
RUN git clone https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1
RUN git clone https://github.com/bats-core/bats-support /bats-support
RUN git clone https://github.com/bats-core/bats-assert /bats-assert
RUN /bats-core/install.sh /usr/local
# Use supervisord to run nginx in the background
COPY ./test/test-config/alpine-supervisord.conf /etc/supervisord.conf
CMD tail -f /dev/null

+ 47
- 0
test/Dockerfile-centos6 View File

@ -0,0 +1,47 @@
FROM centos:centos6
# Note this image uses gawk
# Note if you are running this using WSL2 you need to put the following lines in %userprofile%\.wslconfig
# [wsl2]
# kernelCommandLine = vsyscall=emulate
# Centos 6 is EOL and is no longer available from the usual mirrors, so switch to https://vault.centos.org
RUN sed -i 's/enabled=1/enabled=0/g' /etc/yum/pluginconf.d/fastestmirror.conf && \
sed -i 's/^mirrorlist/#mirrorlist/g' /etc/yum.repos.d/*.repo && \
sed -i 's;^#baseurl=http://mirror;baseurl=https://vault;g' /etc/yum.repos.d/*.repo
# Update and install required software
RUN yum -y install epel-release
RUN yum -y install git curl dnsutils ldns wget nginx
RUN yum -y install ftp vsftpd
RUN yum -y install openssh-server
# Setup ftp
ENV VSFTPD_CONF=/etc/vsftpd/vsftpd.conf
ENV FTP_PASSIVE_DEFAULT=true
COPY test/test-config/vsftpd.conf /etc/vsftpd/vsftpd.conf
RUN adduser ftpuser
RUN echo 'ftpuser:ftpuser' | chpasswd
RUN adduser www-data
RUN usermod -G www-data ftpuser
RUN usermod -G www-data root
RUN mkdir -p /var/www/.well-known/acme-challenge
RUN chown -R www-data.www-data /var/www
RUN chmod g+w -R /var/www
WORKDIR /root
RUN mkdir -p /etc/nginx/pki/private
COPY ./test/test-config/nginx-ubuntu-no-ssl /etc/nginx/conf.d/default.conf
# BATS (Bash Automated Testings)
RUN git clone https://github.com/bats-core/bats-core.git /bats-core # --branch v1.2.1
RUN git clone https://github.com/bats-core/bats-support /bats-support
RUN git clone https://github.com/bats-core/bats-assert /bats-assert
RUN /bats-core/install.sh /usr/local
# Hack to disable BATS pretty formatter which stopped working on centos6
ENV CI=yes
EXPOSE 80 443
# Run eternal loop - for testing
CMD [ "tail", "-f", "/dev/null" ]

+ 32
- 0
test/Dockerfile-centos7 View File

@ -0,0 +1,32 @@
FROM centos:centos7
# Update and install required software
RUN yum -y update
RUN yum -y install epel-release
RUN yum -y install git curl ldns bind-utils wget which nginx
RUN yum -y install ftp vsftpd
RUN yum -y install openssh-server
WORKDIR /root
RUN mkdir -p /etc/nginx/pki/private
COPY ./test/test-config/nginx-ubuntu-no-ssl /etc/nginx/conf.d/default.conf
COPY ./test/test-config/nginx-centos7.conf /etc/nginx/nginx.conf
# Setup ftp
ENV VSFTPD_CONF=/etc/vsftpd/vsftpd.conf
ENV FTP_PASSIVE_DEFAULT=true
COPY test/test-config/vsftpd.conf /etc/vsftpd/vsftpd.conf
RUN adduser ftpuser
RUN echo 'ftpuser:ftpuser' | chpasswd
RUN adduser www-data
RUN usermod -G www-data ftpuser
RUN usermod -G www-data root
RUN mkdir -p /var/www/.well-known/acme-challenge
RUN chown -R www-data.www-data /var/www
RUN chmod g+w -R /var/www
# BATS (Bash Automated Testings)
RUN git clone --depth 1 https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1
RUN git clone --depth 1 https://github.com/bats-core/bats-support /bats-support
RUN git clone --depth 1 https://github.com/bats-core/bats-assert /bats-assert
RUN /bats-core/install.sh /usr/local

+ 28
- 0
test/Dockerfile-centos7-duckdns View File

@ -0,0 +1,28 @@
FROM centos:centos7
# Note this image uses gawk
# Update and install required software
RUN yum -y update
RUN yum -y install epel-release
RUN yum -y install git curl bind-utils ldns wget which nginx
ENV staging "true"
ENV dynamic_dns "dynu"
ENV DUCKDNS_TOKEN 1d616aa9-b8e4-4bb4-b312-3289de82badb
WORKDIR /root
RUN mkdir -p /etc/nginx/pki/private
COPY ./test/test-config/nginx-ubuntu-no-ssl /etc/nginx/conf.d/default.conf
COPY ./test/test-config/nginx-centos7.conf /etc/nginx/nginx.conf
# BATS (Bash Automated Testings)
RUN git clone --depth 1 https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1
RUN git clone --depth 1 https://github.com/bats-core/bats-support /bats-support
RUN git clone --depth 1 https://github.com/bats-core/bats-assert /bats-assert
RUN /bats-core/install.sh /usr/local
EXPOSE 80 443
# Run eternal loop - for testing
CMD [ "tail", "-f", "/dev/null" ]

+ 29
- 0
test/Dockerfile-centos7-dynu View File

@ -0,0 +1,29 @@
FROM centos:centos7
# Note this image uses gawk
# Update and install required software
RUN yum -y update
RUN yum -y install epel-release
RUN yum -y install git curl bind-utils ldns wget which nginx
ENV staging "true"
ENV dynamic_dns "duckdns"
ENV DYNU_API_KEY 65cXefd35XbYf36546eg5dYcZT6X52Y2
WORKDIR /root
RUN mkdir /etc/nginx/pki
RUN mkdir /etc/nginx/pki/private
COPY ./test/test-config/nginx-ubuntu-no-ssl /etc/nginx/conf.d/default.conf
COPY ./test/test-config/nginx-centos7.conf /etc/nginx/nginx.conf
# BATS (Bash Automated Testings)
RUN git clone https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1
RUN git clone https://github.com/bats-core/bats-support /bats-support
RUN git clone https://github.com/bats-core/bats-assert /bats-assert
RUN /bats-core/install.sh /usr/local
EXPOSE 80 443
# Run eternal loop - for testing
CMD tail -f /dev/null

+ 34
- 0
test/Dockerfile-centos8 View File

@ -0,0 +1,34 @@
FROM centos:centos8
# Note this image uses drill, does not have dig or nslookup installed
# Update and install required software
RUN yum -y update
RUN yum -y install epel-release
RUN yum -y install git curl bind-utils wget which nginx
RUN yum -y install ftp vsftpd
RUN yum -y install openssh-server
WORKDIR /root
RUN mkdir -p /etc/nginx/pki/private
COPY ./test/test-config/nginx-ubuntu-no-ssl /etc/nginx/conf.d/default.conf
COPY ./test/test-config/nginx-centos7.conf /etc/nginx/nginx.conf
# Setup ftp
ENV VSFTPD_CONF=/etc/vsftpd/vsftpd.conf
ENV FTP_PASSIVE_DEFAULT=true
COPY test/test-config/vsftpd.conf /etc/vsftpd/vsftpd.conf
RUN adduser ftpuser
RUN echo 'ftpuser:ftpuser' | chpasswd
RUN adduser www-data
RUN usermod -G www-data ftpuser
RUN usermod -G www-data root
RUN mkdir -p /var/www/.well-known/acme-challenge
RUN chown -R www-data.www-data /var/www
RUN chmod g+w -R /var/www
# BATS (Bash Automated Testings)
RUN git clone --depth 1 https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1
RUN git clone --depth 1 https://github.com/bats-core/bats-support /bats-support
RUN git clone --depth 1 https://github.com/bats-core/bats-assert /bats-assert
RUN /bats-core/install.sh /usr/local

+ 32
- 0
test/Dockerfile-debian View File

@ -0,0 +1,32 @@
FROM debian:latest
# Note this image uses mawk 1.3
# Update and install required software
RUN apt-get update --fix-missing
RUN apt-get install -y git curl dnsutils ldnsutils wget nginx-light
RUN apt-get install -y ftp vsftpd
RUN apt-get install -y openssh-server
WORKDIR /root
RUN mkdir -p /etc/nginx/pki/private
# Setup ftp
ENV VSFTPD_CONF=/etc/vsftpd.conf
ENV FTP_PASSIVE_DEFAULT=false
COPY test/test-config/vsftpd.conf /etc/vsftpd.conf
RUN adduser ftpuser
RUN echo 'ftpuser:ftpuser' | chpasswd
RUN adduser ftpuser www-data
RUN adduser root www-data
RUN chown -R www-data.www-data /var/www
RUN chmod g+w -R /var/www
# BATS (Bash Automated Testings)
RUN git clone --depth 1 https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1
RUN git clone --depth 1 https://github.com/bats-core/bats-support /bats-support
RUN git clone --depth 1 https://github.com/bats-core/bats-assert /bats-assert
RUN /bats-core/install.sh /usr/local
# Run eternal loop - for testing
CMD [ "tail", "-f", "/dev/null" ]

+ 38
- 0
test/Dockerfile-ubuntu View File

@ -0,0 +1,38 @@
FROM ubuntu:latest
# Note this image uses mawk1.3
# Set noninteractive otherwise tzdata hangs
ENV DEBIAN_FRONTEND noninteractive
# Update and install required software
RUN apt-get update --fix-missing
RUN apt-get install -y git curl dnsutils ldnsutils wget nginx-light
RUN apt-get install -y vim dos2unix # for debugging
RUN apt-get install -y ftp vsftpd
RUN apt-get install -y openssh-server
# Setup ftp
ENV VSFTPD_CONF=/etc/vsftpd.conf
ENV FTP_PASSIVE_DEFAULT=false
COPY test/test-config/vsftpd.conf /etc/vsftpd.conf
RUN adduser ftpuser
RUN echo 'ftpuser:ftpuser' | chpasswd
RUN adduser ftpuser www-data
RUN adduser root www-data
RUN chown -R www-data.www-data /var/www
RUN chmod g+w -R /var/www
WORKDIR /root
# Prevent "Can't load /root/.rnd into RNG" error from openssl
RUN touch /root/.rnd
# BATS (Bash Automated Testings)
RUN git clone --depth 1 https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1
RUN git clone --depth 1 https://github.com/bats-core/bats-support /bats-support
RUN git clone --depth 1 https://github.com/bats-core/bats-assert /bats-assert
RUN /bats-core/install.sh /usr/local
# Run eternal loop - for testing
CMD [ "tail", "-f", "/dev/null" ]

+ 30
- 0
test/Dockerfile-ubuntu-duckdns View File

@ -0,0 +1,30 @@
FROM ubuntu:latest
# Note this image uses mawk1.3
# Set noninteractive otherwise tzdata hangs
ENV DEBIAN_FRONTEND noninteractive
# Ensure tests in this image use the staging server
ENV staging "true"
ENV dynamic_dns "duckdns"
ENV DUCKDNS_TOKEN 1d616aa9-b8e4-4bb4-b312-3289de82badb
# Update and install required software
RUN apt-get update --fix-missing
RUN apt-get install -y git curl dnsutils ldnsutils wget nginx-light
RUN apt-get install -y vim dos2unix # for debugging
WORKDIR /root
# Prevent "Can't load /root/.rnd into RNG" error from openssl
RUN touch /root/.rnd
# BATS (Bash Automated Testings)
RUN git clone --depth 1 https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1
RUN git clone --depth 1 https://github.com/bats-core/bats-support /bats-support
RUN git clone --depth 1 https://github.com/bats-core/bats-assert /bats-assert
RUN /bats-core/install.sh /usr/local
# Run eternal loop - for testing
CMD [ "tail", "-f", "/dev/null" ]

+ 30
- 0
test/Dockerfile-ubuntu-dynu View File

@ -0,0 +1,30 @@
FROM ubuntu:latest
# Note this image uses mawk1.3
# Set noninteractive otherwise tzdata hangs
ENV DEBIAN_FRONTEND noninteractive
# Ensure tests in this image use the staging server
ENV staging "true"
ENV dynamic_dns "dynu"
ENV DYNU_API_KEY 65cXefd35XbYf36546eg5dYcZT6X52Y2
# Update and install required software
RUN apt-get update --fix-missing
RUN apt-get install -y git curl dnsutils ldnsutils wget nginx-light
RUN apt-get install -y vim dos2unix # for debugging
WORKDIR /root
# Prevent "Can't load /root/.rnd into RNG" error from openssl
RUN touch /root/.rnd
# BATS (Bash Automated Testings)
RUN git clone https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1
RUN git clone https://github.com/bats-core/bats-support /bats-support
RUN git clone https://github.com/bats-core/bats-assert /bats-assert
RUN /bats-core/install.sh /usr/local
# Run eternal loop - for testing
CMD tail -f /dev/null

+ 36
- 0
test/Dockerfile-ubuntu16 View File

@ -0,0 +1,36 @@
FROM ubuntu:xenial
# xenial = 16
# Note this image uses mawk
# Update and install required software
RUN apt-get update --fix-missing
RUN apt-get install -y git curl dnsutils ldnsutils wget nginx-light
RUN apt-get install -y ftp vsftpd
RUN apt-get install -y openssh-server
WORKDIR /root
RUN mkdir -p /etc/nginx/pki/private
COPY ./test/test-config/nginx-ubuntu-no-ssl /etc/nginx/sites-enabled/default
# Setup ftp
ENV VSFTPD_CONF=/etc/vsftpd.conf
ENV FTP_PASSIVE_DEFAULT=false
COPY test/test-config/vsftpd.conf /etc/vsftpd.conf
# The default init.d script seems to have an incorrect check that vsftpd has started
COPY test/test-config/vsftpd.initd /etc/init.d/vsftpd
RUN adduser ftpuser
RUN echo 'ftpuser:ftpuser' | chpasswd
RUN adduser ftpuser www-data
RUN adduser root www-data
RUN chown -R www-data.www-data /var/www
RUN chmod g+w -R /var/www
# BATS (Bash Automated Testings)
RUN git clone --depth 1 https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1
RUN git clone --depth 1 https://github.com/bats-core/bats-support /bats-support
RUN git clone --depth 1 https://github.com/bats-core/bats-assert /bats-assert
RUN /bats-core/install.sh /usr/local
# Run eternal loop - for testing
CMD [ "tail", "-f", "/dev/null" ]

+ 41
- 0
test/Dockerfile-ubuntu18 View File

@ -0,0 +1,41 @@
FROM ubuntu:bionic
# bionic = 18 LTS (long term support)
# Note this image uses gawk
# Update and install required software
RUN apt-get update --fix-missing
RUN apt-get install -y git curl dnsutils ldnsutils wget gawk nginx-light
RUN apt-get install -y ftp vsftpd
RUN apt-get install -y openssh-server
WORKDIR /root
RUN mkdir -p /etc/nginx/pki/private
COPY ./test/test-config/nginx-ubuntu-no-ssl /etc/nginx/sites-enabled/default
# Setup ftp
ENV VSFTPD_CONF=/etc/vsftpd.conf
ENV FTP_PASSIVE_DEFAULT=false
COPY test/test-config/vsftpd.conf /etc/vsftpd.conf
# The default init.d script seems to have an incorrect check that vsftpd has started
COPY test/test-config/vsftpd.initd /etc/init.d/vsftpd
RUN adduser ftpuser
RUN echo 'ftpuser:ftpuser' | chpasswd
RUN adduser ftpuser www-data
RUN adduser root www-data
RUN chown -R www-data.www-data /var/www
RUN chmod g+w -R /var/www
# Prevent "Can't load /root/.rnd into RNG" error from openssl
RUN touch /root/.rnd
# BATS (Bash Automated Testings)
RUN git clone --depth 1 https://github.com/bats-core/bats-core.git /bats-core --branch v1.2.1
RUN git clone --depth 1 https://github.com/bats-core/bats-support /bats-support
RUN git clone --depth 1 https://github.com/bats-core/bats-assert /bats-assert
RUN /bats-core/install.sh /usr/local
EXPOSE 80 443
# Run eternal loop - for testing
CMD [ "tail", "-f", "/dev/null" ]

+ 35
- 0
test/README-Testing.md View File

@ -0,0 +1,35 @@
# Testing
## Continuous Integration
For continuous integration testing we have the following:
`gitactions` script which runs whenever a PR is pushed:
1. Uses `docker-compose` to start `pebble` (letsencrypt test server) and `challtestsrv` (minimal dns client for pebble)
2. Then runs the `bats` test scripts (all the files with a ".bats" extension) for each OS (alpine, centos6, debian, ubuntu)
3. Runs the `bats` test script against the staging server (using ubuntu docker image and duckdns.org)
## To run all the tests on a single OS
1. Start `pebble` and `challtestsrv` using ```docker-compose up -d --build```
2. Run the test suite ```run-test.sh [<os>]```
3. eg. `run-test.sh ubuntu16`
## To run a single bats test on a single OS
1. Start `pebble` and `challtestsrv` using ```docker-compose up -d --build```
2. ```run-test.sh <os> bats <bats test script>```
3. e.g. `run-test.sh ubuntu bats /getssl/test/1-simple-http01.bats`
## To debug a test
1. Start `pebble` and `challtestsrv` using ```docker-compose up -d --build```
2. ```run-test.sh <os> /getssl/test/debug-test.sh <getssl config file>```
3. e.g. `run-test.sh ubuntu /getssl/test/debug-test.sh -d /getssl/test/test-config/getssl-http01-cfg`
## TODO
1. Test wildcards
2. Test SSH, SFTP, SCP
3. Test change of key algorithm (should automatically delete and re-create account.key)

+ 30
- 0
test/debug-test.sh View File

@ -0,0 +1,30 @@
#!/usr/bin/env bash
# This runs getssl outside of the BATS framework for debugging, etc, against pebble
# Usage: /getssl/test/debug-test.sh getssl-http01.cfg
DEBUG=""
if [ $# -eq 2 ]; then
DEBUG=$1
shift
fi
#shellcheck disable=SC1091
source /getssl/test/test_helper.bash 3>&1
CONFIG_FILE=$1
if [ ! -e "$CONFIG_FILE" ]; then
CONFIG_FILE=${CODE_DIR}/test/test-config/${CONFIG_FILE}
fi
setup_environment 3>&1
# Only add the pebble CA to the cert bundle if using pebble
if grep -q pebble "${CONFIG_FILE}"; then
export CURL_CA_BUNDLE=/root/pebble-ca-bundle.crt
fi
"${CODE_DIR}/getssl" -c "$GETSSL_HOST" 3>&1
cp "${CONFIG_FILE}" "${INSTALL_DIR}/.getssl/${GETSSL_HOST}/getssl.cfg"
# shellcheck disable=SC2086
"${CODE_DIR}/getssl" ${DEBUG} -f "$GETSSL_HOST" 3>&1

+ 6
- 0
test/dns_add_fail View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
# Special test script which will always fail to update dns
echo "This is a test script to check retry works if DNS isn't updated"
exit 0

+ 9
- 0
test/restart-ftpd View File

@ -0,0 +1,9 @@
#!/usr/bin/env bash
if [ "$GETSSL_OS" = "alpine" ]; then
killall -HUP vsftpd >&3-
elif [[ "$GETSSL_OS" == "centos"[78] ]]; then
pgrep vsftpd | head -1 | xargs kill -HUP
else
service vsftpd restart >/dev/null >&3-
fi

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save