Closes#34749, closes#59722.
All outbound BlueBubbles HTTP calls now route through a single typed
BlueBubblesClient that resolves SSRF policy and auth material once
at construction, instead of each of the 17 callsites computing its
own SsrFPolicy and threading it through blueBubblesFetchWithTimeout.
Three-mode policy resolved in one place (previously inlined in
attachments.ts only):
1. { allowPrivateNetwork: true } — user opted in
2. { allowedHostnames: [trustedHost] } — narrow allowlist
3. undefined — non-SSRF fallback path
Pluggable auth via BlueBubblesAuthStrategy so the ?password= →
header-auth switch (#66869) becomes a one-line default flip.
downloadAttachment threads this.ssrfPolicy to BOTH fetchRemoteMedia
AND the fetchImpl callback, closing #34749 where the legacy helper
silently omitted the policy on the callback path. reactions.ts now
uses the same policy as every other call, closing #59722 where the
asymmetric `{}` fallback blocked private-IP BB deployments.
Monitor test files install the shared SSRF-guard passthrough to
accommodate the guarded request path — required because the
consolidation moves callers from the unguarded fallback onto the
mode-2 allowlist by default for self-hosted BB servers.
Net: +171 / -310 LOC across BB files; BB test suite stays green
at 462/462. Lint clean. pnpm tsgo and pnpm build have pre-existing
unrelated errors on origin/main (codex/discord/qa-lab and
amazon-bedrock-mantle runtime-deps staging) — both identical on clean
main before this branch.
Future-proofed (not flipped here):
- #66869 header auth cutover (one-line default change)
- #67752 SSRF tightening (now single-point-of-change)