Class: GooglePayRuby::SignatureVerifier
- Inherits:
-
Object
- Object
- GooglePayRuby::SignatureVerifier
- Defined in:
- lib/google_pay_ruby/signature_verifier.rb
Overview
Implements Google Pay ECv2 signature verification as specified in: https://developers.google.com/pay/api/web/guides/resources/payment-data-cryptography
Verification steps:
1. Fetch Google root signing keys
2. Verify intermediate signing key signature against non-expired root keys
3. Verify intermediate signing key hasn't expired
4. Verify message signature using intermediate signing key
Constant Summary collapse
- SENDER_ID =
'Google'- PROTOCOL_VERSION =
'ECv2'- GOOGLE_ROOT_SIGNING_KEYS_PROD_URL =
'https://payments.developers.google.com/paymentmethodtoken/keys.json'- GOOGLE_ROOT_SIGNING_KEYS_TEST_URL =
'https://payments.developers.google.com/paymentmethodtoken/test/keys.json'
Instance Method Summary collapse
-
#initialize(root_signing_keys: nil, recipient_id:, test: false) ⇒ SignatureVerifier
constructor
A new instance of SignatureVerifier.
-
#verify!(token, raw_token_json: nil) ⇒ void
Runs all verification steps (1-4) on the given token.
Constructor Details
#initialize(root_signing_keys: nil, recipient_id:, test: false) ⇒ SignatureVerifier
Returns a new instance of SignatureVerifier.
32 33 34 35 36 |
# File 'lib/google_pay_ruby/signature_verifier.rb', line 32 def initialize(root_signing_keys: nil, recipient_id:, test: false) @root_signing_keys = root_signing_keys @recipient_id = recipient_id @test = test end |
Instance Method Details
#verify!(token, raw_token_json: nil) ⇒ void
This method returns an undefined value.
Runs all verification steps (1-4) on the given token. Raises GooglePaymentDecryptionError on any verification failure.
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/google_pay_ruby/signature_verifier.rb', line 47 def verify!(token, raw_token_json: nil) protocol_version = token['protocolVersion'] || token[:protocolVersion] unless protocol_version == PROTOCOL_VERSION raise GooglePaymentDecryptionError.new( "Unsupported protocol version: #{protocol_version}. Only ECv2 is supported." ) end intermediate_signing_key = token['intermediateSigningKey'] || token[:intermediateSigningKey] unless intermediate_signing_key raise GooglePaymentDecryptionError.new('Missing intermediateSigningKey in token') end signed_key_json = intermediate_signing_key['signedKey'] || intermediate_signing_key[:signedKey] signatures = intermediate_signing_key['signatures'] || intermediate_signing_key[:signatures] unless signed_key_json && signatures raise GooglePaymentDecryptionError.new('Missing signedKey or signatures in intermediateSigningKey') end # Extract original signedKey and signedMessage from raw JSON if available. # This preserves the exact byte sequences (including unicode escapes like \u003d) # that Google used when computing signatures. if raw_token_json raw_signed_key = extract_json_string_value(raw_token_json, 'signedKey') = extract_json_string_value(raw_token_json, 'signedMessage') signed_key_json = raw_signed_key if raw_signed_key = end # Step 2: Verify intermediate signing key signature against non-expired root keys verify_intermediate_signing_key_signature!(signed_key_json, signatures) # Step 3: Verify intermediate signing key hasn't expired verify_intermediate_signing_key_expiration!(signed_key_json) # Step 4: Verify message signature using intermediate signing key = || token['signedMessage'] || token[:signedMessage] signature = token['signature'] || token[:signature] unless && signature raise GooglePaymentDecryptionError.new('Missing signedMessage or signature in token') end parsed_signed_key = JSON.parse(signed_key_json) intermediate_key_value = parsed_signed_key['keyValue'] (, signature, intermediate_key_value) end |