multipass 1.1.4 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
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