mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Add tests for channel conversion and event handling in Messaging
- Implement `test_convert_channels_rewrites_account_action_suffixes` to ensure that account action suffixes are correctly rewritten to user-scoped channels. - Add `test_convert_channels_drops_account_actions_for_guest` to verify that account actions are dropped for guests without a user ID. - Introduce `test_from_payload_does_not_suffix_account_for_nested_user_events` to confirm that nested user events do not leak action suffixes onto account channels.
This commit is contained in:
@@ -399,7 +399,11 @@ class Realtime extends MessagingAdapter
|
||||
|
||||
/**
|
||||
* Converts the channels from the Query Params into an array.
|
||||
* Also renames the account channel to account.USER_ID and removes all illegal account channel variations.
|
||||
* Also renames the account channel to account.USER_ID, rewrites action-suffixed
|
||||
* account variants (`account.create`, `account.update`, `account.upsert`,
|
||||
* `account.delete`) to `account.USER_ID.{action}` so they match the channels
|
||||
* fromPayload() publishes for top-level user events, and removes all other
|
||||
* illegal account channel variations (e.g. another user's `account.{otherId}`).
|
||||
*/
|
||||
public static function convertChannels(array $channels, string $userId): array
|
||||
{
|
||||
@@ -407,15 +411,26 @@ class Realtime extends MessagingAdapter
|
||||
|
||||
foreach ($channels as $key => $value) {
|
||||
switch (true) {
|
||||
case str_starts_with($key, 'account.'):
|
||||
unset($channels[$key]);
|
||||
break;
|
||||
|
||||
case $key === 'account':
|
||||
if (! empty($userId)) {
|
||||
$channels['account.'.$userId] = $value;
|
||||
}
|
||||
break;
|
||||
|
||||
case \in_array(\substr($key, \strlen('account.')), self::SUPPORTED_ACTIONS, true) && str_starts_with($key, 'account.'):
|
||||
// Translate `account.{action}` into the user-scoped `account.{userId}.{action}`
|
||||
// so a subscriber only receives their own account events. Without the rewrite
|
||||
// the literal `account.{action}` channel would match every user's events.
|
||||
unset($channels[$key]);
|
||||
if (! empty($userId)) {
|
||||
$action = \substr($key, \strlen('account.'));
|
||||
$channels['account.'.$userId.'.'.$action] = $value;
|
||||
}
|
||||
break;
|
||||
|
||||
case str_starts_with($key, 'account.'):
|
||||
unset($channels[$key]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -672,6 +687,21 @@ class Realtime extends MessagingAdapter
|
||||
$action = $parts[$count - 2];
|
||||
}
|
||||
|
||||
// The `users` branch emits only user-level account channels
|
||||
// (`account`, `account.{userId}`) regardless of event depth, so nested events
|
||||
// like `users.U.sessions.S.create` or `users.U.challenges.C.create` would
|
||||
// otherwise be suffixed as `account.create` — making a subscription to
|
||||
// `account.create` receive unrelated session/challenge/recovery/verification
|
||||
// events. Restrict suffixing to top-level user events where the action sits
|
||||
// at parts[2] (`users.U.create`, `users.U.update.email`, etc.).
|
||||
if (
|
||||
$action !== null
|
||||
&& ($parts[0] ?? null) === 'users'
|
||||
&& ($parts[2] ?? null) !== $action
|
||||
) {
|
||||
$action = null;
|
||||
}
|
||||
|
||||
if ($action !== null && ! empty($channels)) {
|
||||
$augmented = $channels;
|
||||
foreach ($channels as $channel) {
|
||||
|
||||
Reference in New Issue
Block a user