Commit Graph
3 Commits
  • unifios: extract JSON-split helper, document RSA/ECC name collision (#7200)
    * Extract _uos_split_json helper, document RSA/ECC name-prefix collision
    
    Per neilpang's non-blocking review notes on #7184: the _normalizeJson +
    split-into-lines block was duplicated at both call sites, now shared via
    _uos_split_json(). Also documents (without changing behavior, since it's
    harmless today) that an RSA and ECC deploy of the same domain share the
    generated name's prefix, each removing the other's entry on cleanup --
    citing haproxy.sh/lighttpd.sh's existing .rsa/.ecdsa suffix pattern as
    the fix if this ever needs addressing.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    
    * Replace grep -F with a portable matcher, fix RSA/ECC name collision
    
    grep -F isn't on Solaris, and dropping it naively breaks matching:
    wildcard domains and dots collide as regex. _uos_grep_literal replaces
    both call sites with a case-based literal match instead.
    
    _uos_name now includes the key type, so RSA and ECC deploys of the
    same domain no longer share a cleanup scope.
    
    Per neilpang's review on #7200.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    
    * Fix echo's \n handling in _uos_grep_literal, drop unneeded Le_Keylength guard
    
    echo does not behave consistently across different environments. dash
    interprets literal \n in a line, splitting it.  printf '%s\n' does not and matches
    _uos_split_json's existing pattern. printf behaves more consistently across
    environments and is generally preferred over echo.
    
    Le_Keylength guard was a no-op and didn't help under set -u either;
    _isEccKey already handles empty. Kept the shellcheck warning suppressed
    inline instead of assigning to a core Le_* var.
    
    Per neilpang's review on #7200.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    
    ---------
    
    Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
  • deploy/unifios: document UniFi OS hardware support, not just self-hosted
    The certificate REST API this hook drives is UniFi OS's own, not
    specific to the self-hosted UniFi OS Server: user reports confirm it on
    a UDM Pro (UniFi OS 5.1.26) and a UCG Fiber (5.0.16). Reframe the scope
    around the endpoint rather than the product line, state that the choice
    between unifi and unifios is local/SSH file access vs remote REST API,
    and note that the management port is 11443 on UniFi OS Server but 443
    on hardware, so DEPLOY_UNIFIOS_HOST must be set there.
  • Add UniFi OS Server deploy hook (#7184)
    * Add UniFi OS Server deploy hook
    
    Uses UniFi OS Server's local REST API (login, list, upload, activate,
    remove superseded) since it stores certificates in its own Postgres
    database rather than flat config files, unlike the Cloud Key/UDM
    hardware covered by the existing unifi deploy hook. Tested against
    real instances on both macOS and Ubuntu 26.04 (self-hosted, remote).
    
    * Address review: portable sed/grep, scoped HTTPS_INSECURE, fingerprint matching
    
    - Replace GNU-only \n in sed replacement with a portable literal newline
      (matches dnsapi/dns_cpanel_uapi.sh, dnsapi/dns_glesys.sh); pipe the
      list response through _normalizeJson first for consistent formatting.
    - Use grep -F for the domain-name match instead of an unescaped BRE --
      a wildcard cert name (*.example.com) broke the regex.
    - Drop \W (undocumented, GNU-only) from the cookie lookup in favor of
      an anchored `^Set-Cookie: *NAME=` match.
    - Scope HTTPS_INSECURE=1 inside the hook (matches deploy/proxmoxve.sh,
      deploy/fritzbox.sh) instead of requiring the caller to export it for
      the whole acme.sh run, which would also disable verification for the
      connection to the ACME CA.
    - On a duplicate-certificate response, match the existing entry by
      fingerprint instead of taking the first name match -- with more than
      one stale entry for a domain, the wrong one could get activated.
    - Check the list endpoint's response code before proceeding.
    - Save username/password with the "base64" flag (matches
      deploy/synology_dsm.sh) since _save_conf wraps values in unescaped
      single quotes.
    
    * Rework certificate handling: unique names per upload, drop cleanup
    
    Testing against a real UniFi OS Server showed the server enforces name
    uniqueness independently of fingerprint uniqueness, and that activation is
    exclusive server-wide regardless of name/domain. A unique name per upload
    avoids the name-collision path entirely (previously only handled as a
    retry-of-identical-content edge case), and removes the need for the
    post-hoc cleanup loop, which risked deleting the wrong entry.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    
    * Shorten generated certificate name to Unix epoch seconds
    
    Real-hardware testing showed the UniFi OS Server certificate list's name
    column is fixed-width and doesn't wrap, so a full human-readable timestamp
    overlaps the Expires column and makes both unreadable. Epoch seconds are
    still short enough to fit while remaining unique.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    
    * Add scoped cleanup of old certificate entries, use _time helper
    
    Per review: dropping cleanup entirely went further than the original bug
    required, and left old entries (each holding a private key) accumulating
    indefinitely. Since every upload now gets a name unique to its domain and
    run, cleanup can safely target only entries whose name starts with that
    domain -- entries this hook itself created -- excluding the one just
    activated. Also swaps date +%s for the core _time helper, and rewrote the
    design comments to make them clearer and match the current behavior
    instead of the pre-redesign one.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    
    ---------
    
    Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>