refcode 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +9 -7
- data/lib/refcode/encodable.rb +12 -9
- data/lib/refcode/encoder.rb +4 -0
- data/lib/refcode/version.rb +1 -1
- data/test/refcode_encodable_test.rb +50 -21
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9a685e0c98a5089405fa727a02f854ffc2f27a05
|
4
|
+
data.tar.gz: e44c013ab75a304dabcd4c3c41693dd71eda05f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6cf38bfc747e4fa7a387f7f4e72f5b9d3aa5b788de1944becbb9aa01366f27669efecf66307c42165ea5b2b949114351595210ec8c3145795a4211c899b1ad79
|
7
|
+
data.tar.gz: cebc83c94a985bc14a89ac551d9f38d93f0484086500ffcd83b8f0f4f901aa46093d600b768d7eae3bfb39831687a49acb3c00ff8a22f4adc7005eac89cb12f0
|
data/README.md
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
-
#
|
1
|
+
# RefCode
|
2
2
|
|
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
|
-
application.
|
3
|
+
A ruby gem for converting arbitrary Ruby objects into encrypted, URL-safe strings. The strings can be easily decrypted later for use in your application.
|
6
4
|
|
7
|
-
RefCode was conceived as a way to attach referral data to tracking links. Encryption
|
8
|
-
|
9
|
-
|
5
|
+
RefCode was conceived as a way to attach referral data to tracking links. Encryption makes it unlikely that the links will be tampered with. Still, it is not recommended for sensitive data!
|
6
|
+
|
7
|
+
## Why would you want this?
|
8
|
+
|
9
|
+
Lets say your app needs to track activity around certain pages that are shared among your users. Using RefCode, you can generate URLs pointing to these pages that are meant to be shared across various channels (email, facebook, etc). These links can carry a small amount of encoded data as part of the URL that will guarantee that any events you track due to visits to these links can make use of this extra encoded data. The data might include, for example, which user originally shared the link and on which channel she did so.
|
10
|
+
|
11
|
+
A secondary feature offered by the `Refcode::Encodable` mixin is the ability to guarantee that a given code works only for one (or more) specific page. For example, by using a unique value for the `salt` option that is tied to a single record, the generated code cannot be used with any other record. See the usage example below for a demonstration of this.
|
10
12
|
|
11
13
|
## Implementation
|
12
14
|
|
data/lib/refcode/encodable.rb
CHANGED
@@ -31,15 +31,8 @@ module Refcode
|
|
31
31
|
def encoder
|
32
32
|
Refcode::Encoder.new do |r|
|
33
33
|
check_refcode_options!
|
34
|
-
r.secret = self.class.refcode_options[:secret]
|
35
|
-
|
36
|
-
if salt_option.respond_to? :call
|
37
|
-
r.salt = salt_option.call self
|
38
|
-
elsif salt_option.is_a? Symbol
|
39
|
-
r.salt = self.send salt_option
|
40
|
-
else
|
41
|
-
r.salt = salt_option
|
42
|
-
end
|
34
|
+
r.secret = get_option_value(self.class.refcode_options[:secret])
|
35
|
+
r.salt = get_option_value(self.class.refcode_options[:salt])
|
43
36
|
raise "Value for salt is nil (#{salt_option} given)" if r.salt.nil?
|
44
37
|
end
|
45
38
|
end
|
@@ -48,6 +41,16 @@ module Refcode
|
|
48
41
|
raise RefcodeInitException.new('You must call the has_refcode method in your class definition') unless self.class.refcode_options
|
49
42
|
end
|
50
43
|
|
44
|
+
def get_option_value option
|
45
|
+
if option.respond_to? :call
|
46
|
+
option.call self
|
47
|
+
elsif option.is_a? Symbol
|
48
|
+
self.send option
|
49
|
+
else
|
50
|
+
option
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
51
54
|
end
|
52
55
|
|
53
56
|
end
|
data/lib/refcode/encoder.rb
CHANGED
data/lib/refcode/version.rb
CHANGED
@@ -5,23 +5,34 @@ require File.join(File.dirname(__FILE__),"..","lib","refcode.rb")
|
|
5
5
|
class RefcodeEncodableTest < Test::Unit::TestCase
|
6
6
|
|
7
7
|
SECRET = "a short tidy secret, but not too short!"
|
8
|
+
CODE_CONTENT = {:channel => 'email', :action => 'forward', :user_id => 14325, :unique_hash => 'f'}
|
8
9
|
|
9
10
|
class BareEncodableObject < OpenStruct
|
10
11
|
include Refcode::Encodable
|
11
12
|
end
|
12
|
-
class
|
13
|
-
has_refcode :secret => SECRET, :salt => :
|
13
|
+
class EncodableObjectSaltSymbol < BareEncodableObject
|
14
|
+
has_refcode :secret => SECRET, :salt => :user_id
|
14
15
|
end
|
15
|
-
class
|
16
|
+
class EncodableObjectSaltString < BareEncodableObject
|
16
17
|
has_refcode :secret => SECRET, :salt => "123 abc xyz"
|
17
18
|
end
|
18
|
-
class
|
19
|
-
has_refcode :secret => SECRET, :salt => lambda { |me| "#{me.
|
19
|
+
class EncodableObjectSaltLambda < BareEncodableObject
|
20
|
+
has_refcode :secret => SECRET, :salt => lambda { |me| "#{me.user_id}-42" }
|
21
|
+
end
|
22
|
+
class EncodableObjectSecretSymbol < BareEncodableObject
|
23
|
+
has_refcode :secret => :unique_hash, :salt => :user_id
|
24
|
+
end
|
25
|
+
class EncodableObjectSecretString < BareEncodableObject
|
26
|
+
has_refcode :secret => SECRET, :salt => "123 abc xyz"
|
27
|
+
end
|
28
|
+
class EncodableObjectSecretLambda < BareEncodableObject
|
29
|
+
has_refcode :secret => lambda { |me| me.channel*20 }, :salt => "aaa"
|
20
30
|
end
|
21
31
|
|
22
32
|
def test_should_raise_argument_error_if_generate_refcode_called_without_val
|
23
33
|
assert_raise ArgumentError do
|
24
|
-
|
34
|
+
obj = EncodableObjectSaltString.new CODE_CONTENT
|
35
|
+
obj.generate_refcode
|
25
36
|
end
|
26
37
|
end
|
27
38
|
|
@@ -42,33 +53,51 @@ class RefcodeEncodableTest < Test::Unit::TestCase
|
|
42
53
|
end
|
43
54
|
|
44
55
|
def test_should_raise_an_error_if_salt_is_empty
|
45
|
-
|
56
|
+
obj = EncodableObjectSaltSymbol.new CODE_CONTENT
|
57
|
+
obj.user_id = nil
|
46
58
|
assert_raise RuntimeError do
|
47
|
-
|
48
|
-
|
49
|
-
assert_equal referral_code_content, encodable_object.parse_refcode(code)
|
59
|
+
code = obj.generate_refcode CODE_CONTENT
|
60
|
+
assert_equal CODE_CONTENT, obj.parse_refcode(code)
|
50
61
|
end
|
51
62
|
end
|
52
63
|
|
53
64
|
def test_should_work_with_different_salt_options
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
assert_equal referral_code_content, obj.parse_refcode(code)
|
65
|
+
with_all_fixtures do |klass|
|
66
|
+
obj = klass.new CODE_CONTENT
|
67
|
+
code = obj.generate_refcode CODE_CONTENT
|
68
|
+
assert_equal CODE_CONTENT, obj.parse_refcode(code)
|
59
69
|
end
|
60
70
|
end
|
61
71
|
|
62
|
-
def
|
63
|
-
|
64
|
-
|
65
|
-
|
72
|
+
def test_should_work_with_different_secret_options
|
73
|
+
with_all_fixtures do |klass|
|
74
|
+
obj = klass.new CODE_CONTENT
|
75
|
+
code = obj.generate_refcode CODE_CONTENT
|
76
|
+
assert_equal CODE_CONTENT, obj.parse_refcode(code)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def test_should_adjust_key_length_to_satisfy_encryption_algorithm
|
81
|
+
content = CODE_CONTENT
|
82
|
+
content[:unique_hash] = "x"
|
83
|
+
obj = EncodableObjectSecretSymbol.new content
|
84
|
+
code = obj.generate_refcode content
|
85
|
+
assert_equal content, obj.parse_refcode(code)
|
66
86
|
end
|
67
87
|
|
68
88
|
private
|
69
89
|
|
70
|
-
def
|
71
|
-
|
90
|
+
def with_all_fixtures
|
91
|
+
[
|
92
|
+
EncodableObjectSaltLambda,
|
93
|
+
EncodableObjectSaltString,
|
94
|
+
EncodableObjectSaltSymbol,
|
95
|
+
EncodableObjectSecretLambda,
|
96
|
+
EncodableObjectSecretString,
|
97
|
+
EncodableObjectSecretSymbol
|
98
|
+
].each do |klass|
|
99
|
+
yield klass
|
100
|
+
end
|
72
101
|
end
|
73
102
|
|
74
103
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
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.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jordan Sitkin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-10-
|
11
|
+
date: 2013-10-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: base64url
|