From e6f5b24577d246854e56623a6383a65f101ae678 Mon Sep 17 00:00:00 2001 From: Yaro Shm Date: Thu, 26 Mar 2026 11:07:23 +0100 Subject: [PATCH 1/2] fix: use OpenSSL::PKey.read for APNs key loading OpenSSL::PKey::EC.new(pem_string) no longer accepts PEM/DER key strings since the openssl gem 3.0 (Ruby 3.2+). It now only accepts curve names, causing `OpenSSL::PKey::PKeyError: invalid curve name`. OpenSSL::PKey.read handles PEM/DER formats and is backwards-compatible. Fixes #118 --- lib/action_push_native/service/apns/token_provider.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/action_push_native/service/apns/token_provider.rb b/lib/action_push_native/service/apns/token_provider.rb index a262a9c..f33fc28 100644 --- a/lib/action_push_native/service/apns/token_provider.rb +++ b/lib/action_push_native/service/apns/token_provider.rb @@ -27,7 +27,7 @@ def regenerate_if_expired def generate payload = { iss: config.fetch(:team_id), iat: Time.now.utc.to_i } header = { kid: config.fetch(:key_id) } - private_key = OpenSSL::PKey::EC.new(config.fetch(:encryption_key)) + private_key = OpenSSL::PKey.read(config.fetch(:encryption_key)) JWT.encode(payload, private_key, "ES256", header) end end From c2cdd6171d3e2c3826591cce5b4653f622a242ee Mon Sep 17 00:00:00 2001 From: Yaro Shm Date: Thu, 26 Mar 2026 11:16:22 +0100 Subject: [PATCH 2/2] test: add test for ES256 JWT generation from PEM key Exercises the actual OpenSSL key loading path (previously fully stubbed) to ensure OpenSSL::PKey.read works with PEM-formatted EC keys. --- test/lib/action_push_native/service/apns_test.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/lib/action_push_native/service/apns_test.rb b/test/lib/action_push_native/service/apns_test.rb index c32fc00..987c665 100644 --- a/test/lib/action_push_native/service/apns_test.rb +++ b/test/lib/action_push_native/service/apns_test.rb @@ -179,6 +179,20 @@ class ApnsTest < ActiveSupport::TestCase end end + test "generate produces a valid ES256 JWT from a PEM key" do + ActionPushNative::Service::Apns::TokenProvider.any_instance.unstub(:fresh_access_token) + + ec_key = OpenSSL::PKey::EC.generate("prime256v1") + config = { team_id: "TEAM123", key_id: "KEY456", encryption_key: ec_key.to_pem } + provider = ActionPushNative::Service::Apns::TokenProvider.new(config) + + token = provider.fresh_access_token + + decoded = JWT.decode(token, ec_key, true, algorithm: "ES256") + assert_equal "TEAM123", decoded.first["iss"] + assert_equal "KEY456", decoded.last["kid"] + end + test "connect to APNs development server" do apns = Apns.new(@config.merge(connect_to_development_server: true)) stub_request(:post, "https://api.sandbox.push.apple.com/3/device/123").to_return(status: 200)