Skip to content

Commit

Permalink
fixup! Allow the application to configure Turbo::StreamChannel’s inhe…
Browse files Browse the repository at this point in the history
…ritance

`ApplicationCable::Connection` allows the application to apply
authentication to all streams method, including those from
`Turbo::Broadcastable`.

By allowing `Turbo::StreamsChannel` to inherit from
`ApplicationCable::Channel` we open up a symmetrical path for
authorization.

In the spirit of being secure by default we should be moving towards
making `Turbo.base_stream_channel_class` default to
`"ApplicationCable::Channel"` but doing so without warning would break
applications relying on `ApplicationCable::Connection#authorized?` for
non-turbo broadcastable streams only.

Once we deem it safe we can remove the awkward initialiser and hard code
`ApplicationCable::Channel` as the super class. If people needs
different super classes for `Turbo::StreamsChannel` and custom channels
they can simply add another super class to inherit from in their
application.
  • Loading branch information
ramhoj committed Oct 22, 2024
1 parent 5c8196d commit 5731946
Showing 1 changed file with 22 additions and 18 deletions.
40 changes: 22 additions & 18 deletions test/streams/streams_channel_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -346,28 +346,32 @@ class Turbo::StreamsChannelTest < ActionCable::Channel::TestCase
end

test "confirms subscription when succeeding authorization" do
board = Board.create!(name: "A")
original_authorized = Turbo::StreamsChannel.instance_method(:authorized?)
Turbo::StreamsChannel.define_method(:authorized?) { streamable.name == "A" }
authorizing do |record|
Turbo::StreamsChannel.define_method(:authorized?) { streamable.name == record.name }
subscribe signed_stream_name: signed_stream_name(record)

subscribe signed_stream_name: signed_stream_name(board)

assert subscription.confirmed?
assert_has_stream board.to_gid_param
ensure
Turbo::StreamsChannel.define_method :authorized?, original_authorized
assert subscription.confirmed?
assert_has_stream record.to_gid_param
end
end

test "rejects subscription when failing authorization" do
board = Board.create!(name: "A")
original_authorized = Turbo::StreamsChannel.instance_method(:authorized?)
Turbo::StreamsChannel.define_method(:authorized?) { streamable.name == "B" }

subscribe signed_stream_name: signed_stream_name(board)
authorizing do |record|
Turbo::StreamsChannel.define_method(:authorized?) { streamable.name != record.name }
subscribe signed_stream_name: signed_stream_name(record)

assert subscription.rejected?
assert_no_streams
ensure
Turbo::StreamsChannel.define_method :authorized?, original_authorized
assert subscription.rejected?
assert_no_streams
end
end

private
def authorizing
record = Board.create!(name: "Some name")
original_authorized = Turbo::StreamsChannel.instance_method(:authorized?)
yield record
ensure
Turbo::StreamsChannel.define_method :authorized?, original_authorized
record.destroy
end
end

0 comments on commit 5731946

Please sign in to comment.