@@ -89,35 +89,13 @@ defmodule RealtimeWeb.RealtimeChannel do
8989 socket = assign_authorization_context ( socket , sub_topic , claims ) ,
9090 { :ok , db_conn } <- Connect . lookup_or_start_connection ( tenant_id ) ,
9191 { :ok , socket } <- maybe_assign_policies ( sub_topic , db_conn , socket ) ,
92+ :ok <- can_replay? ( params [ "config" ] , sub_topic , socket ) ,
9293 { :ok , replayed_message_ids } <-
9394 maybe_replay_messages ( params [ "config" ] , sub_topic , db_conn , tenant_id , socket . assigns . private? ) do
9495 tenant_topic = Tenants . tenant_topic ( tenant_id , sub_topic , ! socket . assigns . private? )
9596
96- # presence.read gate carried in the fastlane metadata so the dispatcher can withhold
97- # presence_diff from members denied presence.read:
98- # * public channel (no policies) -> true (no presence authorization, always receive diffs)
99- # * private + presence enabled at join -> the authorized presence.read value (true/false)
100- # * private + presence not enabled -> nil (read not evaluated yet). The dispatcher routes
101- # these diffs to the channel process (handle_info) instead of fastlaning, where presence.read
102- # is consulted at delivery time (it is authorized on-demand when presence is auto-enabled via
103- # a track message - see PresenceHandler).
104- presence_read? =
105- case socket . assigns . policies do
106- nil -> true
107- % Policies { presence: % { read: read } } -> read
108- end
109-
11097 # fastlane subscription
111- metadata =
112- MessageDispatcher . fastlane_metadata (
113- transport_pid ,
114- serializer ,
115- topic ,
116- log_level ,
117- tenant_id ,
118- replayed_message_ids ,
119- presence_read?
120- )
98+ metadata = fastlane_metadata ( socket , replayed_message_ids )
12199
122100 RealtimeWeb.Endpoint . subscribe ( tenant_topic , metadata: metadata )
123101 RealtimeWeb.Endpoint . subscribe ( "realtime:operations:" <> tenant_id , metadata: metadata )
@@ -152,7 +130,9 @@ defmodule RealtimeWeb.RealtimeChannel do
152130 self_broadcast: Join . self_broadcast? ( join ) ,
153131 tenant_topic: tenant_topic ,
154132 channel_name: sub_topic ,
155- presence_enabled?: presence_enabled?
133+ presence_enabled?: presence_enabled? ,
134+ fastlane_metadata: metadata ,
135+ replayed_message_ids: replayed_message_ids
156136 }
157137
158138 assigns =
@@ -350,7 +330,10 @@ defmodule RealtimeWeb.RealtimeChannel do
350330 end
351331 end
352332
353- def handle_info ( _msg , % { assigns: % { policies: % Policies { broadcast: % BroadcastPolicies { read: false } } } } = socket ) do
333+ def handle_info (
334+ % { event: "broadcast" } ,
335+ % { assigns: % { policies: % Policies { broadcast: % BroadcastPolicies { read: false } } } } = socket
336+ ) do
354337 Logger . warning ( "Broadcast message ignored" )
355338 { :noreply , socket }
356339 end
@@ -572,6 +555,8 @@ defmodule RealtimeWeb.RealtimeChannel do
572555 { :ok , db_conn } <- Connect . lookup_or_start_connection ( tenant_id ) ,
573556 { :ok , socket } <- maybe_assign_policies ( channel_name , db_conn , socket ) ,
574557 :ok <- check_read_permissions_revoked ( previous_policies , socket . assigns . policies ) do
558+ socket = maybe_resubscribe_fastlane ( socket )
559+
575560 Helpers . cancel_timer ( pg_sub_ref )
576561 pg_change_params = Enum . map ( pg_change_params , & Map . put ( & 1 , :claims , claims ) )
577562
@@ -989,9 +974,11 @@ defmodule RealtimeWeb.RealtimeChannel do
989974 ) do
990975 socket = assign ( socket , :policies , policies )
991976
992- if match? ( % Policies { broadcast: % BroadcastPolicies { read: false } } , socket . assigns . policies ) ,
993- do: { :error , :unauthorized , "You do not have permissions to read from this Channel topic: #{ topic } " } ,
994- else: { :ok , socket }
977+ % Policies { broadcast: % { read: broadcast_read? } , presence: % { read: presence_read? } } = socket . assigns . policies
978+
979+ if broadcast_read? || presence_read? ,
980+ do: { :ok , socket } ,
981+ else: { :error , :unauthorized , "You do not have permissions to read from this Channel topic: #{ topic } " }
995982 else
996983 { :error , :increase_connection_pool } ->
997984 { :error , :increase_connection_pool }
@@ -1011,6 +998,53 @@ defmodule RealtimeWeb.RealtimeChannel do
1011998
1012999 defp maybe_assign_policies ( _ , _ , socket ) , do: { :ok , assign ( socket , policies: nil ) }
10131000
1001+ # presence.read gate carried in the fastlane metadata so the dispatcher can withhold
1002+ # presence_diff from members denied presence.read:
1003+ # * public channel (no policies) -> true (no presence authorization, always receive diffs)
1004+ # * private + presence enabled at join -> the authorized presence.read value (true/false)
1005+ # * private + presence not enabled -> nil (read not evaluated yet). The dispatcher routes
1006+ # these diffs to the channel process (handle_info) instead of fastlaning, where presence.read
1007+ # is consulted at delivery time (it is authorized on-demand when presence is auto-enabled via
1008+ # a track message - see PresenceHandler).
1009+ defp fastlane_metadata ( socket , replayed_message_ids ) do
1010+ % { assigns: % { tenant: tenant_id , log_level: log_level , policies: policies } } = socket
1011+
1012+ MessageDispatcher . fastlane_metadata (
1013+ socket . transport_pid ,
1014+ socket . serializer ,
1015+ socket . topic ,
1016+ log_level ,
1017+ tenant_id ,
1018+ replayed_message_ids ,
1019+ if ( policies , do: policies . presence . read , else: true ) ,
1020+ if ( policies , do: policies . broadcast . read , else: true )
1021+ )
1022+ end
1023+
1024+ defp maybe_resubscribe_fastlane ( socket ) do
1025+ % { assigns: % { fastlane_metadata: current , tenant: tenant_id , tenant_topic: tenant_topic } } = socket
1026+
1027+ case fastlane_metadata ( socket , socket . assigns . replayed_message_ids ) do
1028+ ^ current ->
1029+ socket
1030+
1031+ updated ->
1032+ for pubsub_topic <- [ tenant_topic , "realtime:operations:" <> tenant_id ] do
1033+ RealtimeWeb.Endpoint . unsubscribe ( pubsub_topic )
1034+ RealtimeWeb.Endpoint . subscribe ( pubsub_topic , metadata: updated )
1035+ end
1036+
1037+ assign ( socket , :fastlane_metadata , updated )
1038+ end
1039+ end
1040+
1041+ defp can_replay? ( % { "broadcast" => % { "replay" => _ } } , topic , % {
1042+ assigns: % { policies: % Policies { broadcast: % BroadcastPolicies { read: false } } }
1043+ } ) ,
1044+ do: { :error , :unauthorized , "You do not have permissions to read from this Channel topic: #{ topic } " }
1045+
1046+ defp can_replay? ( _config , _topic , _socket ) , do: :ok
1047+
10141048 # Detects read permissions that were granted under the previous token but are no longer allowed
10151049 # after re-evaluating the policies with the new token. When that happens we disconnect the channel.
10161050 defp check_read_permissions_revoked ( % Policies { } = previous , % Policies { } = current ) do
0 commit comments