venice 0.4.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/venice/client.rb CHANGED
@@ -3,8 +3,8 @@ require 'net/https'
3
3
  require 'uri'
4
4
 
5
5
  module Venice
6
- ITUNES_PRODUCTION_RECEIPT_VERIFICATION_ENDPOINT = "https://buy.itunes.apple.com/verifyReceipt"
7
- ITUNES_DEVELOPMENT_RECEIPT_VERIFICATION_ENDPOINT = "https://sandbox.itunes.apple.com/verifyReceipt"
6
+ ITUNES_PRODUCTION_RECEIPT_VERIFICATION_ENDPOINT = 'https://buy.itunes.apple.com/verifyReceipt'
7
+ ITUNES_DEVELOPMENT_RECEIPT_VERIFICATION_ENDPOINT = 'https://sandbox.itunes.apple.com/verifyReceipt'
8
8
 
9
9
  class Client
10
10
  attr_accessor :verification_url
@@ -12,13 +12,13 @@ module Venice
12
12
 
13
13
  class << self
14
14
  def development
15
- client = self.new
15
+ client = new
16
16
  client.verification_url = ITUNES_DEVELOPMENT_RECEIPT_VERIFICATION_ENDPOINT
17
17
  client
18
18
  end
19
19
 
20
20
  def production
21
- client = self.new
21
+ client = new
22
22
  client.verification_url = ITUNES_PRODUCTION_RECEIPT_VERIFICATION_ENDPOINT
23
23
  client
24
24
  end
@@ -33,7 +33,8 @@ module Venice
33
33
  @shared_secret = options[:shared_secret] if options[:shared_secret]
34
34
 
35
35
  json = json_response_from_verifying_data(data)
36
- status, receipt_attributes = json['status'].to_i, json['receipt']
36
+ status = json['status'].to_i
37
+ receipt_attributes = json['receipt'].dup
37
38
  receipt_attributes['original_json_response'] = json if receipt_attributes
38
39
 
39
40
  case status
@@ -73,8 +74,8 @@ module Venice
73
74
  http.verify_mode = OpenSSL::SSL::VERIFY_PEER
74
75
 
75
76
  request = Net::HTTP::Post.new(uri.request_uri)
76
- request['Accept'] = "application/json"
77
- request['Content-Type'] = "application/json"
77
+ request['Accept'] = 'application/json'
78
+ request['Content-Type'] = 'application/json'
78
79
  request.body = parameters.to_json
79
80
 
80
81
  response = http.request(request)
@@ -42,7 +42,6 @@ module Venice
42
42
  # For a transaction that was canceled by Apple customer support, the time and date of the cancellation.
43
43
  attr_reader :cancellation_at
44
44
 
45
-
46
45
  def initialize(attributes = {})
47
46
  @quantity = Integer(attributes['quantity']) if attributes['quantity']
48
47
  @product_id = attributes['product_id']
@@ -65,28 +64,26 @@ module Venice
65
64
 
66
65
  self.original = InAppReceipt.new(original_attributes)
67
66
  end
68
-
69
67
  end
70
68
 
71
69
  def to_hash
72
70
  {
73
- :quantity => @quantity,
74
- :product_id => @product_id,
75
- :transaction_id => @transaction_id,
76
- :purchase_date => (@purchased_at.httpdate rescue nil),
77
- :original_transaction_id => (@original.transaction_id rescue nil),
78
- :original_purchase_date => (@original.purchased_at.httpdate rescue nil),
79
- :app_item_id => @app_item_id,
80
- :version_external_identifier => @version_external_identifier,
81
- :expires_at => (@expires_at.httpdate rescue nil),
82
- :cancellation_at => (@cancellation_at.httpdate rescue nil)
71
+ quantity: @quantity,
72
+ product_id: @product_id,
73
+ transaction_id: @transaction_id,
74
+ purchase_date: (@purchased_at.httpdate rescue nil),
75
+ original_transaction_id: (@original.transaction_id rescue nil),
76
+ original_purchase_date: (@original.purchased_at.httpdate rescue nil),
77
+ app_item_id: @app_item_id,
78
+ version_external_identifier: @version_external_identifier,
79
+ expires_at: (@expires_at.httpdate rescue nil),
80
+ cancellation_at: (@cancellation_at.httpdate rescue nil)
83
81
  }
