candy_check 0.1.0.pre → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +23 -0
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +7 -8
  5. data/Guardfile +42 -0
  6. data/MIGRATION_GUIDE_0_2_0.md +141 -0
  7. data/README.md +86 -26
  8. data/Rakefile +1 -1
  9. data/candy_check.gemspec +33 -25
  10. data/lib/candy_check/app_store/receipt_collection.rb +5 -3
  11. data/lib/candy_check/app_store/subscription_verification.rb +25 -1
  12. data/lib/candy_check/app_store/verification.rb +1 -1
  13. data/lib/candy_check/app_store/verifier.rb +11 -11
  14. data/lib/candy_check/cli/app.rb +16 -33
  15. data/lib/candy_check/cli/commands/play_store.rb +12 -13
  16. data/lib/candy_check/play_store.rb +20 -10
  17. data/lib/candy_check/play_store/acknowledger.rb +19 -0
  18. data/lib/candy_check/play_store/android_publisher_service.rb +6 -0
  19. data/lib/candy_check/play_store/product_acknowledgements/acknowledgement.rb +45 -0
  20. data/lib/candy_check/play_store/product_acknowledgements/response.rb +24 -0
  21. data/lib/candy_check/play_store/product_purchases/product_purchase.rb +90 -0
  22. data/lib/candy_check/play_store/product_purchases/product_verification.rb +53 -0
  23. data/lib/candy_check/play_store/subscription_purchases/subscription_purchase.rb +154 -0
  24. data/lib/candy_check/play_store/subscription_purchases/subscription_verification.rb +55 -0
  25. data/lib/candy_check/play_store/verification_failure.rb +8 -6
  26. data/lib/candy_check/play_store/verifier.rb +24 -49
  27. data/lib/candy_check/utils/config.rb +5 -3
  28. data/lib/candy_check/version.rb +1 -1
  29. data/spec/app_store/receipt_collection_spec.rb +33 -0
  30. data/spec/app_store/subscription_verification_spec.rb +35 -2
  31. data/spec/app_store/verifier_spec.rb +24 -5
  32. data/spec/candy_check_spec.rb +2 -2
  33. data/spec/cli/commands/play_store_spec.rb +10 -43
  34. data/spec/fixtures/play_store/random_dummy_key.json +12 -0
  35. data/spec/fixtures/vcr_cassettes/play_store/product_acknowledgements/acknowledged.yml +105 -0
  36. data/spec/fixtures/vcr_cassettes/play_store/product_acknowledgements/already_acknowledged.yml +124 -0
  37. data/spec/fixtures/vcr_cassettes/play_store/product_acknowledgements/refunded.yml +122 -0
  38. data/spec/fixtures/vcr_cassettes/play_store/product_purchases/permission_denied.yml +196 -0
  39. data/spec/fixtures/vcr_cassettes/play_store/product_purchases/response_with_empty_body.yml +183 -0
  40. data/spec/fixtures/vcr_cassettes/play_store/product_purchases/valid_but_not_consumed.yml +122 -0
  41. data/spec/fixtures/vcr_cassettes/play_store/subscription_purchases/permission_denied.yml +196 -0
  42. data/spec/fixtures/vcr_cassettes/play_store/subscription_purchases/valid_but_expired.yml +127 -0
  43. data/spec/play_store/acknowledger_spec.rb +48 -0
  44. data/spec/play_store/product_acknowledgements/acknowledgement_spec.rb +54 -0
  45. data/spec/play_store/product_acknowledgements/response_spec.rb +66 -0
  46. data/spec/play_store/product_purchases/product_purchase_spec.rb +110 -0
  47. data/spec/play_store/product_purchases/product_verification_spec.rb +49 -0
  48. data/spec/play_store/subscription_purchases/subscription_purchase_spec.rb +237 -0
  49. data/spec/play_store/subscription_purchases/subscription_verification_spec.rb +65 -0
  50. data/spec/play_store/verification_failure_spec.rb +18 -18
  51. data/spec/play_store/verifier_spec.rb +32 -96
  52. data/spec/spec_helper.rb +32 -10
  53. metadata +175 -75
  54. data/lib/candy_check/play_store/client.rb +0 -126
  55. data/lib/candy_check/play_store/config.rb +0 -51
  56. data/lib/candy_check/play_store/discovery_repository.rb +0 -33
  57. data/lib/candy_check/play_store/receipt.rb +0 -81
  58. data/lib/candy_check/play_store/subscription.rb +0 -138
  59. data/lib/candy_check/play_store/subscription_verification.rb +0 -30
  60. data/lib/candy_check/play_store/verification.rb +0 -48
  61. data/spec/fixtures/api_cache.dump +0 -1
  62. data/spec/fixtures/play_store/api_cache.dump +0 -1
  63. data/spec/fixtures/play_store/auth_failure.txt +0 -18
  64. data/spec/fixtures/play_store/auth_success.txt +0 -20
  65. data/spec/fixtures/play_store/discovery.txt +0 -2841
  66. data/spec/fixtures/play_store/dummy.p12 +0 -0
  67. data/spec/fixtures/play_store/empty.txt +0 -17
  68. data/spec/fixtures/play_store/products_failure.txt +0 -29
  69. data/spec/fixtures/play_store/products_success.txt +0 -22
  70. data/spec/play_store/client_spec.rb +0 -125
  71. data/spec/play_store/config_spec.rb +0 -96
  72. data/spec/play_store/discovery_respository_spec.rb +0 -31
  73. data/spec/play_store/receipt_spec.rb +0 -88
  74. data/spec/play_store/subscription_spec.rb +0 -138
  75. data/spec/play_store/subscription_verification_spec.rb +0 -98
  76. data/spec/play_store/verification_spec.rb +0 -82
