session_test.rb 8.8 KB

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