84
82
  end
85
83
  alias_method :to_h, :to_hash
86
84
 
87
85
  def to_json
88
- self.to_hash.to_json
86
+ to_hash.to_json
89
87
  end
90
-
91
88
  end
92
89
  end
@@ -1,8 +1,7 @@
1
1
  module Venice
2
2
  class PendingRenewalInfo
3
-
4
3
  # For an expired subscription, the reason for the subscription expiration.
5
- # This key is only present for a receipt containing an expired auto-renewable subscription.
4
+ # This key is only present for a receipt containing an expired auto-renewable subscription.
6
5
  attr_reader :expiration_intent
7
6
 
8
7
  # The current renewal status for the auto-renewable subscription.
@@ -29,14 +28,13 @@ module Venice
29
28
  # Use this value along with the cancellation date to identify possible issues in your app that may lead customers to contact Apple customer support.
30
29
  attr_reader :cancellation_reason
31
30
 
32
-
33
31
  def initialize(attributes)
34
32
  @expiration_intent = Integer(attributes['expiration_intent']) if attributes['expiration_intent']
35
33
  @auto_renew_status = Integer(attributes['auto_renew_status']) if attributes['auto_renew_status']
36
34
  @auto_renew_product_id = attributes['auto_renew_product_id']
37
35
 
38
36
  if attributes['is_in_billing_retry_period']
39
- @is_in_billing_retry_period = (attributes[is_in_billing_retry_period] == "1" ? true : false)
37
+ @is_in_billing_retry_period = (attributes[is_in_billing_retry_period] == '1')
40
38
  end
41
39
 
42
40
  @product_id = attributes['product_id']
@@ -60,7 +58,7 @@ module Venice
60
58
  alias_method :to_h, :to_hash
61
59
 
62
60
  def to_json
63
- self.to_hash.to_json
61
+ to_hash.to_json
64
62
  end
65
63
  end
66
64
  end
@@ -68,29 +68,28 @@ module Venice
68
68
  @pending_renewal_info << PendingRenewalInfo.new(pending_renewal_attributes)
69
69
  end
70
70
  end
71
-
72
71
  end
73
72
 
74
73
  def to_hash
75
74
  {
76
- :bundle_id => @bundle_id,
77
- :application_version => @application_version,
78
- :original_application_version => @original_application_version,
79
- :original_purchase_date => (@original_purchase_date.httpdate rescue nil),
80
- :expires_at => (@expires_at.httpdate rescue nil),
81
- :receipt_type => @receipt_type,
82
- :adam_id => @adam_id,
83
- :download_id => @download_id,
84
- :requested_at => (@requested_at.httpdate rescue nil),
85
- :in_app => @in_app.map{|iap| iap.to_h },
86
- :pending_renewal_info => @pending_renewal_info.map { |pend_info| pend_info.to_h },
87
- :latest_receipt_info => @latest_receipt_info
75
+ bundle_id: @bundle_id,
76
+ application_version: @application_version,
77
+ original_application_version: @original_application_version,
78
+ original_purchase_date: (@original_purchase_date.httpdate rescue nil),
79
+ expires_at: (@expires_at.httpdate rescue nil),
80
+ receipt_type: @receipt_type,
81
+ adam_id: @adam_id,
82
+ download_id: @download_id,
83
+ requested_at: (@requested_at.httpdate rescue nil),
84
+ in_app: @in_app.map(&:to_h),
85
+ pending_renewal_info: @pending_renewal_info.map(&:to_h),
86
+ latest_receipt_info: @latest_receipt_info
88
87
  }
89
88
  end
90
89
  alias_method :to_h, :to_hash
91
90
 
92
91
  def to_json
93
- self.to_hash.to_json
92
+ to_hash.to_json
94
93
  end
95
94
 
96
95
  class << self
@@ -132,26 +131,28 @@ module Venice
132
131
 
133
132
  def message
134
133
  case @code
