Commit Graph
93 Commits
Author SHA1 Message Date
neil ebb5cc4981 deploy/synology_dsm.sh: remove bashisms, keep the hook POSIX sh
The hook is sourced by acme.sh, so the bash shebang never takes
effect: under dash, `[ x == y ]` fails with "unexpected operator",
the 403 branch never triggers and 2FA-OTP login is skipped.
Replace `==` with `=` and use the standard sh shebang.
2026-07-12 16:04:44 +08:00
neil 3989eef5e2 cpanel_uapi: don't spill a redirection error when the key file is absent
With --signcsr the private key never exists in the cert home, so every
renewal printed ".../domain.key: No such file or directory" from the
shell redirection. Skip the key read in that case; the install_ssl call
already ran with an empty key there and cPanel keeps the installed one.

https://github.com/acmesh-official/acme.sh/issues/6228
2026-07-12 13:00:12 +08:00
neil 2c51ac1c27 dns_dynu: include the server response in the authentication error
Same as the dns_cloudns change: a bare "Authentication failed" hides
the actual API error and makes reports undiagnosable.
2026-07-12 12:45:10 +08:00
neil eacf0d6a87 issue bot: tell reporters to redact secrets before posting logs
Debug logs occasionally contain private keys or tokens (issue 6267);
the code-side leak in the haproxy hook was fixed by #6268, this adds
the missing warning to the auto-comment that asks for logs.
2026-07-12 12:32:54 +08:00
neil 099d88e6a9 dns_knot: KNOT_KEY takes the TSIG key data, not a file path
The knsupdate "key" statement wants "[alg:]name secret"; the info block
wrongly described the option as a file path.

https://github.com/acmesh-official/acme.sh/issues/6293
2026-07-12 12:22:28 +08:00
neil 897e219743 issue: never schedule the default renewal past the cert expiry
The default schedule was a fixed CertCreateTime + RenewalDays - 1 day,
which passes notAfter entirely for short-lived certs (internal CAs
today, the CA/B SC-081 47-day maximum later) and leaves an expired cert
in place for weeks. Extract the arithmetic into _calc_next_renew_time
and cap it at one day before expiry (one hour for lifetimes of 24h or
less, mirroring --valid-to scheduling). CAs with ARI are unaffected --
the ARI window still overrides afterwards.