@@ -38,20 +38,53 @@ describe CandyCheck::AppStore::SubscriptionVerification do
38
38
  response = {
39
39
  'status' => 0,
40
40
  'latest_receipt_info' => [
41
- { 'item_id' => 'some_id' },
42
- { 'item_id' => 'some_other_id' }
41
+ { 'item_id' => 'some_id', 'purchase_date' => '2016-04-15 12:52:40 Etc/GMT' },
42
+ { 'item_id' => 'some_other_id', 'purchase_date' => '2016-04-15 12:52:40 Etc/GMT' }
43
43
  ]
44
44
  }
45
45
  with_mocked_response(response) do
46
46
  result = subject.call!
47
47
  result.must_be_instance_of CandyCheck::AppStore::ReceiptCollection
48
48
  result.receipts.must_be_instance_of Array
49
+ result.receipts.size.must_equal(2)
49
50
  last = result.receipts.last
50
51
  last.must_be_instance_of CandyCheck::AppStore::Receipt
51
52
  last.item_id.must_equal('some_other_id')
52
53
  end
53
54
  end
54
55
 
56
+ describe 'filtered product_ids' do
57
+ subject do
58
+ CandyCheck::AppStore::SubscriptionVerification.new(
59
+ endpoint,
60
+ data,
61
+ secret,
62
+ product_ids
63
+ )
64
+ end
65
+ let(:product_ids) { ['product_1'] }
66
+
67
+ it 'returns only filtered reciepts when specifc product_ids are reqested' do
68
+ response = {
69
+ 'status' => 0,
70
+ 'latest_receipt_info' => [
71
+ { 'item_id' => 'some_id', 'product_id' => 'product_1', 'purchase_date' => '2016-04-15 12:52:40 Etc/GMT' },
72
+ { 'item_id' => 'some_other_id', 'product_id' => 'product_1', 'purchase_date' => '2016-04-15 12:52:40 Etc/GMT' },
73
+ { 'item_id' => 'some_id', 'product_id' => 'product_2', 'purchase_date' => '2016-04-15 12:52:40 Etc/GMT' }
74
+ ]
75
+ }
76
+ with_mocked_response(response) do
77
+ result = subject.call!
78
+ result.must_be_instance_of CandyCheck::AppStore::ReceiptCollection
79
+ result.receipts.must_be_instance_of Array
80
+ result.receipts.size.must_equal(2)
81
+ last = result.receipts.last
82
+ last.must_be_instance_of CandyCheck::AppStore::Receipt
83
+ last.item_id.must_equal('some_other_id')
84
+ end
85
+ end
86
+ end
87
+
55
88
  private
56
89
 
57
90
  DummyClient = Struct.new(:response) do
@@ -89,7 +89,7 @@ describe CandyCheck::AppStore::Verifier do
89
89
  subject.verify_subscription(
90
90
  data, secret
91
91
  ).must_be_same_as receipt_collection