135
- when 21000
136
- "The App Store could not read the JSON object you provided."
137
- when 21002
138
- "The data in the receipt-data property was malformed."
139
- when 21003
140
- "The receipt could not be authenticated."
141
- when 21004
142
- "The shared secret you provided does not match the shared secret on file for your account."
143
- when 21005
144
- "The receipt server is not currently available."
145
- when 21006
146
- "This receipt is valid but the subscription has expired. When this status code is returned to your server, the receipt data is also decoded and returned as part of the response."
147
- when 21007
148
- "This receipt is a sandbox receipt, but it was sent to the production service for verification."
149
- when 21008
150
- "This receipt is a production receipt, but it was sent to the sandbox service for verification."
151
- when 21010
152
- "This receipt could not be authorized. Treat this the same as if a purchase was never made."
153
- else
154
- "Unknown Error: #{@code}"
134
+ when 21000
135
+ 'The App Store could not read the JSON object you provided.'
136
+ when 21002
137
+ 'The data in the receipt-data property was malformed.'
138
+ when 21003
139
+ 'The receipt could not be authenticated.'
140
+ when 21004
141
+ 'The shared secret you provided does not match the shared secret on file for your account.'
142
+ when 21005
143
+ 'The receipt server is not currently available.'
144
+ when 21006
145
+ 'This receipt is valid but the subscription has expired. When this status code is returned to your server, the receipt data is also decoded and returned as part of the response.'
146
+ when 21007
147
+ 'This receipt is a sandbox receipt, but it was sent to the production service for verification.'
148
+ when 21008
149
+ 'This receipt is a production receipt, but it was sent to the sandbox service for verification.'
150
+ when 21010
151
+ 'This receipt could not be authorized. Treat this the same as if a purchase was never made.'
152
+ when 21100..21199
153
+ 'Internal data access error.'
154
+ else
155
+ "Unknown Error: #{@code}"
155
156
  end
156
157
  end
157
158
  end
@@ -1,3 +1,3 @@
1
1
  module Venice
2
- VERSION = "0.4.0"
2
+ VERSION = '0.4.1'
3
3
  end
data/spec/client_spec.rb CHANGED
@@ -1,61 +1,78 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Venice::Client do
4
- let(:receipt_data) { "asdfzxcvjklqwer" }
4
+ let(:receipt_data) { 'asdfzxcvjklqwer' }
5
5
  let(:client) { subject }
6
6
 
7
- describe "#verify!" do
8
- context "no shared_secret" do
7
+ describe '#verify!' do
8
+ context 'with a receipt response' do
9
+ before do
10
+ client.stub(:json_response_from_verifying_data).and_return(response)
11
+ end
12
+
13
+ let(:response) do
14
+ {
15
+ 'status' => 0,
16
+ 'receipt' => {}
17
+ }
18
+ end
19
+
20
+ it 'does not generate a self-referencing Hash' do
21
+ receipt = client.verify! 'asdf'
22
+ expect(receipt.original_json_response['receipt']).not_to have_key('original_json_response')
23
+ end
24
+ end
25
+
26
+ context 'no shared_secret' do
9
27
  before do
10
28
  client.shared_secret = nil
11
29
  Venice::Receipt.stub :new
12
30
  end
13
31
 
14
- it "should only include the receipt_data" do
32
+ it 'should only include the receipt_data' do
15
33
  Net::HTTP.any_instance.should_receive(:request) do |post|
16
- post.body.should eq({'receipt-data' => receipt_data}.to_json)
34
+ post.body.should eq({ 'receipt-data' => receipt_data }.to_json)
17
35
  post
18
36
  end
19
37
  client.verify! receipt_data
20
38
  end
21
39
  end
22
40
 
23
- context "with a shared secret" do
24
- let(:secret) { "shhhhhh" }
41
+ context 'with a shared secret' do
42
+ let(:secret) { 'shhhhhh' }
25
43
 
26
44
  before do
27
45
  Venice::Receipt.stub :new
28
46
  end
29
47
 
30
- context "set secret manually" do
48
+ context 'set secret manually' do
31
49
  before do
32
50
  client.shared_secret = secret
33
51
  end
34
52
 
35
- it "should include the secret in the post" do
53
+ it 'should include the secret in the post' do
36
54
  Net::HTTP.any_instance.should_receive(:request) do |post|
37
- post.body.should eq({'receipt-data' => receipt_data, 'password' => secret}.to_json)
55
+ post.body.should eq({ 'receipt-data' => receipt_data, 'password' => secret }.to_json)
38
56
  post
39
57
  end
40
58
  client.verify! receipt_data
