Skip to content

Commit 23fe40f

Browse files
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.
1 parent 8ba6a97 commit 23fe40f

File tree

4 files changed

+73
-1
lines changed

4 files changed

+73
-1
lines changed

config/initializers/web_push.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ def perform
2020
endpoint_ip = @options[:endpoint_ip]
2121

2222
if endpoint_ip
23-
http = Net::HTTP.new(uri.host, uri.port, ipaddr: endpoint_ip)
23+
http = Net::HTTP.new(uri.host, uri.port)
24+
http.ipaddr = endpoint_ip
2425
http.use_ssl = true
2526
http.ssl_timeout = @options[:ssl_timeout] unless @options[:ssl_timeout].nil?
2627
http.open_timeout = @options[:open_timeout] unless @options[:open_timeout].nil?
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
require "test_helper"
2+
3+
class WebPush::PersistentRequestTest < ActiveSupport::TestCase
4+
PUBLIC_TEST_IP = "142.250.185.206"
5+
ENDPOINT = "https://fcm.googleapis.com/fcm/send/test123"
6+
7+
test "pins connection to endpoint_ip" do
8+
request = stub_request(:post, ENDPOINT)
9+
.with(ipaddr: PUBLIC_TEST_IP)
10+
.to_return(status: 201)
11+
12+
notification = WebPush::Notification.new(
13+
title: "Test",
14+
body: "Test notification",
15+
path: "/test",
16+
badge: 0,
17+
endpoint: ENDPOINT,
18+
endpoint_ip: PUBLIC_TEST_IP,
19+
p256dh_key: "BNcRdreALRFXTkOOUHK1EtK2wtaz5Ry4YfYCA_0QTpQtUbVlUls0VJXg7A8u-Ts1XbjhazAkj7I99e8QcYP7DkM",
20+
auth_key: "tBHItJI5svbpez7KI4CCXg"
21+
)
22+
notification.deliver
23+
24+
assert_requested request
25+
end
26+
end

test/test_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
require "rails/test_help"
55
require "webmock/minitest"
6+
require_relative "webmock_ipaddr_extension"
67
require "vcr"
78
require "mocha/minitest"
89
require "turbo/broadcastable/test_helper"

test/webmock_ipaddr_extension.rb

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Extends WebMock to support ipaddr matching for testing IP pinning.
2+
#
3+
# Usage:
4+
# stub_request(:post, "https://example.com/push")
5+
# .with(ipaddr: "93.184.216.34")
6+
# .to_return(status: 201)
7+
#
8+
# If the HTTP connection's ipaddr doesn't match, the stub won't match and
9+
# WebMock will raise an error about an unregistered request.
10+
11+
module WebMock
12+
class RequestSignature
13+
attr_accessor :ipaddr
14+
end
15+
16+
module RequestPatternIpaddrExtension
17+
attr_accessor :ipaddr_pattern
18+
19+
def assign_options(options)
20+
options = options.dup
21+
@ipaddr_pattern = options.delete(:ipaddr) || options.delete("ipaddr")
22+
super(options)
23+
end
24+
25+
def matches?(request_signature)
26+
super && ipaddr_matches?(request_signature)
27+
end
28+
29+
private
30+
def ipaddr_matches?(request_signature)
31+
@ipaddr_pattern.nil? || @ipaddr_pattern == request_signature.ipaddr
32+
end
33+
end
34+
35+
RequestPattern.prepend RequestPatternIpaddrExtension
36+
37+
module NetHTTPUtilityIpaddrExtension
38+
def request_signature_from_request(net_http, request, body = nil)
39+
super.tap { |signature| signature.ipaddr = net_http.ipaddr }
40+
end
41+
end
42+
43+
NetHTTPUtility.singleton_class.prepend NetHTTPUtilityIpaddrExtension
44+
end

0 commit comments

Comments
 (0)