From 510331a1b9d6f64a49ed370dcf027d77344de260 Mon Sep 17 00:00:00 2001 From: Hamed Asghari Date: Mon, 20 Apr 2026 11:20:30 -0600 Subject: [PATCH 1/4] Fix deprecation warning in multi_json gem This change is backwards-compatible with the minimum version of the mutli_json gem specified in the gemspec file. --- lib/pusher/channel.rb | 2 +- lib/pusher/client.rb | 6 ++--- lib/pusher/request.rb | 4 ++-- lib/pusher/resource.rb | 4 ++-- lib/pusher/webhook.rb | 2 +- spec/channel_spec.rb | 2 +- spec/client_spec.rb | 50 +++++++++++++++++++++--------------------- spec/web_hook_spec.rb | 6 ++--- 8 files changed, 38 insertions(+), 38 deletions(-) diff --git a/lib/pusher/channel.rb b/lib/pusher/channel.rb index 5de06a7..0d214d6 100644 --- a/lib/pusher/channel.rb +++ b/lib/pusher/channel.rb @@ -156,7 +156,7 @@ def authentication_string(socket_id, custom_string = nil) # @private Custom data is sent to server as JSON-encoded string # def authenticate(socket_id, custom_data = nil) - custom_data = MultiJson.encode(custom_data) if custom_data + custom_data = MultiJson.dump(custom_data) if custom_data auth = authentication_string(socket_id, custom_data) r = {:auth => auth} r[:channel_data] = custom_data if custom_data diff --git a/lib/pusher/client.rb b/lib/pusher/client.rb index 0de5841..1a78a57 100644 --- a/lib/pusher/client.rb +++ b/lib/pusher/client.rb @@ -374,7 +374,7 @@ def authenticate(channel_name, socket_id, custom_data = nil) def authenticate_user(socket_id, user_data) validate_user_data(user_data) - custom_data = MultiJson.encode(user_data) + custom_data = MultiJson.dump(user_data) auth = authentication_string(socket_id, custom_data) { auth:, user_data: custom_data } @@ -461,7 +461,7 @@ def trigger_batch_params(events) # JSON-encode the data if it's not a string def encode_data(data) return data if data.is_a? String - MultiJson.encode(data) + MultiJson.dump(data) end # Encrypts a message with a key derived from the master key and channel @@ -480,7 +480,7 @@ def encrypt(channel_name, encoded_data) nonce = RbNaCl::Random.random_bytes(secret_box.nonce_bytes) ciphertext = secret_box.encrypt(nonce, encoded_data) - MultiJson.encode({ + MultiJson.dump({ "nonce" => Base64::strict_encode64(nonce), "ciphertext" => Base64::strict_encode64(ciphertext), }) diff --git a/lib/pusher/request.rb b/lib/pusher/request.rb index 16adea2..4edf9ff 100644 --- a/lib/pusher/request.rb +++ b/lib/pusher/request.rb @@ -86,9 +86,9 @@ def send_async def handle_response(status_code, body) case status_code when 200 - return symbolize_first_level(MultiJson.decode(body)) + return symbolize_first_level(MultiJson.load(body)) when 202 - return body.empty? ? true : symbolize_first_level(MultiJson.decode(body)) + return body.empty? ? true : symbolize_first_level(MultiJson.load(body)) when 400 raise Error, "Bad request: #{body}" when 401 diff --git a/lib/pusher/resource.rb b/lib/pusher/resource.rb index 73bbc89..8a0cf2b 100644 --- a/lib/pusher/resource.rb +++ b/lib/pusher/resource.rb @@ -14,12 +14,12 @@ def get_async(params) end def post(params) - body = MultiJson.encode(params) + body = MultiJson.dump(params) create_request(:post, {}, body).send_sync end def post_async(params) - body = MultiJson.encode(params) + body = MultiJson.dump(params) create_request(:post, {}, body).send_async end diff --git a/lib/pusher/webhook.rb b/lib/pusher/webhook.rb index f28782b..71714ba 100644 --- a/lib/pusher/webhook.rb +++ b/lib/pusher/webhook.rb @@ -88,7 +88,7 @@ def data @data ||= begin case @content_type when 'application/json' - MultiJson.decode(@body) + MultiJson.load(@body) else raise "Unknown Content-Type (#{@content_type})" end diff --git a/spec/channel_spec.rb b/spec/channel_spec.rb index 198246b..5d99645 100644 --- a/spec/channel_spec.rb +++ b/spec/channel_spec.rb @@ -133,7 +133,7 @@ def authentication_string(*data) end it 'should return a hash with signature including custom data and data as json string' do - allow(MultiJson).to receive(:encode).with(@custom_data).and_return 'a json string' + allow(MultiJson).to receive(:dump).with(@custom_data).and_return 'a json string' response = @channel.authenticate('1.1', @custom_data) diff --git a/spec/client_spec.rb b/spec/client_spec.rb index d22e211..0e7d0c6 100644 --- a/spec/client_spec.rb +++ b/spec/client_spec.rb @@ -235,7 +235,7 @@ api_path = %r{/apps/20/channels} stub_request(:get, api_path).to_return({ :status => 200, - :body => MultiJson.encode('channels' => { + :body => MultiJson.dump('channels' => { "channel1" => {}, "channel2" => {} }) @@ -254,7 +254,7 @@ api_path = %r{/apps/20/channels/mychannel} stub_request(:get, api_path).to_return({ :status => 200, - :body => MultiJson.encode({ + :body => MultiJson.dump({ 'occupied' => false, }) }) @@ -288,7 +288,7 @@ stub_request(:get, api_path) .to_return({ :status => 500, :body => "Server error" }) .then - .to_return({ :status => 200, :body => MultiJson.encode({ 'occupied' => false }) }) + .to_return({ :status => 200, :body => MultiJson.dump({ 'occupied' => false }) }) expect { @client.channel_info('mychannel') }.to raise_error(Pusher::Error) expect(@client.channel_info('mychannel')).to eq({ :occupied => false }) @@ -298,7 +298,7 @@ api_path = %r{/apps/20/channels/mychannel} stub_request(:get, api_path).to_return({ :status => 200, - :body => MultiJson.encode({ 'occupied' => false }) + :body => MultiJson.dump({ 'occupied' => false }) }) http_client = @client.sync_http_client @@ -313,7 +313,7 @@ api_path = %r{/apps/20/channels/mychannel/users} stub_request(:get, api_path).to_return({ :status => 200, - :body => MultiJson.encode({ + :body => MultiJson.dump({ 'users' => [{ 'id' => 1 }] }) }) @@ -329,7 +329,7 @@ end it 'should return a hash with signature including custom data and data as json string' do - allow(MultiJson).to receive(:encode).with(@custom_data).and_return 'a json string' + allow(MultiJson).to receive(:dump).with(@custom_data).and_return 'a json string' response = @client.authenticate('test_channel', '1.1', @custom_data) @@ -340,7 +340,7 @@ end it 'should include a shared_secret if the private-encrypted channel' do - allow(MultiJson).to receive(:encode).with(@custom_data).and_return 'a json string' + allow(MultiJson).to receive(:dump).with(@custom_data).and_return 'a json string' @client.instance_variable_set(:@encryption_master_key, '3W1pfB/Etr+ZIlfMWwZP3gz8jEeCt4s2pe6Vpr+2c3M=') response = @client.authenticate('private-encrypted-test_channel', '1.1', @custom_data) @@ -360,7 +360,7 @@ end it 'should return a hash with signature including custom data and data as json string' do - allow(MultiJson).to receive(:encode).with(@user_data).and_return 'a json string' + allow(MultiJson).to receive(:dump).with(@user_data).and_return 'a json string' response = @client.authenticate_user('1.1', @user_data) @@ -377,7 +377,7 @@ @api_path = %r{/apps/20/events} stub_request(:post, @api_path).to_return({ :status => 200, - :body => MultiJson.encode({}) + :body => MultiJson.dump({}) }) end @@ -399,7 +399,7 @@ :socket_id => "12.34" }) expect(WebMock).to have_requested(:post, @api_path).with { |req| - parsed = MultiJson.decode(req.body) + parsed = MultiJson.load(req.body) expect(parsed["name"]).to eq('event') expect(parsed["channels"]).to eq(["mychannel", "c2"]) expect(parsed["socket_id"]).to eq('12.34') @@ -409,14 +409,14 @@ it "should convert non string data to JSON before posting" do @client.trigger(['mychannel'], 'event', {'some' => 'data'}) expect(WebMock).to have_requested(:post, @api_path).with { |req| - expect(MultiJson.decode(req.body)["data"]).to eq('{"some":"data"}') + expect(MultiJson.load(req.body)["data"]).to eq('{"some":"data"}') } end it "should accept a single channel as well as an array" do @client.trigger('mychannel', 'event', {'some' => 'data'}) expect(WebMock).to have_requested(:post, @api_path).with { |req| - expect(MultiJson.decode(req.body)["channels"]).to eq(['mychannel']) + expect(MultiJson.load(req.body)["channels"]).to eq(['mychannel']) } end @@ -427,7 +427,7 @@ @client.trigger('mychannel', 'event', {'some' => 'data'}) }.to raise_error(Pusher::ConfigurationError) expect(WebMock).not_to have_requested(:post, @api_path).with { |req| - expect(MultiJson.decode(req.body)["channels"]).to eq(['mychannel']) + expect(MultiJson.load(req.body)["channels"]).to eq(['mychannel']) } end end @@ -459,13 +459,13 @@ ) expect(WebMock).to have_requested(:post, @api_path).with { |req| - data = MultiJson.decode(MultiJson.decode(req.body)["data"]) + data = MultiJson.load(MultiJson.load(req.body)["data"]) key = RbNaCl::Hash.sha256( 'private-encrypted-channel' + encryption_master_key ) - expect(MultiJson.decode(RbNaCl::SecretBox.new(key).decrypt( + expect(MultiJson.load(RbNaCl::SecretBox.new(key).decrypt( Base64.strict_decode64(data["nonce"]), Base64.strict_decode64(data["ciphertext"]), ))).to eq({ 'some' => 'data' }) @@ -478,7 +478,7 @@ @api_path = %r{/apps/20/batch_events} stub_request(:post, @api_path).to_return({ :status => 200, - :body => MultiJson.encode({}) + :body => MultiJson.dump({}) }) end @@ -493,7 +493,7 @@ {channel: 'mychannel', name: 'event', data: 'already encoded'}, ) expect(WebMock).to have_requested(:post, @api_path).with { |req| - parsed = MultiJson.decode(req.body) + parsed = MultiJson.load(req.body) expect(parsed).to eq( "batch" => [ { "channel" => "mychannel", "name" => "event", "data" => "{\"some\":\"data\"}"}, @@ -529,19 +529,19 @@ ) expect(WebMock).to have_requested(:post, @api_path).with { |req| - batch = MultiJson.decode(req.body)["batch"] + batch = MultiJson.load(req.body)["batch"] expect(batch.length).to eq(2) expect(batch[0]["channel"]).to eq("private-encrypted-channel") expect(batch[0]["name"]).to eq("event") - data = MultiJson.decode(batch[0]["data"]) + data = MultiJson.load(batch[0]["data"]) key = RbNaCl::Hash.sha256( 'private-encrypted-channel' + encryption_master_key ) - expect(MultiJson.decode(RbNaCl::SecretBox.new(key).decrypt( + expect(MultiJson.load(RbNaCl::SecretBox.new(key).decrypt( Base64.strict_decode64(data["nonce"]), Base64.strict_decode64(data["ciphertext"]), ))).to eq({ 'some' => 'data' }) @@ -558,7 +558,7 @@ @api_path = %r{/apps/20/events} stub_request(:post, @api_path).to_return({ :status => 200, - :body => MultiJson.encode({}) + :body => MultiJson.dump({}) }) end @@ -577,7 +577,7 @@ :socket_id => "12.34" }).callback { expect(WebMock).to have_requested(:post, @api_path).with { |req| - expect(MultiJson.decode(req.body)["socket_id"]).to eq('12.34') + expect(MultiJson.load(req.body)["socket_id"]).to eq('12.34') } EM.stop } @@ -588,7 +588,7 @@ EM.run { @client.trigger_async('mychannel', 'event', {'some' => 'data'}).callback { expect(WebMock).to have_requested(:post, @api_path).with { |req| - expect(MultiJson.decode(req.body)["data"]).to eq('{"some":"data"}') + expect(MultiJson.load(req.body)["data"]).to eq('{"some":"data"}') } EM.stop } @@ -620,7 +620,7 @@ it "should format the respose hash with symbols at first level" do stub_request(verb, @url_regexp).to_return({ :status => 200, - :body => MultiJson.encode({'something' => {'a' => 'hash'}}) + :body => MultiJson.dump({'something' => {'a' => 'hash'}}) }) expect(call_api).to eq({ :something => {'a' => 'hash'} @@ -751,7 +751,7 @@ EM.run { stub_request(verb, @url_regexp).to_return({ :status => 200, - :body => MultiJson.encode({'something' => {'a' => 'hash'}}) + :body => MultiJson.dump({'something' => {'a' => 'hash'}}) }) call_api.callback { |response| expect(response).to eq({ diff --git a/spec/web_hook_spec.rb b/spec/web_hook_spec.rb index 2655b5d..10118d8 100644 --- a/spec/web_hook_spec.rb +++ b/spec/web_hook_spec.rb @@ -19,7 +19,7 @@ 'HTTP_X_PUSHER_KEY' => '1234', 'HTTP_X_PUSHER_SIGNATURE' => 'asdf', 'CONTENT_TYPE' => 'application/json', - 'rack.input' => StringIO.new(MultiJson.encode(@hook_data)) + 'rack.input' => StringIO.new(MultiJson.dump(@hook_data)) }) wh = Pusher::WebHook.new(request) expect(wh.key).to eq('1234') @@ -32,7 +32,7 @@ :key => '1234', :signature => 'asdf', :content_type => 'application/json', - :body => MultiJson.encode(@hook_data), + :body => MultiJson.dump(@hook_data), } wh = Pusher::WebHook.new(request) expect(wh.key).to eq('1234') @@ -43,7 +43,7 @@ describe "after initialization" do before :each do - @body = MultiJson.encode(@hook_data) + @body = MultiJson.dump(@hook_data) request = { :key => '1234', :signature => hmac('asdf', @body), From 31a63028a8f4801c90f3356c107795ea3e15361b Mon Sep 17 00:00:00 2001 From: Hamed Asghari Date: Mon, 20 Apr 2026 11:22:10 -0600 Subject: [PATCH 2/4] Add logger gem to development dependencies The specs were failing locally otherwise --- pusher.gemspec | 1 + 1 file changed, 1 insertion(+) diff --git a/pusher.gemspec b/pusher.gemspec index 71ee54f..d4cc697 100644 --- a/pusher.gemspec +++ b/pusher.gemspec @@ -28,6 +28,7 @@ Gem::Specification.new do |s| s.add_development_dependency "rack", "~> 2.2" s.add_development_dependency "json", "~> 2.3" s.add_development_dependency "rbnacl", "~> 7.1" + s.add_development_dependency "logger", "~> 1.0" s.files = Dir["lib/**/*"] + %w[CHANGELOG.md LICENSE README.md] s.require_paths = ["lib"] From e0a7b6794901b191df112cbd05873db02b15aaa6 Mon Sep 17 00:00:00 2001 From: Hamed Asghari Date: Mon, 20 Apr 2026 11:23:12 -0600 Subject: [PATCH 3/4] Fix RSpec deprecation warnings --- spec/channel_spec.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/channel_spec.rb b/spec/channel_spec.rb index 5d99645..aef45d1 100644 --- a/spec/channel_spec.rb +++ b/spec/channel_spec.rb @@ -95,7 +95,7 @@ def stub_post_to_raise(e) describe "#authentication_string" do def authentication_string(*data) - lambda { @channel.authentication_string(*data) } + @channel.authentication_string(*data) end it "should return an authentication string given a socket id" do @@ -106,17 +106,17 @@ def authentication_string(*data) it "should raise error if authentication is invalid" do [nil, ''].each do |invalid| - expect(authentication_string(invalid)).to raise_error Pusher::Error + expect { authentication_string(invalid) }.to raise_error Pusher::Error end end describe 'with extra string argument' do it 'should be a string or nil' do - expect(authentication_string('1.1', 123)).to raise_error Pusher::Error - expect(authentication_string('1.1', {})).to raise_error Pusher::Error + expect { authentication_string('1.1', 123) }.to raise_error Pusher::Error + expect { authentication_string('1.1', {}) }.to raise_error Pusher::Error - expect(authentication_string('1.1', 'boom')).not_to raise_error - expect(authentication_string('1.1', nil)).not_to raise_error + expect { authentication_string('1.1', 'boom') }.not_to raise_error + expect { authentication_string('1.1', nil) }.not_to raise_error end it "should return an authentication string given a socket id and custom args" do From 2807c768a9ed453f6283311bc1d2f8514456d134 Mon Sep 17 00:00:00 2001 From: Hamed Asghari Date: Mon, 20 Apr 2026 11:23:46 -0600 Subject: [PATCH 4/4] Suppress expected deprecation warning in specs --- spec/client_spec.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/client_spec.rb b/spec/client_spec.rb index 0e7d0c6..96f41b2 100644 --- a/spec/client_spec.rb +++ b/spec/client_spec.rb @@ -125,11 +125,11 @@ end it 'should set port and scheme if "encrypted" disabled' do - client = Pusher::Client.new({ - :encrypted => false, - }) - expect(client.scheme).to eq('http') - expect(client.port).to eq(80) + expect do + client = Pusher::Client.new({ :encrypted => false }) + expect(client.scheme).to eq('http') + expect(client.port).to eq(80) + end.to output(/\[DEPRECATION\] `encrypted` is deprecated/).to_stderr end it 'should use TLS port and scheme if "encrypted" or "use_tls" are not set' do