41
59
  end
42
60
  end
43
61
 
44
- context "set secret when verification" do
45
- let(:options) { {shared_secret: secret} }
62
+ context 'set secret when verification' do
63
+ let(:options) { { shared_secret: secret } }
46
64
 
47
- it "should include the secret in the post" do
65
+ it 'should include the secret in the post' do
48
66
  Net::HTTP.any_instance.should_receive(:request) do |post|
49
- post.body.should eq({'receipt-data' => receipt_data, 'password' => secret}.to_json)
67
+ post.body.should eq({ 'receipt-data' => receipt_data, 'password' => secret }.to_json)
50
68
  post
51
69
  end
52
70
  client.verify! receipt_data, options
53
71
  end
54
72
  end
55
-
56
73
  end
57
74
 
58
- context "with a latest receipt info attribute" do
75
+ context 'with a latest receipt info attribute' do
59
76
  before do
60
77
  client.stub(:json_response_from_verifying_data).and_return(response)
61
78
  end
@@ -64,37 +81,36 @@ describe Venice::Client do
64
81
  {
65
82
  'status' => 0,
66
83
  'receipt' => {},
67
- 'latest_receipt' => "<encoded string>",
84
+ 'latest_receipt' => '<encoded string>',
68
85
  'latest_receipt_info' => [
69
86
  {
70
- "original_purchase_date_pst" => "2012-12-30 09:39:24 America/Los_Angeles",
71
- "unique_identifier" => "0000b01147b8",
72
- "original_transaction_id" => "1000000061051565",
73
- "expires_date" => "1365114731000",
74
- "transaction_id" => "1000000070104252",
75
- "quantity" => "1",
76
- "product_id" => "com.ficklebits.nsscreencast.monthly_sub",
77
- "original_purchase_date_ms" => "1356889164000",
78
- "bid" => "com.ficklebits.nsscreencast",
79
- "web_order_line_item_id" => "1000000026812043",
80
- "bvrs" => "0.1",
81
- "expires_date_formatted" => "2013-04-04 22:32:11 Etc/GMT",
82
- "purchase_date" => "2013-04-04 22:27:11 Etc/GMT",
83
- "purchase_date_ms" => "1365114431000",
84
- "expires_date_formatted_pst" => "2013-04-04 15:32:11 America/Los_Angeles",
85
- "purchase_date_pst" => "2013-04-04 15:27:11 America/Los_Angeles",
86
- "original_purchase_date" => "2012-12-30 17:39:24 Etc/GMT",
87
- "item_id" => "590265423"
87
+ 'original_purchase_date_pst' => '2012-12-30 09:39:24 America/Los_Angeles',
88
+ 'unique_identifier' => '0000b01147b8',
89
+ 'original_transaction_id' => '1000000061051565',
90
+ 'expires_date' => '1365114731000',
91
+ 'transaction_id' => '1000000070104252',
92
+ 'quantity' => '1',
93
+ 'product_id' => 'com.ficklebits.nsscreencast.monthly_sub',
94
+ 'original_purchase_date_ms' => '1356889164000',
95
+ 'bid' => 'com.ficklebits.nsscreencast',
96
+ 'web_order_line_item_id' => '1000000026812043',
97
+ 'bvrs' => '0.1',
98
+ 'expires_date_formatted' => '2013-04-04 22:32:11 Etc/GMT',
99
+ 'purchase_date' => '2013-04-04 22:27:11 Etc/GMT',
100
+ 'purchase_date_ms' => '1365114431000',
101
+ 'expires_date_formatted_pst' => '2013-04-04 15:32:11 America/Los_Angeles',
102
+ 'purchase_date_pst' => '2013-04-04 15:27:11 America/Los_Angeles',
103
+ 'original_purchase_date' => '2012-12-30 17:39:24 Etc/GMT',
104
+ 'item_id' => '590265423'
88
105
  }
89
106
  ]
90
107
  }
91
108
  end
92
109
 
93
- it "should create a latest receipt" do
110
+ it 'should create a latest receipt' do
94
111
  receipt = client.verify! 'asdf'
95
112
  receipt.latest_receipt_info.should_not be_nil
96
113
  end
97
114
  end
98
-
99
115
  end
100
116
  end
@@ -1,26 +1,24 @@
1
1
  require 'spec_helper.rb'
