fake_stripe 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING.md +33 -0
  3. data/LICENSE +19 -0
  4. data/README.md +66 -0
  5. data/Rakefile +8 -0
  6. data/lib/fake_stripe.rb +49 -0
  7. data/lib/fake_stripe/assets/v1.js +38 -0
  8. data/lib/fake_stripe/assets/v2-mock.js +18 -0
  9. data/lib/fake_stripe/assets/v2.js +757 -0
  10. data/lib/fake_stripe/configuration.rb +15 -0
  11. data/lib/fake_stripe/fixtures/cancel_subscription.json +18 -0
  12. data/lib/fake_stripe/fixtures/cancel_transfer.json +161 -0
  13. data/lib/fake_stripe/fixtures/capture_charge.json +51 -0
  14. data/lib/fake_stripe/fixtures/close_dispute.json +13 -0
  15. data/lib/fake_stripe/fixtures/create_card.json +21 -0
  16. data/lib/fake_stripe/fixtures/create_charge.json +45 -0
  17. data/lib/fake_stripe/fixtures/create_coupon.json +17 -0
  18. data/lib/fake_stripe/fixtures/create_customer.json +51 -0
  19. data/lib/fake_stripe/fixtures/create_invoice.json +52 -0
  20. data/lib/fake_stripe/fixtures/create_invoiceitem.json +15 -0
  21. data/lib/fake_stripe/fixtures/create_plan.json +14 -0
  22. data/lib/fake_stripe/fixtures/create_recipient.json +25 -0
  23. data/lib/fake_stripe/fixtures/create_subscription.json +18 -0
  24. data/lib/fake_stripe/fixtures/create_token.json +26 -0
  25. data/lib/fake_stripe/fixtures/create_transfer.json +161 -0
  26. data/lib/fake_stripe/fixtures/delete_card.json +4 -0
  27. data/lib/fake_stripe/fixtures/delete_coupon.json +4 -0
  28. data/lib/fake_stripe/fixtures/delete_customer.json +4 -0
  29. data/lib/fake_stripe/fixtures/delete_customer_discount.json +4 -0
  30. data/lib/fake_stripe/fixtures/delete_invoiceitem.json +4 -0
  31. data/lib/fake_stripe/fixtures/delete_plan.json +4 -0
  32. data/lib/fake_stripe/fixtures/delete_recipient.json +4 -0
  33. data/lib/fake_stripe/fixtures/delete_subscription_discount.json +4 -0
  34. data/lib/fake_stripe/fixtures/list_application_fees.json +55 -0
  35. data/lib/fake_stripe/fixtures/list_balance_history.json +76 -0
  36. data/lib/fake_stripe/fixtures/list_cards.json +70 -0
  37. data/lib/fake_stripe/fixtures/list_charges.json +146 -0
  38. data/lib/fake_stripe/fixtures/list_coupons.json +58 -0
  39. data/lib/fake_stripe/fixtures/list_customers.json +157 -0
  40. data/lib/fake_stripe/fixtures/list_events.json +172 -0
  41. data/lib/fake_stripe/fixtures/list_invoiceitems.json +52 -0
  42. data/lib/fake_stripe/fixtures/list_invoices.json +199 -0
  43. data/lib/fake_stripe/fixtures/list_plans.json +49 -0
  44. data/lib/fake_stripe/fixtures/list_recipients.json +82 -0
  45. data/lib/fake_stripe/fixtures/list_subscriptions.json +100 -0
  46. data/lib/fake_stripe/fixtures/list_transfers.json +488 -0
  47. data/lib/fake_stripe/fixtures/pay_invoice.json +65 -0
  48. data/lib/fake_stripe/fixtures/refund_application_fee.json +17 -0
  49. data/lib/fake_stripe/fixtures/refund_charge.json +51 -0
  50. data/lib/fake_stripe/fixtures/retrieve_account.json +19 -0
  51. data/lib/fake_stripe/fixtures/retrieve_application_fee.json +17 -0
  52. data/lib/fake_stripe/fixtures/retrieve_balance.json +16 -0
  53. data/lib/fake_stripe/fixtures/retrieve_balance_transaction.json +23 -0
  54. data/lib/fake_stripe/fixtures/retrieve_card.json +21 -0
  55. data/lib/fake_stripe/fixtures/retrieve_charge.json +45 -0
  56. data/lib/fake_stripe/fixtures/retrieve_coupon.json +17 -0
  57. data/lib/fake_stripe/fixtures/retrieve_customer.json +51 -0
  58. data/lib/fake_stripe/fixtures/retrieve_event.json +56 -0
  59. data/lib/fake_stripe/fixtures/retrieve_invoice.json +64 -0
  60. data/lib/fake_stripe/fixtures/retrieve_invoice_line_items.json +61 -0
  61. data/lib/fake_stripe/fixtures/retrieve_invoiceitem.json +15 -0
  62. data/lib/fake_stripe/fixtures/retrieve_plan.json +14 -0
  63. data/lib/fake_stripe/fixtures/retrieve_recipient.json +25 -0
  64. data/lib/fake_stripe/fixtures/retrieve_subscription.json +31 -0
  65. data/lib/fake_stripe/fixtures/retrieve_token.json +26 -0
  66. data/lib/fake_stripe/fixtures/retrieve_transfer.json +161 -0
  67. data/lib/fake_stripe/fixtures/retrieve_upcoming_invoice.json +63 -0
  68. data/lib/fake_stripe/fixtures/update_card.json +21 -0
  69. data/lib/fake_stripe/fixtures/update_charge.json +45 -0
  70. data/lib/fake_stripe/fixtures/update_customer.json +51 -0
  71. data/lib/fake_stripe/fixtures/update_dispute.json +13 -0
  72. data/lib/fake_stripe/fixtures/update_invoice.json +64 -0
  73. data/lib/fake_stripe/fixtures/update_invoiceitem.json +15 -0
  74. data/lib/fake_stripe/fixtures/update_plan.json +14 -0
  75. data/lib/fake_stripe/fixtures/update_recipient.json +25 -0
  76. data/lib/fake_stripe/fixtures/update_subscription.json +18 -0
  77. data/lib/fake_stripe/fixtures/update_transfer.json +161 -0
  78. data/lib/fake_stripe/initializers/webmock.rb +3 -0
  79. data/lib/fake_stripe/stub_app.rb +307 -0
  80. data/lib/fake_stripe/stub_stripe_js.rb +29 -0
  81. data/lib/fake_stripe/version.rb +3 -0
  82. metadata +211 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c7b987c214a1ff6edd50c5b79ba6adb060ccfb3c
4
+ data.tar.gz: 1f279550aa2d4c885c6487528645d396579229db
5
+ SHA512:
6
+ metadata.gz: 3f3653167729c7bc6ef172843c53f9ce0567b3bc71e13503e6632f650b97e8fd1d95c17154ea1e88b3ee81dc15a3e4a69c0cab8912948f0f18f4fee6ad53e78d
7
+ data.tar.gz: d0ab0d0b5dbbf08bdc8e50309e7144991c4e6faf716cc583d44698dec2fbddd5ef9c8e491de60c9d541c56c168b4a8e97606d7adb03fd50cfb215ab499dad1cb
@@ -0,0 +1,33 @@
1
+ ## Steps
2
+
3
+ 1. Fork the repo.
4
+
5
+ 2. Run the tests. We only take pull requests with passing tests, and it's great
6
+ to know that you have a clean slate: `bundle && rake`
7
+
8
+ 3. Create your feature branch (`git checkout -b my-new-feature`).
9
+
10
+ 4. Add a test for your change. Only refactoring and documentation changes
11
+ require no new tests. If you are adding functionality or fixing a bug, we need
12
+ a test!
13
+
14
+ 5. Make the test pass.
15
+
16
+ 6. Commit your changes (`git commit -am 'Add some feature'`).
17
+
18
+ 7. Push to the branch (`git push origin my-new-feature`).
19
+
20
+ 8. Create new Pull Request
21
+
22
+ At this point you're waiting on us. We like to at least comment on, if not
23
+ accept, pull requests within three business days (and, typically, one business
24
+ day). We may suggest some changes or improvements or alternatives.
25
+
26
+ ## Syntax
27
+
28
+ * Two spaces, no tabs.
29
+ * No trailing whitespace. Blank lines should not have any space.
30
+ * Prefer &&/|| over and/or.
31
+ * MyClass.my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
32
+ * a = b and not a=b.
33
+ * Follow the conventions you see used in the source already.
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2013 thoughtbot, inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
@@ -0,0 +1,66 @@
1
+ # fake\_stripe, a Stripe fake
2
+
3
+ This library is a way to test [Stripe](http://www.stripe.com/) code without hitting Stripe's
4
+ servers. It uses
5
+ [Capybara::Server](https://github.com/jnicklas/capybara/blob/master/lib/capybara/server.rb)
6
+ and [Webmock](https://github.com/bblimke/webmock) to intercept all of the calls from Stripe's
7
+ Ruby library and returns JSON that the Stripe library can parse.
8
+
9
+ ## Installation
10
+
11
+ ### Gemfile
12
+
13
+ Add the `fake_stripe` Gem to the `:test` group in your Gemfile:
14
+
15
+ ```ruby
16
+ # Gemfile
17
+ group :test do
18
+ gem 'fake_stripe'
19
+ end
20
+ ```
21
+
22
+ Remember to run `bundle install`.
23
+
24
+ ### Stripe settings
25
+
26
+ Set the `STRIPE_JS_HOST` constant in an initializer:
27
+
28
+ ```ruby
29
+ # config/initilialzers/stripe.rb
30
+ Stripe.api_key = ENV['STRIPE_API_KEY']
31
+
32
+ unless defined? STRIPE_JS_HOST
33
+ STRIPE_JS_HOST = 'https://js.stripe.com'
34
+ end
35
+ ```
36
+
37
+ Include the Stripe JavaScript in your application template:
38
+
39
+ ```rhtml
40
+ # app/views/layouts/application.html.erb
41
+ <%= javascript_include_tag "#{STRIPE_JS_HOST}/v1/" %>
42
+ ```
43
+
44
+ When the test suite runs `fake_stripe` will override the address for
45
+ `STRIPE_JS_HOST` and serve up a local version of [Stripe.js](https://stripe.com/docs/stripe.js).
46
+
47
+ ### In Tests
48
+
49
+ Require the library in your spec support:
50
+
51
+ ```ruby
52
+ # spec/support/fake_stripe.rb
53
+ require 'fake_stripe'
54
+
55
+ RSpec.configure do |config|
56
+ config.before(:each) do
57
+ FakeStripe.stub_stripe
58
+ end
59
+ end
60
+ ```
61
+
62
+ ## Contributing
63
+
64
+ Please see [CONTRIBUTING.md][1] for more details.
65
+
66
+ [1]: https://github.com/thoughtbot/fake_stripe/blob/master/CONTRIBUTING.md
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+
8
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,49 @@
1
+ require 'fake_stripe/configuration'
2
+ require 'fake_stripe/initializers/webmock'
3
+ require 'fake_stripe/stub_app'
4
+ require 'fake_stripe/stub_stripe_js'
5
+
6
+ module FakeStripe
7
+ extend Configuration
8
+
9
+ VALID_CARD_NUMBER = '4242424242424242'
10
+
11
+ def self.charge_count
12
+ @@charge_count
13
+ end
14
+
15
+ def self.charge_count=(charge_count)
16
+ @@charge_count = charge_count
17
+ end
18
+
19
+ def self.refund_count
20
+ @@refund_count
21
+ end
22
+
23
+ def self.refund_count=(refund_count)
24
+ @@refund_count = refund_count
25
+ end
26
+
27
+ def self.customer_count
28
+ @@customer_count
29
+ end
30
+
31
+ def self.customer_count=(customer_count)
32
+ @@customer_count = customer_count
33
+ end
34
+
35
+ def self.reset
36
+ @@charge_count = 0
37
+ @@customer_count = 0
38
+ @@refund_count = 0
39
+ end
40
+
41
+ def self.stub_stripe
42
+ Stripe.api_key = 'FAKE_STRIPE_API_KEY'
43
+ FakeStripe.reset
44
+ stub_request(:any, /api.stripe.com/).to_rack(FakeStripe::StubApp)
45
+ end
46
+ end
47
+
48
+ server = FakeStripe::StubStripeJS.boot
49
+ STRIPE_JS_HOST = "http://#{server.host}:#{server.port}"
@@ -0,0 +1,38 @@
1
+ window.Stripe = {
2
+ createToken: function(creditCard, handler) {
3
+ function isValidCardNumber(number) {
4
+ var validCardNumbers = ['4242424242424242', '4242 4242 4242 4242'];
5
+ return $.inArray(number, validCardNumbers) >= 0;
6
+ }
7
+
8
+ if (isValidCardNumber(creditCard.number)) {
9
+ handler(200, {
10
+ id: 123,
11
+ card: {
12
+ last4: 4242,
13
+ brand: 'Visa',
14
+ exp_month: '12',
15
+ exp_year: '2018'
16
+ }
17
+ });
18
+ } else {
19
+ handler(402, {
20
+ error: {
21
+ code: 'incorrect_number',
22
+ message: 'Your card number is incorrect',
23
+ param: 'number',
24
+ type: 'card_error'
25
+ }
26
+ });
27
+ }
28
+ },
29
+ cardType: function(value) { return 'Visa' },
30
+ setPublishableKey: function() {},
31
+ validateCardNumber: function(value) { return true; },
32
+ validateCVC: function(value) { return true; },
33
+ validateExpiry: function(value) { return true; }
34
+ };
35
+
36
+ window.Stripe.card = {
37
+ createToken: window.Stripe.createToken
38
+ };
@@ -0,0 +1,18 @@
1
+ (function() {
2
+ this.Stripe.ajaxJSONP = function(options) {
3
+ if (options.url.indexOf("tokens") > -1) {
4
+ return options.success({
5
+ id: 123,
6
+ card: {
7
+ last4: 4242,
8
+ brand: 'Visa',
9
+ exp_month: '12',
10
+ exp_year: '2018'
11
+ }
12
+ }, 200);
13
+ } else {
14
+ throw(options.url + " has not been mocked by FakeStripe. " +
15
+ "Please submit a pull request to implement this action.");
16
+ }
17
+ };
18
+ }).call(this);
@@ -0,0 +1,757 @@
1
+ (function() {
2
+ var Stripe, exports, key, _i, _len,
3
+ __hasProp = {}.hasOwnProperty,
4
+ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
5
+ _this = this;
6
+
7
+ this.Stripe = (function() {
8
+
9
+ function Stripe() {}
10
+
11
+ Stripe.version = 2;
12
+
13
+ Stripe.endpoint = 'https://api.stripe.com/v1';
14
+
15
+ Stripe.setPublishableKey = function(key) {
16
+ Stripe.key = key;
17
+ };
18
+
19
+ Stripe.complete = function(callback, errorMessage) {
20
+ return function(type, xhr, options) {
21
+ var timestamp;
22
+ if (type !== 'success') {
23
+ timestamp = Math.round(new Date().getTime() / 1000);
24
+ (new Image).src = "https://q.stripe.com?event=stripejs-error&type=" + type + "&key=" + Stripe.key + "&timestamp=" + timestamp;
25
+ return typeof callback === "function" ? callback(500, {
26
+ error: {
27
+ code: type,
28
+ type: type,
29
+ message: errorMessage
30
+ }
31
+ }) : void 0;
32
+ }
33
+ };
34
+ };
35
+
36
+ return Stripe;
37
+
38
+ }).call(this);
39
+
40
+ Stripe = this.Stripe;
41
+
42
+ this.Stripe.token = (function() {
43
+
44
+ function token() {}
45
+
46
+ token.validate = function(data, name) {
47
+ if (!data) {
48
+ throw name + ' required';
49
+ }
50
+ if (typeof data !== 'object') {
51
+ throw name + ' invalid';
52
+ }
53
+ };
54
+
55
+ token.formatData = function(data, attrs) {
56
+ if (Stripe.utils.isElement(data)) {
57
+ data = Stripe.utils.paramsFromForm(data, attrs);
58
+ }
59
+ Stripe.utils.underscoreKeys(data);
60
+ return data;
61
+ };
62
+
63
+ token.create = function(params, callback) {
64
+ params.key || (params.key = Stripe.key || Stripe.publishableKey);
65
+ Stripe.utils.validateKey(params.key);
66
+ return Stripe.ajaxJSONP({
67
+ url: "" + Stripe.endpoint + "/tokens",
68
+ data: params,
69
+ method: 'POST',
70
+ success: function(body, status) {
71
+ return typeof callback === "function" ? callback(status, body) : void 0;
72
+ },
73
+ complete: Stripe.complete(callback, "A network error has occurred, and you have not been charged. Please try again."),
74
+ timeout: 40000
75
+ });
76
+ };
77
+
78
+ token.get = function(token, callback) {
79
+ if (!token) {
80
+ throw 'token required';
81
+ }
82
+ Stripe.utils.validateKey(Stripe.key);
83
+ return Stripe.ajaxJSONP({
84
+ url: "" + Stripe.endpoint + "/tokens/" + token,
85
+ data: {
86
+ key: Stripe.key
87
+ },
88
+ success: function(body, status) {
89
+ return typeof callback === "function" ? callback(status, body) : void 0;
90
+ },
91
+ complete: Stripe.complete(callback, "A network error has occurred loading data from Stripe. Please try again."),
92
+ timeout: 40000
93
+ });
94
+ };
95
+
96
+ return token;
97
+
98
+ }).call(this);
99
+
100
+ this.Stripe.card = (function(_super) {
101
+
102
+ __extends(card, _super);
103
+
104
+ function card() {
105
+ return card.__super__.constructor.apply(this, arguments);
106
+ }
107
+
108
+ card.tokenName = 'card';
109
+
110
+ card.whitelistedAttrs = ['number', 'cvc', 'exp_month', 'exp_year', 'name', 'address_line1', 'address_line2', 'address_city', 'address_state', 'address_zip', 'address_country'];
111
+
112
+ card.createToken = function(data, params, callback) {
113
+ var amount;
114
+ if (params == null) {
115
+ params = {};
116
+ }
117
+ Stripe.token.validate(data, 'card');
118
+ if (typeof params === 'function') {
119
+ callback = params;
120
+ params = {};
121
+ } else if (typeof params !== 'object') {
122
+ amount = parseInt(params, 10);
123
+ params = {};
124
+ if (amount > 0) {
125
+ params.amount = amount;
126
+ }
127
+ }
128
+ params[card.tokenName] = Stripe.token.formatData(data, card.whitelistedAttrs);
129
+ return Stripe.token.create(params, callback);
130
+ };
131
+
132
+ card.getToken = function(token, callback) {
133
+ return Stripe.token.get(token, callback);
134
+ };
135
+
136
+ card.validateCardNumber = function(num) {
137
+ num = (num + '').replace(/\s+|-/g, '');
138
+ return num.length >= 10 && num.length <= 16 && card.luhnCheck(num);
139
+ };
140
+
141
+ card.validateCVC = function(num) {
142
+ num = Stripe.utils.trim(num);
143
+ return /^\d+$/.test(num) && num.length >= 3 && num.length <= 4;
144
+ };
145
+
146
+ card.validateExpiry = function(month, year) {
147
+ var currentTime, expiry;
148
+ month = Stripe.utils.trim(month);
149
+ year = Stripe.utils.trim(year);
150
+ if (!/^\d+$/.test(month)) {
151
+ return false;
152
+ }
153
+ if (!/^\d+$/.test(year)) {
154
+ return false;
155
+ }
156
+ if (!(parseInt(month, 10) <= 12)) {
157
+ return false;
158
+ }
159
+ expiry = new Date(year, month);
160
+ currentTime = new Date;
161
+ expiry.setMonth(expiry.getMonth() - 1);
162
+ expiry.setMonth(expiry.getMonth() + 1, 1);
163
+ return expiry > currentTime;
164
+ };
165
+
166
+ card.luhnCheck = function(num) {
167
+ var digit, digits, odd, sum, _i, _len;
168
+ odd = true;
169
+ sum = 0;
170
+ digits = (num + '').split('').reverse();
171
+ for (_i = 0, _len = digits.length; _i < _len; _i++) {
172
+ digit = digits[_i];
173
+ digit = parseInt(digit, 10);
174
+ if ((odd = !odd)) {
175
+ digit *= 2;
176
+ }
177
+ if (digit > 9) {
178
+ digit -= 9;
179
+ }
180
+ sum += digit;
181
+ }
182
+ return sum % 10 === 0;
183
+ };
184
+
185
+ card.cardType = function(num) {
186
+ return card.cardTypes[num.slice(0, 2)] || 'Unknown';
187
+ };
188
+
189
+ card.cardTypes = (function() {
190
+ var num, types, _i, _j;
191
+ types = {};
192
+ for (num = _i = 40; _i <= 49; num = ++_i) {
193
+ types[num] = 'Visa';
194
+ }
195
+ for (num = _j = 50; _j <= 59; num = ++_j) {
196
+ types[num] = 'MasterCard';
197
+ }
198
+ types[34] = types[37] = 'American Express';
199
+ types[60] = types[62] = types[64] = types[65] = 'Discover';
200
+ types[35] = 'JCB';
201
+ types[30] = types[36] = types[38] = types[39] = 'Diners Club';
202
+ return types;
203
+ })();
204
+
205
+ return card;
206
+
207
+ }).call(this, this.Stripe.token);
208
+
209
+ this.Stripe.bankAccount = (function(_super) {
210
+
211
+ __extends(bankAccount, _super);
212
+
213
+ function bankAccount() {
214
+ return bankAccount.__super__.constructor.apply(this, arguments);
215
+ }
216
+
217
+ bankAccount.tokenName = 'bank_account';
218
+
219
+ bankAccount.whitelistedAttrs = ['country', 'routing_number', 'account_number'];
220
+
221
+ bankAccount.createToken = function(data, params, callback) {
222
+ if (params == null) {
223
+ params = {};
224
+ }
225
+ Stripe.token.validate(data, 'bank account');
226
+ if (typeof params === 'function') {
227
+ callback = params;
228
+ params = {};
229
+ }
230
+ params[bankAccount.tokenName] = Stripe.token.formatData(data, bankAccount.whitelistedAttrs);
231
+ return Stripe.token.create(params, callback);
232
+ };
233
+
234
+ bankAccount.getToken = function(token, callback) {
235
+ return Stripe.token.get(token, callback);
236
+ };
237
+
238
+ bankAccount.validateRoutingNumber = function(num, country) {
239
+ num = Stripe.utils.trim(num);
240
+ switch (country) {
241
+ case 'US':
242
+ return /^\d+$/.test(num) && num.length === 9 && bankAccount.routingChecksum(num);
243
+ case 'CA':
244
+ return /\d{5}\-\d{3}/.test(num) && num.length === 9;
245
+ default:
246
+ return true;
247
+ }
248
+ };
249
+
250
+ bankAccount.validateAccountNumber = function(num, country) {
251
+ num = Stripe.utils.trim(num);
252
+ switch (country) {
253
+ case 'US':
254
+ return /^\d+$/.test(num) && num.length >= 1 && num.length <= 17;
255
+ default:
256
+ return true;
257
+ }
258
+ };
259
+
260
+ bankAccount.routingChecksum = function(num) {
261
+ var digits, index, sum, _i, _len, _ref;
262
+ sum = 0;
263
+ digits = (num + '').split('');
264
+ _ref = [0, 3, 6];
265
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
266
+ index = _ref[_i];
267
+ sum += parseInt(digits[index]) * 3;
268
+ sum += parseInt(digits[index + 1]) * 7;
269
+ sum += parseInt(digits[index + 2]);
270
+ }
271
+ return sum !== 0 && sum % 10 === 0;
272
+ };
273
+
274
+ return bankAccount;
275
+
276
+ }).call(this, this.Stripe.token);
277
+
278
+ this.Stripe.bitcoinReceiver = (function() {
279
+
280
+ function bitcoinReceiver() {}
281
+
282
+ bitcoinReceiver._whitelistedAttrs = ['amount', 'currency', 'email', 'description'];
283
+
284
+ bitcoinReceiver.createReceiver = function(data, callback) {
285
+ var params;
286
+ Stripe.token.validate(data, 'bitcoin_receiver data');
287
+ params = Stripe.token.formatData(data, this._whitelistedAttrs);
288
+ params.key = Stripe.key || Stripe.publishableKey;
289
+ Stripe.utils.validateKey(params.key);
290
+ return Stripe.ajaxJSONP({
291
+ url: "" + Stripe.endpoint + "/bitcoin/receivers",
292
+ data: params,
293
+ method: 'POST',
294
+ success: function(body, status) {
295
+ return typeof callback === "function" ? callback(status, body) : void 0;
296
+ },
297
+ complete: Stripe.complete(callback, "A network error has occurred while creating a Bitcoin address. Please try again."),
298
+ timeout: 40000
299
+ });
300
+ };
301
+
302
+ bitcoinReceiver.getReceiver = function(id, callback) {
303
+ var key;
304
+ if (!id) {
305
+ throw 'receiver id required';
306
+ }
307
+ key = Stripe.key || Stripe.publishableKey;
308
+ Stripe.utils.validateKey(key);
309
+ return Stripe.ajaxJSONP({
310
+ url: "" + Stripe.endpoint + "/bitcoin/receivers/" + id,
311
+ data: {
312
+ key: key
313
+ },
314
+ success: function(body, status) {
315
+ return typeof callback === "function" ? callback(status, body) : void 0;
316
+ },
317
+ complete: Stripe.complete(callback, "A network error has occurred loading data from Stripe. Please try again."),
318
+ timeout: 40000
319
+ });
320
+ };
321
+
322
+ bitcoinReceiver._activeReceiverPolls = {};
323
+
324
+ bitcoinReceiver._clearReceiverPoll = function(receiverId) {
325
+ return delete bitcoinReceiver._activeReceiverPolls[receiverId];
326
+ };
327
+
328
+ bitcoinReceiver._pollInterval = 1500;
329
+
330
+ bitcoinReceiver.pollReceiver = function(receiverId, callback) {
331
+ if (this._activeReceiverPolls[receiverId] != null) {
332
+ throw "You are already polling receiver " + receiverId + ". Please cancel that poll before polling it again.";
333
+ }
334
+ this._activeReceiverPolls[receiverId] = {};
335
+ return this._pollReceiver(receiverId, callback);
336
+ };
337
+
338
+ bitcoinReceiver._pollReceiver = function(receiverId, callback) {
339
+ bitcoinReceiver.getReceiver(receiverId, function(status, body) {
340
+ var pollInterval, timeoutId;
341
+ if (bitcoinReceiver._activeReceiverPolls[receiverId] == null) {
342
+ return;
343
+ }
344
+ if (status === 200 && body.filled) {
345
+ bitcoinReceiver._clearReceiverPoll(receiverId);
346
+ return typeof callback === "function" ? callback(status, body) : void 0;
347
+ } else if (status >= 400 && status < 500) {
348
+ bitcoinReceiver._clearReceiverPoll(receiverId);
349
+ return typeof callback === "function" ? callback(status, body) : void 0;
350
+ } else {
351
+ pollInterval = status === 500 ? 5000 : bitcoinReceiver._pollInterval;
352
+ timeoutId = setTimeout(function() {
353
+ return bitcoinReceiver._pollReceiver(receiverId, callback);
354
+ }, pollInterval);
355
+ return bitcoinReceiver._activeReceiverPolls[receiverId]['timeoutId'] = timeoutId;
356
+ }
357
+ });
358
+ };
359
+
360
+ bitcoinReceiver.cancelReceiverPoll = function(receiverId) {
361
+ var activeReceiver;
362
+ activeReceiver = bitcoinReceiver._activeReceiverPolls[receiverId];
363
+ if (activeReceiver == null) {
364
+ throw "You are not polling receiver " + receiverId + ".";
365
+ }
366
+ if (activeReceiver['timeoutId'] != null) {
367
+ clearTimeout(activeReceiver['timeoutId']);
368
+ }
369
+ bitcoinReceiver._clearReceiverPoll(receiverId);
370
+ };
371
+
372
+ return bitcoinReceiver;
373
+
374
+ }).call(this);
375
+
376
+ exports = ['createToken', 'getToken', 'cardType', 'validateExpiry', 'validateCVC', 'validateCardNumber'];
377
+
378
+ for (_i = 0, _len = exports.length; _i < _len; _i++) {
379
+ key = exports[_i];
380
+ this.Stripe[key] = this.Stripe.card[key];
381
+ }
382
+
383
+ if (typeof module !== "undefined" && module !== null) {
384
+ module.exports = this.Stripe;
385
+ }
386
+
387
+ if (typeof define === "function") {
388
+ define('stripe', [], function() {
389
+ return _this.Stripe;
390
+ });
391
+ }
392
+
393
+ }).call(this);
394
+ (function() {
395
+ var e, requestID, serialize,
396
+ __slice = [].slice;
397
+
398
+ e = encodeURIComponent;
399
+
400
+ requestID = new Date().getTime();
401
+
402
+ serialize = function(object, result, scope) {
403
+ var key, value;
404
+ if (result == null) {
405
+ result = [];
406
+ }
407
+ for (key in object) {
408
+ value = object[key];
409
+ if (scope) {
410
+ key = "" + scope + "[" + key + "]";
411
+ }
412
+ if (typeof value === 'object') {
413
+ serialize(value, result, key);
414
+ } else {
415
+ result.push("" + key + "=" + (e(value)));
416
+ }
417
+ }
418
+ return result.join('&').replace(/%20/g, '+');
419
+ };
420
+
421
+ this.Stripe.ajaxJSONP = function(options) {
422
+ var abort, abortTimeout, callbackName, head, script, xhr;
423
+ if (options == null) {
424
+ options = {};
425
+ }
426
+ callbackName = 'sjsonp' + (++requestID);
427
+ script = document.createElement('script');
428
+ abortTimeout = null;
429
+ abort = function(reason) {
430
+ var _ref;
431
+ if (reason == null) {
432
+ reason = 'abort';
433
+ }
434
+ clearTimeout(abortTimeout);
435
+ if ((_ref = script.parentNode) != null) {
436
+ _ref.removeChild(script);
437
+ }
438
+ if (callbackName in window) {
439
+ window[callbackName] = (function() {});
440
+ }
441
+ return typeof options.complete === "function" ? options.complete(reason, xhr, options) : void 0;
442
+ };
443
+ xhr = {
444
+ abort: abort
445
+ };
446
+ script.onerror = function() {
447
+ xhr.abort();
448
+ return typeof options.error === "function" ? options.error(xhr, options) : void 0;
449
+ };
450
+ window[callbackName] = function() {
451
+ var args;
452
+ args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
453
+ clearTimeout(abortTimeout);
454
+ script.parentNode.removeChild(script);
455
+ try {
456
+ delete window[callbackName];
457
+ } catch (e) {
458
+ window[callbackName] = void 0;
459
+ }
460
+ if (typeof options.success === "function") {
461
+ options.success.apply(options, args);
462
+ }
463
+ return typeof options.complete === "function" ? options.complete('success', xhr, options) : void 0;
464
+ };
465
+ options.data || (options.data = {});
466
+ options.data.callback = callbackName;
467
+ if (options.method) {
468
+ options.data._method = options.method;
469
+ }
470
+ script.src = options.url + '?' + serialize(options.data);
471
+ head = document.getElementsByTagName('head')[0];
472
+ head.appendChild(script);
473
+ if (options.timeout > 0) {
474
+ abortTimeout = setTimeout(function() {
475
+ return xhr.abort('timeout');
476
+ }, options.timeout);
477
+ }
478
+ return xhr;
479
+ };
480
+
481
+ }).call(this);
482
+ (function() {
483
+ var __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
484
+
485
+ this.Stripe.utils = (function() {
486
+
487
+ function utils() {}
488
+
489
+ utils.trim = function(str) {
490
+ return (str + '').replace(/^\s+|\s+$/g, '');
491
+ };
492
+
493
+ utils.underscore = function(str) {
494
+ return (str + '').replace(/([A-Z])/g, function($1) {
495
+ return "_" + ($1.toLowerCase());
496
+ }).replace(/-/g, '_');
497
+ };
498
+
499
+ utils.underscoreKeys = function(data) {
500
+ var key, value, _results;
501
+ _results = [];
502
+ for (key in data) {
503
+ value = data[key];
504
+ delete data[key];
505
+ _results.push(data[this.underscore(key)] = value);
506
+ }
507
+ return _results;
508
+ };
509
+
510
+ utils.isElement = function(el) {
511
+ if (typeof el !== 'object') {
512
+ return false;
513
+ }
514
+ if ((typeof jQuery !== "undefined" && jQuery !== null) && el instanceof jQuery) {
515
+ return true;
516
+ }
517
+ return el.nodeType === 1;
518
+ };
519
+
520
+ utils.paramsFromForm = function(form, whitelist) {
521
+ var attr, input, inputs, select, selects, values, _i, _j, _len, _len1;
522
+ if (whitelist == null) {
523
+ whitelist = [];
524
+ }
525
+ if ((typeof jQuery !== "undefined" && jQuery !== null) && form instanceof jQuery) {
526
+ form = form[0];
527
+ }
528
+ inputs = form.getElementsByTagName('input');
529
+ selects = form.getElementsByTagName('select');
530
+ values = {};
531
+ for (_i = 0, _len = inputs.length; _i < _len; _i++) {
532
+ input = inputs[_i];
533
+ attr = this.underscore(input.getAttribute('data-stripe'));
534
+ if (__indexOf.call(whitelist, attr) < 0) {
535
+ continue;
536
+ }
537
+ values[attr] = input.value;
538
+ }
539
+ for (_j = 0, _len1 = selects.length; _j < _len1; _j++) {
540
+ select = selects[_j];
541
+ attr = this.underscore(select.getAttribute('data-stripe'));
542
+ if (__indexOf.call(whitelist, attr) < 0) {
543
+ continue;
544
+ }
545
+ if (select.selectedIndex != null) {
546
+ values[attr] = select.options[select.selectedIndex].value;
547
+ }
548
+ }
549
+ return values;
550
+ };
551
+
552
+ utils.validateKey = function(key) {
553
+ if (!key || typeof key !== 'string') {
554
+ throw new Error('You did not set a valid publishable key. ' + 'Call Stripe.setPublishableKey() with your publishable key. ' + 'For more info, see https://stripe.com/docs/stripe.js');
555
+ }
556
+ if (/\s/g.test(key)) {
557
+ throw new Error('Your key is invalid, as it contains whitespace. ' + 'For more info, see https://stripe.com/docs/stripe.js');
558
+ }
559
+ if (/^sk_/.test(key)) {
560
+ throw new Error('You are using a secret key with Stripe.js, instead of the publishable one. ' + 'For more info, see https://stripe.com/docs/stripe.js');
561
+ }
562
+ };
563
+
564
+ return utils;
565
+
566
+ })();
567
+
568
+ }).call(this);
569
+ (function() {
570
+ var __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
571
+
572
+ this.Stripe.validator = {
573
+ boolean: function(expected, value) {
574
+ if (!(value === 'true' || value === 'false')) {
575
+ return "Enter a boolean string (true or false)";
576
+ }
577
+ },
578
+ integer: function(expected, value) {
579
+ if (!/^\d+$/.test(value)) {
580
+ return "Enter an integer";
581
+ }
582
+ },
583
+ positive: function(expected, value) {
584
+ if (!(!this.integer(expected, value) && parseInt(value, 10) > 0)) {
585
+ return "Enter a positive value";
586
+ }
587
+ },
588
+ range: function(expected, value) {
589
+ var _ref;
590
+ if (_ref = parseInt(value, 10), __indexOf.call(expected, _ref) < 0) {
591
+ return "Needs to be between " + expected[0] + " and " + expected[expected.length - 1];
592
+ }
593
+ },
594
+ required: function(expected, value) {
595
+ if (expected && (!(value != null) || value === '')) {
596
+ return "Required";
597
+ }
598
+ },
599
+ year: function(expected, value) {
600
+ if (!/^\d{4}$/.test(value)) {
601
+ return "Enter a 4-digit year";
602
+ }
603
+ },
604
+ birthYear: function(expected, value) {
605
+ var year;
606
+ year = this.year(expected, value);
607
+ if (year) {
608
+ return year;
609
+ } else if (parseInt(value, 10) > 2000) {
610
+ return "You must be over 18";
611
+ } else if (parseInt(value, 10) < 1900) {
612
+ return "Enter your birth year";
613
+ }
614
+ },
615
+ month: function(expected, value) {
616
+ if (this.integer(expected, value)) {
617
+ return "Please enter a month";
618
+ }
619
+ if (this.range([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], value)) {
620
+ return "Needs to be between 1 and 12";
621
+ }
622
+ },
623
+ choices: function(expected, value) {
624
+ if (__indexOf.call(expected, value) < 0) {
625
+ return "Not an acceptable value for this field";
626
+ }
627
+ },
628
+ email: function(expected, value) {
629
+ if (!/^[^@<\s>]+@[^@<\s>]+$/.test(value)) {
630
+ return "That doesn't look like an email address";
631
+ }
632
+ },
633
+ url: function(expected, value) {
634
+ if (!/^https?:\/\/.+\..+/.test(value)) {
635
+ return "Not a valid url";
636
+ }
637
+ },
638
+ usTaxID: function(expected, value) {
639
+ if (!/^\d{2}-?\d{1}-?\d{2}-?\d{4}$/.test(value)) {
640
+ return "Not a valid tax ID";
641
+ }
642
+ },
643
+ ein: function(expected, value) {
644
+ if (!/^\d{2}-?\d{7}$/.test(value)) {
645
+ return "Not a valid EIN";
646
+ }
647
+ },
648
+ ssnLast4: function(expected, value) {
649
+ if (!/^\d{4}$/.test(value)) {
650
+ return "Not a valid last 4 digits for an SSN";
651
+ }
652
+ },
653
+ ownerPersonalID: function(country, value) {
654
+ var match;
655
+ match = (function() {
656
+ switch (country) {
657
+ case 'CA':
658
+ return /^\d{3}-?\d{3}-?\d{3}$/.test(value);
659
+ case 'US':
660
+ return true;
661
+ }
662
+ })();
663
+ if (!match) {
664
+ return "Not a valid ID";
665
+ }
666
+ },
667
+ bizTaxID: function(country, value) {
668
+ var fieldName, match, regex, regexes, validation, validations, _i, _len;
669
+ validations = {
670
+ 'CA': ['Tax ID', [/^\d{9}$/]],
671
+ 'US': ['EIN', [/^\d{2}-?\d{7}$/]]
672
+ };
673
+ validation = validations[country];
674
+ if (validation != null) {
675
+ fieldName = validation[0];
676
+ regexes = validation[1];
677
+ match = false;
678
+ for (_i = 0, _len = regexes.length; _i < _len; _i++) {
679
+ regex = regexes[_i];
680
+ if (regex.test(value)) {
681
+ match = true;
682
+ break;
683
+ }
684
+ }
685
+ if (!match) {
686
+ return "Not a valid " + fieldName;
687
+ }
688
+ }
689
+ },
690
+ zip: function(country, value) {
691
+ var match;
692
+ match = (function() {
693
+ switch (country.toUpperCase()) {
694
+ case 'CA':
695
+ return /^[\d\w]{6}$/.test(value != null ? value.replace(/\s+/g, '') : void 0);
696
+ case 'US':
697
+ return /^\d{5}$/.test(value) || /^\d{9}$/.test(value);
698
+ }
699
+ })();
700
+ if (!match) {
701
+ return "Not a valid zip";
702
+ }
703
+ },
704
+ bankAccountNumber: function(expected, value) {
705
+ if (!/^\d{1,17}$/.test(value)) {
706
+ return "Invalid bank account number";
707
+ }
708
+ },
709
+ usRoutingNumber: function(value) {
710
+ var index, part1, part2, part3, total, _i, _ref;
711
+ if (!/^\d{9}$/.test(value)) {
712
+ return "Routing number must have 9 digits";
713
+ }
714
+ total = 0;
715
+ for (index = _i = 0, _ref = value.length - 1; _i <= _ref; index = _i += 3) {
716
+ part1 = parseInt(value.charAt(index), 10) * 3;
717
+ part2 = parseInt(value.charAt(index + 1), 10) * 7;
718
+ part3 = parseInt(value.charAt(index + 2), 10);
719
+ total += part1 + part2 + part3;
720
+ }
721
+ if (!(total !== 0 && total % 10 === 0)) {
722
+ return "Invalid routing number";
723
+ }
724
+ },
725
+ caRoutingNumber: function(value) {
726
+ if (!/^\d{5}\-\d{3}$/.test(value)) {
727
+ return "Invalid transit number";
728
+ }
729
+ },
730
+ routingNumber: function(country, value) {
731
+ switch (country.toUpperCase()) {
732
+ case 'CA':
733
+ return this.caRoutingNumber(value);
734
+ case 'US':
735
+ return this.usRoutingNumber(value);
736
+ }
737
+ },
738
+ phoneNumber: function(expected, value) {
739
+ var number;
740
+ number = value.replace(/[^0-9]/g, '');
741
+ if (number.length !== 10) {
742
+ return "Invalid phone number";
743
+ }
744
+ },
745
+ bizDBA: function(expected, value) {
746
+ if (!/^.{1,23}$/.test(value)) {
747
+ return "Statement descriptors can only have up to 23 characters";
748
+ }
749
+ },
750
+ nameLength: function(expected, value) {
751
+ if (value.length === 1) {
752
+ return 'Names need to be longer than one character';
753
+ }
754
+ }
755
+ };
756
+
757
+ }).call(this);