session_test.rb 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  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 "use 'https' protocol by default for all sessions" do
  48. assert_equal 'https', ShopifyAPI::Session.protocol
  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/admin', @assigned_site.to_s
  58. assert_equal 'https://fakeshop.myshopify.com/admin', 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 "#temp reset ShopifyAPI::Base.site to original value when using a non-standard port" do
  98. ShopifyAPI::Session.setup(:api_key => "key", :secret => "secret")
  99. session1 = ShopifyAPI::Session.new('fakeshop.myshopify.com:3000', 'token1')
  100. ShopifyAPI::Base.activate_session(session1)
  101. end
  102. test "myshopify_domain supports non-standard ports" do
  103. begin
  104. ShopifyAPI::Session.setup(:api_key => "key", :secret => "secret", :myshopify_domain => 'localhost', port: '3000')
  105. session = ShopifyAPI::Session.new('fakeshop.localhost:3000', 'token1')
  106. ShopifyAPI::Base.activate_session(session)
  107. assert_equal 'https://fakeshop.localhost:3000/admin', ShopifyAPI::Base.site.to_s
  108. session = ShopifyAPI::Session.new('fakeshop', 'token1')
  109. ShopifyAPI::Base.activate_session(session)
  110. assert_equal 'https://fakeshop.localhost:3000/admin', ShopifyAPI::Base.site.to_s
  111. ensure
  112. ShopifyAPI::Session.myshopify_domain = "myshopify.com"
  113. ShopifyAPI::Session.port = nil
  114. end
  115. end
  116. test "return site for session" do
  117. session = ShopifyAPI::Session.new("testshop.myshopify.com", "any-token")
  118. assert_equal "https://testshop.myshopify.com/admin", session.site
  119. end
  120. test "return_token_if_signature_is_valid" do
  121. fake nil,
  122. url: 'https://testshop.myshopify.com/admin/oauth/access_token',
  123. method: :post,
  124. body: '{"access_token":"any-token"}'
  125. session = ShopifyAPI::Session.new("testshop.myshopify.com")
  126. params = { code: 'any-code', timestamp: Time.now }
  127. token = session.request_token(params.merge(hmac: generate_signature(params)))
  128. assert_equal "any-token", token
  129. assert_equal "any-token", session.token
  130. end
  131. test "extra parameters are stored in session" do
  132. fake nil,
  133. url: 'https://testshop.myshopify.com/admin/oauth/access_token',
  134. method: :post,
  135. body: '{"access_token":"any-token","foo":"example"}'
  136. session = ShopifyAPI::Session.new("testshop.myshopify.com")
  137. params = { code: 'any-code', timestamp: Time.now }
  138. assert session.request_token(params.merge(hmac: generate_signature(params)))
  139. assert_equal ({ "foo" => "example" }), session.extra
  140. end
  141. test "expires_in is automatically converted in expires_at" do
  142. fake nil,
  143. url: 'https://testshop.myshopify.com/admin/oauth/access_token',
  144. method: :post,
  145. body: '{"access_token":"any-token","expires_in":86393}'
  146. session = ShopifyAPI::Session.new("testshop.myshopify.com")
  147. Timecop.freeze do
  148. params = { code: 'any-code', timestamp: Time.now }
  149. assert session.request_token(params.merge(hmac: generate_signature(params)))
  150. expires_at = Time.now.utc + 86393
  151. assert_equal ({ "expires_at" => expires_at.to_i }), session.extra
  152. assert session.expires_at.is_a?(Time)
  153. assert_equal expires_at.to_i, session.expires_at.to_i
  154. assert_equal 86393, session.expires_in
  155. assert_equal false, session.expired?
  156. Timecop.travel(session.expires_at) do
  157. assert_equal true, session.expired?
  158. end
  159. end
  160. end
  161. test "raise error if signature does not match expected" do
  162. params = {:code => "any-code", :timestamp => Time.now}
  163. signature = generate_signature(params)
  164. params[:foo] = 'world'
  165. assert_raises(ShopifyAPI::ValidationException) do
  166. session = ShopifyAPI::Session.new("testshop.myshopify.com")
  167. session.request_token(params.merge(:hmac => signature))
  168. end
  169. end
  170. test "raise error if timestamp is too old" do
  171. params = {:code => "any-code", :timestamp => Time.now - 2.days}
  172. signature = generate_signature(params)
  173. params[:foo] = 'world'
  174. assert_raises(ShopifyAPI::ValidationException) do
  175. session = ShopifyAPI::Session.new("testshop.myshopify.com")
  176. session.request_token(params.merge(:hmac => signature))
  177. end
  178. end
  179. test "return true when the signature is valid and the keys of params are \
  180. strings" do
  181. params = { 'code' => 'any-code', 'timestamp' => Time.now }
  182. params[:hmac] = generate_signature(params)
  183. assert_equal true, ShopifyAPI::Session.validate_signature(params)
  184. end
  185. test "return true when validating signature of params with ampersand \
  186. and equal sign characters" do
  187. ShopifyAPI::Session.secret = 'secret'
  188. params = { 'a' => '1&b=2', 'c=3&d' => '4' }
  189. to_sign = 'a=1%26b=2&c%3D3%26d=4'
  190. params[:hmac] = generate_signature(to_sign)
  191. assert_equal true, ShopifyAPI::Session.validate_signature(params)
  192. end
  193. test "return true when validating signature of params with percent sign\
  194. characters" do
  195. ShopifyAPI::Session.secret = 'secret'
  196. params = { 'a%3D1%26b' => '2%26c%3D3' }
  197. to_sign = 'a%253D1%2526b=2%2526c%253D3'
  198. params[:hmac] = generate_signature(to_sign)
  199. assert_equal true, ShopifyAPI::Session.validate_signature(params)
  200. end
  201. private
  202. def make_sorted_params(params)
  203. params.with_indifferent_access.except(
  204. :signature, :hmac, :action, :controller
  205. ).collect { |k, v| "#{k}=#{v}" }.sort.join('&')
  206. end
  207. def generate_signature(params)
  208. params = make_sorted_params(params) if params.is_a?(Hash)
  209. OpenSSL::HMAC.hexdigest(
  210. OpenSSL::Digest::SHA256.new,
  211. ShopifyAPI::Session.secret, params
  212. )
  213. end
  214. end