https://github.com/acmesh-official/acme.sh/issues/6305
2026-07-12 12:12:18 +08:00
neil a9590c5bd7 workflows: run issue/wiki automation only in the upstream repo 2026-07-12 11:49:53 +08:00
neil c0d62eb934 wiki-guard: skip on forks (no <fork>.wiki repo to check out) 2026-07-12 11:43:07 +08:00
neil 44c045b056 notify: add the customscript hook
The wiki has documented "21. Set notification for customscript" since
2022 but the implementation (#4193) was never merged, so following the
wiki failed with "Cannot find the hook file". Same interface as
documented: the script gets subject, content and status code as three
arguments. Unlike #4193, the target script is invoked directly instead
of through eval -- the subject/content contain domain names and CA
messages, and eval would allow command injection through them.

https://github.com/acmesh-official/acme.sh/issues/6377
2026-07-12 11:36:45 +08:00
neil e94631de44 dns_pdns: probe zones with the server-side name filter in _get_root
The unfiltered GET /zones lists every zone on the server; with large
installations (100k zones) root-zone detection took minutes per domain.
Probe each walk-up candidate with ?zone=<name> instead (exact match per
the PowerDNS API docs); servers that ignore the parameter return the
full list, which the existing check still handles.

https://github.com/acmesh-official/acme.sh/issues/6382
2026-07-12 11:20:53 +08:00
neil a49f8c1992 mydevil: replace BSD-only cut -w with tr + plain cut
cut -w (split on whitespace) is a FreeBSD extension unknown to GNU
coreutils; squeeze blanks into tabs with tr first so the field
extraction is POSIX.

https://github.com/acmesh-official/acme.sh/issues/6452
2026-07-12 10:49:49 +08:00
neil 7d0283ca2c dns_zonomi: make the API endpoint configurable via ZM_Api
RimuHosting (which owns zonomi) exposes the identical API at
https://rimuhosting.com/dns/dyndns.jsp; an overridable endpoint serves
both providers with one hook. The default stays zonomi.com and is not
written to the account conf.

https://github.com/acmesh-official/acme.sh/issues/6475
2026-07-12 10:26:40 +08:00
neil 76811857a0 dns_cpanel: quote inner expansion in suffix strip (SC2295) 2026-07-12 09:35:22 +08:00
neil 22a5ae3ceb dns_cloudns: include the server response in the login error
https://github.com/acmesh-official/acme.sh/issues/6520
2026-07-12 09:34:59 +08:00
neil 04e0422526 precheck: log the socat recommendation with _info instead of _err
Missing socat only matters for standalone mode; the text even says the
warning can be ignored. Printing it to stderr made every --upgrade in a
cron noisy for DNS-only users who redirect stdout.

https://github.com/acmesh-official/acme.sh/issues/6525
2026-07-12 09:30:46 +08:00
neil 2215f1b988 notify: clear inherited _H1.._H5 before running each notify hook
The dns/deploy hooks export _H1.._H5 in the main process, and the
notify hooks run in a subshell that inherits them. A hook that does
not overwrite every slot (ntfy without NTFY_TOKEN, slack, telegram,
etc.) sent the stale headers with its request, leaking another
service's Authorization credentials to the notify endpoint.

https://github.com/acmesh-official/acme.sh/issues/6801
2026-07-11 11:56:58 +08:00
neil 9366c2e065 dns_cpanel: resolve the most specific zone in _get_root
With both domain.tld and sub.domain.tld zones on the account, the first
endswith hit could pick the parent zone while cPanel stores the record
in the most specific one, so the cleanup never found the record and
left an orphaned _acme-challenge TXT entry. Pick the longest matching
zone with an exact literal suffix match (_endswith treats the needle as
a regex, letting xdomain.tld wrongly match zone domain.tld).

https://github.com/acmesh-official/acme.sh/issues/6807
2026-07-11 11:42:32 +08:00
neil 58cd667d65 dns_njalla.sh: accept string record ids when removing records
The Njalla API returns record ids as JSON strings now; the numeric-only
pattern matched nothing, so the removal never found the record id.
Match both quoted and bare ids.

from https://github.com/acmesh-official/acme.sh/pull/5121
2026-07-10 20:47:31 +08:00
neil 2058a77d83 acme.sh: fix variable name typo _excapedAlgnames -> _escapedAltnames
from https://github.com/acmesh-official/acme.sh/pull/6547
2026-07-10 19:37:36 +08:00
neil 660a5e322c deploy/synology_dsm.sh: use grep -Eo '[0-9]+' when extracting error codes
grep -o '[0-9]*' can match the empty string; GNU grep skips empty
matches but BSD greps handle them differently, breaking the 2FA
login flow on OpenBSD. Force a non-empty match at all three sites.

from https://github.com/acmesh-official/acme.sh/pull/6725
2026-07-10 18:37:32 +08:00
neil fa763db105 dns_pleskxml.sh: use grep -F when matching interpolated values
fulldomain/txtvalue/root_domain_name were interpolated into grep
regex patterns; match them as fixed strings instead.

from https://github.com/acmesh-official/acme.sh/pull/7031
2026-07-10 12:05:28 +08:00
neil 90b4795bb1 issue: strip the trailing dot of a fully-qualified alias domain
A trailing dot in --domain-alias/--challenge-alias was passed through
to the dnsapi hook verbatim. Providers with exact-match record-name
lookups (e.g. Cloudflare's name= filter) then never find the record,
so rm never deletes it and relic TXT records accumulate on every issue.
Stripping in issue() also fixes certs with a dotted alias already
saved in domain.conf.

fix https://github.com/acmesh-official/acme.sh/issues/4636
2026-07-10 11:22:20 +08:00
neil 534a1714dc dns_me.sh: use LC_ALL=C so the request date header is always English
LC_ALL in the environment overrides both LC_TIME and LANG, so LANG=C
alone still produced localized day/month names on non-English systems
and DNS Made Easy rejected the request date header. An LC_ALL=C
command prefix beats every locale variable (same pattern as
dns_oci.sh).

Fixes #4272. Closes #4271. Thanks to @Nickinthebox.
2026-07-10 11:20:08 +08:00
neil 45c0ad4112 Add _cleardeployconf to clear deploy hook keys from domain conf
Mirrors _clearaccountconf_mutable: clears the SAVED_ prefixed key and
the legacy unprefixed key. Replaces the local copy in synology_dsm.sh
and the direct _cleardomainconf call in multideploy.sh.

Closes #4722. Thanks to @sg1888.
2026-07-10 11:05:40 +08:00
neil 83b52e0cd7 notify/smtp.sh: add --crlf so curl sends CRLF line endings
Postfix with smtpd_forbid_bare_newline (default hardening since 3.9,
after SMTP smuggling) rejects the message with
"521 5.5.2 Error: bare <LF> received". RFC 5321 requires CRLF.
The python sender is unaffected (smtplib already emits CRLF).

fix https://github.com/acmesh-official/acme.sh/issues/7104
2026-07-10 10:38:52 +08:00
neil bed15ba844 dns_freedns.sh: use grep -E, BRE \| alternation is a GNU extension
OpenBSD grep treats \| in a BRE as a literal | character, so
_freedns_domain_id never matched any row and every domain lookup
failed with "Domain not found". Switch to ERE with -E, keeping the
parens escaped so the (.*) suffix branch still requires literal
parentheses and does not widen the match (e.g. searching example.com
must not match example.company).

Reported-by: @katiekloss @boretom
Ref: https://github.com/acmesh-official/acme.sh/issues/2305
2026-07-10 10:23:59 +08:00
neil ca118be754 issue.yml: match tracking issue title variants 2026-07-10 10:02:59 +08:00
neil cc64a73230 one-click revert and ban 2026-07-06 17:39:56 +08:00
neil f2b37b32ff add more events 2026-07-06 16:36:16 +08:00
neil 73df21abc4 clean 2026-07-06 16:30:41 +08:00
neil 919492df13 wiki-guard: use WIKI_GUARD_TOKEN (PAT with read:org) to enumerate org write members 2026-07-06 16:27:26 +08:00
neil e4eaa59063 wiki-guard: log the number of write-access members loaded 2026-07-06 15:23:45 +08:00
neil 2b5a19d34a wiki-guard: trust repo/org members with write access in all rule checks 2026-07-06 15:11:35 +08:00
neil dc1b06006f issue.yml: assign and label "Report bugs to" tracking issues instead of posting the upgrade boilerplate 2026-07-06 14:27:00 +08:00
neil 8585d9f4a7 wiki-monitor: skip notification for the maintainer's own wiki changes 2026-07-06 14:23:51 +08:00
neil ca8ab7f8b5 add wiki-guard workflow: auto-restore wiki pages deleted or renamed by non-maintainer 2026-07-06 13:35:37 +08:00
neil 2a175f97e8 toPkcs8: support --password and re-export the pkcs8 file on renewal (#4134) 2026-07-05 18:04:24 +08:00
neil d3af3315da dnsapi/dns_edgedns: use the system clock for the request timestamp (#3973) 2026-07-05 18:02:34 +08:00
neil 7b6d96387c migrate the legacy ACMEDNS_UPDATE_URL from the account conf (#3899) 2026-07-05 17:48:33 +08:00
neil cabe432539 add bash completion for commands and parameters, installed via --install (#307) 2026-07-05 17:39:50 +08:00
neil 1746fbdb25 support multiple account emails (#1309)
ACCOUNT_EMAIL / --email now accepts a comma- or space-separated list
and registers all of them as ACME contact entries. The ZeroSSL EAB
endpoint takes a single address, so the first one is used there.
2026-07-05 17:37:40 +08:00
neil d2b3772631 deploy/panos: do not commit when the cert or key import failed (#4716)
Committing after a failed import leaves a mismatched cert/key pair on
the firewall (PAN-OS does not validate the pair at commit time), which
can lock the admin out of the https management interface.
2026-07-05 17:13:59 +08:00
neil e964157bff _install_win_taskscheduler: zero-pad the minute in the schtasks /ST value (#4950) 2026-07-05 17:13:24 +08:00
neil 934711e51d notify/aws_ses: add container/instance IAM role auth (IMDSv2)
aws_ses_send calls `_use_container_role || _use_instance_role` when no
static AWS keys are set, but those functions were never defined -- only
_use_metadata was -- so role-based auth silently fell through to the
"no api key" error. Add both, using the current IMDSv2-capable versions
from dns_aws.sh, and set the IMDSv2 token header in _use_metadata so the
credential fetch works on IMDSv2-only instances.

Closes #4742
2026-07-05 17:09:51 +08:00
neil 7def43481a dns_regru: require a dot boundary in root zone matching
_get_root matched a registered domain anywhere as a substring of the
challenge domain, so with both "test.com.ru" and "subtest.com.ru" in the
account, issuing for subtest.com.ru wrongly picked test.com.ru as the
root (it is a substring of "sub-test.com.ru"). Anchor the match to a '.'
boundary so a shorter domain no longer matches a longer subdomain label.

Fixes the issue reported in #5036 (thanks @koledas)
Closes #5036
2026-07-05 16:57:59 +08:00
neil defd64022d dnsapi/dns_namecom: probe the root zone with GetDomain instead of listing all domains
The domain list is paginated at 1000 entries per page and only the
first page was fetched, so accounts with more than 1000 domains never
found the root zone.

fix https://github.com/acmesh-official/acme.sh/issues/5051
2026-07-05 16:53:14 +08:00
neil 4256e3532b _regAccount: error out clearly when the eab-hmac-key cannot be base64-decoded
An undecodable key (e.g. broken LibreSSL base64 -d -A) used to produce
the cryptic "Usage: _hmac hashalg secret [outputhex]" and an empty EAB
signature that the CA rejects with 403.

https://github.com/acmesh-official/acme.sh/issues/4082
2026-07-05 16:32:57 +08:00
neil 1f94fd7fd5 add Apache workflow to test the --apache mode
Runs le_test_apache from acmetest against Pebble, with Apache
listening on Pebble's HTTP-01 validation port.
2026-07-05 16:31:51 +08:00
neil 507baff2ef deploy/docker: allow setting key file mode and owner in the container
The docker deploy hook copied the key file preserving the source mode
(root:root 0600), so a non-root container service (uid >= 1000) could not
read it. Add DEPLOY_DOCKER_CONTAINER_KEY_MODE and
DEPLOY_DOCKER_CONTAINER_KEY_OWNER, applied via chmod/chown inside the
container after the key is copied and before the reload command.

Closes #5333
2026-07-05 16:30:46 +08:00
neil 504540e67c dnsapi/dns_autodns: escape XML special characters in credentials (#5317) 2026-07-05 16:29:58 +08:00
neil cacafc9c23 add Nginx workflow to test the --nginx mode
Runs le_test_nginx from acmetest against Pebble: nginx listens on
Pebble's HTTP-01 validation port with an aaPanel/BT style
"location ^~ /" reverse proxy block, the regression case of #6125.
2026-07-05 16:18:37 +08:00
neil 1cd63e1480 _createcsr: omit CN from the CSR subject when it exceeds 64 characters (#4867) 2026-07-05 16:02:52 +08:00
neil 31b13caf8b DNS.yml: fix workflow warnings
- replace deprecated set-output with GITHUB_OUTPUT
- untap aws/tap before brew install to silence tap trust warning
- inject safe.directory=* for cygwin git so the checkout post step
  no longer fails with dubious ownership (exit 128)
2026-07-05 15:51:38 +08:00
neil 1e2cd50fc9 deploy/haproxy: use printf instead of "echo -e" for the stats socket payload
dash's echo has no -e flag and sends a literal "-e " prefix to the
socket, so haproxy rejects the command and the hot update always fails
on Debian/Ubuntu (/bin/sh = dash). Also accept "Transaction updated",
which haproxy replies when an uncommitted transaction already exists.

fix https://github.com/acmesh-official/acme.sh/issues/6165
2026-07-05 15:44:26 +08:00
neil 77047eb0ef fix CSR reading on systems without a default openssl.cnf (e.g. NetBSD)
"openssl req -noout -in" aborts when the default config file is missing;
reading a CSR needs no config, so pass -config /dev/null explicitly.

Stock NetBSD does not install /etc/openssl/openssl.cnf, so --signcsr
never worked there.
2026-07-04 23:55:16 +08:00
neil 4978782fb8 renewAll: error out if CERT_HOME is not a directory
With a misconfigured $HOME / CERT_HOME the glob over "$CERT_HOME"/*.*
matches nothing, so renewAll silently does nothing and returns success --
--renew-all / --cron appears to work while renewing no certificates.
Check that CERT_HOME is a directory up front and return 1 with a clear
error instead.

Closes #4508
2026-07-04 23:40:31 +08:00
neil 9764f67619 dns_cn: convert IDN domain to punycode before API calls
Core-Networks' API rejects Unicode domain names with "invalid domain";
it requires punycode. dns_cn_add / dns_cn_rm passed the raw challenge
domain straight through, so IDN certs failed at the TXT add step
(issue #4804). Run fulldomain through _idn() in both functions. For
ASCII/punycode input _idn() is a pass-through, so non-IDN domains are
unaffected.

Fixes #4804
2026-07-04 21:58:57 +08:00
neil 988afd0f59 _isIPv4: do not glob segments, require exactly 4 octets
The unquoted splitting let a "*" segment expand against files in the
current directory, so "*.*.*.*" could pass as a valid IPv4 address
(issue 4971). The old code also accepted "", "1.2.3", "1.2.3.4.5",
"1..2.3" and bare numbers. Split with IFS under set -f, require 4
octets, and validate each as a 1-3 digit number <= 255.

Based on https://github.com/acmesh-official/acme.sh/pull/4974
fix https://github.com/acmesh-official/acme.sh/issues/4971
2026-07-04 21:34:46 +08:00
neil fbf3b41c54 dns_inwx: fix _get_root false zone match for single-letter subdomains
_get_root matched the candidate zone with _contains (grep), which treats
the domain as a regex. For "-d g.<zone>" the candidate "g.<zone>" matched
"<string>...<zone>" because '.' matches the '>' after "string" and the 'g'
comes from the "<string>" tag, so "g.<zone>" was wrongly taken as the root
zone (sub=_acme-challenge instead of _acme-challenge.g). Anchor the match
to <string>$h</string> and escape dots so the zone is compared literally.

Fixes #5129
2026-07-04 20:28:56 +08:00
neil ede9a86d46 Accept both 401 and 403 for deactivated account detection
RFC 8555 sec 7.3.6 requires 401 (Unauthorized) when a request is
signed by a deactivated account, which ZeroSSL follows, while
Boulder (Let's Encrypt) historically returns 403. Check both codes
in _regAccount and deactivateaccount.

fix https://github.com/acmesh-official/acme.sh/issues/5138
2026-07-04 20:21:27 +08:00
neil d3e12694b9 fix "identifiers are duplicated" when signing a CSR with a wildcard CN also present in SAN
_contains matches with grep regex, so the '*' in "DNS:*.example.com," never
matched and the subject was appended to the identifiers a second time.
Escape the wildcard before the check, the same way the sed removal already does.

fix https://github.com/acmesh-official/acme.sh/issues/5251
2026-07-04 19:56:37 +08:00
neil a105126063 _date2time: pass date via argv to python to prevent code injection (#6463)
https://github.com/acmesh-official/acme.sh/issues/6463
2026-07-04 19:14:36 +08:00
neil 917bebd460 dns_huaweicloud: add optional HUAWEICLOUD_Region (default ap-southeast-1)
The DNS endpoint and IAM token scope project were hardcoded to
ap-southeast-1, which fails for accounts without that region enabled.

fix https://github.com/acmesh-official/acme.sh/issues/5302
2026-07-04 19:06:46 +08:00
neil bcbfe25d08 haproxy.sh: use two-argument -header form for LibreSSL (#3438) 2026-07-04 18:50:29 +08:00
neil bbfb6f50ae deploy/cpanel_uapi: strip YAML double quotes around wildcard domains in list_domains output
fix https://github.com/acmesh-official/acme.sh/issues/6115
2026-07-04 18:46:59 +08:00
neil 6df2d9e451 dns_da: document that special characters in DA_Api credentials must be percent-encoded
https://github.com/acmesh-official/acme.sh/issues/3468
2026-07-04 18:19:45 +08:00
neil 1a36823461 https://github.com/acmesh-official/acme.sh/issues/3201 2026-07-04 16:55:49 +08:00
neil 7653eaab31 fix https://github.com/acmesh-official/acme.sh/issues/4879#issuecomment-2942728895 2026-07-04 11:44:32 +08:00
neil 6cd0c00a21 extract authorizations parsing into _authorizations_from_order, fix IPv6 urls (#6326) 2026-07-04 11:23:11 +08:00
neil b4de9e8621 fix docker deploy hook on podman, check exec ExitCode instead of response body (#4977) 2026-07-04 10:49:32 +08:00
neil 0a6abaf8a1 fix https://github.com/acmesh-official/acme.sh/issues/6388 2026-07-04 00:39:52 +08:00
neil 0df051577c fix https://github.com/acmesh-official/acme.sh/issues/6609 2026-07-04 00:06:26 +08:00
neil 7fb40f0ccf fix https://github.com/acmesh-official/acme.sh/issues/6609 2026-07-03 23:55:23 +08:00
neil 780f2ad5dc dns_ali: do not rely on "_url_encode upper-hex" so the signature works with older bundled libraries (e.g. Proxmox VE) https://github.com/acmesh-official/acme.sh/issues/6272 2026-07-03 23:44:22 +08:00
neil ac5624536b dns_gd: fix root zone detection for API-restricted accounts https://github.com/acmesh-official/acme.sh/issues/4487 2026-07-03 23:34:27 +08:00
neil b974bbd6d6 fix upgrade with a relative --home path https://github.com/acmesh-official/acme.sh/issues/6477 2026-07-03 23:34:27 +08:00
neil 20254cbaf0 dns_dnsimple: support user tokens (dnsimple_u_*) https://github.com/acmesh-official/acme.sh/issues/6491 2026-07-03 23:02:35 +08:00
neil f4d2db64ef dns_gd: skip readback check when GoDaddy API returns UNKNOWN_DOMAIN https://github.com/acmesh-official/acme.sh/issues/6517 2026-07-03 22:49:40 +08:00
neil 92a1b47108 forbid spaces in the --home/--config-home path https://github.com/acmesh-official/acme.sh/issues/2163 2026-07-03 22:26:50 +08:00
neil 5038d12d62 forbid using --days together with --valid-to https://github.com/acmesh-official/acme.sh/pull/6572 2026-07-03 21:55:37 +08:00
neil 92bd80c07d fix https://github.com/acmesh-official/acme.sh/issues/6914 2026-07-03 20:07:42 +08:00
neil ad99628e50 fix https://github.com/acmesh-official/acme.sh/issues/6917 2026-07-03 20:04:32 +08:00
neil eabd23a551 fix https://github.com/acmesh-official/acme.sh/issues/6963 2026-07-03 19:38:42 +08:00
neil 1241649501 fix https://github.com/acmesh-official/acme.sh/issues/7009 2026-07-03 19:38:21 +08:00
neil 9900adb007 fix https://github.com/acmesh-official/acme.sh/issues/4756 2026-07-03 19:01:10 +08:00
neil 116c05fbff fix https://github.com/acmesh-official/acme.sh/issues/6400 2026-07-02 23:30:56 +08:00
neil 42e13fa797 fix https://github.com/acmesh-official/acme.sh/issues/6851 2026-07-02 23:18:26 +08:00
neil ccd2f04c33 fix https://github.com/acmesh-official/acme.sh/issues/6986 2026-07-02 23:15:41 +08:00
neil e52d75d762 fix https://github.com/acmesh-official/acme.sh/issues/7062 2026-07-02 13:09:59 +08:00
neil 81100db2f3 fix https://github.com/acmesh-official/acme.sh/issues/6498 2026-07-01 21:59:41 +08:00
neil a7ccfcf91d fix 2026-07-01 21:33:24 +08:00
neil d0fcafe29b fix https://github.com/acmesh-official/acme.sh/issues/7035 2026-07-01 21:22:36 +08:00
neil c38182897d fix ghostbsd 2026-07-01 18:59:14 +08:00