session_test.rb 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. require 'test_helper'
  2. require 'timecop'
  3. class SessionTest < Test::Unit::TestCase
  4. def setup
  5. super
  6. ShopifyAPI::Session.secret = 'secret'
  7. end
  8. test "not be valid without a url" do
  9. session = ShopifyAPI::Session.new(nil, "any-token", any_api_version)
  10. assert_not session.valid?
  11. end
  12. test "not be valid without token" do
  13. session = ShopifyAPI::Session.new("testshop.myshopify.com", nil, any_api_version)
  14. assert_not session.valid?
  15. end
  16. test "not be valid without an api version" do
  17. session = ShopifyAPI::Session.new("testshop.myshopify.com", "any-token", nil)
  18. assert_not session.valid?
  19. end
  20. test "be valid with any token, any url and version" do
  21. session = ShopifyAPI::Session.new("testshop.myshopify.com", "any-token", any_api_version)
  22. assert session.valid?
  23. end
  24. test "not raise error without params" do
  25. assert_nothing_raised do
  26. ShopifyAPI::Session.new("testshop.myshopify.com", "any-token", any_api_version)
  27. end
  28. end
  29. test "ignore everything but the subdomain in the shop" do
  30. assert_equal(
  31. "https://testshop.myshopify.com",
  32. ShopifyAPI::Session.new("http://user:pass@testshop.notshopify.net/path", "any-token", any_api_version).site
  33. )
  34. end
  35. test "append the myshopify domain if not given" do
  36. assert_equal "https://testshop.myshopify.com", ShopifyAPI::Session.new("testshop", "any-token", any_api_version).site
  37. end
  38. test "not raise error without params" do
  39. assert_nothing_raised do
  40. ShopifyAPI::Session.new("testshop.myshopify.com", "any-token", any_api_version)
  41. end
  42. end
  43. test "raise error if params passed but signature omitted" do
  44. assert_raises(ShopifyAPI::ValidationException) do
  45. session = ShopifyAPI::Session.new("testshop.myshopify.com", nil, any_api_version)
  46. session.request_token({'code' => 'any-code'})
  47. end
  48. end
  49. test "setup api_key and secret for all sessions" do
  50. ShopifyAPI::Session.setup(:api_key => "My test key", :secret => "My test secret")
  51. assert_equal "My test key", ShopifyAPI::Session.api_key
  52. assert_equal "My test secret", ShopifyAPI::Session.secret
  53. end
  54. test "#temp reset ShopifyAPI::Base.site to original value" do
  55. ShopifyAPI::Session.setup(:api_key => "key", :secret => "secret")
  56. session1 = ShopifyAPI::Session.new('fakeshop.myshopify.com', 'token1', :no_version)
  57. ShopifyAPI::Base.activate_session(session1)
  58. ShopifyAPI::Session.temp("testshop.myshopify.com", "any-token", :unstable) {
  59. @assigned_site = ShopifyAPI::Base.site
  60. @assigned_version = ShopifyAPI::Base.api_version
  61. }
  62. assert_equal('https://testshop.myshopify.com', @assigned_site.to_s)
  63. assert_equal('https://fakeshop.myshopify.com', ShopifyAPI::Base.site.to_s)
  64. assert_equal(ShopifyAPI::ApiVersion::Unstable.new, @assigned_version)
  65. assert_equal(ShopifyAPI::ApiVersion::NoVersion.new, ShopifyAPI::Base.api_version)
  66. end
  67. test "create_permission_url returns correct url with single scope no redirect uri" do
  68. ShopifyAPI::Session.setup(:api_key => "My_test_key", :secret => "My test secret")
  69. session = ShopifyAPI::Session.new('http://localhost.myshopify.com', 'any-token', any_api_version)
  70. scope = ["write_products"]
  71. permission_url = session.create_permission_url(scope)
  72. assert_equal "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&scope=write_products", permission_url
  73. end
  74. test "create_permission_url returns correct url with single scope and redirect uri" do
  75. ShopifyAPI::Session.setup(:api_key => "My_test_key", :secret => "My test secret")
  76. session = ShopifyAPI::Session.new('http://localhost.myshopify.com', 'any-token', any_api_version)
  77. scope = ["write_products"]
  78. permission_url = session.create_permission_url(scope, "http://my_redirect_uri.com")
  79. assert_equal "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&scope=write_products&redirect_uri=http://my_redirect_uri.com", permission_url
  80. end
  81. test "create_permission_url returns correct url with dual scope no redirect uri" do
  82. ShopifyAPI::Session.setup(:api_key => "My_test_key", :secret => "My test secret")
  83. session = ShopifyAPI::Session.new('http://localhost.myshopify.com', 'any-token', any_api_version)
  84. scope = ["write_products","write_customers"]
  85. permission_url = session.create_permission_url(scope)
  86. assert_equal "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&scope=write_products,write_customers", permission_url
  87. end
  88. test "create_permission_url returns correct url with no scope no redirect uri" do
  89. ShopifyAPI::Session.setup(:api_key => "My_test_key", :secret => "My test secret")
  90. session = ShopifyAPI::Session.new('http://localhost.myshopify.com', 'any-token', any_api_version)
  91. scope = []
  92. permission_url = session.create_permission_url(scope)
  93. assert_equal "https://localhost.myshopify.com/admin/oauth/authorize?client_id=My_test_key&scope=", permission_url
  94. end
  95. test "raise exception if code invalid in request token" do
  96. ShopifyAPI::Session.setup(:api_key => "My test key", :secret => "My test secret")
  97. session = ShopifyAPI::Session.new('http://localhost.myshopify.com', nil, any_api_version)
  98. fake nil, :url => 'https://localhost.myshopify.com/admin/oauth/access_token',:method => :post, :status => 404, :body => '{"error" : "invalid_request"}'
  99. assert_raises(ShopifyAPI::ValidationException) do
  100. session.request_token(params={:code => "bad-code"})
  101. end
  102. assert_equal false, session.valid?
  103. end
  104. test "return site for session" do
  105. session = ShopifyAPI::Session.new("testshop.myshopify.com", "any-token", any_api_version)
  106. assert_equal "https://testshop.myshopify.com", session.site
  107. end
  108. test "return_token_if_signature_is_valid" do
  109. api_version = any_api_version
  110. fake nil,
  111. url: "https://testshop.myshopify.com/admin/oauth/access_token",
  112. method: :post,
  113. body: '{"access_token":"any-token"}'
  114. session = ShopifyAPI::Session.new("testshop.myshopify.com", nil, api_version)
  115. params = { code: 'any-code', timestamp: Time.now }
  116. token = session.request_token(params.merge(hmac: generate_signature(params)))
  117. assert_equal "any-token", token
  118. assert_equal "any-token", session.token
  119. end
  120. test "extra parameters are stored in session" do
  121. api_version = ShopifyAPI::ApiVersion::Unstable.new
  122. fake nil,
  123. url: "https://testshop.myshopify.com/admin/oauth/access_token",
  124. method: :post,
  125. body: '{"access_token":"any-token","foo":"example"}'
  126. session = ShopifyAPI::Session.new("testshop.myshopify.com", nil, api_version)
  127. params = { code: 'any-code', timestamp: Time.now }
  128. assert session.request_token(params.merge(hmac: generate_signature(params)))
  129. assert_equal ({ "foo" => "example" }), session.extra
  130. end
  131. test "expires_in is automatically converted in expires_at" do
  132. api_version = any_api_version
  133. fake nil,
  134. url: "https://testshop.myshopify.com/admin/oauth/access_token",
  135. method: :post,
  136. body: '{"access_token":"any-token","expires_in":86393}'
  137. session = ShopifyAPI::Session.new("testshop.myshopify.com", nil, api_version)
  138. Timecop.freeze do
  139. params = { code: 'any-code', timestamp: Time.now }
  140. assert session.request_token(params.merge(hmac: generate_signature(params)))
  141. expires_at = Time.now.utc + 86393
  142. assert_equal ({ "expires_at" => expires_at.to_i }), session.extra
  143. assert session.expires_at.is_a?(Time)
  144. assert_equal expires_at.to_i, session.expires_at.to_i
  145. assert_equal 86393, session.expires_in
  146. assert_equal false, session.expired?
  147. Timecop.travel(session.expires_at) do
  148. assert_equal true, session.expired?
  149. end
  150. end
  151. end
  152. test "raise error if signature does not match expected" do
  153. params = {:code => "any-code", :timestamp => Time.now}
  154. signature = generate_signature(params)
  155. params[:foo] = 'world'
  156. assert_raises(ShopifyAPI::ValidationException) do
  157. session = ShopifyAPI::Session.new("testshop.myshopify.com", nil, any_api_version)
  158. session.request_token(params.merge(:hmac => signature))
  159. end
  160. end
  161. test "raise error if timestamp is too old" do
  162. params = {:code => "any-code", :timestamp => Time.now - 2.days}
  163. signature = generate_signature(params)
  164. params[:foo] = 'world'
  165. assert_raises(ShopifyAPI::ValidationException) do
  166. session = ShopifyAPI::Session.new("testshop.myshopify.com", nil, any_api_version)
  167. session.request_token(params.merge(:hmac => signature))
  168. end
  169. end
  170. test "return true when the signature is valid and the keys of params are strings" do
  171. params = { 'code' => 'any-code', 'timestamp' => Time.now }
  172. params[:hmac] = generate_signature(params)
  173. assert_equal true, ShopifyAPI::Session.validate_signature(params)
  174. end
  175. test "return true when validating signature of params with ampersand and equal sign characters" do
  176. ShopifyAPI::Session.secret = 'secret'
  177. params = { 'a' => '1&b=2', 'c=3&d' => '4' }
  178. to_sign = 'a=1%26b=2&c%3D3%26d=4'
  179. params[:hmac] = generate_signature(to_sign)
  180. assert_equal true, ShopifyAPI::Session.validate_signature(params)
  181. end
  182. test "return true when validating signature of params with percent sign characters" do
  183. ShopifyAPI::Session.secret = 'secret'
  184. params = { 'a%3D1%26b' => '2%26c%3D3' }
  185. to_sign = 'a%253D1%2526b=2%2526c%253D3'
  186. params[:hmac] = generate_signature(to_sign)
  187. assert_equal true, ShopifyAPI::Session.validate_signature(params)
  188. end
  189. private
  190. def make_sorted_params(params)
  191. params.with_indifferent_access.except(
  192. :signature, :hmac, :action, :controller
  193. ).collect { |k, v| "#{k}=#{v}" }.sort.join('&')
  194. end
  195. def generate_signature(params)
  196. params = make_sorted_params(params) if params.is_a?(Hash)
  197. OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, ShopifyAPI::Session.secret, params)
  198. end
  199. def any_api_version
  200. [ShopifyAPI::ApiVersion::NoVersion.new, ShopifyAPI::ApiVersion::Unstable.new].sample(1).first
  201. end
  202. end