mirror of
https://github.com/stripe/stripe-ruby.git
synced 2025-12-06 00:00:29 -05:00
Merge branch 'beta' into latest-codegen-beta
This commit is contained in:
commit
f65e81567f
@ -13,7 +13,6 @@ require "set"
|
|||||||
require "socket"
|
require "socket"
|
||||||
require "uri"
|
require "uri"
|
||||||
require "forwardable"
|
require "forwardable"
|
||||||
require "base64"
|
|
||||||
|
|
||||||
# Version
|
# Version
|
||||||
require "stripe/api_version"
|
require "stripe/api_version"
|
||||||
@ -52,7 +51,6 @@ require "stripe/api_resource_test_helpers"
|
|||||||
require "stripe/singleton_api_resource"
|
require "stripe/singleton_api_resource"
|
||||||
require "stripe/webhook"
|
require "stripe/webhook"
|
||||||
require "stripe/stripe_configuration"
|
require "stripe/stripe_configuration"
|
||||||
require "stripe/request_signing_authenticator"
|
|
||||||
require "stripe/thin_event"
|
require "stripe/thin_event"
|
||||||
|
|
||||||
# Named API resources
|
# Named API resources
|
||||||
|
|||||||
@ -1,79 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Stripe
|
|
||||||
class RequestSigningAuthenticator
|
|
||||||
AUTHORIZATION_HEADER_NAME = "Authorization"
|
|
||||||
CONTENT_TYPE_HEADER_NAME = "Content-Type"
|
|
||||||
STRIPE_CONTEXT_HEADER_NAME = "Stripe-Context"
|
|
||||||
STRIPE_ACCOUNT_HEADER_NAME = "Stripe-Account"
|
|
||||||
CONTENT_DIGEST_HEADER_NAME = "Content-Digest"
|
|
||||||
SIGNATURE_INPUT_HEADER_NAME = "Signature-Input"
|
|
||||||
SIGNATURE_HEADER_NAME = "Signature"
|
|
||||||
|
|
||||||
attr_reader :auth_token, :sign_lambda
|
|
||||||
|
|
||||||
def initialize(auth_token, sign_lambda)
|
|
||||||
raise ArgumentError, "auth_token must be a string" unless auth_token.is_a?(String)
|
|
||||||
raise ArgumentError, "sign_lambda must be a lambda" unless sign_lambda.is_a?(Proc)
|
|
||||||
|
|
||||||
@auth_token = auth_token
|
|
||||||
@sign_lambda = sign_lambda
|
|
||||||
end
|
|
||||||
|
|
||||||
def authenticate(method, headers, body)
|
|
||||||
covered_headers = [CONTENT_TYPE_HEADER_NAME,
|
|
||||||
CONTENT_DIGEST_HEADER_NAME,
|
|
||||||
STRIPE_CONTEXT_HEADER_NAME,
|
|
||||||
STRIPE_ACCOUNT_HEADER_NAME,
|
|
||||||
AUTHORIZATION_HEADER_NAME,]
|
|
||||||
|
|
||||||
headers[AUTHORIZATION_HEADER_NAME] = "STRIPE-V2-SIG #{auth_token}"
|
|
||||||
|
|
||||||
if method == :get
|
|
||||||
covered_headers -= [CONTENT_TYPE_HEADER_NAME,
|
|
||||||
CONTENT_DIGEST_HEADER_NAME,]
|
|
||||||
else
|
|
||||||
content = body || ""
|
|
||||||
headers[CONTENT_DIGEST_HEADER_NAME] =
|
|
||||||
%(sha-256=:#{content_digest(content)}:)
|
|
||||||
end
|
|
||||||
|
|
||||||
covered_headers_formatted = covered_headers
|
|
||||||
.map { |string| %("#{string.downcase}") }
|
|
||||||
.join(" ")
|
|
||||||
|
|
||||||
signature_input = "(#{covered_headers_formatted});created=#{created_time}"
|
|
||||||
|
|
||||||
inputs = covered_headers
|
|
||||||
.map { |header| %("#{header.downcase}": #{headers[header]}) }
|
|
||||||
.join("\n")
|
|
||||||
|
|
||||||
signature_base = %(#{inputs}\n"@signature-params": #{signature_input})
|
|
||||||
.encode(Encoding::UTF_8)
|
|
||||||
|
|
||||||
headers[SIGNATURE_INPUT_HEADER_NAME] = "sig1=#{signature_input}"
|
|
||||||
|
|
||||||
headers[SIGNATURE_HEADER_NAME] =
|
|
||||||
"sig1=:#{encoded_signature(signature_base)}:"
|
|
||||||
end
|
|
||||||
|
|
||||||
private def sign(signature_base)
|
|
||||||
@sign_lambda.call(signature_base)
|
|
||||||
end
|
|
||||||
|
|
||||||
private def encoded_signature(signature_base)
|
|
||||||
Base64.strict_encode64(sign(signature_base))
|
|
||||||
rescue StandardError
|
|
||||||
raise AuthenticationError, "Encountered '#{e.message} (#{e.class})' " \
|
|
||||||
"when calculating request signature."
|
|
||||||
end
|
|
||||||
|
|
||||||
private def content_digest(content)
|
|
||||||
Base64.strict_encode64(OpenSSL::Digest.new("SHA256").digest(content))
|
|
||||||
end
|
|
||||||
|
|
||||||
private def created_time
|
|
||||||
Time.now.to_i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@ -1,112 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require File.expand_path("../test_helper", __dir__)
|
|
||||||
|
|
||||||
module Stripe
|
|
||||||
class RequestSigningAuthenticatorTest < Test::Unit::TestCase
|
|
||||||
TEST_AUTH_TOKEN = "keyid"
|
|
||||||
TEST_SIGN_LAMBDA = -> {}
|
|
||||||
|
|
||||||
context "initialize" do
|
|
||||||
should "raise error if given non-String auth token" do
|
|
||||||
assert_raises ArgumentError do
|
|
||||||
Stripe::RequestSigningAuthenticator.new(123, TEST_SIGN_LAMBDA)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should "raise error if given non-lambda sign function" do
|
|
||||||
assert_raises ArgumentError do
|
|
||||||
Stripe::RequestSigningAuthenticator.new(TEST_AUTH_TOKEN, nil)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
should "create a new authenticator with valid arguments" do
|
|
||||||
authenticator = Stripe::RequestSigningAuthenticator.new(TEST_AUTH_TOKEN, TEST_SIGN_LAMBDA)
|
|
||||||
assert_equal(authenticator.auth_token, TEST_AUTH_TOKEN)
|
|
||||||
assert_equal(authenticator.sign_lambda, TEST_SIGN_LAMBDA)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context ".authenticate" do
|
|
||||||
setup do
|
|
||||||
RequestSigningAuthenticator.any_instance.stubs(:created_time).returns(123_456_789)
|
|
||||||
end
|
|
||||||
|
|
||||||
should "applies signature for POST requests" do
|
|
||||||
signature_bases = []
|
|
||||||
sign = lambda { |signature_base|
|
|
||||||
signature_bases.push(signature_base)
|
|
||||||
[1, 2, 3, 4, 5].pack("C*")
|
|
||||||
}
|
|
||||||
|
|
||||||
authenticator = RequestSigningAuthenticator.new(TEST_AUTH_TOKEN, sign)
|
|
||||||
headers = { "Content-Type" => "application/json" }
|
|
||||||
authenticator.authenticate(:post, headers, '{"string":"String!"}')
|
|
||||||
|
|
||||||
assert_equal("\"content-type\": application/json\n" \
|
|
||||||
"\"content-digest\": sha-256=:HA3i38j+04ac71IzPtG1JK8o4q9sPK0fYPmJHmci5bg=:\n" \
|
|
||||||
"\"stripe-context\": \n" \
|
|
||||||
"\"stripe-account\": \n" \
|
|
||||||
"\"authorization\": STRIPE-V2-SIG keyid\n" \
|
|
||||||
"\"@signature-params\": (\"content-type\" \"content-digest\" \"stripe-context\" \"stripe-account\" \"authorization\");created=123456789",
|
|
||||||
signature_bases[0].force_encoding(Encoding::UTF_8))
|
|
||||||
|
|
||||||
assert_equal('sig1=("content-type" "content-digest" "stripe-context" "stripe-account" "authorization");' \
|
|
||||||
"created=123456789", headers["Signature-Input"])
|
|
||||||
assert_equal("sha-256=:HA3i38j+04ac71IzPtG1JK8o4q9sPK0fYPmJHmci5bg=:", headers["Content-Digest"])
|
|
||||||
assert_equal("sig1=:AQIDBAU=:", headers["Signature"])
|
|
||||||
assert_equal("STRIPE-V2-SIG keyid", headers["Authorization"])
|
|
||||||
end
|
|
||||||
|
|
||||||
should "applies signature for DELETE requests" do
|
|
||||||
signature_bases = []
|
|
||||||
sign = lambda { |signature_base|
|
|
||||||
signature_bases.push(signature_base)
|
|
||||||
[1, 2, 3, 4, 5].pack("C*")
|
|
||||||
}
|
|
||||||
|
|
||||||
authenticator = RequestSigningAuthenticator.new(TEST_AUTH_TOKEN, sign)
|
|
||||||
headers = { "Content-Type" => "application/json" }
|
|
||||||
authenticator.authenticate(:delete, headers, nil)
|
|
||||||
|
|
||||||
assert_equal("\"content-type\": application/json\n" \
|
|
||||||
"\"content-digest\": sha-256=:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=:\n" \
|
|
||||||
"\"stripe-context\": \n" \
|
|
||||||
"\"stripe-account\": \n" \
|
|
||||||
"\"authorization\": STRIPE-V2-SIG keyid\n" \
|
|
||||||
"\"@signature-params\": (\"content-type\" \"content-digest\" \"stripe-context\" \"stripe-account\" \"authorization\");created=123456789",
|
|
||||||
signature_bases[0].force_encoding(Encoding::UTF_8))
|
|
||||||
|
|
||||||
assert_equal('sig1=("content-type" "content-digest" "stripe-context" "stripe-account" "authorization");' \
|
|
||||||
"created=123456789", headers["Signature-Input"])
|
|
||||||
assert_equal("sha-256=:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=:", headers["Content-Digest"])
|
|
||||||
assert_equal("sig1=:AQIDBAU=:", headers["Signature"])
|
|
||||||
assert_equal("STRIPE-V2-SIG keyid", headers["Authorization"])
|
|
||||||
end
|
|
||||||
|
|
||||||
should "applies signature for GET requests" do
|
|
||||||
signature_bases = []
|
|
||||||
sign = lambda { |signature_base|
|
|
||||||
signature_bases.push(signature_base)
|
|
||||||
[1, 2, 3, 4, 5].pack("C*")
|
|
||||||
}
|
|
||||||
|
|
||||||
authenticator = RequestSigningAuthenticator.new(TEST_AUTH_TOKEN, sign)
|
|
||||||
headers = {}
|
|
||||||
authenticator.authenticate(:get, headers, nil)
|
|
||||||
|
|
||||||
assert_equal("\"stripe-context\": \n" \
|
|
||||||
"\"stripe-account\": \n" \
|
|
||||||
"\"authorization\": STRIPE-V2-SIG keyid\n" \
|
|
||||||
"\"@signature-params\": (\"stripe-context\" \"stripe-account\" \"authorization\");created=123456789",
|
|
||||||
signature_bases[0].force_encoding(Encoding::UTF_8))
|
|
||||||
|
|
||||||
assert_equal('sig1=("stripe-context" "stripe-account" "authorization");' \
|
|
||||||
"created=123456789", headers["Signature-Input"])
|
|
||||||
assert_nil(headers["Content-Digest"])
|
|
||||||
assert_equal("sig1=:AQIDBAU=:", headers["Signature"])
|
|
||||||
assert_equal("STRIPE-V2-SIG keyid", headers["Authorization"])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Loading…
x
Reference in New Issue
Block a user