Using websocket-rails, I can use the following code in my controller to tricker a websocket publish event:
WebsocketRails[:channel_name].trigger('event_name', { foo: "bar" }.to_json)
My goal is to create a pub-sub channel for the current user only. Take for example the event "new chat message sent". I want to push this event only the receiver's channel.
I'm currently making a unique channel name for each user based on their ID. I put the following code in my controller (having defined a current_user method elsewhere:
WebsocketRails[:"user#{current_user.id}"].trigger("event_name", { foo: "bar" }.to_json)
And then in my Javascript, I subscribe the current user to their own channel with the following:
<% if @current_user %>
var dispatcher = new WebSocketRails('localhost:3000/websocket');
channel = dispatcher.subscribe('user<%= @current_user.id %>');
channel.bind('event_name', function(data) {
console.log(data)
});
<% end %>
The gist of it is using string interpolation to make a new channel for each user, i.e.
user12
and user123
channels.
The problem is this is not really secure. Any user can access anyone else's
private channel just by pasting some Javascript in. For example, if user #1 wants
to access user #2's news feed, they could just type dispatcher.subscribe('user2')
.
How would you solve this issue? Is there another pub-sub library which has this feature built into it?
Looking on WebsocketRails' wiki entry on the subject, I tried adding the follolwing code to config/initializers/websockets.rb
WebsocketRails::EventMap.describe do
namespace :websocket_rails do
subscribe :subscribe_private, to: ConnectionsController, with_method: :authorize_channels
end
end
And the following to app/controllers/connections_controller.rb
class ConnectionsController < WebsocketRails::BaseController
def authorize_channels
channel_name = WebsocketRails[message[:channel]]
current_user = User.find_by(id: session["current_user_id"])
if current_user && "user#{current_user.id}".eql?(channel_name)
accept_channel current_user
else
deny_channel({ message: "auth failed" })
end
end
end
And then elsewhere, I'm calling WebsocketRails[:"user#{@current_user.id}"].make_private
This doesn't seem to have any effect though.