4

I am wondering how to limit the connection to a channel or the streaming of messages over a channel in rails5. Currently I groups with users in the groups working with pundit and the connection to the websocket happens within that group. If a malicious user randomly guessed groups they could potentially read a message over a socket they shouldn't.

When you create a new message the following code is run in my controller:

if message.save
    ActionCable.server.broadcast(
        "messages_{message.groupchat_id}_channel",
        message: message.content,
        user: message.user.email
    )
    head :ok
end

I have no idea what I'm doing.

Prabhakar Poudel
  • 339
  • 7
  • 19
Billy Ferguson
  • 1,429
  • 11
  • 23

2 Answers2

4

Here's the solution I found to use Pundit with Activecable.

First we need access to the user model. You can do that by following the instructions in the Action Cable Overview - Connection Setup. Mainly you need to change the code in connection.rb

# app/channels/application_cable/connection.rb
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user
     
    def connect
      self.current_user = find_verified_user
    end
     
    private
    def find_verified_user
       if verified_user = User.find_by(id: cookies.encrypted[:user_id])
          verified_user
        else
          reject_unauthorized_connection
        end
     end
  end
end

Note: you may need to use a different way of finding your user. I'm using devise_token_auth and so needed to pass the uid, token, and client_id to the connection.rb and then got the user via this code:

if user && user.valid_token?(token, client_id)
  user
else
  reject_unauthorized_connection
end

I mention this just because how you get your user may vary. The main thing is that you need to use identified_by current_user and set it.

Another thing which I did not immediately find in the documentation, is that the current_user is now accessible by your channels. Since the user name may be different than your pundit_user name, I found it easiest to manually pass the user to Pundit at that point. So in subscribing with my channel file, I had this code:

def subscribed
  message = MessagePolicy::Scope.new(self.current_user, Project).resolve.find(params[:message])
  stream_for message
end

You could of course also manually authorize this way, instead of using Scope:

MessagePolicy.new(self.current_user, message).show?
Prabhakar Poudel
  • 339
  • 7
  • 19
Alex
  • 1,977
  • 3
  • 13
  • 20
-2

You can add another layer of security for actioncable connections in app/channels/application_cable/connection.rb file.

You can follow this tutorial. I think this give you some idea: https://www.learnenough.com/action-cable-tutorial#sec-login_protection

ritzz.soni
  • 335
  • 1
  • 15