Correctly initialise WebPush connection (#2417)

The `ipaddr` arg here is being interpreted as a positional arg (since
the keyword arg doesn't exist), which results in an invalid connection
object. This was causing push notifications to silently fail.

We should initialise the property on the object instead.
This commit is contained in:
Kevin McConnell
2026-01-22 20:03:02 +00:00
committed by GitHub
parent 8ba6a97014
commit 23fe40fa81
4 changed files with 73 additions and 1 deletions
+2 -1
View File
@@ -20,7 +20,8 @@ module WebPush::PersistentRequest
endpoint_ip = @options[:endpoint_ip]
if endpoint_ip
http = Net::HTTP.new(uri.host, uri.port, ipaddr: endpoint_ip)
http = Net::HTTP.new(uri.host, uri.port)
http.ipaddr = endpoint_ip
http.use_ssl = true
http.ssl_timeout = @options[:ssl_timeout] unless @options[:ssl_timeout].nil?
http.open_timeout = @options[:open_timeout] unless @options[:open_timeout].nil?
@@ -0,0 +1,26 @@
require "test_helper"
class WebPush::PersistentRequestTest < ActiveSupport::TestCase
PUBLIC_TEST_IP = "142.250.185.206"
ENDPOINT = "https://fcm.googleapis.com/fcm/send/test123"
test "pins connection to endpoint_ip" do
request = stub_request(:post, ENDPOINT)
.with(ipaddr: PUBLIC_TEST_IP)
.to_return(status: 201)
notification = WebPush::Notification.new(
title: "Test",
body: "Test notification",
path: "/test",
badge: 0,
endpoint: ENDPOINT,
endpoint_ip: PUBLIC_TEST_IP,
p256dh_key: "BNcRdreALRFXTkOOUHK1EtK2wtaz5Ry4YfYCA_0QTpQtUbVlUls0VJXg7A8u-Ts1XbjhazAkj7I99e8QcYP7DkM",
auth_key: "tBHItJI5svbpez7KI4CCXg"
)
notification.deliver
assert_requested request
end
end
+1
View File
@@ -3,6 +3,7 @@ require_relative "../config/environment"
require "rails/test_help"
require "webmock/minitest"
require_relative "webmock_ipaddr_extension"
require "vcr"
require "mocha/minitest"
require "turbo/broadcastable/test_helper"
+44
View File
@@ -0,0 +1,44 @@
# Extends WebMock to support ipaddr matching for testing IP pinning.
#
# Usage:
# stub_request(:post, "https://example.com/push")
# .with(ipaddr: "93.184.216.34")
# .to_return(status: 201)
#
# If the HTTP connection's ipaddr doesn't match, the stub won't match and
# WebMock will raise an error about an unregistered request.
module WebMock
class RequestSignature
attr_accessor :ipaddr
end
module RequestPatternIpaddrExtension
attr_accessor :ipaddr_pattern
def assign_options(options)
options = options.dup
@ipaddr_pattern = options.delete(:ipaddr) || options.delete("ipaddr")
super(options)
end
def matches?(request_signature)
super && ipaddr_matches?(request_signature)
end
private
def ipaddr_matches?(request_signature)
@ipaddr_pattern.nil? || @ipaddr_pattern == request_signature.ipaddr
end
end
RequestPattern.prepend RequestPatternIpaddrExtension
module NetHTTPUtilityIpaddrExtension
def request_signature_from_request(net_http, request, body = nil)
super.tap { |signature| signature.ipaddr = net_http.ipaddr }
end
end
NetHTTPUtility.singleton_class.prepend NetHTTPUtilityIpaddrExtension
end