refcode 0.1.0 → 0.1.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.
- 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
|