amazon-iap2 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8e2ea5bc00fa3737874d5678fc2dc174da91728a
4
+ data.tar.gz: ab7cb4564cf7c4a8c4e5d8ba46d162acd1c1f505
5
+ SHA512:
6
+ metadata.gz: 60f70a661b9c409e6d73b55e65ce97f5e9fac4281fc5d1b97fb71acf1bd9303becba9b73aa7afddb0b79c72e4666e9ba6c84313b589f5d347da5a0cfea6b1574
7
+ data.tar.gz: 2021fbb12b7a4ed45a3538b2a62fe57977930c29456775c40d03e42287c7da5a63c3af82c4decbc0fc75c19874570c648705351f420e453e081b88bf98a8389c
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .DS_Store
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in amazon-iap2.gemspec
4
+ gemspec
5
+
6
+ gem "rspec"
7
+ gem "webmock"
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Chris Sturgill
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,113 @@
1
+ # Amazon::Iap
2
+
3
+ This gem is a simple implementation of the Amazon receipt verfication service outlined
4
+ [here](https://developer.amazon.com/sdk/in-app-purchasing/documentation/rvs.html).
5
+
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'amazon-iap'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install amazon-iap
20
+
21
+ ## Usage
22
+
23
+ **NOTE:** Amazon does not deploy a sandbox environment for testing purposes. Rather,
24
+ they give you access to a deployable WAR file. You can use this WAR file to easily deploy your
25
+ own sandbox environment on Heroku. See [here](https://devcenter.heroku.com/articles/war-deployment#command-line)
26
+ for more details.
27
+
28
+ Initialize a client, passing in the developer secret and (optionally) the host. If a host is not
29
+ passed, it will use Amazon's production endpoint.
30
+
31
+ ```ruby
32
+ client = Amazon::Iap::Client.new 'my_developer_secret', 'http://iap-staging.domain.com' # staging server
33
+ client = Amazon::Iap::Client.new 'my_developer_secret' # production server
34
+ ```
35
+
36
+ From there, you can call either `verify` or `renew` on the client and pass in the user id and purchase token:
37
+
38
+ ```ruby
39
+ result = client.verify 'some-user-id', 'some-purchase-token'
40
+ result = client.renew 'some-user-id', 'some-purchase-token'
41
+ ```
42
+
43
+ By default, the `verify` method will automatically try to renew expired tokens, and will recall `verify`
44
+ against the new token returned. If you do not want this behavior, simply pass in `false` as the third
45
+ attribute to the `verify` method:
46
+
47
+ ```ruby
48
+ result = client.verify 'some-user-id', 'some-purchase-token', false
49
+ ```
50
+
51
+ ## Returned Values
52
+
53
+ An instance of Amazon::Iap::Result is returned from both methods, the attributes being the underscored versions
54
+ of the hash keys returned in the JSON object. For convenience, we also add `start_time` and `end_time` attributes
55
+ which are `Time` representations of the milliseconds returned in `start_date` and `end_date` respectively. E.g.,
56
+
57
+ ```ruby
58
+ result = client.verify 'some-user-id', 'some-purchase-token'
59
+
60
+ result.class.name # "Amazon::Iap::Result"
61
+ result.item_type # "SUBSCRIPTION"
62
+ result.sku # "some-sku"
63
+ result.start_date # 1378751554943
64
+ result.start_time # 2013-09-09 14:32:34 -0400
65
+ result.end_date # nil
66
+ result.end_time # nil
67
+ result.purchase_token # "some-purchase-token"
68
+ ```
69
+
70
+ <!-- -->
71
+
72
+ ```ruby
73
+ result = client.renew 'some-user-id', 'some-purchase-token'
74
+
75
+ result.class.name # "Amazon::Iap::Result"
76
+ result.purchase_token # "some-new-purchase-token"
77
+ ```
78
+
79
+ ## Exception Handling
80
+
81
+ Any non-200 status code will raise an exception. For convenience in internal controls, each status code raises
82
+ a distinct exception. Take a look at the [Amazon::Iap::Result class](lib/amazon/iap/result.rb) for specifics.
83
+
84
+ Example exception handling:
85
+
86
+ ```ruby
87
+ begin
88
+ result = client.verify 'some-user-id', 'some-purchase-token'
89
+ rescue Amazon::Iap::Exceptions::InternalError => e
90
+ # enqueue to try again later
91
+ end
92
+ ```
93
+
94
+ For convenience, all exceptions inherit from `Amazon::Iap::Exceptions::Exception` so you can rescue from
95
+ any exception (or as a default):
96
+
97
+ ```ruby
98
+ begin
99
+ result = client.verify 'some-user-id', 'some-purchase-token'
100
+ rescue Amazon::Iap::Exceptions::InternalError => e
101
+ # enqueue to try again later
102
+ rescue Amazon::Iap::Exceptions::Exception => e
103
+ # log the exception
104
+ end
105
+ ```
106
+
107
+ ## Contributing
108
+
109
+ 1. Fork it
110
+ 2. Create your feature branch (`git checkout -b some-new-feature`)
111
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
112
+ 4. Push to the branch (`git push origin some-new-feature`)
113
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'amazon/iap2/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'amazon-iap2'
8
+ spec.version = Amazon::Iap2::VERSION
9
+ spec.authors = ['Blinkist', 'DailyBurn']
10
+ spec.email = ['sj@blinkist.com']
11
+ spec.description = %q{Verify Amazon in app purchases with IAP 2}
12
+ spec.summary = %q{Verify Amazon in app purchases with IAP 2}
13
+ spec.homepage = 'https://github.com/blinkist/amazon-iap2'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.3'
22
+ end
@@ -0,0 +1,10 @@
1
+ require 'amazon/iap2/version'
2
+ require 'amazon/iap2/exceptions'
3
+ require 'amazon/iap2/client'
4
+ require 'amazon/iap2/result'
5
+
6
+ module Amazon
7
+ module Iap2
8
+ # Your code goes here...
9
+ end
10
+ end
@@ -0,0 +1,19 @@
1
+ class Amazon::Iap2::Client
2
+ require 'net/http'
3
+ require 'uri'
4
+
5
+ PRODUCTION_HOST = 'https://appstore-sdk.amazon.com'
6
+
7
+ def initialize(developer_secret, host=nil)
8
+ @developer_secret = developer_secret
9
+ @host = host || PRODUCTION_HOST
10
+ end
11
+
12
+ def verify(user_id, receipt_id)
13
+ path = "/version/1.0/verifyReceiptId/developer/#{@developer_secret}/user/#{user_id}/receiptId/#{receipt_id}"
14
+ uri = URI.parse "#{@host}#{path}"
15
+ req = Net::HTTP::Get.new uri.request_uri
16
+ res = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') { |http| http.request req }
17
+ Amazon::Iap2::Result.new res
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ module Amazon
2
+ module Iap2
3
+ module Exceptions
4
+ class Exception < Exception; end
5
+ class EmptyResponse < Amazon::Iap2::Exceptions::Exception; end
6
+ class InvalidTransaction < Amazon::Iap2::Exceptions::Exception; end
7
+ class InvalidSharedSecret < Amazon::Iap2::Exceptions::Exception; end
8
+ class InvalidUserId < Amazon::Iap2::Exceptions::Exception; end
9
+ class InternalError < Amazon::Iap2::Exceptions::Exception; end
10
+ class General < Amazon::Iap2::Exceptions::Exception; end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,37 @@
1
+ require "json"
2
+
3
+ class Amazon::Iap2::Result
4
+ attr_accessor :product_type, :product_id, :parent_product_id,
5
+ :purchase_date, :purchase_time,
6
+ :cancel_date, :cancel_time,
7
+ :receipt_id,
8
+ :quantity,
9
+ :test_transaction,
10
+ :beta_product
11
+
12
+ def initialize(response)
13
+ case response.code.to_i
14
+ when 200
15
+ parsed = JSON.load(response.body)
16
+
17
+ raise Amazon::Iap2::Exceptions::EmptyResponse unless parsed
18
+
19
+ if parsed.has_key? 'purchaseDate'
20
+ parsed['purchaseTime'] = parsed['purchaseDate'].nil? ? nil : Time.at(parsed['purchaseDate'] / 1000)
21
+ end
22
+ if parsed.has_key? 'cancelDate'
23
+ parsed['cancelTime'] = parsed['cancelDate'].nil? ? nil : Time.at(parsed['cancelDate'] / 1000)
24
+ end
25
+
26
+ parsed.each do |key, value|
27
+ underscore = key.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z\d])([A-Z])/, '\1_\2').tr('-', '_').downcase
28
+ send "#{underscore}=", value
29
+ end
30
+ when 400 then raise Amazon::Iap2::Exceptions::InvalidTransaction
31
+ when 496 then raise Amazon::Iap2::Exceptions::InvalidSharedSecret
32
+ when 497 then raise Amazon::Iap2::Exceptions::InvalidUserId
33
+ when 500 then raise Amazon::Iap2::Exceptions::InternalError
34
+ else raise Amazon::Iap2::Exceptions::General
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,5 @@
1
+ module Amazon
2
+ module Iap2
3
+ VERSION = "0.1"
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ require "rspec"
2
+ require "webmock/rspec"
3
+ require "amazon/iap2"
4
+
5
+ RSpec.configure do |config|
6
+ config.color = true
7
+ config.full_backtrace=true
8
+
9
+ end
@@ -0,0 +1,68 @@
1
+ require "spec_helper"
2
+ require "amazon/iap2/client"
3
+
4
+ describe Amazon::Iap2::Client do
5
+
6
+ subject { described_class.new secret }
7
+
8
+ let(:secret) { "someSecret" }
9
+ let(:receipt_id) { "12345" }
10
+ let(:user_id) { "aUser" }
11
+
12
+ context ".verify" do
13
+
14
+ it "calls the verify url" do
15
+ stub = build_stub user_id, receipt_id
16
+ subject.verify user_id, receipt_id
17
+
18
+ expect(stub).to have_been_requested
19
+ end
20
+
21
+ it "returns the result object" do
22
+ response = build_response receipt_id
23
+ build_stub user_id, receipt_id, 200, response
24
+
25
+ result = subject.verify user_id, receipt_id
26
+
27
+ expect(result.product_type).to eql(response["productType"])
28
+ expect(result.product_id).to eql(response["productId"])
29
+ expect(result.parent_product_id).to eql(response["parentProductId"])
30
+
31
+ expect(result.receipt_id).to eql(response["receiptId"])
32
+ expect(result.quantity).to eql(response["quantity"])
33
+ expect(result.test_transaction).to eql(response["testTransaction"])
34
+ expect(result.beta_product).to eql(response["betaProduct"])
35
+
36
+ expect(result.purchase_date).to eql(response["purchaseDate"])
37
+ expect(result.purchase_time).to eql(Time.at(response["purchaseDate"] / 1000))
38
+ expect(result.cancel_date).to eql(response["cancelDate"])
39
+ expect(result.cancel_time).to eql(Time.at(response["cancelDate"] / 1000))
40
+
41
+ end
42
+
43
+ end
44
+
45
+
46
+ def build_stub(user_id, receipt_id, status=200, response=nil)
47
+ response = build_response receipt_id unless response
48
+
49
+ stub_request(:get, url(user_id, receipt_id)).to_return(:body => response.to_json, :status => status)
50
+ end
51
+
52
+ def url(user_id, receipt_id)
53
+ "https://appstore-sdk.amazon.com/version/1.0/verifyReceiptId/developer/#{secret}/user/#{user_id}/receiptId/#{receipt_id}"
54
+ end
55
+
56
+ def build_response(receipt_id)
57
+ {
58
+ "betaProduct" => true,
59
+ "cancelDate" => (Time.now.to_i + 2629743) * 1000, # one month from now
60
+ "productId" => "sub1",
61
+ "productType" => "SUBSCRIPTION",
62
+ "purchaseDate" => Time.now.to_i * 1000,
63
+ "receiptId" => "#{receipt_id}",
64
+ "testTransaction" => true
65
+ }
66
+ end
67
+
68
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: amazon-iap2
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Blinkist
8
+ - DailyBurn
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-10-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.3'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.3'
28
+ description: Verify Amazon in app purchases with IAP 2
29
+ email:
30
+ - sj@blinkist.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - ".gitignore"
36
+ - Gemfile
37
+ - LICENSE.txt
38
+ - README.md
39
+ - Rakefile
40
+ - amazon-iap2.gemspec
41
+ - lib/amazon/iap2.rb
42
+ - lib/amazon/iap2/client.rb
43
+ - lib/amazon/iap2/exceptions.rb
44
+ - lib/amazon/iap2/result.rb
45
+ - lib/amazon/iap2/version.rb
46
+ - spec/spec_helper.rb
47
+ - spec/specs/client_spec.rb
48
+ homepage: https://github.com/blinkist/amazon-iap2
49
+ licenses:
50
+ - MIT
51
+ metadata: {}
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 2.4.2
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: Verify Amazon in app purchases with IAP 2
72
+ test_files:
73
+ - spec/spec_helper.rb
74
+ - spec/specs/client_spec.rb