2
2
 
3
3
  describe Venice::InAppReceipt do
4
-
5
- describe ".new" do
6
-
4
+ describe '.new' do
7
5
  let :attributes do
8
6
  {
9
- "quantity" => 1,
10
- "product_id" => "com.foo.product1",
11
- "transaction_id" => "1000000070107235",
12
- "purchase_date" => "2014-05-28 14:47:53 Etc/GMT",
13
- "purchase_date_ms" => "1401288473000",
14
- "purchase_date_pst" => "2014-05-28 07:47:53 America/Los_Angeles",
15
- "original_transaction_id" => "140xxx867509",
16
- "original_purchase_date" => "2014-05-28 14:47:53 Etc/GMT",
17
- "original_purchase_date_ms" => "1401288473000",
18
- "original_purchase_date_pst" => "2014-05-28 07:47:53 America/Los_Angeles",
19
- "is_trial_period" => false,
20
- "version_external_identifier" => "123",
21
- "app_item_id" => 'com.foo.app1',
22
- "expires_date" => "2014-06-28 07:47:53 America/Los_Angeles",
23
- "expires_date_ms" => "1403941673000"
7
+ 'quantity' => 1,
8
+ 'product_id' => 'com.foo.product1',
9
+ 'transaction_id' => '1000000070107235',
10
+ 'purchase_date' => '2014-05-28 14:47:53 Etc/GMT',
11
+ 'purchase_date_ms' => '1401288473000',
12
+ 'purchase_date_pst' => '2014-05-28 07:47:53 America/Los_Angeles',
13
+ 'original_transaction_id' => '140xxx867509',
14
+ 'original_purchase_date' => '2014-05-28 14:47:53 Etc/GMT',
15
+ 'original_purchase_date_ms' => '1401288473000',
16
+ 'original_purchase_date_pst' => '2014-05-28 07:47:53 America/Los_Angeles',
17
+ 'is_trial_period' => false,
18
+ 'version_external_identifier' => '123',
19
+ 'app_item_id' => 'com.foo.app1',
20
+ 'expires_date' => '2014-06-28 07:47:53 America/Los_Angeles',
21
+ 'expires_date_ms' => '1403941673000'
24
22
  }
25
23
  end
26
24
 
@@ -29,30 +27,26 @@ describe Venice::InAppReceipt do
29
27
  end
30
28
 
31
29
  its(:quantity) { 1 }
32
- its(:product_id) { "com.foo.product1" }
33
- its(:transaction_id) { "1000000070107235" }
30
+ its(:product_id) { 'com.foo.product1' }
31
+ its(:transaction_id) { '1000000070107235' }
34
32
  its(:purchased_at) { should be_instance_of DateTime }
35
33
  its(:app_item_id) { 'com.foo.app1' }
36
- its(:version_external_identifier) { "123" }
34
+ its(:version_external_identifier) { '123' }
37
35
  its(:original) { should be_instance_of Venice::InAppReceipt }
38
36
  its(:expires_at) { should be_instance_of Time }
39
37
 
40
38
  it "should parse the 'original' attributes" do
41
39
  subject.original.should be_instance_of Venice::InAppReceipt
42
- subject.original.transaction_id.should == "140xxx867509"
40
+ subject.original.transaction_id.should == '140xxx867509'
43
41
  subject.original.purchased_at.should be_instance_of DateTime
44
42
  end
45
43
 
46
- it "should output a hash with attributes" do
47
- in_app_receipt.to_h.should include(:quantity => 1,
48
- :product_id => "com.foo.product1",
49
- :transaction_id => "1000000070107235",
50
- :purchase_date => "Wed, 28 May 2014 14:47:53 GMT",
51
- :original_purchase_date => "Wed, 28 May 2014 14:47:53 GMT"
52
- )
44
+ it 'should output a hash with attributes' do
45
+ in_app_receipt.to_h.should include(quantity: 1,
46
+ product_id: 'com.foo.product1',
47
+ transaction_id: '1000000070107235',
48
+ purchase_date: 'Wed, 28 May 2014 14:47:53 GMT',
49
+ original_purchase_date: 'Wed, 28 May 2014 14:47:53 GMT')
53
50
  end
54
-
55
-
56
51
  end
57
-
58
52
  end