fernet 1.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.
- data/fernet.gemspec +4 -2
- data/lib/fernet.rb +4 -0
- data/lib/fernet/generator.rb +4 -4
- data/lib/fernet/secret.rb +2 -2
- data/lib/fernet/verifier.rb +21 -8
- data/lib/fernet/version.rb +1 -1
- data/lib/shim/base64.rb +21 -0
- data/spec/fernet_spec.rb +18 -5
- metadata +67 -32
data/fernet.gemspec
CHANGED
@@ -4,8 +4,8 @@ require File.expand_path('../lib/fernet/version', __FILE__)
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["Harold Giménez"]
|
6
6
|
gem.email = ["harold.gimenez@gmail.com"]
|
7
|
-
gem.description = %q{Delicious HMAC Digest(if) authentication}
|
8
|
-
gem.summary = %q{Easily generate and verify HMAC based authentication tokens}
|
7
|
+
gem.description = %q{Delicious HMAC Digest(if) authentication and encryption}
|
8
|
+
gem.summary = %q{Easily generate and verify AES encrypted HMAC based authentication tokens}
|
9
9
|
gem.homepage = ""
|
10
10
|
|
11
11
|
gem.files = `git ls-files`.split($\)
|
@@ -15,5 +15,7 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.require_paths = ["lib"]
|
16
16
|
gem.version = Fernet::VERSION
|
17
17
|
|
18
|
+
gem.add_dependency "yajl-ruby"
|
19
|
+
|
18
20
|
gem.add_development_dependency "rspec"
|
19
21
|
end
|
data/lib/fernet.rb
CHANGED
@@ -3,6 +3,10 @@ require 'fernet/generator'
|
|
3
3
|
require 'fernet/verifier'
|
4
4
|
require 'fernet/secret'
|
5
5
|
|
6
|
+
if RUBY_VERSION == '1.8.7'
|
7
|
+
require 'shim/base64'
|
8
|
+
end
|
9
|
+
|
6
10
|
module Fernet
|
7
11
|
def self.generate(secret, encrypt = true, &block)
|
8
12
|
Generator.new(secret, encrypt).generate(&block)
|
data/lib/fernet/generator.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'base64'
|
2
|
-
require '
|
2
|
+
require 'yajl'
|
3
3
|
require 'openssl'
|
4
4
|
require 'date'
|
5
5
|
|
@@ -16,13 +16,13 @@ module Fernet
|
|
16
16
|
|
17
17
|
def generate
|
18
18
|
yield self if block_given?
|
19
|
-
data.merge!(issued_at
|
19
|
+
data.merge!(:issued_at => DateTime.now)
|
20
20
|
|
21
21
|
if encrypt?
|
22
22
|
iv = encrypt_data!
|
23
23
|
@payload = "#{base64(data)}|#{base64(iv)}"
|
24
24
|
else
|
25
|
-
@payload = base64(
|
25
|
+
@payload = base64(Yajl::Encoder.encode(data))
|
26
26
|
end
|
27
27
|
|
28
28
|
mac = OpenSSL::HMAC.hexdigest('sha256', payload, signing_key)
|
@@ -47,7 +47,7 @@ module Fernet
|
|
47
47
|
iv = cipher.random_iv
|
48
48
|
cipher.iv = iv
|
49
49
|
cipher.key = encryption_key
|
50
|
-
@data = cipher.update(
|
50
|
+
@data = cipher.update(Yajl::Encoder.encode(data)) + cipher.final
|
51
51
|
iv
|
52
52
|
end
|
53
53
|
|
data/lib/fernet/secret.rb
CHANGED
@@ -6,12 +6,12 @@ module Fernet
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def encryption_key
|
9
|
-
@secret.
|
9
|
+
@secret.slice(@secret.size/2, @secret.size)
|
10
10
|
end
|
11
11
|
|
12
12
|
def signing_key
|
13
13
|
if @encrypt
|
14
|
-
@secret.
|
14
|
+
@secret.slice(0, @secret.size/2)
|
15
15
|
else
|
16
16
|
@secret
|
17
17
|
end
|
data/lib/fernet/verifier.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
require 'base64'
|
2
|
-
require '
|
2
|
+
require 'yajl'
|
3
3
|
require 'openssl'
|
4
4
|
require 'date'
|
5
5
|
|
6
6
|
module Fernet
|
7
7
|
class Verifier
|
8
8
|
attr_reader :token, :data
|
9
|
-
|
9
|
+
attr_accessor :ttl, :enforce_ttl
|
10
10
|
|
11
11
|
def initialize(secret, decrypt)
|
12
|
-
@secret
|
13
|
-
@decrypt
|
12
|
+
@secret = Secret.new(secret, decrypt)
|
13
|
+
@decrypt = decrypt
|
14
|
+
@ttl = 60
|
15
|
+
@enforce_ttl = true
|
14
16
|
end
|
15
17
|
|
16
18
|
def verify_token(token)
|
@@ -27,7 +29,7 @@ module Fernet
|
|
27
29
|
end
|
28
30
|
|
29
31
|
def inspect
|
30
|
-
"#<Fernet::Verifier @secret=[masked] @token=#{@token} @data=#{@data.inspect} @
|
32
|
+
"#<Fernet::Verifier @secret=[masked] @token=#{@token} @data=#{@data.inspect} @ttl=#{@ttl}>"
|
31
33
|
end
|
32
34
|
alias to_s inspect
|
33
35
|
|
@@ -38,18 +40,22 @@ module Fernet
|
|
38
40
|
parts = @token.split('|')
|
39
41
|
if decrypt?
|
40
42
|
encrypted_data, iv, @received_signature = *parts
|
41
|
-
@data =
|
43
|
+
@data = Yajl::Parser.parse(decrypt!(encrypted_data, Base64.urlsafe_decode64(iv)))
|
42
44
|
signing_blob = "#{encrypted_data}|#{iv}"
|
43
45
|
else
|
44
46
|
encoded_data, @received_signature = *parts
|
45
47
|
signing_blob = encoded_data
|
46
|
-
@data =
|
48
|
+
@data = Yajl::Parser.parse(Base64.urlsafe_decode64(encoded_data))
|
47
49
|
end
|
48
50
|
@regenerated_mac = OpenSSL::HMAC.hexdigest('sha256', signing_blob, signing_key)
|
49
51
|
end
|
50
52
|
|
51
53
|
def token_recent_enough?
|
52
|
-
|
54
|
+
if enforce_ttl?
|
55
|
+
DateTime.parse(data['issued_at']) > (now - ttl)
|
56
|
+
else
|
57
|
+
true
|
58
|
+
end
|
53
59
|
end
|
54
60
|
|
55
61
|
def signatures_match?
|
@@ -80,5 +86,12 @@ module Fernet
|
|
80
86
|
@decrypt
|
81
87
|
end
|
82
88
|
|
89
|
+
def enforce_ttl?
|
90
|
+
@enforce_ttl
|
91
|
+
end
|
92
|
+
|
93
|
+
def now
|
94
|
+
DateTime.now
|
95
|
+
end
|
83
96
|
end
|
84
97
|
end
|
data/lib/fernet/version.rb
CHANGED
data/lib/shim/base64.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Base64.class_eval do
|
2
|
+
def strict_encode64(bin)
|
3
|
+
encode64(bin).tr("\n",'')
|
4
|
+
end
|
5
|
+
|
6
|
+
def strict_decode64(str)
|
7
|
+
unless str.include?("\n")
|
8
|
+
decode64(str)
|
9
|
+
else
|
10
|
+
raise(ArgumentError,"invalid base64")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def urlsafe_encode64(bin)
|
15
|
+
strict_encode64(bin).tr("+/", "-_")
|
16
|
+
end
|
17
|
+
|
18
|
+
def urlsafe_decode64(str)
|
19
|
+
strict_decode64(str.tr("-_", "+/"))
|
20
|
+
end
|
21
|
+
end
|
data/spec/fernet_spec.rb
CHANGED
@@ -3,11 +3,11 @@ require 'fernet'
|
|
3
3
|
|
4
4
|
describe Fernet do
|
5
5
|
let(:token_data) do
|
6
|
-
{ email
|
6
|
+
{ :email => 'harold@heroku.com', :id => '123', :arbitrary => 'data' }
|
7
7
|
end
|
8
8
|
|
9
|
-
let(:secret)
|
10
|
-
let(:bad_secret) { '
|
9
|
+
let(:secret) { 'JrdICDH6x3M7duQeM8dJEMK4Y5TkBIsYDw1lPy35RiY=' }
|
10
|
+
let(:bad_secret) { 'badICDH6x3M7duQeM8dJEMK4Y5TkBIsYDw1lPy35RiY=' }
|
11
11
|
|
12
12
|
it 'can verify tokens it generates' do
|
13
13
|
token = Fernet.generate(secret) do |generator|
|
@@ -45,7 +45,7 @@ describe Fernet do
|
|
45
45
|
end
|
46
46
|
|
47
47
|
Fernet.verify(bad_secret, token) do |verifier|
|
48
|
-
verifier.
|
48
|
+
verifier.ttl = 0
|
49
49
|
end.should be_false
|
50
50
|
end
|
51
51
|
|
@@ -57,6 +57,20 @@ describe Fernet do
|
|
57
57
|
Fernet.verify(secret, token).should be_true
|
58
58
|
end
|
59
59
|
|
60
|
+
it 'can TTL enforcement' do
|
61
|
+
token = Fernet.generate(secret) do |generator|
|
62
|
+
generator.data = token_data
|
63
|
+
end
|
64
|
+
|
65
|
+
Fernet.verify(secret, token) do |verifier|
|
66
|
+
def verifier.now
|
67
|
+
Time.now + 99999999999
|
68
|
+
end
|
69
|
+
verifier.enforce_ttl = false
|
70
|
+
true
|
71
|
+
end.should be_true
|
72
|
+
end
|
73
|
+
|
60
74
|
it 'generates without custom data' do
|
61
75
|
token = Fernet.generate(secret)
|
62
76
|
|
@@ -88,5 +102,4 @@ describe Fernet do
|
|
88
102
|
verifier.data['password'].should == 'password1'
|
89
103
|
end
|
90
104
|
end
|
91
|
-
|
92
105
|
end
|
metadata
CHANGED
@@ -1,34 +1,59 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: fernet
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 13
|
5
5
|
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 1
|
9
|
+
version: "1.1"
|
6
10
|
platform: ruby
|
7
|
-
authors:
|
8
|
-
- Harold
|
11
|
+
authors:
|
12
|
+
- "Harold Gim\xC3\xA9nez"
|
9
13
|
autorequire:
|
10
14
|
bindir: bin
|
11
15
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
16
|
+
|
17
|
+
date: 2012-08-15 00:00:00 Z
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
20
|
+
name: yajl-ruby
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
hash: 3
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
15
34
|
name: rspec
|
16
|
-
|
35
|
+
prerelease: false
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
17
37
|
none: false
|
18
|
-
requirements:
|
19
|
-
- -
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
hash: 3
|
42
|
+
segments:
|
43
|
+
- 0
|
44
|
+
version: "0"
|
22
45
|
type: :development
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
email:
|
46
|
+
version_requirements: *id002
|
47
|
+
description: Delicious HMAC Digest(if) authentication and encryption
|
48
|
+
email:
|
27
49
|
- harold.gimenez@gmail.com
|
28
50
|
executables: []
|
51
|
+
|
29
52
|
extensions: []
|
53
|
+
|
30
54
|
extra_rdoc_files: []
|
31
|
-
|
55
|
+
|
56
|
+
files:
|
32
57
|
- .gitignore
|
33
58
|
- .rspec
|
34
59
|
- Gemfile
|
@@ -41,32 +66,42 @@ files:
|
|
41
66
|
- lib/fernet/secret.rb
|
42
67
|
- lib/fernet/verifier.rb
|
43
68
|
- lib/fernet/version.rb
|
69
|
+
- lib/shim/base64.rb
|
44
70
|
- spec/fernet_spec.rb
|
45
71
|
- spec/spec_helper.rb
|
46
|
-
homepage:
|
72
|
+
homepage: ""
|
47
73
|
licenses: []
|
74
|
+
|
48
75
|
post_install_message:
|
49
76
|
rdoc_options: []
|
50
|
-
|
77
|
+
|
78
|
+
require_paths:
|
51
79
|
- lib
|
52
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
81
|
none: false
|
54
|
-
requirements:
|
55
|
-
- -
|
56
|
-
- !ruby/object:Gem::Version
|
57
|
-
|
58
|
-
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
hash: 3
|
86
|
+
segments:
|
87
|
+
- 0
|
88
|
+
version: "0"
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
90
|
none: false
|
60
|
-
requirements:
|
61
|
-
- -
|
62
|
-
- !ruby/object:Gem::Version
|
63
|
-
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
hash: 3
|
95
|
+
segments:
|
96
|
+
- 0
|
97
|
+
version: "0"
|
64
98
|
requirements: []
|
99
|
+
|
65
100
|
rubyforge_project:
|
66
101
|
rubygems_version: 1.8.10
|
67
102
|
signing_key:
|
68
103
|
specification_version: 3
|
69
|
-
summary: Easily generate and verify HMAC based authentication tokens
|
70
|
-
test_files:
|
104
|
+
summary: Easily generate and verify AES encrypted HMAC based authentication tokens
|
105
|
+
test_files:
|
71
106
|
- spec/fernet_spec.rb
|
72
107
|
- spec/spec_helper.rb
|