spec/acceptance/realtime/presence_spec.rb in ably-0.1.6 vs spec/acceptance/realtime/presence_spec.rb in ably-0.2.0
- old
+ new
@@ -20,11 +20,11 @@
let(:channel_rest_client_one) { client_one.rest_client.channel(channel_name) }
let(:presence_client_one) { channel_client_one.presence }
let(:channel_client_two) { client_two.channel(channel_name) }
let(:presence_client_two) { channel_client_two.presence }
- let(:client_data_payload) { SecureRandom.hex(8) }
+ let(:data_payload) { SecureRandom.hex(8) }
specify 'an attached channel that is not presence maintains presence state' do
run_reactor do
channel_anonymous_client.attach do
presence_anonymous_client.subscribe(:enter) do |presence_message|
@@ -124,11 +124,11 @@
end
end
specify 'verify two clients appear in members from #get' do
run_reactor do
- presence_client_one.enter(client_data: client_data_payload)
+ presence_client_one.enter(data: data_payload)
presence_client_two.enter
entered_callback = Proc.new do
next unless presence_client_one.state == :entered && presence_client_two.state == :entered
@@ -138,11 +138,11 @@
members = presence_client_one.get
member_client_one = members.find { |presence| presence.client_id == client_one.client_id }
member_client_two = members.find { |presence| presence.client_id == client_two.client_id }
expect(member_client_one).to be_a(Ably::Models::PresenceMessage)
- expect(member_client_one.client_data).to eql(client_data_payload)
+ expect(member_client_one.data).to eql(data_payload)
expect(member_client_two).to be_a(Ably::Models::PresenceMessage)
stop_reactor
end
end
@@ -156,11 +156,11 @@
run_reactor do
client_two_subscribe_messages = []
subscribe_client_one_leaving_callback = Proc.new do |presence_message|
expect(presence_message.client_id).to eql(client_one.client_id)
- expect(presence_message.client_data).to eql(client_data_payload)
+ expect(presence_message.data).to eql(data_payload)
expect(presence_message.action).to eq(:leave)
stop_reactor
end
@@ -169,48 +169,190 @@
expect(presence_message.action).to eq(:enter)
presence_client_two.unsubscribe &subscribe_self_callback
presence_client_two.subscribe &subscribe_client_one_leaving_callback
- presence_client_one.leave client_data: client_data_payload
+ presence_client_one.leave data: data_payload
end
end
presence_client_one.enter do
presence_client_two.enter
presence_client_two.subscribe &subscribe_self_callback
end
end
end
- specify 'verify REST #get returns current members' do
+ specify 'REST #get returns current members' do
run_reactor do
- presence_client_one.enter(client_data: client_data_payload) do
+ presence_client_one.enter(data: data_payload) do
members = channel_rest_client_one.presence.get
this_member = members.first
expect(this_member).to be_a(Ably::Models::PresenceMessage)
expect(this_member.client_id).to eql(client_one.client_id)
- expect(this_member.client_data).to eql(client_data_payload)
+ expect(this_member.data).to eql(data_payload)
stop_reactor
end
end
end
- specify 'verify REST #get returns no members once left' do
+ specify 'REST #get returns no members once left' do
run_reactor do
- presence_client_one.enter(client_data: client_data_payload) do
+ presence_client_one.enter(data: data_payload) do
presence_client_one.leave do
members = channel_rest_client_one.presence.get
expect(members.count).to eql(0)
stop_reactor
end
end
end
end
+ context 'encoding and decoding of presence message data' do
+ let(:secret_key) { SecureRandom.hex(32) }
+ let(:cipher_options) { { key: secret_key, algorithm: 'aes', mode: 'cbc', key_length: 256 } }
+ let(:channel_name) { SecureRandom.hex(32) }
+ let(:encrypted_channel) { client_one.channel(channel_name, encrypted: true, cipher_params: cipher_options) }
+ let(:channel_rest_client_one) { client_one.rest_client.channel(channel_name, encrypted: true, cipher_params: cipher_options) }
+
+ let(:crypto) { Ably::Util::Crypto.new(cipher_options) }
+
+ let(:data) { { 'key' => SecureRandom.hex(64) } }
+ let(:data_as_json) { data.to_json }
+ let(:data_as_cipher) { crypto.encrypt(data.to_json) }
+
+ it 'encrypts presence message data' do
+ run_reactor do
+ encrypted_channel.attach do
+ encrypted_channel.presence.enter data: data
+ end
+
+ encrypted_channel.presence.__incoming_msgbus__.unsubscribe(:presence) # remove all subscribe callbacks that could decrypt the message
+ encrypted_channel.presence.__incoming_msgbus__.subscribe(:presence) do |presence|
+ if protocol == :json
+ expect(presence['encoding']).to eql('json/utf-8/cipher+aes-256-cbc/base64')
+ expect(crypto.decrypt(Base64.decode64(presence['data']))).to eql(data_as_json)
+ else
+ expect(presence['encoding']).to eql('json/utf-8/cipher+aes-256-cbc')
+ expect(crypto.decrypt(presence['data'])).to eql(data_as_json)
+ end
+ stop_reactor
+ end
+ end
+ end
+
+ it '#subscribe emits decrypted enter events' do
+ run_reactor do
+ encrypted_channel.attach do
+ encrypted_channel.presence.enter data: data
+ end
+
+ encrypted_channel.presence.subscribe(:enter) do |presence_message|
+ expect(presence_message.encoding).to be_nil
+ expect(presence_message.data).to eql(data)
+ stop_reactor
+ end
+ end
+ end
+
+ it '#subscribe emits decrypted update events' do
+ run_reactor do
+ encrypted_channel.attach do
+ encrypted_channel.presence.enter(data: 'to be updated') do
+ encrypted_channel.presence.update data: data
+ end
+ end
+
+ encrypted_channel.presence.subscribe(:update) do |presence_message|
+ expect(presence_message.encoding).to be_nil
+ expect(presence_message.data).to eql(data)
+ stop_reactor
+ end
+ end
+ end
+
+ it '#subscribe emits decrypted leave events' do
+ run_reactor do
+ encrypted_channel.attach do
+ encrypted_channel.presence.enter(data: 'to be updated') do
+ encrypted_channel.presence.leave data: data
+ end
+ end
+
+ encrypted_channel.presence.subscribe(:leave) do |presence_message|
+ expect(presence_message.encoding).to be_nil
+ expect(presence_message.data).to eql(data)
+ stop_reactor
+ end
+ end
+ end
+
+ it '#get returns a list of members with decrypted data' do
+ run_reactor do
+ encrypted_channel.attach do
+ encrypted_channel.presence.enter(data: data) do
+ member = encrypted_channel.presence.get.first
+ expect(member.encoding).to be_nil
+ expect(member.data).to eql(data)
+ stop_reactor
+ end
+ end
+ end
+ end
+
+ it 'REST #get returns a list of members with decrypted data' do
+ run_reactor do
+ encrypted_channel.attach do
+ encrypted_channel.presence.enter(data: data) do
+ member = channel_rest_client_one.presence.get.first
+ expect(member.encoding).to be_nil
+ expect(member.data).to eql(data)
+ stop_reactor
+ end
+ end
+ end
+ end
+
+ context 'when cipher settings do not match publisher' do
+ let(:incompatible_cipher_options) { { key: secret_key, algorithm: 'aes', mode: 'cbc', key_length: 128 } }
+ let(:incompatible_encrypted_channel) { client_two.channel(channel_name, encrypted: true, cipher_params: incompatible_cipher_options) }
+
+ it 'delivers an unencoded presence message left with encoding value' do
+ run_reactor do
+ incompatible_encrypted_channel.attach do
+ encrypted_channel.attach do
+ encrypted_channel.presence.enter(data: data) do
+ member = incompatible_encrypted_channel.presence.get.first
+ expect(member.encoding).to match(/cipher\+aes-256-cbc/)
+ expect(member.data).to_not eql(data)
+ stop_reactor
+ end
+ end
+ end
+ end
+ end
+
+ it 'emits an error when cipher does not match and presence data cannot be decoded' do
+ run_reactor do
+ incompatible_encrypted_channel.attach do
+ incompatible_encrypted_channel.on(:error) do |error|
+ expect(error).to be_a(Ably::Exceptions::CipherError)
+ expect(error.message).to match(/Cipher algorithm AES-128-CBC does not match/)
+ stop_reactor
+ end
+
+ encrypted_channel.attach do
+ encrypted_channel.presence.enter data: data
+ end
+ end
+ end
+ end
+ end
+ end
+
specify 'expect :left event once underlying connection is closed' do
run_reactor do
presence_client_one.on(:left) do
expect(presence_client_one.state).to eq(:left)
stop_reactor
@@ -219,38 +361,38 @@
client_one.close
end
end
end
- specify 'expect :left event with no client data to retain original client_data in Leave event' do
+ specify 'expect :left event with no client data to retain original data in Leave event' do
run_reactor do
presence_client_one.subscribe(:leave) do |message|
expect(presence_client_one.get.count).to eq(0)
- expect(message.client_data).to eq(client_data_payload)
+ expect(message.data).to eq(data_payload)
stop_reactor
end
- presence_client_one.enter(client_data: client_data_payload) do
+ presence_client_one.enter(data: data_payload) do
presence_client_one.leave
end
end
end
specify '#update automatically connects' do
run_reactor do
- presence_client_one.update(client_data: client_data_payload) do
+ presence_client_one.update(data: data_payload) do
expect(presence_client_one.state).to eq(:entered)
stop_reactor
end
end
end
- specify '#update changes the client_data' do
+ specify '#update changes the data' do
run_reactor do
- presence_client_one.enter(client_data: 'prior') do
- presence_client_one.update(client_data: client_data_payload)
+ presence_client_one.enter(data: 'prior') do
+ presence_client_one.update(data: data_payload)
end
presence_client_one.subscribe(:update) do |message|
- expect(message.client_data).to eql(client_data_payload)
+ expect(message.data).to eql(data_payload)
stop_reactor
end
end
end