multipass 1.1.4 → 1.2.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.
data/.gitignore CHANGED
@@ -1 +1,2 @@
1
1
  .rake_tasks
2
+ pkg
@@ -1,5 +1,5 @@
1
1
  ---
2
2
  :major: 1
3
- :minor: 1
4
- :patch: 4
3
+ :minor: 2
4
+ :patch: 1
5
5
  :build:
@@ -1,24 +1,36 @@
1
1
  require 'time'
2
+ require 'ezcrypto'
2
3
 
3
4
  class MultiPass
4
5
  class Invalid < StandardError
5
- @@message = "The MultiPass token is invalid."
6
+ class << self
7
+ attr_accessor :message
8
+ end
9
+ self.message = "The MultiPass token is invalid."
10
+
11
+ attr_reader :data, :json, :options
12
+
13
+ def initialize(data = nil, json = nil, options = nil)
14
+ @data = data
15
+ @json = json
16
+ @options = options
17
+ end
6
18
 
7
19
  def message
8
- @@message
20
+ self.class.message
9
21
  end
10
22
 
11
23
  alias to_s message
12
24
  end
13
25
 
14
26
  class ExpiredError < Invalid
15
- @@message = "The MultiPass token has expired."
27
+ self.message = "The MultiPass token has expired."
16
28
  end
17
29
  class JSONError < Invalid
18
- @@message = "The decrypted MultiPass token is not valid JSON."
30
+ self.message = "The decrypted MultiPass token is not valid JSON."
19
31
  end
20
32
  class DecryptError < Invalid
21
- @@message = "The MultiPass token was not able to be decrypted."
33
+ self.message = "The MultiPass token was not able to be decrypted."
22
34
  end
23
35
 
24
36
  def self.encode(site_key, api_key, options = {})
@@ -29,15 +41,19 @@ class MultiPass
29
41
  new(site_key, api_key).decode(data)
30
42
  end
31
43
 
32
- def initialize(site_key, api_key)
44
+ # options:
45
+ # :url_safe => true
46
+ def initialize(site_key, api_key, options = {})
33
47
  @site_key = site_key
34
48
  @api_key = api_key
35
- if !Object.const_defined?(:EzCrypto)
36
- require 'ezcrypto'
37
- end
49
+ @url_safe = !options.key?(:url_safe) || options[:url_safe]
38
50
  @crypto_key = EzCrypto::Key.with_password(@site_key, @api_key)
39
51
  end
40
52
 
53
+ def url_safe?
54
+ !!@url_safe
55
+ end
56
+
41
57
  # Encrypts the given hash into a multipass string.
42
58
  def encode(options = {})
43
59
  options[:expires] = case options[:expires]
@@ -45,22 +61,23 @@ class MultiPass
45
61
  when Time, DateTime, Date then options[:expires].to_s
46
62
  else options[:expires].to_s
47
63
  end
48
- @crypto_key.encrypt64(options.to_json)
64
+ self.class.encode_64 @crypto_key.encrypt(options.to_json), @url_safe
49
65
  end
50
66
 
51
67
  # Decrypts the given multipass string and parses it as JSON. Then, it checks
52
68
  # for a valid expiration date.
53
69
  def decode(data)
54
- json = @crypto_key.decrypt64(data)
70
+ json = options = nil
71
+ json = @crypto_key.decrypt(self.class.decode_64(data, @url_safe))
55
72
 
56
73
  if json.nil?
57
- raise MultiPass::DecryptError
74
+ raise MultiPass::DecryptError.new(data)
58
75
  end
59
76
 
60
- options = decode_json(json)
77
+ options = decode_json(data, json)
61
78
 
62
79
  if !options.is_a?(Hash)
63
- raise MultiPass::JSONError
80
+ raise MultiPass::JSONError.new(data, json, options)
64
81
  end
65
82
 
66
83
  options.keys.each do |key|
@@ -68,29 +85,55 @@ class MultiPass
68
85
  end
69
86
 
70
87
  if options[:expires].nil? || Time.now.utc > Time.parse(options[:expires])
71
- raise MultiPass::ExpiredError
88
+ raise MultiPass::ExpiredError.new(data, json, options)
72
89
  end
73
90
 
74
91
  options
75
92
  rescue CipherError
76
- raise MultiPass::DecryptError
93
+ raise MultiPass::DecryptError.new(data, json, options)
77
94
  end
78
95
 
79
96
  CipherError = OpenSSL.const_defined?(:CipherError) ? OpenSSL::CipherError : OpenSSL::Cipher::CipherError
80
97
 
81
- private
82
98
  if Object.const_defined?(:ActiveSupport)
83
- def decode_json(s)
99
+ include ActiveSupport::Base64
100
+ else
101
+ require 'base64'
102
+ end
103
+
104
+ def self.encode_64(s, url_safe = true)
105
+ b = Base64.encode64(s)
106
+ b.gsub! /\n/, ''
107
+ if url_safe
108
+ b.tr! '+', '-'
109
+ b.tr! '/', '_'
110
+ b.chomp! '='
111
+ end
112
+ b
113
+ end
114
+
115
+ def self.decode_64(s, url_safe = true)
116
+ if url_safe
117
+ s = s.dup
118
+ s.tr! '-', '+'
119
+ s.tr! '_', '/'
120
+ s << '='
121
+ end
122
+ Base64.decode64(s)
123
+ end
124
+
125
+ if Object.const_defined?(:ActiveSupport)
126
+ def decode_json(data, s)
84
127
  ActiveSupport::JSON.decode(s)
85
128
  rescue ActiveSupport::JSON::ParseError
86
- raise MultiPass::JSONError
129
+ raise MultiPass::JSONError.new(data, s)
87
130
  end
88
131
  else
89
132
  require 'json'
