mirror of
https://github.com/acmesh-official/acme.sh.git
synced 2026-08-13 12:33:30 +02:00
Compare commits
3 commits
4a3bc2c919
...
41bdd4cd0e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
41bdd4cd0e | ||
|
|
a89ba9c2e5 | ||
|
|
2e2782f0d8 |
3 changed files with 421 additions and 189 deletions
114
deploy/ikuai.sh
Normal file
114
deploy/ikuai.sh
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
# Here is a script to deploy cert to ikuai using curl
|
||||
#
|
||||
# it requires following environment variables:
|
||||
#
|
||||
# IKUAI_SCHEME="http" - http or https , defaults to "http"
|
||||
# IKUAI_HOSTNAME="localhost" - host , defaults to "192.168.9.1"
|
||||
# IKUAI_PORT="80" - port , defaults to "80"
|
||||
# IKUAI_USERNAME="admin" - username , defaults to "admin"
|
||||
# IKUAI_PASSWORD="yourPassword" - password
|
||||
# IKUAI_CERT_ID=1 - ikuai cert id , defaults to 1, and only 1 is supported for now !!!
|
||||
#
|
||||
#returns 0 means success, otherwise error.
|
||||
#
|
||||
######## Public functions #####################
|
||||
#
|
||||
#domain keyfile certfile cafile fullchain
|
||||
ikuai_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
# Get deploy conf
|
||||
_getdeployconf IKUAI_SCHEME
|
||||
_getdeployconf IKUAI_HOSTNAME
|
||||
_getdeployconf IKUAI_PORT
|
||||
_getdeployconf IKUAI_USERNAME
|
||||
_getdeployconf IKUAI_PASSWORD
|
||||
_getdeployconf IKUAI_CERT_ID
|
||||
|
||||
# Use default if not provided
|
||||
[ -n "$IKUAI_SCHEME" ] || IKUAI_SCHEME="http"
|
||||
[ -n "$IKUAI_HOSTNAME" ] || IKUAI_HOSTNAME="192.168.9.1"
|
||||
[ -n "$IKUAI_PORT" ] || IKUAI_PORT=80
|
||||
[ -n "$IKUAI_USERNAME" ] || IKUAI_USERNAME="admin"
|
||||
[ -n "$IKUAI_CERT_ID" ] || IKUAI_CERT_ID=1
|
||||
|
||||
if [ -z "$IKUAI_PASSWORD" ]; then
|
||||
_err "please define IKUAI_PASSWORD."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_debug2 IKUAI_SCHEME "$IKUAI_SCHEME"
|
||||
_debug2 IKUAI_HOSTNAME "$IKUAI_HOSTNAME"
|
||||
_debug2 IKUAI_PORT "$IKUAI_PORT"
|
||||
_debug2 IKUAI_USERNAME "$IKUAI_USERNAME"
|
||||
_secure_debug2 IKUAI_PASSWORD "$IKUAI_PASSWORD"
|
||||
|
||||
_info "Login to ikuai ..."
|
||||
_ikuai_url="$IKUAI_SCHEME://$IKUAI_HOSTNAME:$IKUAI_PORT"
|
||||
_pass_md5="$(printf "%s" "$IKUAI_PASSWORD" | _digest md5 hex | _lower_case)"
|
||||
_pass_salt="$(printf "salt_11%s" "$IKUAI_PASSWORD" | _base64)"
|
||||
_debug2 _ikuai_url "$_ikuai_url"
|
||||
|
||||
_login_req="{\"username\":\"$IKUAI_USERNAME\",\"passwd\":\"$_pass_md5\",\"pass\":\"$_pass_salt\",\"remember_password\":\"\"}"
|
||||
_response=$(_post "$_login_req" "$_ikuai_url/Action/login" "" "POST" "application/json")
|
||||
|
||||
_err_msg="$(printf "%s" "$_response" | _normalizeJson | _egrep_o '"ErrMsg":"[^"]*"' | cut -d'"' -f 4)"
|
||||
# check ErrMsg
|
||||
if [ "$_err_msg" != "Success" ]; then
|
||||
_err "Failed to login to ikuai: $_err_msg"
|
||||
return 1
|
||||
fi
|
||||
# check cookie
|
||||
_cookie="$(grep -i '^set-cookie:' "$HTTP_HEADER" | _head_n 1 | cut -d " " -f 2 | sed 's/;.*//')"
|
||||
if [ -z "$_cookie" ]; then
|
||||
_err "Fail to get the cookie."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Set cookie header
|
||||
_H1="Cookie: $_cookie; username=$IKUAI_USERNAME; login=1"
|
||||
|
||||
_info "Deploy the cert to ikuai ... "
|
||||
|
||||
# Should replace \n to @ ," " to #
|
||||
_cert_content_single_line="$(tr <"$_cfullchain" '\n' '@' | tr ' ' '#')"
|
||||
_key_content_single_line="$(tr <"$_ckey" '\n' '@' | tr ' ' '#')"
|
||||
|
||||
_debug2 _cert_content_single_line "$_cert_content_single_line"
|
||||
_secure_debug2 _key_content_single_line "$_key_content_single_line"
|
||||
|
||||
_key_manager_req="{\"func_name\":\"key_manager\",\"action\":\"save\",\"param\":{\"ca\":\"$_cert_content_single_line\",\"key\":\"$_key_content_single_line\",\"id\":$IKUAI_CERT_ID,\"enabled\":\"yes\",\"comment\":\"\"}}"
|
||||
_response=$(_post "$_key_manager_req" "$_ikuai_url/Action/call" "" "POST" "application/json")
|
||||
|
||||
_err_msg="$(printf "%s" "$_response" | _normalizeJson | _egrep_o '"ErrMsg":"[^"]*"' | cut -d'"' -f 4)"
|
||||
# check ErrMsg
|
||||
if [ "$_err_msg" != "Success" ]; then
|
||||
_err "Failed to deploy the cert to ikuai: $_err_msg"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Save the deploy config ... "
|
||||
# Save the config
|
||||
_savedeployconf IKUAI_SCHEME "$IKUAI_SCHEME"
|
||||
_savedeployconf IKUAI_HOSTNAME "$IKUAI_HOSTNAME"
|
||||
_savedeployconf IKUAI_PORT "$IKUAI_PORT"
|
||||
_savedeployconf IKUAI_USERNAME "$IKUAI_USERNAME"
|
||||
_savedeployconf IKUAI_PASSWORD "$IKUAI_PASSWORD"
|
||||
_savedeployconf IKUAI_CERT_ID "$IKUAI_CERT_ID"
|
||||
|
||||
_info "Successfully deployed certificate to ikuai. Enjoy! :>"
|
||||
|
||||
return 0
|
||||
}
|
||||
307
deploy/unifios.sh
Normal file
307
deploy/unifios.sh
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
#!/usr/bin/env sh
|
||||
# Deploy hook for UniFi OS Server (self-hosted).
|
||||
#
|
||||
# Supports:
|
||||
# - UniFi OS Server on macOS
|
||||
# - UniFi OS Server on Linux
|
||||
# - UniFi OS Server on Windows should also work (runs under WSL2), but
|
||||
# has not been tested.
|
||||
#
|
||||
# Tested on: Ubuntu 26.04 (remote) and macOS 26.6 (local).
|
||||
#
|
||||
# This is a different product from the Cloud Key / UDM hardware and
|
||||
# self-hosted Unifi Controller covered by the `unifi` deploy hook above
|
||||
# (that hook already covers Cloud Key running UnifiOS v2.0.0+/Gen2/2+) --
|
||||
# this hook targets the separately-installed, self-hosted "UniFi OS Server"
|
||||
# application instead, which stores certificates in its own Postgres
|
||||
# database via a REST API rather than a Java keystore, so the `unifi`
|
||||
# hook's approach does not apply here.
|
||||
#
|
||||
# UniFi OS Server exposes a REST API on its management port (default
|
||||
# 11443) that its own web UI uses for certificate management:
|
||||
# POST /api/auth/login - session login (cookie + JWT)
|
||||
# GET /api/userCertificates - list uploaded certificates
|
||||
# POST /api/userCertificates - upload a new certificate
|
||||
# DELETE /api/userCertificates/{id} - remove a certificate
|
||||
# PUT /api/userCertificates/{id}/status - activate/deactivate a certificate
|
||||
#
|
||||
# This was reverse-engineered from the browser's Network tab while using the
|
||||
# real GUI upload/activate/delete flow -- it is undocumented but is the same
|
||||
# code path the UI uses, so it's far more robust than editing settings.yaml,
|
||||
# http/local-certs.conf, or the underlying Postgres user_certificates table
|
||||
# directly (all of which are also touched by this API, but only as a result
|
||||
# of the app's own internal logic, which handles cert parsing, active-cert
|
||||
# bookkeeping, and nginx config regeneration correctly on its own).
|
||||
#
|
||||
# Auth: POST /api/auth/login returns a `TOKEN` cookie containing a JWT whose
|
||||
# payload has a `csrfToken` claim. That value must be echoed back as the
|
||||
# `x-csrf-token` header on every subsequent state-changing request (a classic
|
||||
# double-submit CSRF pattern). No other cookies were found to be necessary.
|
||||
#
|
||||
# Uses core acme.sh helpers throughout (_post/_get, _json_encode,
|
||||
# _durl_replace_base64, _dbase64, _egrep_o) rather than raw curl -k or
|
||||
# python3, so the wget fallback, --debug tracing, and CA_BUNDLE are all
|
||||
# honored the same as every other hook. The management API's cert is
|
||||
# self-signed (it's a management-only port, not meant for public exposure),
|
||||
# so this hook sets HTTPS_INSECURE=1 itself, scoped to its own subshell (see
|
||||
# acme.sh's per-hook sourcing in _deploy) -- it does not weaken TLS
|
||||
# verification for the rest of the acme.sh run, e.g. the connection to the
|
||||
# ACME CA.
|
||||
#
|
||||
# Design: This hook does not save a certificate ID between renewals. Each
|
||||
# upload gets a name unique to that run: the domain name plus a timestamp.
|
||||
# This name never collides with an entry from a previous deploy. This is
|
||||
# true even if that entry is still active. The hook uploads and activates
|
||||
# the new certificate before it removes any old entries. If a failure
|
||||
# occurs during this process, the server still has a valid, active
|
||||
# certificate. The hook removes old entries only after activation is
|
||||
# complete. It removes only entries whose name starts with the domain name,
|
||||
# because this is the hook's own naming convention. As a result, this step
|
||||
# can only affect entries that this hook created for this domain. It can
|
||||
# never affect a certificate that a user uploaded manually, and it can
|
||||
# never affect a self-signed certificate.
|
||||
#
|
||||
# Settings:
|
||||
# DEPLOY_UNIFIOS_HOST - base URL of the management API
|
||||
# (default: "https://localhost:11443")
|
||||
# DEPLOY_UNIFIOS_USERNAME - UniFi OS Server admin username (required)
|
||||
# DEPLOY_UNIFIOS_PASSWORD - UniFi OS Server admin password (required)
|
||||
#
|
||||
# Example:
|
||||
# export DEPLOY_UNIFIOS_USERNAME="acmeuser"
|
||||
# export DEPLOY_UNIFIOS_PASSWORD="xxxxx"
|
||||
# acme.sh --deploy -d example.com --deploy-hook unifios
|
||||
#
|
||||
# Please report bugs to https://github.com/acmesh-official/acme.sh/issues/7182
|
||||
|
||||
_uos_response_code() {
|
||||
# tr strips the trailing newline along with form feeds; re-terminate
|
||||
# before the second _egrep_o, whose sed fallback (used wherever egrep -o
|
||||
# is unavailable) drops an unterminated final line on some platforms.
|
||||
_uos_code="$(_egrep_o <"$HTTP_HEADER" "^HTTP[^ ]* .*$" | cut -d " " -f 2-100 | tr -d "\f\n")"
|
||||
printf '%s\n' "$_uos_code" | _egrep_o "^[0-9][0-9]*"
|
||||
}
|
||||
|
||||
_uos_response_cookie() {
|
||||
# $1 = cookie name
|
||||
grep <"$HTTP_HEADER" -i "^Set-Cookie: *$1=" | _tail_n 1 | _egrep_o "$1=[^;]*" | _head_n 1
|
||||
}
|
||||
|
||||
unifios_deploy() {
|
||||
_cdomain="$1"
|
||||
_ckey="$2"
|
||||
_ccert="$3"
|
||||
_cca="$4"
|
||||
_cfullchain="$5"
|
||||
|
||||
_debug _cdomain "$_cdomain"
|
||||
_debug _ckey "$_ckey"
|
||||
_debug _ccert "$_ccert"
|
||||
_debug _cca "$_cca"
|
||||
_debug _cfullchain "$_cfullchain"
|
||||
|
||||
# Scoped to this hook's own subshell -- does not affect the rest of the
|
||||
# acme.sh run (e.g. the connection to the ACME CA).
|
||||
export HTTPS_INSECURE=1
|
||||
|
||||
_getdeployconf DEPLOY_UNIFIOS_HOST
|
||||
DEPLOY_UNIFIOS_HOST="${DEPLOY_UNIFIOS_HOST:-https://localhost:11443}"
|
||||
_savedeployconf DEPLOY_UNIFIOS_HOST "$DEPLOY_UNIFIOS_HOST"
|
||||
_debug DEPLOY_UNIFIOS_HOST "$DEPLOY_UNIFIOS_HOST"
|
||||
|
||||
_getdeployconf DEPLOY_UNIFIOS_USERNAME
|
||||
_getdeployconf DEPLOY_UNIFIOS_PASSWORD
|
||||
|
||||
if [ -z "$DEPLOY_UNIFIOS_USERNAME" ] || [ -z "$DEPLOY_UNIFIOS_PASSWORD" ]; then
|
||||
_err "DEPLOY_UNIFIOS_USERNAME and DEPLOY_UNIFIOS_PASSWORD must be set."
|
||||
return 1
|
||||
fi
|
||||
_debug DEPLOY_UNIFIOS_USERNAME "$DEPLOY_UNIFIOS_USERNAME"
|
||||
_secure_debug DEPLOY_UNIFIOS_PASSWORD "$DEPLOY_UNIFIOS_PASSWORD"
|
||||
|
||||
_info "Logging in to UniFi OS Server API at $DEPLOY_UNIFIOS_HOST..."
|
||||
|
||||
# _json_encode always appends a trailing "\n" escape, even to input with
|
||||
# no trailing newline (it normalizes via `echo`, unconditionally adding
|
||||
# one). That's harmless for the key/cert file content below, which
|
||||
# legitimately ends in a real newline anyway, but wrong for these plain
|
||||
# strings -- strip the spurious escape it leaves behind.
|
||||
_uos_user_json="$(printf '%s' "$DEPLOY_UNIFIOS_USERNAME" | _json_encode)"
|
||||
_uos_user_json="${_uos_user_json%\\n}"
|
||||
_uos_pass_json="$(printf '%s' "$DEPLOY_UNIFIOS_PASSWORD" | _json_encode)"
|
||||
_uos_pass_json="${_uos_pass_json%\\n}"
|
||||
_login_body="{\"username\":\"$_uos_user_json\",\"password\":\"$_uos_pass_json\",\"token\":\"\",\"rememberMe\":false}"
|
||||
|
||||
_login_json="$(_post "$_login_body" "$DEPLOY_UNIFIOS_HOST/api/auth/login" "" "POST" "application/json")"
|
||||
_login_code="$(_uos_response_code)"
|
||||
|
||||
if [ "$_login_code" != "200" ]; then
|
||||
_err "Login failed (HTTP $_login_code)."
|
||||
_err "Response: $_login_json"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Credentials are proven correct now -- save them, rather than only at the
|
||||
# very end, so a later step failing doesn't discard a working login.
|
||||
# base64-encoded: _save_conf wraps values in single quotes with no
|
||||
# escaping, so a literal "'" in the password would otherwise corrupt the
|
||||
# domain conf (see deploy/synology_dsm.sh for the same pattern).
|
||||
_savedeployconf DEPLOY_UNIFIOS_USERNAME "$DEPLOY_UNIFIOS_USERNAME" "base64"
|
||||
_savedeployconf DEPLOY_UNIFIOS_PASSWORD "$DEPLOY_UNIFIOS_PASSWORD" "base64"
|
||||
|
||||
_uos_token="$(_uos_response_cookie TOKEN)"
|
||||
if [ -z "$_uos_token" ]; then
|
||||
_err "Login succeeded but no TOKEN cookie was returned."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_H1="Cookie: $_uos_token"
|
||||
export _H1
|
||||
|
||||
_uos_jwt_payload="$(echo "$_uos_token" | cut -d '=' -f 2- | cut -d '.' -f 2)"
|
||||
_uos_csrf="$(_durl_replace_base64 "$_uos_jwt_payload" | _dbase64 | _egrep_o '"csrfToken":"[^"]*"' | cut -d '"' -f 4)"
|
||||
if [ -z "$_uos_csrf" ]; then
|
||||
_err "Could not extract csrfToken from session token."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_H2="x-csrf-token: $_uos_csrf"
|
||||
export _H2
|
||||
|
||||
_info "Uploading new certificate..."
|
||||
# "name" is a purely cosmetic label -- the server never validates it
|
||||
# against the certificate's actual CN/SAN, and accepts arbitrary text
|
||||
# including spaces (confirmed: a cert for example.com served correctly
|
||||
# after being uploaded under the unrelated name "totally unrelated label").
|
||||
# The only constraint that matters here is uniqueness: the server rejects
|
||||
# a second entry with a name it already has, so a bare domain name would
|
||||
# collide with the previous deploy's entry on every renewal after the
|
||||
# first. A full human-readable timestamp would make that obvious in the
|
||||
# UI, but the certificate list's name column is fixed-width and doesn't
|
||||
# wrap (confirmed against the real UI: a long name overlaps the Expires
|
||||
# column and makes both unreadable), so keep the suffix short instead --
|
||||
# Unix epoch seconds are still unique enough for this purpose.
|
||||
_uos_name="$_cdomain $(_time)"
|
||||
_uos_key_json="$(_json_encode <"$_ckey")"
|
||||
_uos_cert_json="$(_json_encode <"$_cfullchain")"
|
||||
_create_body="{\"name\":\"$_uos_name\",\"key\":\"$_uos_key_json\",\"cert\":\"$_uos_cert_json\"}"
|
||||
|
||||
_create_json="$(_post "$_create_body" "$DEPLOY_UNIFIOS_HOST/api/userCertificates" "" "POST" "application/json")"
|
||||
_create_code="$(_uos_response_code)"
|
||||
|
||||
if [ "$_create_code" = "201" ]; then
|
||||
_new_id="$(echo "$_create_json" | _egrep_o '"id":"[^"]*"' | _head_n 1 | cut -d '"' -f 4)"
|
||||
if [ -z "$_new_id" ]; then
|
||||
_err "Could not determine new certificate ID from upload response."
|
||||
return 1
|
||||
fi
|
||||
elif [ "$_create_code" = "400" ] && echo "$_create_json" | grep -q "USER_CERTIFICATE_DUPLICATE"; then
|
||||
# HTTP 400 alone just means "bad request" -- it's the USER_CERTIFICATE_DUPLICATE
|
||||
# code in the response body, checked above, that actually confirms this.
|
||||
# The name above is unique to this run, so a duplicate here can only be
|
||||
# the server's other uniqueness constraint: this exact certificate (by
|
||||
# fingerprint) already exists as some other entry -- most likely a retry
|
||||
# after a prior run already uploaded it (a real renewal always produces a
|
||||
# new fingerprint, so this shouldn't happen in normal cron use). The
|
||||
# response body doesn't include the existing entry's id, so look it up
|
||||
# by fingerprint instead.
|
||||
# The API's own fingerprint field is SHA-1 (20 bytes), not SHA-256 --
|
||||
# confirmed against a real response, e.g.
|
||||
# "fingerprint":"FC:02:50:9C:3B:3F:B7:79:9D:CA:4D:7C:AC:92:E7:D5:EA:F1:3A:29"
|
||||
# (20 colon-separated groups). _fingerprint (core helper) strips the
|
||||
# colons that field has, so re-insert them rather than stripping the
|
||||
# JSON's own colons, which would also remove the ones separating every
|
||||
# key from its value.
|
||||
_uos_fingerprint="$(_fingerprint "$_cfullchain" sha1)"
|
||||
if [ -z "$_uos_fingerprint" ]; then
|
||||
_err "Could not compute the certificate's fingerprint."
|
||||
return 1
|
||||
fi
|
||||
_uos_fingerprint="$(echo "$_uos_fingerprint" | sed 's/\(..\)/\1:/g; s/:$//')"
|
||||
|
||||
_list_json="$(_get "$DEPLOY_UNIFIOS_HOST/api/userCertificates")"
|
||||
_list_code="$(_uos_response_code)"
|
||||
if [ "$_list_code" != "200" ]; then
|
||||
_err "Failed to list existing certificates (HTTP $_list_code)."
|
||||
_err "Response: $_list_json"
|
||||
return 1
|
||||
fi
|
||||
# _normalizeJson collapses the response to one predictable line (no stray
|
||||
# whitespace around colons, no embedded CR/LF the server might emit) but
|
||||
# also strips the trailing newline entirely -- re-terminate before the
|
||||
# split below, since some sed implementations drop an unterminated final
|
||||
# line rather than processing it.
|
||||
_list_json="$(echo "$_list_json" | _normalizeJson)"
|
||||
# A literal embedded newline (not the two-character "\n", which GNU sed
|
||||
# treats as a newline in the replacement but POSIX doesn't define and BSD
|
||||
# sed emits literally) splits it one JSON object per line so grep can
|
||||
# match a single certificate entry at a time.
|
||||
_list_json="$(
|
||||
printf '%s\n' "$_list_json" | sed 's/},{/},\
|
||||
{/g'
|
||||
)"
|
||||
_new_id="$(echo "$_list_json" | grep -F "\"fingerprint\":\"$_uos_fingerprint\"" | _egrep_o '"id":"[^"]*"' | _head_n 1 | cut -d '"' -f 4)"
|
||||
if [ -z "$_new_id" ]; then
|
||||
_err "Certificate upload rejected as a duplicate (server reported USER_CERTIFICATE_DUPLICATE), but no existing entry matching this fingerprint was found."
|
||||
_err "Response: $_create_json"
|
||||
return 1
|
||||
fi
|
||||
# Reusing the existing entry rather than deleting it and re-uploading
|
||||
# under today's name+timestamp: the served content is identical either
|
||||
# way, so replacing it would only cost an extra delete+create round trip
|
||||
# for no functional benefit. The tradeoff is cosmetic -- this entry keeps
|
||||
# whatever name it was given whenever it was originally uploaded, so it
|
||||
# won't reflect today's date in the UI.
|
||||
_info "Certificate already present as entry $_new_id; reusing it."
|
||||
else
|
||||
_err "Certificate upload failed (HTTP $_create_code)."
|
||||
_err "Response: $_create_json"
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Activating certificate $_new_id..."
|
||||
_activate_json="$(_post '{"active":true}' "$DEPLOY_UNIFIOS_HOST/api/userCertificates/$_new_id/status" "" "PUT" "application/json")"
|
||||
_activate_code="$(_uos_response_code)"
|
||||
|
||||
if [ "$_activate_code" != "200" ]; then
|
||||
_err "Failed to activate new certificate (HTTP $_activate_code)."
|
||||
_err "Response: $_activate_json"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# UniFi OS Server activation is exclusive server-wide. Tests against the
|
||||
# real API confirm this: activation of one entry deactivates whichever
|
||||
# other entry was active before, no matter its name or domain. As a
|
||||
# result, the server serves the certificate that this hook just activated.
|
||||
# This certificate is already live. If the removal of old entries below
|
||||
# fails, the hook logs the failure. The deploy does not fail because of
|
||||
# this.
|
||||
_info "Checking for old certificate entries to remove..."
|
||||
_list_json="$(_get "$DEPLOY_UNIFIOS_HOST/api/userCertificates")"
|
||||
_list_code="$(_uos_response_code)"
|
||||
if [ "$_list_code" != "200" ]; then
|
||||
_err "Failed to list certificates for cleanup (HTTP $_list_code) -- leaving old entries in place."
|
||||
else
|
||||
_list_json="$(echo "$_list_json" | _normalizeJson)"
|
||||
_list_json="$(
|
||||
printf '%s\n' "$_list_json" | sed 's/},{/},\
|
||||
{/g'
|
||||
)"
|
||||
# The pattern below matches the domain name followed by a space. If the
|
||||
# space is missing, the pattern can also match a different domain that
|
||||
# starts with the same text as this domain.
|
||||
_old_ids="$(echo "$_list_json" | grep -F "\"name\":\"$_cdomain " | _egrep_o '"id":"[^"]*"' | cut -d '"' -f 4 | grep -v "^$_new_id$")"
|
||||
for _old_id in $_old_ids; do
|
||||
_info "Removing old certificate entry $_old_id..."
|
||||
_del_json="$(_post "" "$DEPLOY_UNIFIOS_HOST/api/userCertificates/$_old_id" "" "DELETE")"
|
||||
_del_code="$(_uos_response_code)"
|
||||
if [ "$_del_code" != "204" ] && [ "$_del_code" != "200" ]; then
|
||||
_err "Failed to delete old certificate $_old_id (HTTP $_del_code) -- leaving it in place."
|
||||
_err "Response: $_del_json"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
_info "UniFi OS Server certificate deployed and activated successfully."
|
||||
return 0
|
||||
}
|
||||
|
|
@ -1,189 +0,0 @@
|
|||
#!/usr/bin/env sh
|
||||
# shellcheck disable=SC2034
|
||||
dns_linode_info='Linode.com (Old)
|
||||
Deprecated. Use dns_linode_v4
|
||||
Site: Linode.com
|
||||
Options:
|
||||
LINODE_API_KEY API Key
|
||||
Author: Philipp Grosswiler <philipp.grosswiler@swiss-design.net>
|
||||
'
|
||||
|
||||
LINODE_API_URL="https://api.linode.com/?api_key=$LINODE_API_KEY&api_action="
|
||||
|
||||
######## Public functions #####################
|
||||
|
||||
#Usage: dns_linode_add _acme-challenge.www.domain.com "XKrxpRBosdIKFzxW_CT3KLZNf6q0HG9i01zxXp5CPBs"
|
||||
dns_linode_add() {
|
||||
fulldomain="${1}"
|
||||
txtvalue="${2}"
|
||||
|
||||
if ! _Linode_API; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Using Linode"
|
||||
_debug "Calling: dns_linode_add() '${fulldomain}' '${txtvalue}'"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "Domain does not exist."
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_parameters="&DomainID=$_domain_id&Type=TXT&Name=$_sub_domain&Target=$txtvalue"
|
||||
|
||||
if _rest GET "domain.resource.create" "$_parameters" && [ -n "$response" ]; then
|
||||
_resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1)
|
||||
_debug _resource_id "$_resource_id"
|
||||
|
||||
if [ -z "$_resource_id" ]; then
|
||||
_err "Error adding the domain resource."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Domain resource successfully added."
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
#Usage: dns_linode_rm _acme-challenge.www.domain.com
|
||||
dns_linode_rm() {
|
||||
fulldomain="${1}"
|
||||
|
||||
if ! _Linode_API; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Using Linode"
|
||||
_debug "Calling: dns_linode_rm() '${fulldomain}'"
|
||||
|
||||
_debug "First detect the root zone"
|
||||
if ! _get_root "$fulldomain"; then
|
||||
_err "Domain does not exist."
|
||||
return 1
|
||||
fi
|
||||
_debug _domain_id "$_domain_id"
|
||||
_debug _sub_domain "$_sub_domain"
|
||||
_debug _domain "$_domain"
|
||||
|
||||
_parameters="&DomainID=$_domain_id"
|
||||
|
||||
if _rest GET "domain.resource.list" "$_parameters" && [ -n "$response" ]; then
|
||||
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
|
||||
|
||||
resource="$(echo "$response" | _egrep_o "{.*\"NAME\":\s*\"$_sub_domain\".*}")"
|
||||
if [ "$resource" ]; then
|
||||
_resource_id=$(printf "%s\n" "$resource" | _egrep_o "\"RESOURCEID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
|
||||
if [ "$_resource_id" ]; then
|
||||
_debug _resource_id "$_resource_id"
|
||||
|
||||
_parameters="&DomainID=$_domain_id&ResourceID=$_resource_id"
|
||||
|
||||
if _rest GET "domain.resource.delete" "$_parameters" && [ -n "$response" ]; then
|
||||
_resource_id=$(printf "%s\n" "$response" | _egrep_o "\"ResourceID\":\s*[0-9]+" | cut -d : -f 2 | tr -d " " | _head_n 1)
|
||||
_debug _resource_id "$_resource_id"
|
||||
|
||||
if [ -z "$_resource_id" ]; then
|
||||
_err "Error deleting the domain resource."
|
||||
return 1
|
||||
fi
|
||||
|
||||
_info "Domain resource successfully deleted."
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
|
||||
_Linode_API() {
|
||||
if [ -z "$LINODE_API_KEY" ]; then
|
||||
LINODE_API_KEY=""
|
||||
|
||||
_err "You didn't specify the Linode API key yet."
|
||||
_err "Please create your key and try again."
|
||||
|
||||
return 1
|
||||
fi
|
||||
|
||||
_saveaccountconf LINODE_API_KEY "$LINODE_API_KEY"
|
||||
}
|
||||
|
||||
#################### Private functions below ##################################
|
||||
#_acme-challenge.www.domain.com
|
||||
#returns
|
||||
# _sub_domain=_acme-challenge.www
|
||||
# _domain=domain.com
|
||||
# _domain_id=12345
|
||||
_get_root() {
|
||||
domain=$1
|
||||
i=2
|
||||
p=1
|
||||
|
||||
if _rest GET "domain.list"; then
|
||||
response="$(echo "$response" | tr -d "\n" | tr '{' "|" | sed 's/|/&{/g' | tr "|" "\n")"
|
||||
while true; do
|
||||
h=$(printf "%s" "$domain" | cut -d . -f "$i"-100)
|
||||
_debug h "$h"
|
||||
if [ -z "$h" ]; then
|
||||
#not valid
|
||||
return 1
|
||||
fi
|
||||
|
||||
hostedzone="$(echo "$response" | _egrep_o "{.*\"DOMAIN\":\s*\"$h\".*}")"
|
||||
if [ "$hostedzone" ]; then
|
||||
_domain_id=$(printf "%s\n" "$hostedzone" | _egrep_o "\"DOMAINID\":\s*[0-9]+" | _head_n 1 | cut -d : -f 2 | tr -d \ )
|
||||
if [ "$_domain_id" ]; then
|
||||
_sub_domain=$(printf "%s" "$domain" | cut -d . -f 1-"$p")
|
||||
_domain=$h
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
p=$i
|
||||
i=$(_math "$i" + 1)
|
||||
done
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
#method method action data
|
||||
_rest() {
|
||||
mtd="$1"
|
||||
ep="$2"
|
||||
data="$3"
|
||||
|
||||
_debug mtd "$mtd"
|
||||
_debug ep "$ep"
|
||||
|
||||
export _H1="Accept: application/json"
|
||||
export _H2="Content-Type: application/json"
|
||||
|
||||
if [ "$mtd" != "GET" ]; then
|
||||
# both POST and DELETE.
|
||||
_debug data "$data"
|
||||
response="$(_post "$data" "$LINODE_API_URL$ep" "" "$mtd")"
|
||||
else
|
||||
response="$(_get "$LINODE_API_URL$ep$data")"
|
||||
fi
|
||||
|
||||
if [ "$?" != "0" ]; then
|
||||
_err "error $ep"
|
||||
return 1
|
||||
fi
|
||||
_debug2 response "$response"
|
||||
return 0
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue