tinypass 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. checksums.yaml +15 -0
  2. data/.DS_Store +0 -0
  3. data/.gitignore +20 -0
  4. data/.rspec +2 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +32 -0
  8. data/Rakefile +19 -0
  9. data/lib/.DS_Store +0 -0
  10. data/lib/tinypass.rb +48 -0
  11. data/lib/tinypass/.DS_Store +0 -0
  12. data/lib/tinypass/builder.rb +7 -0
  13. data/lib/tinypass/builder/client_builder.rb +40 -0
  14. data/lib/tinypass/builder/client_parser.rb +48 -0
  15. data/lib/tinypass/builder/cookie_parser.rb +25 -0
  16. data/lib/tinypass/builder/json_msg_builder.rb +115 -0
  17. data/lib/tinypass/builder/open_encoder.rb +11 -0
  18. data/lib/tinypass/builder/secure_encoder.rb +15 -0
  19. data/lib/tinypass/builder/security_utils.rb +67 -0
  20. data/lib/tinypass/gateway.rb +104 -0
  21. data/lib/tinypass/offer.rb +23 -0
  22. data/lib/tinypass/policies.rb +5 -0
  23. data/lib/tinypass/policies/discount_policy.rb +25 -0
  24. data/lib/tinypass/policies/policy.rb +25 -0
  25. data/lib/tinypass/policies/pricing_policy.rb +13 -0
  26. data/lib/tinypass/policies/restriction_policy.rb +14 -0
  27. data/lib/tinypass/price_option.rb +66 -0
  28. data/lib/tinypass/resource.rb +17 -0
  29. data/lib/tinypass/token.rb +6 -0
  30. data/lib/tinypass/token/access_token.rb +163 -0
  31. data/lib/tinypass/token/access_token_list.rb +71 -0
  32. data/lib/tinypass/token/access_token_store.rb +59 -0
  33. data/lib/tinypass/token/meter.rb +76 -0
  34. data/lib/tinypass/token/meter_helper.rb +82 -0
  35. data/lib/tinypass/token/token_data.rb +72 -0
  36. data/lib/tinypass/ui.rb +2 -0
  37. data/lib/tinypass/ui/html_widget.rb +29 -0
  38. data/lib/tinypass/ui/purchase_request.rb +34 -0
  39. data/lib/tinypass/utils.rb +34 -0
  40. data/lib/tinypass/version.rb +3 -0
  41. data/spec/.DS_Store +0 -0
  42. data/spec/acceptance/basic_workflow_spec.rb +81 -0
  43. data/spec/integration/.DS_Store +0 -0
  44. data/spec/integration/cases/.DS_Store +0 -0
  45. data/spec/integration/cases/basic_spec.rb +53 -0
  46. data/spec/integration/cases/combo_spec.rb +43 -0
  47. data/spec/integration/cases/metered_reminder_spec.rb +42 -0
  48. data/spec/integration/cases/metered_strict_spec.rb +54 -0
  49. data/spec/integration/cases/metered_views_spec.rb +92 -0
  50. data/spec/integration/client_builder_and_parser_spec.rb +21 -0
  51. data/spec/spec_helper.rb +33 -0
  52. data/spec/support/.DS_Store +0 -0
  53. data/spec/support/acceptance.rb +13 -0
  54. data/spec/support/tinypass_factories.rb +25 -0
  55. data/spec/unit/.DS_Store +0 -0
  56. data/spec/unit/builder/.DS_Store +0 -0
  57. data/spec/unit/builder/client_builder_spec.rb +23 -0
  58. data/spec/unit/builder/client_parser_spec.rb +27 -0
  59. data/spec/unit/builder/cookie_parser_spec.rb +39 -0
  60. data/spec/unit/builder/json_msg_builder_spec.rb +73 -0
  61. data/spec/unit/builder/open_encoder_spec.rb +15 -0
  62. data/spec/unit/builder/secure_encoder_spec.rb +23 -0
  63. data/spec/unit/builder/security_utils_spec.rb +42 -0
  64. data/spec/unit/gateway_spec.rb +80 -0
  65. data/spec/unit/offer_spec.rb +31 -0
  66. data/spec/unit/policies/.DS_Store +0 -0
  67. data/spec/unit/policies/discount_policy_spec.rb +40 -0
  68. data/spec/unit/policies/pricing_policy_spec.rb +23 -0
  69. data/spec/unit/policies/restriction_policy_spec.rb +35 -0
  70. data/spec/unit/price_option_spec.rb +109 -0
  71. data/spec/unit/resource_spec.rb +24 -0
  72. data/spec/unit/tinypass_spec.rb +51 -0
  73. data/spec/unit/token/.DS_Store +0 -0
  74. data/spec/unit/token/access_token_list_spec.rb +94 -0
  75. data/spec/unit/token/access_token_spec.rb +267 -0
  76. data/spec/unit/token/access_token_store_spec.rb +93 -0
  77. data/spec/unit/token/meter_helper_spec.rb +103 -0
  78. data/spec/unit/token/meter_spec.rb +66 -0
  79. data/spec/unit/token/token_data_spec.rb +66 -0
  80. data/spec/unit/ui/.DS_Store +0 -0
  81. data/spec/unit/ui/html_widget_spec.rb +89 -0
  82. data/spec/unit/ui/purchase_request_spec.rb +46 -0
  83. data/spec/unit/utils_spec.rb +57 -0
  84. data/tinypass.gemspec +35 -0
  85. metadata +330 -0
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NjVkNzU2MGVjNWZiMmI4YWI0YTg4YzkzNDNlMzVhYjQ4MTcyMDMyMg==
5
+ data.tar.gz: !binary |-
6
+ OTZmMjk2OGNlOTM5ODFiMzE0MTk2ZGVkNzNhNTYzYjIzNWFlMTYzZg==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NDlkODJjMjA0NGRmN2JiYmYxYzE1NDViNjExY2U4YzkzNzRlZmE1OTY0MmU5
10
+ OTk0MjZlZDVjMDI5NmFiZjBlNDM1NTJkODE3NDNmYWFlMzYxYTExYWMwMDNj
11
+ ZTJiNzVmZWU4NmQ5ZGZiNjNkNTViMzg5MTUxZmNlYzA4ZTk2YTg=
12
+ data.tar.gz: !binary |-
13
+ ZmQ2ZjQwNmI0ZGQyMDBjZmJhNWJmMGM5NjFkMGM1NzJhNTBiMDA2NzNkOTJl
14
+ OGZmMjU1MmMzZjI1YTlhOGU2YjNhNGQ4YWMwNzRkZTU4ZDE1YmE0ZTJjZmUx
15
+ ZTE5ZmJiMTY1NTI2ZTkwZDViYzllNzRhOWY3NzkwMWFjYmE5OTg=
Binary file
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .svn
4
+ .bundle
5
+ .config
6
+ .env
7
+ .yardoc
8
+ .ruby-version
9
+ Gemfile.lock
10
+ InstalledFiles
11
+ _yardoc
12
+ coverage
13
+ doc/
14
+ lib/bundler/man
15
+ pkg
16
+ rdoc
17
+ spec/reports
18
+ test/tmp
19
+ test/version_tmp
20
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in tinypass.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Taavo Smith
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,32 @@
1
+ # Tinypass
2
+
3
+ A Ruby implementation of the [Tinypass](http://tinypass.com) API,
4
+ [also available](http://developer.tinypass.com/downloads) for Java, PHP, and .NET.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'tinypass'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Manual installation is also possible with:
17
+
18
+ $ gem install tinypass
19
+
20
+ For usage instructions please see the [Tinypass Developer Documentation](http://developer.tinypass.com/main/index).
21
+
22
+ ## Requirements
23
+
24
+ - Ruby 1.9.2 or above.
25
+
26
+ ## Contributing
27
+
28
+ 1. Fork it
29
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
30
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
31
+ 4. Push to the branch (`git push origin my-new-feature`)
32
+ 5. Create new Pull Request
@@ -0,0 +1,19 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new
5
+
6
+ task :default => :spec
7
+ task :test => :spec
8
+
9
+ desc "Open a pry session preloaded with this library"
10
+ task :console do
11
+ sh "pry -I./lib -rtinypass"
12
+ end
13
+ task :c => :console
14
+
15
+ desc "Run specs with code coverage"
16
+ task :coverage do
17
+ ENV['COVERAGE'] = 'true'
18
+ Rake::Task["spec"].execute
19
+ end
Binary file
@@ -0,0 +1,48 @@
1
+ require 'tinypass/builder'
2
+ require 'tinypass/gateway'
3
+ require 'tinypass/offer'
4
+ require 'tinypass/price_option'
5
+ require 'tinypass/policies'
6
+ require 'tinypass/resource'
7
+ require 'tinypass/token'
8
+ require 'tinypass/ui'
9
+ require 'tinypass/utils'
10
+
11
+ require 'tinypass/version'
12
+
13
+ module Tinypass
14
+ extend self
15
+ extend Gateway
16
+
17
+ API_ENDPOINT_PROD = "https://api.tinypass.com"
18
+ API_ENDPOINT_SANDBOX = "https://sandbox.tinypass.com"
19
+
20
+ attr_accessor :sandbox, :aid, :private_key
21
+
22
+ class Config
23
+ VERSION = "2.0.7"
24
+ MSG_VERSION = "2.0p"
25
+
26
+ CONTEXT = "/v2"
27
+ REST_CONTEXT = "/r2"
28
+
29
+ COOKIE_PREFIX = "__TP_"
30
+ COOKIE_SUFFIX = "_TOKEN"
31
+
32
+ attr_accessor :sandbox, :aid, :private_key
33
+
34
+ def self.app_prefix(aid)
35
+ COOKIE_PREFIX + aid
36
+ end
37
+
38
+ def self.token_cookie_name(aid = Tinypass::aid)
39
+ COOKIE_PREFIX + aid + COOKIE_SUFFIX
40
+ end
41
+
42
+ def self.endpoint
43
+ return Tinypass::API_ENDPOINT_DEV if defined?(Tinypass::API_ENDPOINT_DEV)
44
+
45
+ Tinypass.sandbox ? Tinypass::API_ENDPOINT_SANDBOX : Tinypass::API_ENDPOINT_PROD
46
+ end
47
+ end
48
+ end
Binary file
@@ -0,0 +1,7 @@
1
+ require 'tinypass/builder/client_builder'
2
+ require 'tinypass/builder/client_parser'
3
+ require 'tinypass/builder/cookie_parser'
4
+ require 'tinypass/builder/json_msg_builder'
5
+ require 'tinypass/builder/open_encoder'
6
+ require 'tinypass/builder/secure_encoder'
7
+ require 'tinypass/builder/security_utils'
@@ -0,0 +1,40 @@
1
+ module Tinypass
2
+ class ClientBuilder
3
+ TYPE_JSON = 'j'
4
+
5
+ ENCODING_AES = 'a'
6
+ ENCODING_OPEN = 'o'
7
+
8
+ STD_ENC = "{jax}"
9
+ ZIP_ENC = "{jzx}"
10
+ OPEN_ENC = "{jox}"
11
+
12
+ def initialize(settings = '')
13
+ @private_key = Tinypass.private_key
14
+ @mask = '{'
15
+
16
+ @builder = JsonMsgBuilder.new
17
+ @mask << TYPE_JSON
18
+
19
+ if settings[2] == ENCODING_OPEN
20
+ @encoder = OpenEncoder.new
21
+ @mask << ENCODING_OPEN
22
+ else
23
+ @encoder = SecureEncoder.new(@private_key)
24
+ @mask << ENCODING_AES
25
+ end
26
+
27
+ @mask << 'x}'
28
+ end
29
+
30
+ def build_access_tokens(tokens)
31
+ tokens = AccessTokenList.new(tokens) if tokens.kind_of?(AccessToken)
32
+ @mask + @encoder.encode(@builder.build_access_tokens(tokens))
33
+ end
34
+
35
+ def build_purchase_request(requests)
36
+ requests = Array(requests)
37
+ @mask + @encoder.encode(@builder.build_purchase_requests(requests))
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,48 @@
1
+ module Tinypass
2
+ class ClientParser
3
+ DATA_BLOCK_START_SIGNATURE = /{\w\w\w}/
4
+
5
+ def parse_access_tokens(message)
6
+ tokens = []
7
+ blocks = split_message_string(message)
8
+
9
+ blocks.each do |block|
10
+ block_data = setup_implementations(block)
11
+ list = @parser.parse_access_tokens(@encoder.decode(block_data))
12
+ tokens += list.tokens
13
+ end
14
+
15
+ AccessTokenList.new(tokens)
16
+ end
17
+
18
+ private
19
+
20
+ def split_message_string(message)
21
+ start = -1
22
+ list = []
23
+
24
+ message.scan(DATA_BLOCK_START_SIGNATURE) do
25
+ list << message[start...Regexp.last_match.begin(0)] if start >= 0
26
+ start = Regexp.last_match.begin(0)
27
+ end
28
+ list << message[start..-1] if start >= 0
29
+
30
+ list
31
+ end
32
+
33
+ def setup_implementations(block)
34
+ block = ClientBuilder::STD_ENC if block.empty?
35
+
36
+ @parser = JsonMsgBuilder.new
37
+
38
+ if block[2] == ClientBuilder::ENCODING_OPEN
39
+ @encoder = OpenEncoder.new
40
+ else
41
+ @encoder = SecureEncoder.new(Tinypass.private_key)
42
+ end
43
+
44
+ block.sub!(/^{...}/, '')
45
+ block
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,25 @@
1
+ module Tinypass
2
+ module CookieParser
3
+ extend self
4
+
5
+ COOKIE_PARSER = /[^=\s]+=[^=;]*/
6
+
7
+ def extract_cookie_value(key, cookies_string)
8
+ return if cookies_string.empty?
9
+
10
+ keys_found = false
11
+
12
+ cookies_string.scan(COOKIE_PARSER).each do |cookie_string|
13
+ cookie_key, cookie_value = cookie_string.split('=')
14
+
15
+ keys_found = true
16
+
17
+ return cookie_value if cookie_key == key
18
+ end
19
+
20
+ return if keys_found
21
+
22
+ cookies_string
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,115 @@
1
+ require 'multi_json'
2
+
3
+ module Tinypass
4
+ class JsonMsgBuilder
5
+ def parse_access_tokens(json_string)
6
+ json_data = MultiJson.load(json_string)
7
+
8
+ # 1.0 tokens can't be parsed in this version
9
+ return AccessTokenList.new([]) if json_data.respond_to?(:has_key?) && json_data.has_key?('tokens')
10
+
11
+ access_tokens = []
12
+ Array(json_data).each do |json_datum|
13
+ next if json_datum['rid'].to_s.empty?
14
+
15
+ token_data = TokenData.new(json_datum)
16
+ access_tokens << AccessToken.new(token_data)
17
+ end
18
+
19
+ AccessTokenList.new(access_tokens)
20
+ end
21
+
22
+ def build_access_tokens(list)
23
+ tokens = []
24
+
25
+ list.each do |token|
26
+ tokens << token.token_data.values
27
+ end
28
+
29
+ MultiJson.dump(tokens)
30
+ end
31
+
32
+ def build_access_token(token)
33
+ MultiJson.dump(token.token_data.values)
34
+ end
35
+
36
+ def build_purchase_requests(requests)
37
+ data = []
38
+
39
+ requests.each do |request|
40
+ data << build_purchase_request(request)
41
+ end
42
+
43
+ MultiJson.dump(data)
44
+ end
45
+
46
+ private
47
+
48
+ def build_purchase_request(request)
49
+ data = {
50
+ o1: build_offer(request.primary_offer),
51
+ t: Time.now.to_i,
52
+ v: Config::MSG_VERSION,
53
+ cb: request.callback
54
+ }
55
+
56
+ data[:ip] = request.client_ip if request.client_ip
57
+ data[:uref] = request.user_ref if request.user_ref
58
+ data[:opts] = request.options if request.options && request.options.any?
59
+ data[:o2] = build_offer(request.secondary_offer) if request.secondary_offer
60
+
61
+ data
62
+ end
63
+
64
+ def build_offer(offer)
65
+ data = {
66
+ rid: offer.resource.rid,
67
+ rnm: offer.resource.name,
68
+ rurl: offer.resource.url,
69
+ pos: build_price_options(offer.pricing.price_options),
70
+ pol: build_policies(offer.policies)
71
+ }
72
+
73
+ data[:tags] = offer.tags if offer.tags
74
+
75
+ data
76
+ end
77
+
78
+ def build_price_options(price_options)
79
+ data = {}
80
+
81
+ price_options.each_with_index do |price_option, i|
82
+ key = "opt#{ i }"
83
+ data[key] = build_price_option(price_option)
84
+ end
85
+
86
+ data
87
+ end
88
+
89
+ def build_price_option(price_option)
90
+ data = {
91
+ price: price_option.price || '',
92
+ exp: price_option.access_period || '',
93
+ caption: price_option.caption || ''
94
+ }
95
+
96
+ if price_option.start_date_in_secs && price_option.start_date_in_secs > 0
97
+ data[:sd] = price_option.start_date_in_secs
98
+ end
99
+
100
+ if price_option.end_date_in_secs && price_option.end_date_in_secs > 0
101
+ data[:ed] = price_option.end_date_in_secs
102
+ end
103
+
104
+ if price_option.split_pays.any?
105
+ data[:splits] = price_option.split_pays.map { |email, amount| "#{ email }=#{ amount }" }
106
+ end
107
+
108
+ data
109
+ end
110
+
111
+ def build_policies(policies)
112
+ policies.map { |policy| policy.to_hash }
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,11 @@
1
+ module Tinypass
2
+ class OpenEncoder
3
+ def encode(msg)
4
+ msg
5
+ end
6
+
7
+ def decode(msg)
8
+ msg
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module Tinypass
2
+ class SecureEncoder
3
+ def initialize(private_key)
4
+ @private_key = private_key
5
+ end
6
+
7
+ def encode(message)
8
+ Tinypass::SecurityUtils::encrypt(@private_key, message)
9
+ end
10
+
11
+ def decode(message)
12
+ Tinypass::SecurityUtils::decrypt(@private_key, message)
13
+ end
14
+ end
15
+ end