refcode 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +35 -27
- data/lib/refcode.rb +1 -0
- data/lib/refcode/encodable.rb +8 -2
- data/lib/refcode/encoder.rb +1 -1
- data/lib/refcode/errors.rb +6 -0
- data/lib/refcode/version.rb +1 -1
- data/test/refcode_encodable_test.rb +74 -0
- data/test/refcode_encoder_test.rb +42 -0
- metadata +6 -3
- data/test/refcode_test.rb +0 -81
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b45526e91ab90f8b69e43976b600a8bbfa1dbdc0
|
4
|
+
data.tar.gz: f580b982c0f61c0021f77b53f0f607047569ebdb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 21d4ebf71a2fb58ebf43068289ae42b80646b78f8bb8fdbdd05be8ac0e0778f044d21bf466b04f0cd640cef75ae14cff2828dacfecbea19eec5d67180ab8e0fe
|
7
|
+
data.tar.gz: 25d0b08552e8e4f4c84080f084bd78d3ae89914aa380c9b81434b6993ee653f264b77961394d586615e213f6bbd262dab56f718cdf5f7d621020b8a5db527760
|
data/README.md
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
# Refcode
|
2
2
|
|
3
|
-
|
4
|
-
URL-safe strings. The strings can be
|
3
|
+
A ruby gem for converting arbitrary Ruby objects into encrypted,
|
4
|
+
URL-safe strings. The strings can be easily decrypted later for use in your
|
5
5
|
application.
|
6
6
|
|
7
|
-
|
7
|
+
RefCode was conceived as a way to attach referral data to tracking links. Encryption
|
8
8
|
makes it unlikely that the links will be tampered with. Still, it is not recommended
|
9
|
-
for critically sensitive
|
10
|
-
link tracking system.
|
9
|
+
for critically sensitive data!
|
11
10
|
|
12
11
|
## Implementation
|
13
12
|
|
@@ -33,41 +32,50 @@ Or install it yourself as:
|
|
33
32
|
|
34
33
|
## Usage
|
35
34
|
|
36
|
-
|
35
|
+
RefCode can be used in two ways. Most simply, you can use the `Refcode::Encoder` class directly.
|
37
36
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
37
|
+
```ruby
|
38
|
+
encoder = Refcode::Encoder.new do |e|
|
39
|
+
e.secret = "a long crunchy secret"
|
40
|
+
e.salt = "some salt"
|
41
|
+
end
|
42
42
|
|
43
|
-
|
44
|
-
|
43
|
+
something = OpenStruct.new(channel: 'facebook', action: 'message', user_id: 43765)
|
44
|
+
encoded_param = encoder.encode something
|
45
45
|
|
46
|
-
|
46
|
+
# in some future request:
|
47
47
|
|
48
|
-
|
49
|
-
|
48
|
+
something = encoder.decode params[:encoded_param]
|
49
|
+
puts something.channel #=> 'facebook'
|
50
|
+
```
|
50
51
|
|
51
52
|
For added convenience when using Refcode with an ORM such as ActiveRecord, a module called `Refcode::Encodable` is also provided.
|
52
53
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
54
|
+
```ruby
|
55
|
+
class Job < ActiveRecord::Base
|
56
|
+
include Refcode::Encodable
|
57
|
+
has_refcode secret: 'a long crunchy secret', salt: :id
|
58
|
+
end
|
57
59
|
|
58
|
-
|
59
|
-
|
60
|
+
# the salt option of the has_refcode method can accept a proc/lambda, string
|
61
|
+
# or a symbol representing an existing method on the class (id in this case)
|
60
62
|
|
61
|
-
|
63
|
+
# in some controller code:
|
62
64
|
|
63
|
-
|
64
|
-
|
65
|
+
@job = Job.find params[:id]
|
66
|
+
referral_code = @job.generate_refcode channel: 'facebook', action: 'message', user_id: 43765
|
65
67
|
|
66
|
-
|
68
|
+
# and in another action:
|
67
69
|
|
68
|
-
|
69
|
-
|
70
|
+
@job = Job.find params[:id]
|
71
|
+
referral_data = @job.parse_refcode params[:encoded_param]
|
72
|
+
```
|
70
73
|
|
74
|
+
## Features for 1.0
|
75
|
+
|
76
|
+
- ~~Encodable mixin~~
|
77
|
+
- ~~Better exception handling~~
|
78
|
+
- More complete tests against encoding non-core ruby class values
|
71
79
|
|
72
80
|
## Contributing
|
73
81
|
|
data/lib/refcode.rb
CHANGED
data/lib/refcode/encodable.rb
CHANGED
@@ -7,11 +7,12 @@ module Refcode
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def generate_refcode val
|
10
|
-
|
10
|
+
check_refcode_options!
|
11
11
|
encoder.encode val
|
12
12
|
end
|
13
13
|
|
14
14
|
def parse_refcode code
|
15
|
+
check_refcode_options!
|
15
16
|
encoder.decode code
|
16
17
|
end
|
17
18
|
|
@@ -29,10 +30,11 @@ module Refcode
|
|
29
30
|
|
30
31
|
def encoder
|
31
32
|
Refcode::Encoder.new do |r|
|
33
|
+
check_refcode_options!
|
32
34
|
r.secret = self.class.refcode_options[:secret]
|
33
35
|
salt_option = self.class.refcode_options[:salt]
|
34
36
|
if salt_option.respond_to? :call
|
35
|
-
r.salt = salt_option.call
|
37
|
+
r.salt = salt_option.call self
|
36
38
|
elsif salt_option.is_a? Symbol
|
37
39
|
r.salt = self.send salt_option
|
38
40
|
else
|
@@ -42,6 +44,10 @@ module Refcode
|
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
47
|
+
def check_refcode_options!
|
48
|
+
raise RefcodeInitException.new('You must call the has_refcode method in your class definition') unless self.class.refcode_options
|
49
|
+
end
|
50
|
+
|
45
51
|
end
|
46
52
|
|
47
53
|
end
|
data/lib/refcode/encoder.rb
CHANGED
data/lib/refcode/version.rb
CHANGED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'test/unit'
|
3
|
+
require File.join(File.dirname(__FILE__),"..","lib","refcode.rb")
|
4
|
+
|
5
|
+
class RefcodeEncodableTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
SECRET = "a short tidy secret, but not too short!"
|
8
|
+
|
9
|
+
class BareEncodableObject < OpenStruct
|
10
|
+
include Refcode::Encodable
|
11
|
+
end
|
12
|
+
class EncodableObjectSymbol < BareEncodableObject
|
13
|
+
has_refcode :secret => SECRET, :salt => :record_id
|
14
|
+
end
|
15
|
+
class EncodableObjectString < BareEncodableObject
|
16
|
+
has_refcode :secret => SECRET, :salt => "123 abc xyz"
|
17
|
+
end
|
18
|
+
class EncodableObjectSaltyLambda < BareEncodableObject
|
19
|
+
has_refcode :secret => SECRET, :salt => lambda { |me| "#{me.record_id}-42" }
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_should_raise_argument_error_if_generate_refcode_called_without_val
|
23
|
+
assert_raise ArgumentError do
|
24
|
+
encodable_object.generate_refcode
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_should_raise_error_if_refcode_methods_called_before_has_refcode
|
29
|
+
[:generate_refcode, :parse_refcode].each do |m|
|
30
|
+
assert_raise Refcode::RefcodeInitException do
|
31
|
+
obj = BareEncodableObject.new :some => 'value'
|
32
|
+
obj.send m, "bogus value"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_should_raise_argument_error_if_has_refcode_called_without_correct_options
|
38
|
+
assert_raise ArgumentError do
|
39
|
+
obj = BareEncodableObject.new :some => 'value'
|
40
|
+
obj.class.has_refcode :whatever => 'wrong'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_should_raise_an_error_if_salt_is_empty
|
45
|
+
encodable_object.record_id = nil
|
46
|
+
assert_raise RuntimeError do
|
47
|
+
referral_code_content = { :channel => 'email', :action => 'forward', :user_id => 14325 }
|
48
|
+
code = encodable_object.generate_refcode referral_code_content
|
49
|
+
assert_equal referral_code_content, encodable_object.parse_refcode(code)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_should_work_with_different_salt_options
|
54
|
+
[EncodableObjectSaltyLambda, EncodableObjectString].each do |klass|
|
55
|
+
referral_code_content = { :channel => 'email', :action => 'forward', :user_id => 14325 }
|
56
|
+
obj = klass.new referral_code_content
|
57
|
+
code = obj.generate_refcode referral_code_content
|
58
|
+
assert_equal referral_code_content, obj.parse_refcode(code)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_encodable_against_hash
|
63
|
+
referral_code_content = { :channel => 'email', :action => 'forward', :user_id => 14325 }
|
64
|
+
code = encodable_object.generate_refcode referral_code_content
|
65
|
+
assert_equal referral_code_content, encodable_object.parse_refcode(code)
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def encodable_object
|
71
|
+
@encodable_object ||= EncodableObjectSymbol.new :name => 'Unimportant Value', :record_id => 381598
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
require 'test/unit'
|
3
|
+
require File.join(File.dirname(__FILE__),"..","lib","refcode.rb")
|
4
|
+
|
5
|
+
class RefcodeEncoderTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
SECRET = "686cb0461769ebed556f56bc88c956bfdf786646ab1920f58201723c557ccbaeb57112fd53302c06475e6e19a176ba617ee284b091d375858cb259e8578c620f"
|
8
|
+
SALT = "dcc74de5efdab0d80b5d763f8a63bef3d37c7453ee45446fbbccd26648af8ca6a112576dafbf5475f3cd7b968703cc9e0682ee45b8b622045cec287908f536e8"
|
9
|
+
|
10
|
+
def test_encoder_against_hash
|
11
|
+
test_hash = { :channel => 'email', :record_id => 49203, :action => 'forward' }
|
12
|
+
assert_equal test_hash, encode_and_decode(test_hash)
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_encoder_against_string
|
16
|
+
test_string = "secret referral data"
|
17
|
+
assert_equal test_string, encode_and_decode(test_string)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_encoder_against_int
|
21
|
+
assert_equal 4857, encode_and_decode(4857)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_encoder_against_open_struct
|
25
|
+
test_struct = OpenStruct.new({:test => 42})
|
26
|
+
assert_equal test_struct, encode_and_decode(test_struct)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def encoder
|
32
|
+
@encoder ||= Refcode::Encoder.new do |e|
|
33
|
+
e.secret = SECRET
|
34
|
+
e.salt = SALT
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def encode_and_decode val
|
39
|
+
encoder.decode(encoder.encode(val))
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: refcode
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jordan Sitkin
|
@@ -81,9 +81,11 @@ files:
|
|
81
81
|
- lib/refcode.rb
|
82
82
|
- lib/refcode/encodable.rb
|
83
83
|
- lib/refcode/encoder.rb
|
84
|
+
- lib/refcode/errors.rb
|
84
85
|
- lib/refcode/version.rb
|
85
86
|
- refcode.gemspec
|
86
|
-
- test/
|
87
|
+
- test/refcode_encodable_test.rb
|
88
|
+
- test/refcode_encoder_test.rb
|
87
89
|
homepage: http://github.com/dustMason/refcode
|
88
90
|
licenses:
|
89
91
|
- MIT
|
@@ -109,4 +111,5 @@ signing_key:
|
|
109
111
|
specification_version: 4
|
110
112
|
summary: Hide sensitive data in plain sight, right in your URL
|
111
113
|
test_files:
|
112
|
-
- test/
|
114
|
+
- test/refcode_encodable_test.rb
|
115
|
+
- test/refcode_encoder_test.rb
|
data/test/refcode_test.rb
DELETED
@@ -1,81 +0,0 @@
|
|
1
|
-
require 'ostruct'
|
2
|
-
require 'test/unit'
|
3
|
-
require File.join(File.dirname(__FILE__),"..","lib","refcode.rb")
|
4
|
-
|
5
|
-
class RefcodeTest < Test::Unit::TestCase
|
6
|
-
|
7
|
-
SECRET = "686cb0461769ebed556f56bc88c956bfdf786646ab1920f58201723c557ccbaeb57112fd53302c06475e6e19a176ba617ee284b091d375858cb259e8578c620f"
|
8
|
-
SALT = "dcc74de5efdab0d80b5d763f8a63bef3d37c7453ee45446fbbccd26648af8ca6a112576dafbf5475f3cd7b968703cc9e0682ee45b8b622045cec287908f536e8"
|
9
|
-
|
10
|
-
class BareEncodableObject < OpenStruct
|
11
|
-
include Refcode::Encodable
|
12
|
-
end
|
13
|
-
class EncodableObject < BareEncodableObject
|
14
|
-
has_refcode :secret => SECRET, :salt => :record_id
|
15
|
-
end
|
16
|
-
|
17
|
-
def test_encoder_against_hash
|
18
|
-
test_hash = { :channel => 'email', :record_id => 49203, :action => 'forward' }
|
19
|
-
assert_equal test_hash, encode_and_decode(test_hash)
|
20
|
-
end
|
21
|
-
|
22
|
-
def test_encoder_against_string
|
23
|
-
test_string = "secret referral data"
|
24
|
-
assert_equal test_string, encode_and_decode(test_string)
|
25
|
-
end
|
26
|
-
|
27
|
-
def test_encoder_against_int
|
28
|
-
assert_equal 4857, encode_and_decode(4857)
|
29
|
-
end
|
30
|
-
|
31
|
-
def test_encoder_against_open_struct
|
32
|
-
test_struct = OpenStruct.new({:test => 42})
|
33
|
-
assert_equal test_struct, encode_and_decode(test_struct)
|
34
|
-
end
|
35
|
-
|
36
|
-
def test_should_raise_argument_error_if_generate_refcode_called_without_val
|
37
|
-
assert_raise ArgumentError do
|
38
|
-
encodable_object.generate_refcode
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def test_should_raise_error_if_generate_refcode_called_before_has_refcode
|
43
|
-
assert_raise ArgumentError do
|
44
|
-
obj = BareEncodableObject.new :some => 'value'
|
45
|
-
obj.generate_refcode
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def test_should_raise_an_error_if_salt_is_empty
|
50
|
-
encodable_object.record_id = nil
|
51
|
-
assert_raise RuntimeError do
|
52
|
-
referral_code_content = { :channel => 'email', :action => 'forward', :user_id => 14325 }
|
53
|
-
code = encodable_object.generate_refcode referral_code_content
|
54
|
-
assert_equal referral_code_content, encodable_object.parse_refcode(code)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def test_encodable_against_hash
|
59
|
-
referral_code_content = { :channel => 'email', :action => 'forward', :user_id => 14325 }
|
60
|
-
code = encodable_object.generate_refcode referral_code_content
|
61
|
-
assert_equal referral_code_content, encodable_object.parse_refcode(code)
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
def encodable_object
|
67
|
-
@encodable_object ||= EncodableObject.new :name => 'Unimportant Value', :record_id => 381598
|
68
|
-
end
|
69
|
-
|
70
|
-
def encoder
|
71
|
-
@encoder ||= Refcode::Encoder.new do |e|
|
72
|
-
e.secret = SECRET
|
73
|
-
e.salt = SALT
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def encode_and_decode val
|
78
|
-
encoder.decode(encoder.encode(val))
|
79
|
-
end
|
80
|
-
|
81
|
-
end
|