90
- def decode_json(s)
133
+ def decode_json(data, s)
91
134
  JSON.parse(s)
92
135
  rescue JSON::ParserError
93
- raise MultiPass::JSONError
136
+ raise MultiPass::JSONError.new(data, s)
94
137
  end
95
138
  end
96
139
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{multipass}
8
- s.version = "1.1.4"
8
+ s.version = "1.2.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["rick"]
12
- s.date = %q{2009-12-17}
12
+ s.date = %q{2010-01-01}
13
13
  s.email = %q{technoweenie@gmail.com}
14
14
  s.extra_rdoc_files = [
15
15
  "LICENSE",
@@ -1,28 +1,15 @@
1
1
  $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
2
2
  require 'rubygems'
3
3
  require 'test/unit'
4
- require 'ezcrypto'
5
4
  require 'multipass'
5
+ #require 'active_support'
6
6
 
7
- class MultiPassTest < Test::Unit::TestCase
8
- def setup
9
- @date = Time.now + 1234
10
- @input = {:expires => @date, :email => 'ricky@bobby.com'}
11
- @output = @input.merge(:expires => @input[:expires].to_s)
12
- @key = EzCrypto::Key.with_password('example', 'abc')
13
- @mp = MultiPass.new('example', 'abc')
14
- end
15
-
7
+ module MultiPassTests
16
8
  def test_encodes_multipass
17
- expected = @key.encrypt64(@output.to_json)
9
+ expected = MultiPass.encode_64(@key.encrypt(@output.to_json), @mp.url_safe?)
18
10
  assert_equal expected, @mp.encode(@input)
19
11
  end
20
12
 
21
- def test_encodes_multipass_with_class_method
22
- expected = @key.encrypt64(@output.to_json)
23
- assert_equal expected, MultiPass.encode('example', 'abc', @input)
24
- end
25
-
26
13
  def test_decodes_multipass
27
14
  encoded = @mp.encode(@input)
28
15
  assert_equal @input, @mp.decode(encoded)
@@ -54,4 +41,97 @@ class MultiPassTest < Test::Unit::TestCase
54
41
  @mp.decode(encrypted)
55
42
  end
56
43
  end
44
+ end
45
+
46
+ class StandardMultiPassTest < Test::Unit::TestCase
47
+ include MultiPassTests
48
+
49
+ def setup
50
+ @date = Time.now + 1234
51
+ @input = {:expires => @date, :email => 'ricky@bobby.com'}
52
+ @output = @input.merge(:expires => @input[:expires].to_s)
53
+ @key = EzCrypto::Key.with_password('example', 'abc')
54
+ @mp = MultiPass.new('example', 'abc', :url_safe => false)
55
+ end
56
+ end
57
+
58
+ class UrlSafeMultiPassTest < Test::Unit::TestCase
59
+ include MultiPassTests
60
+
61
+ def test_encodes_multipass_with_class_method
62
+ expected = MultiPass.encode_64(@key.encrypt(@output.to_json), @mp.url_safe?)
63
+ assert_equal expected, MultiPass.encode('example', 'abc', @input)
64
+ end
65
+
66
+ def setup
67
+ @date = Time.now + 1234
68
+ @input = {:expires => @date, :email => 'ricky@bobby.com'}
69
+ @output = @input.merge(:expires => @input[:expires].to_s)
70
+ @key = EzCrypto::Key.with_password('example', 'abc')
71
+ @mp = MultiPass.new('example', 'abc', :url_safe => true)
72
+ end
73
+ end
74
+
75
+ class ErrorTest < Test::Unit::TestCase
76
+ def setup
77
+ @key = EzCrypto::Key.with_password('example', 'abc')
78
+ @mp = MultiPass.new('example', 'abc')
79
+ end
80
+
81
+ def test_decrypt_error_stores_data
82
+ begin
83
+ @mp.decode 'abc'
84
+ rescue MultiPass::DecryptError => e
85
+ assert_equal 'abc', e.data
86
+ end
87
+ end
88
+
89
+ def test_json_error_stores_data
90
+ begin
91
+ data = @key.encrypt64("abc")
92
+ @mp.decode data
93
+ rescue MultiPass::JSONError => e
94
+ assert_equal data, e.data
95
+ end
96
+ end
97
+
98
+ def test_json_error_stores_json
99
+ begin
100
+ data = @key.encrypt64("{a")
101
+ @mp.decode data
102
+ rescue MultiPass::JSONError => e
103
+ assert_equal "{a", e.json
104
+ end
105
+ end
106
+
107
+ def test_expiration_error_stores_data
108
+ begin
109
+ json = {:expires => Time.now - 5, :email => 'ricky@bobby.com'}.to_json
110
+ data = @key.encrypt64(json)
111
+ @mp.decode data
112
+ rescue MultiPass::ExpiredError => e
113
+ assert_equal data, e.data
114
+ end
115
+ end
116
+
117
+ def test_expiration_error_stores_json
118
+ begin
119
+ json = {:expires => Time.now - 5, :email => 'ricky@bobby.com'}.to_json
120
+ data = @key.encrypt64(json)
121
+ @mp.decode data
122
+ rescue MultiPass::ExpiredError => e
123
+ assert_equal json, e.json
124
+ end
125
+ end
126
+
127
+ def test_expiration_error_stores_options
128
+ begin
129
+ opt = {:expires => (Time.now - 5).to_s, :email => 'ricky@bobby.com'}
130
+ json = opt.to_json
131
+ data = @key.encrypt64(json)
132
+ @mp.decode data
133
+ rescue MultiPass::ExpiredError => e
134
+ assert_equal opt, e.options
135
+ end
136
+ end
57
137
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: multipass
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.4
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - rick
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-12-17 00:00:00 -08:00
12
+ date: 2010-01-01 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency