session_test.rb 8.8 KB

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