* Harden DirectAdmin GET requests and assertions
- Avoid trailing ? on empty GET query strings
- Send only user param for CMD_API_SHOW_USER_CONFIG
- Assert exact user key and package path in tests
* Address review nits: exact query and no-query assertions
* Refactor getLoginUrl and improve error handling
* Replace error_log with getLog()->error
* Fall back to the plain CWP panel URL when SSO is unavailable
The auto-login endpoint is not available on every API key, so a failed
user_session request must not break the login button. Mirror the WHM
manager: log the failure (username only, never tokens or URLs) and
return the standard panel URL.
Use timer 5, matching CWP's own WHMCS module, and cover the new
behaviour with unit tests.
* Reuse the CWP test manager helper for the session request test
* Handle transport failures and non-string session URLs in CWP login
Convert Symfony transport exceptions into Server_Exception so every
CWP request failure funnels through the plain panel URL fallback,
and only accept a non-empty string session URL.
* Bound the CWP session request duration
Limit user_session to 10s idle / 20s total so a hung panel fails fast
to the manual login URL instead of stalling the page load. Other
operations keep the existing client defaults.
---------
Co-authored-by: Adam Daley <admdly@users.noreply.github.com>
* Fix WHM activation failing when package already exists (#4560)
- Request listpkgs with want=all and parse both legacy package and modern data.pkg shapes
- On addpkg already-exists, sync via editpkg and continue; only block activation on other errors
- Include WHM reason in Server_Exception and fix placeholder keys
* Add WHM API terms to spellcheck dictionary
* Address review: use typed exception for WHM already-exists, keep reasons out of API errors
- Add Server_PackageExistsException; request() now throws generic messages and translates already-exists at the WHM boundary
- checkPackageExists() catches the typed exception instead of matching getMessage()
* Fix Rector findings: remove unused catch variable and setAccessible call
* Handle modern WHM metadata.result failures in Whm::request
---------
Co-authored-by: opencode <opencode@localhost>
- Servicedomain order validation accepts the product context like
its sibling service modules, fixing a TypeError when ordering
domains through the cart. Fixes FOSSBILLING-Q0R.
- cPanel account sync casts the suspended flag to bool, fixing a
TypeError when the API reports it as an integer.
Fixes FOSSBILLING-N3T.
* Harden URL, mail, and locale handling
* Keep Sentry hardening mail test offline with unsupported DSN scheme
* Move Sentry regression tests into their module test files
* Drop Sentry issue IDs from regression test names
* Drop Sentry issue ID from Twig cache failure test name
* Drop Sentry issue IDs from test comments
Fix TypeError in Server_Manager::getPasswordLength()
_config['passwordLength'] is untyped, and stored server configs have
been observed carrying a numeric string rather than an int, which
violates this method's declared int return type. Cast defensively at
the boundary.
Confirmed live via Sentry (FOSSBILLING-MZA): ~7,800 occurrences since
June, still ongoing, always fatal to the whole cron run because the
error propagates out of order activation uncaught.
* Fix WHM reseller accounts always getting an empty ACL list
Server_Manager_Whm::createAccount() called $package->getAcllist(),
but Server_Package has never had that method. Its __call() silently
swallows calls to undefined methods and returns '', so every reseller
account created via WHM had setacls called with an empty acllist -
wiping out the initial privileges WHM had just granted via
setupreseller.
Wire the ACL list through the existing custom-value mechanism instead
(same pattern already used for cgi, cpmod, maxlst, hasshell), and skip
the setacls call entirely when the hosting plan defines no 'acl'
custom value, so the reseller keeps WHM's default privileges instead
of having them stripped.
Fixes#4173
* Whitelist WHM API action names for cspell
src/library/Server/Manager/** is excluded from spellcheck entirely, so
Whm.php's own use of these WHM API1 action/field names never tripped
the checker. tests/Unit/Server/Manager/WhmTest.php isn't under that
exclusion, so add the same words DirectAdmin's custom-value keys
already use this pattern for (listpkgs, addpkg, createacct,
setupreseller, setacls, acllist) to cspell.json's ignoreWords.
* Plesk module creates the account, the subscription but the plan i...
Server_Manager_Plesk::createSubscriptionProps() built the webspace add/set request from custom hosting/limits/permissions values but never told Plesk which service plan to assign, so accounts were provisioned outside of any named plan; the fix adds the FOSSBilling hosting plan's name as the request's plan-name, matching how every other adapter (CWP, DirectAdmin, Hestia, WHM) already passes the package name through.
* 🐛 Don't send plan-name on Plesk subscription updates
CodeRabbit correctly flagged that Plesk's webspace/set schema has no plan-related
node at all (unlike add, which supports plan-name/plan-id/plan-guid/plan-external-id).
Sending plan-name through changeAccountPackage() -> webspace/set would have hit the
same XSD-sequence rejection as the original ordering bug, just for a different
reason -- an element Plesk doesn't recognize there at all.
plan-name now stays scoped to the add path only, matching the same conditional
pattern already used for htype. Changing an existing subscription's assigned plan
isn't supported by this code path; that would need a separate switch-subscription
operation (plan-guid/plan-external-id), which is out of scope for #2799.
---------
Co-authored-by: Adam Daley <admdly@users.noreply.github.com>
* 🐛 Fix Plesk subscription updates sending an invalid webspace 'set' request
Server_Manager_Plesk::createSubscriptionProps() built the same gen_setup/hosting/limits/permissions
payload for both the 'add' and 'set' webspace operations and placed it directly under the action
node. Plesk's API requires 'set' requests to wrap those settings in <filter> (which subscription to
update) and <values> nodes instead, and its update schema (SetGenSetupType) doesn't accept the
'htype' element that creation does. As written, every call to updateSubscription() (invoked from
changeAccountPackage() when a client's plan changes) sent Plesk a request it would reject.
This only affects the 'set' path; 'add' already matched Plesk's schema for subscription creation.
* 📝 Add 'htype' to cspell word list
src/library/Server/Manager/** is excluded from spellcheck, so this Plesk API field name was
never flagged there, but tests/Unit/Server/Manager/PleskTest.php isn't excluded and now
references it directly.
* 🐛 Filter Plesk webspace 'set' requests by domain, not owner-login
CodeRabbit correctly flagged that filtering by 'owner-login' matches every webspace
a customer owns; Plesk's 'set' operation applies the whole <values> block to every
webspace the filter matches. For a customer with more than one subscription, both
updateSubscription() (createSubscriptionProps 'set') and the pre-existing
changeAccountDomain() would silently overwrite limits/permissions/domain on
subscriptions other than the one being changed.
Filter by 'name' (the domain) instead, matching the single-subscription scoping
deleteSubscription() already uses. changeAccountDomain() now captures the current
domain before setDomain() overwrites it, since it needs the old value for the filter
and the new value for gen_setup.
Also added 'webspace'/'webspaces' to the cspell word list alongside 'htype', for the
same reason as the prior commit -- tests/Unit/Server/Manager isn't spellcheck-exempt.
* 🧹 Assert full gen_setup key order for the add action in PleskTest
Per CodeRabbit nitpick: the test checked htype's presence but not that it's
positioned between owner-login and ip_address as the docblock claims.
* 🧹 Trim redundant comment in createSubscriptionProps
The 'set' branch repeated the filter/values explanation already given in the
method's docblock; kept only the owner-login-vs-name rationale, which was the
actual new information.
* Apply suggested fix to tests/Unit/FOSSBilling/RateLimiterTest.php from Copilot Autofix
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
* Apply suggested fix to tests/Unit/FOSSBilling/RateLimiterTest.php from Copilot Autofix
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
* Apply suggested fix to src/library/Server/Manager/Directadmin.php from Copilot Autofix
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
* Apply suggested fix to tests/Unit/FOSSBilling/Api/AbstractApiTest.php from Copilot Autofix
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
* Remove tests path from CODEOWNERS
* Apply suggested fix to src/modules/Order/Service.php from Copilot Autofix
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
* Fix uncancel emails and zero-credit payments
* Preserve orders when invoice generation fails
* Fix RateLimiterTest CI failures from prior autofix commits
- Add a public RateLimiter::getStatus() so tests can read the token
limit for a policy without hardcoding it (getRateLimitState() now
reuses it).
- Fix consumeOrThrow test's toThrow() call: Pest expects the assertion
closure as the first argument (with the exception type-hinted), not
as a second argument alongside the class string.
* Fix DirectAdmin apostrophe entity decoding to avoid trailing semicolon
str_replace(''', "'", $data) also matched the fully-terminated
' entity, replacing just the ' part and leaving the semicolon
behind (e.g. "O'Brien" became "O';Brien"). Replace the terminated
form first, then the legacy unterminated form, so both decode to a
plain apostrophe.
* Fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>