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 +1 -0
- data/VERSION.yml +2 -2
- data/lib/multipass.rb +64 -21
- data/multipass.gemspec +2 -2
- data/test/multipass_test.rb +96 -16
- metadata +2 -2
data/.gitignore
CHANGED
data/VERSION.yml
CHANGED
data/lib/multipass.rb
CHANGED
@@ -1,24 +1,36 @@
|
|
1
1
|
require 'time'
|
2
|
+
require 'ezcrypto'
|
2
3
|
|
3
4
|
class MultiPass
|
4
5
|
class Invalid < StandardError
|
5
|
-
|
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
|
-
|
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
|
-
|
27
|
+
self.message = "The MultiPass token has expired."
|
16
28
|
end
|
17
29
|
class JSONError < Invalid
|
18
|
-
|
30
|
+
self.message = "The decrypted MultiPass token is not valid JSON."
|
19
31
|
end
|
20
32
|
class DecryptError < Invalid
|
21
|
-
|
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
|
-
|
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
|
-
|
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.
|
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 =
|
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
|
-
|
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
|
data/multipass.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{multipass}
|
8
|
-
s.version = "1.1
|
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{
|
12
|
+
s.date = %q{2010-01-01}
|
13
13
|
s.email = %q{technoweenie@gmail.com}
|
14
14
|
s.extra_rdoc_files = [
|
15
15
|
"LICENSE",
|
data/test/multipass_test.rb
CHANGED
@@ -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
|
-
|
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.
|
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
|
+
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:
|
12
|
+
date: 2010-01-01 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|