92
- assert_recorded([production_endpoint, data, secret])
92
+ assert_recorded([production_endpoint, data, secret, nil])
93
93
  end
94
94
  end
95
95
 
@@ -97,7 +97,7 @@ describe CandyCheck::AppStore::Verifier do
97
97
  failure = get_failure(21_000)
98
98
  with_mocked_verifier(failure) do
99
99
  subject.verify_subscription(data, secret).must_be_same_as failure
100
- assert_recorded([production_endpoint, data, secret])
100
+ assert_recorded([production_endpoint, data, secret, nil])
101
101
  end
102
102
  end
103
103
 
@@ -106,11 +106,21 @@ describe CandyCheck::AppStore::Verifier do
106
106
  with_mocked_verifier(failure, receipt) do
107
107
  subject.verify_subscription(data, secret).must_be_same_as receipt
108
108
  assert_recorded(
109
- [production_endpoint, data, secret],
110
- [sandbox_endpoint, data, secret]
109
+ [production_endpoint, data, secret, nil],
110
+ [sandbox_endpoint, data, secret, nil]
111
111
  )
112
112
  end
113
113
  end
114
+
115
+ it 'passed the product_ids' do
116
+ product_ids = ['product_1']
117
+ with_mocked_verifier(receipt_collection) do
118
+ subject.verify_subscription(
119
+ data, secret, product_ids
120
+ ).must_be_same_as receipt_collection
121
+ assert_recorded([production_endpoint, data, secret, product_ids])
122
+ end
123
+ end
114
124
  end
115
125
 
116
126
  private
@@ -134,8 +144,17 @@ describe CandyCheck::AppStore::Verifier do
134
144
  CandyCheck::AppStore::VerificationFailure.fetch(code)
135
145
  end
136
146
 
137
- DummyAppStoreVerification = Struct.new(:endpoint, :data, :secret) do
147
+ class DummyAppStoreVerification
148
+ attr_reader :endpoint, :data, :secret, :product_ids
138
149
  attr_accessor :results
150
+
151
+ def initialize(endpoint, data, secret, product_ids = nil)
152
+ @endpoint = endpoint
153
+ @data = data
154
+ @secret = secret
155
+ @product_ids = product_ids
156
+ end
157
+
139
158
  def call!
140
159
  results.shift
141
160
  end
@@ -1,9 +1,9 @@
1
- require 'spec_helper'
1
+ require "spec_helper"
2
2
 
3
3
  describe CandyCheck do
4
4
  subject { CandyCheck }
5
5
 
6
- it 'has a version' do
6
+ it "has a version" do
7
7
  subject::VERSION.wont_be_nil
8
8
  end
9
9
  end
@@ -1,51 +1,18 @@
1
- require 'spec_helper'
1
+ require "spec_helper"
2
2
 
3
3
  describe CandyCheck::CLI::Commands::PlayStore do
4
4
  include WithCommand
5
- subject { CandyCheck::CLI::Commands::PlayStore }
6
- let(:arguments) { [package, product_id, token, options] }
7
- let(:package) { 'the_package' }
8
- let(:product_id) { 'the_product' }
9
- let(:token) { 'the_token' }
10
- let(:options) do
11
- {
12
- application_name: 'YourApplication',
13
- application_version: '1.0',
14
- issuer: 'abcdefg@developer.gserviceaccount.com',
15
- key_file: 'local/google.p12',
16
- key_secret: 'notasecret'
17
- }
18
- end
5
+ subject { CandyCheck::CLI::Commands::PlayStore.new(package_name, product_id, token, "json_key_file" => json_key_file) }
6
+ let(:package_name) { "my_package_name" }
7
+ let(:product_id) { "my_product_id" }
8
+ let(:token) { "my_token" }
9
+ let(:json_key_file) { File.expand_path("../../fixtures/play_store/random_dummy_key.json", __dir__) }
19
10
 
20
- before do
21
- stub = proc do |*args|
22
- @verifier = DummyPlayStoreVerifier.new(*args)
23
- end
24
- CandyCheck::PlayStore::Verifier.stub :new, stub do
11
+ it "calls and outputs the verifier" do
12
+ VCR.use_cassette("play_store/product_purchases/valid_but_not_consumed") do
25
13
  run_command!
26
- end
27
- end
28
-
29
- it 'calls and outputs the verifier' do
30
- options.each do |k, v|
31
- @verifier.config.public_send(k).must_equal v
32
- end
33
- @verifier.arguments.must_equal [package, product_id, token]
34
- out.must_be 'Hash:', result: :stubbed
35
- end
36
-
37
- private
38
-
39
- DummyPlayStoreVerifier = Struct.new(:config) do
40
- attr_reader :arguments, :booted
41
-
42
- def boot!
43
- @booted = true
44
- end
45
-
46
- def verify(*arguments)
47
- @arguments = arguments
48
- { result: :stubbed }
14
+ assert_equal "CandyCheck::PlayStore::ProductPurchases::ProductPurchase:", out.lines.first
15
+ assert_equal CandyCheck::PlayStore::ProductPurchases::ProductPurchase, out.lines[1].class
49
16
  end
50
17
  end
51
18
  end
@@ -0,0 +1,12 @@
1
+ {
2
+ "type": "service_account",
3
+ "project_id": "example",
4
+ "private_key_id": "123456789",
5
+ "private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEoAIBAAKCAQEAvR7l72CT7UBP6P+02Iut8gKKbKyekz/pQxnckPp1VafuaIwC\nMvYfP4ffVJTcY5IhU9mISNxZf6YDQ0TuD1aOrZYG9wsIgGY0nXhOUZxe/Q5I+V7D\nOI/hSzKF7W0cNCvaJPUSo8+soCLNSQ5mjnV3sRZ6uJwGFN30i1GulqHHKkx3vGxb\niaAL9YG58dPSbPGHFTA/epqUyd1fzCuWHyL9dHW7aw4RroNyEtVdiftAQfaK20I2\nueeDfuEtCPaxQYFQqbz5kKnXQx3fwHRpC7/84xHxsrY576evGxHw4p5EJD37scNN\ncneTG3Ly79/VVSAlrSm6ltutx0+S70scCqK0ewIDAQABAoH/MjwC15LPuDVdBIbn\ngp2XlrEWE8fGV1ainzA/ZkMg55+ztBF8hAzcQAPXTqA76jbmo18k1DWzkDSIqVWl\n5m0XeQRg1T4ZBAIh97H9G7BtispAl/yT3nJZZaAF8wsIctMzHp36VYjUUbTs0nsA\nwtZw9JkEAAVxmBlc26TWuyw9uv4fYXuR+uOsWH8jTTVPvxM9FaCCdK+dOMnswm7Y\nlOAlJj5dANkB2KPwIeE461ThyMo9GHEjpsvciMhKLuBoTSucNkhdgapAmYTSI+/1\nf1cA/KEdCMs9ANr1HFujeS01+N1Xrw/yW6EazaDN1oFHCVORtlB295Eac0Wq6y/P\npf1BAoGBAPIw4HQWsolU3f4FdIvc2POAcSJDRgt++I9Qt/QXq1SJ2dGKIveFiJgo\nZjCfHQFVZ8xl64cLzQ1WagZA1JBbbk9g5RxHDxRv7q+Kn3ogugDo9GUoQvpuuAU6\nXHoR/mLinDorJUnttL3U49xTMfrrut4qkUg+daBVptPtylpio6EDAoGBAMfnYq08\nfd/cPEQ2XPeswgtzXsKNLqA6UXBM7ZauKaFLByjy8peMMF6JPOYlBKQif5k+Egmu\nWIe8oTm8Nn5Ymt32bEd+MkHUC7kFzQeiXnM3u0oKzJMXLAvjSTs296g50YM5zJTC\nl64ACQmQOLZ9tdKorl52ZcmdbBEcZ2uwRvkpAoGAKhs5SrWPgLTSi5FjO9W/mkYg\nZTaQ/PqsOC5ubO+Yh/AXgIiln6cFon6Tlax0HIE+tJibpDT3B3SYplGrIxXiTcao\nzovEIWd8deSB6Xe7HuFhbBzd2DBbqf0FiuuJ8KM5ShuqNfovzDkxDGMic198c5eu\n/oJtbNy3Tm0vGxu/GwUCgYAgmRPXShkAq0pMmUzZups+AMdAFIO47ymelXzc6HOz\ncKevPsbefabZk6mRohG6rkF+fMe2Om8HW3QzFQUR32MJtQh9NA//+hMbTd3cU9bx\nFPJ+pXostkehfKPReyoxjZQjwQYicAUKA8l1fMYyxBclTgp5Lvd0RC5+L9KRlgJM\n2QKBgGVIWRNVpGg38dDqdq/4ue1BoTFhqoMGi6WQm3xa+NH+lyJGacdUhGRz8PxN\nhVKpIj8ljg2Rq/CA9qSgL/Z9rhn8QUMWULuAroCp0S2pMBtZ2RB+Mg2FdVFR9/Ft\nfG7co6mKUGkFPtr48EMfeKY88BRsp3yGOsROGdDsCHItjOVH\n-----END RSA PRIVATE KEY-----\n",
6
+ "client_email": "info@example.com",
7
+ "client_id": "123456789",
8
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
9
+ "token_uri": "https://oauth2.googleapis.com/token",
10
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
11
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/example.iam.gserviceaccount.com"
12
+ }
@@ -0,0 +1,105 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://www.googleapis.com/oauth2/v4/token
6
+ body:
7
+ encoding: ASCII-8BIT
8
+ string: params
9
+ headers:
10
+ User-Agent:
11
+ - Faraday v1.0.1
12
+ Content-Type:
13
+ - application/x-www-form-urlencoded
14
+ Accept-Encoding:
15
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
16
+ Accept:
17
+ - "*/*"
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Content-Type:
24
+ - application/json; charset=UTF-8
25
+ Vary:
26
+ - Origin
27
+ - Referer
28
+ - X-Origin
29
+ Date:
30
+ - Mon, 22 Jun 2020 11:38:56 GMT
31
+ Server:
32
+ - scaffolding on HTTPServer2
33
+ Cache-Control:
34
+ - private
35
+ X-Xss-Protection:
36
+ - '0'
37
+ X-Frame-Options:
38
+ - SAMEORIGIN
39
+ X-Content-Type-Options:
40
+ - nosniff
41
+ Alt-Svc:
42
+ - h3-28=":443"; ma=2592000,h3-27=":443"; ma=2592000,h3-25=":443"; ma=2592000,h3-T050=":443";
43
+ ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443";
44
+ ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443";
45
+ ma=2592000; v="46,43"
46
+ Transfer-Encoding:
47
+ - chunked
48
+ body:
49
+ encoding: ASCII-8BIT
50
+ string: '{"access_token":"access_token","expires_in":3599,"token_type":"Bearer"}'
51
+ recorded_at: Mon, 22 Jun 2020 11:38:56 GMT
52
+ - request:
53
+ method: post
54
+ uri: https://www.googleapis.com/androidpublisher/v3/applications/fake_package_name/purchases/products/fake_product_id/tokens/fake_token:acknowledge
55
+ body:
56
+ encoding: UTF-8
57
+ string: ''
58
+ headers:
59
+ User-Agent:
60
+ - unknown/0.0.0 google-api-ruby-client/0.34.1 Mac OS X/10.14.6 (gzip)
61
+ Accept:
62
+ - "*/*"
63
+ Accept-Encoding:
64
+ - gzip,deflate
65
+ Date:
66
+ - Mon, 22 Jun 2020 11:38:56 GMT
67
+ X-Goog-Api-Client:
68
+ - gl-ruby/2.5.1 gdcl/0.34.1
69
+ Authorization:
70
+ - Bearer some_token
71
+ Content-Type:
72
+ - application/x-www-form-urlencoded
73
+ response:
74
+ status:
75
+ code: 204
76
+ message: No Content
77
+ headers:
78
+ Content-Type:
79
+ - application/json; charset=UTF-8
80
+ Vary:
81
+ - Origin
82
+ - Referer
83
+ - X-Origin
84
+ Date:
85
+ - Mon, 22 Jun 2020 11:38:57 GMT
86
+ Server:
87
+ - ESF
88
+ Content-Length:
89
+ - '0'
90
+ X-Xss-Protection:
91
+ - '0'
92
+ X-Frame-Options:
93
+ - SAMEORIGIN
94
+ X-Content-Type-Options:
95
+ - nosniff
96
+ Alt-Svc:
97
+ - h3-28=":443"; ma=2592000,h3-27=":443"; ma=2592000,h3-25=":443"; ma=2592000,h3-T050=":443";
98
+ ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443";
99
+ ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443";
100
+ ma=2592000; v="46,43"
101
+ body:
102
+ encoding: UTF-8
103
+ string: ''
104
+ recorded_at: Mon, 22 Jun 2020 11:38:57 GMT
105
+ recorded_with: VCR 6.0.0
@@ -0,0 +1,124 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://www.googleapis.com/oauth2/v4/token
6
+ body:
7
+ encoding: ASCII-8BIT
8
+ string: params
9
+ headers:
10
+ User-Agent:
11
+ - Faraday v1.0.1
12
+ Content-Type:
13
+ - application/x-www-form-urlencoded
14
+ Accept-Encoding:
15
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
16
+ Accept:
17
+ - "*/*"
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Content-Type:
24
+ - application/json; charset=UTF-8
25
+ Vary:
26
+ - Origin
27
+ - Referer
28
+ - X-Origin
29
+ Date:
30
+ - Mon, 22 Jun 2020 13:11:45 GMT
31
+ Server:
32
+ - scaffolding on HTTPServer2
33
+ Cache-Control:
34
+ - private
35
+ X-Xss-Protection:
36
+ - '0'
37
+ X-Frame-Options:
38
+ - SAMEORIGIN
39
+ X-Content-Type-Options:
40
+ - nosniff
41
+ Alt-Svc:
42
+ - h3-28=":443"; ma=2592000,h3-27=":443"; ma=2592000,h3-25=":443"; ma=2592000,h3-T050=":443";
43
+ ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443";
44
+ ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443";
45
+ ma=2592000; v="46,43"
46
+ Transfer-Encoding:
47
+ - chunked
48
+ body:
49
+ encoding: ASCII-8BIT
50
+ string: '{"access_token":"access_token","expires_in":3599,"token_type":"Bearer"}'
51
+ recorded_at: Mon, 22 Jun 2020 13:11:45 GMT
52
+ - request:
53
+ method: post
54
+ uri: https://www.googleapis.com/androidpublisher/v3/applications/fake_package_name/purchases/products/fake_product_id/tokens/fake_token:acknowledge
55
+ body:
56
+ encoding: UTF-8
57
+ string: ''
58
+ headers:
59
+ User-Agent:
60
+ - unknown/0.0.0 google-api-ruby-client/0.34.1 Mac OS X/10.14.6 (gzip)
61
+ Accept:
62
+ - "*/*"
63
+ Accept-Encoding:
64
+ - gzip,deflate
65
+ Date:
66
+ - Mon, 22 Jun 2020 13:11:45 GMT
67
+ X-Goog-Api-Client:
68
+ - gl-ruby/2.5.1 gdcl/0.34.1
69
+ Authorization:
70
+ - Bearer some_token
71
+ Content-Type:
72
+ - application/x-www-form-urlencoded
73
+ response:
74
+ status:
75
+ code: 400
76
+ message: Bad Request
77
+ headers:
78
+ Content-Type:
79
+ - application/json; charset=UTF-8
80
+ Vary:
81
+ - Origin
82
+ - Referer
83
+ - X-Origin
84
+ Content-Encoding:
85
+ - gzip
86
+ Date:
87
+ - Mon, 22 Jun 2020 13:11:46 GMT
88
+ Server:
89
+ - ESF
90
+ Cache-Control:
91
+ - private
92
+ X-Xss-Protection:
93
+ - '0'
94
+ X-Frame-Options:
95
+ - SAMEORIGIN
96
+ X-Content-Type-Options:
97
+ - nosniff
98
+ Alt-Svc:
99
+ - h3-28=":443"; ma=2592000,h3-27=":443"; ma=2592000,h3-25=":443"; ma=2592000,h3-T050=":443";
100
+ ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443";
101
+ ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443";
102
+ ma=2592000; v="46,43"
103
+ Transfer-Encoding:
104
+ - chunked
105
+ body:
106
+ encoding: UTF-8
107
+ string: |
108
+ {
109
+ "error": {
110
+ "code": 400,
111
+ "message": "The purchase is not in a valid state to perform the desired operation.",
112
+ "errors": [
113
+ {
114
+ "message": "The purchase is not in a valid state to perform the desired operation.",
115
+ "domain": "androidpublisher",
116
+ "reason": "invalidPurchaseState",
117
+ "location": "token",
118
+ "locationType": "parameter"
119
+ }
120
+ ]
121
+ }
122
+ }
123
+ recorded_at: Mon, 22 Jun 2020 13:11:46 GMT
124
+ recorded_with: VCR 6.0.0
@@ -0,0 +1,122 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://www.googleapis.com/oauth2/v4/token
6
+ body:
7
+ encoding: ASCII-8BIT
8
+ string: params
9
+ headers:
10
+ User-Agent:
11
+ - Faraday v1.0.1
12
+ Content-Type:
13
+ - application/x-www-form-urlencoded
14
+ Accept-Encoding:
15
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
16
+ Accept:
17
+ - "*/*"
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Content-Type:
24
+ - application/json; charset=UTF-8
25
+ Vary:
26
+ - Origin
27
+ - Referer
28
+ - X-Origin
29
+ Date:
30
+ - Mon, 22 Jun 2020 14:37:46 GMT
31
+ Server:
32
+ - scaffolding on HTTPServer2
33
+ Cache-Control:
34
+ - private
35
+ X-Xss-Protection:
36
+ - '0'
37
+ X-Frame-Options:
38
+ - SAMEORIGIN
39
+ X-Content-Type-Options:
40
+ - nosniff
41
+ Alt-Svc:
42
+ - h3-28=":443"; ma=2592000,h3-27=":443"; ma=2592000,h3-25=":443"; ma=2592000,h3-T050=":443";
43
+ ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443";
44
+ ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443";
45
+ ma=2592000; v="46,43"
46
+ Transfer-Encoding:
47
+ - chunked
48
+ body:
49
+ encoding: ASCII-8BIT
50
+ string: '{"access_token":"access_token","expires_in":3599,"token_type":"Bearer"}'
51
+ recorded_at: Mon, 22 Jun 2020 14:37:46 GMT
52
+ - request:
53
+ method: post
54
+ uri: https://www.googleapis.com/androidpublisher/v3/applications/fake_package_name/purchases/products/fake_product_id/tokens/fake_token:acknowledge
55
+ body:
56
+ encoding: UTF-8
57
+ string: ''
58
+ headers:
59
+ User-Agent:
60
+ - unknown/0.0.0 google-api-ruby-client/0.34.1 Mac OS X/10.14.6 (gzip)
61
+ Accept:
62
+ - "*/*"
63
+ Accept-Encoding:
64
+ - gzip,deflate
65
+ Date:
66
+ - Mon, 22 Jun 2020 14:37:46 GMT
67
+ X-Goog-Api-Client:
68
+ - gl-ruby/2.5.1 gdcl/0.34.1
69
+ Authorization:
70
+ - Bearer some_token
71
+ Content-Type:
72
+ - application/x-www-form-urlencoded
73
+ response:
74
+ status:
75
+ code: 400
76
+ message: Bad Request
77
+ headers:
78
+ Content-Type:
79
+ - application/json; charset=UTF-8
80
+ Vary:
81
+ - Origin
82
+ - Referer
83
+ - X-Origin
84
+ Content-Encoding:
85
+ - gzip
86
+ Date:
87
+ - Mon, 22 Jun 2020 14:37:47 GMT
88
+ Server:
89
+ - ESF
90
+ Cache-Control:
91
+ - private
92
+ X-Xss-Protection:
93
+ - '0'
94
+ X-Frame-Options:
95
+ - SAMEORIGIN
96
+ X-Content-Type-Options:
97
+ - nosniff
98
+ Alt-Svc:
99
+ - h3-28=":443"; ma=2592000,h3-27=":443"; ma=2592000,h3-25=":443"; ma=2592000,h3-T050=":443";
100
+ ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q049=":443"; ma=2592000,h3-Q048=":443";
101
+ ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443";
102
+ ma=2592000; v="46,43"
103
+ Transfer-Encoding:
104
+ - chunked
105
+ body:
106
+ encoding: UTF-8
107
+ string: |
108
+ {
109
+ "error": {
110
+ "code": 400,
111
+ "message": "The product purchase is not owned by the user.",
112
+ "errors": [
113
+ {
114
+ "message": "The product purchase is not owned by the user.",
115
+ "domain": "androidpublisher",
116
+ "reason": "productNotOwnedByUser"
117
+ }
118
+ ]
119
+ }
120
+ }
121
+ recorded_at: Mon, 22 Jun 2020 14:37:47 GMT
122
+ recorded_with: VCR 6.0.0