fernet 2.1.1 → 2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -23,6 +23,13 @@ module Fernet
23
23
  #
24
24
  # Returns the fernet token as a string
25
25
  def self.generate(secret, message = '', opts = {})
26
+ # OpenSSL::Cipher loses all encoding informaion upon decoding ciphertext
27
+ # and everything comes out as ASCII. To prevent that, let's just explicitly
28
+ # convert input value to UTF-8 so we can assume the decrypted value will
29
+ # also be unicode. This is not exactly a wonderful solution, but it's
30
+ # better than just returning ASCII with mangled unicode bytes in it.
31
+ message = message.encode(Encoding::UTF_8) if message
32
+
26
33
  Generator.new(opts.merge({secret: secret, message: message})).
27
34
  generate
28
35
  end
@@ -35,7 +35,7 @@ module Fernet
35
35
 
36
36
  # Public: Returns the token's message
37
37
  def message
38
- @token.message
38
+ @token.message.dup.force_encoding(Encoding::UTF_8)
39
39
  end
40
40
 
41
41
  # Deprecated: returns the token's message
@@ -1,3 +1,3 @@
1
1
  module Fernet
2
- VERSION = "2.1.1"
2
+ VERSION = "2.2"
3
3
  end
metadata CHANGED
@@ -1,18 +1,20 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fernet
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: '2.2'
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Harold Giménez
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2015-04-09 00:00:00.000000000 Z
12
+ date: 2015-12-17 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: valcro
15
16
  requirement: !ruby/object:Gem::Requirement
17
+ none: false
16
18
  requirements:
17
19
  - - '='
18
20
  - !ruby/object:Gem::Version
@@ -20,6 +22,7 @@ dependencies:
20
22
  type: :runtime
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
23
26
  requirements:
24
27
  - - '='
25
28
  - !ruby/object:Gem::Version
@@ -27,17 +30,35 @@ dependencies:
27
30
  - !ruby/object:Gem::Dependency
28
31
  name: rspec
29
32
  requirement: !ruby/object:Gem::Requirement
33
+ none: false
30
34
  requirements:
31
- - - ">="
35
+ - - ~>
32
36
  - !ruby/object:Gem::Version
33
- version: '0'
37
+ version: '3.4'
34
38
  type: :development
35
39
  prerelease: false
36
40
  version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
37
42
  requirements:
38
- - - ">="
43
+ - - ~>
39
44
  - !ruby/object:Gem::Version
40
- version: '0'
45
+ version: '3.4'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '10.4'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '10.4'
41
62
  description: Delicious HMAC Digest(if) authentication and AES-128-CBC encryption
42
63
  email:
43
64
  - harold.gimenez@gmail.com
@@ -45,17 +66,8 @@ executables: []
45
66
  extensions: []
46
67
  extra_rdoc_files: []
47
68
  files:
48
- - ".gitignore"
49
- - ".gitmodules"
50
- - ".rdoc_options"
51
- - ".rspec"
52
- - ".travis.yml"
53
- - Gemfile
54
69
  - LICENSE
55
70
  - README.md
56
- - Rakefile
57
- - fernet.gemspec
58
- - lib/fernet.rb
59
71
  - lib/fernet/bit_packing.rb
60
72
  - lib/fernet/configuration.rb
61
73
  - lib/fernet/encryption.rb
@@ -65,41 +77,35 @@ files:
65
77
  - lib/fernet/token.rb
66
78
  - lib/fernet/verifier.rb
67
79
  - lib/fernet/version.rb
68
- - spec/acceptance/generate_spec.rb
69
- - spec/acceptance/verify_spec.rb
70
- - spec/bit_packing_spec.rb
71
- - spec/fernet_spec.rb
72
- - spec/secret_spec.rb
73
- - spec/spec_helper.rb
74
- - spec/token_spec.rb
75
- homepage: ''
80
+ - lib/fernet.rb
81
+ homepage: https://github.com/fernet/fernet-rb
76
82
  licenses: []
77
- metadata: {}
78
83
  post_install_message:
79
84
  rdoc_options: []
80
85
  require_paths:
81
86
  - lib
82
87
  required_ruby_version: !ruby/object:Gem::Requirement
88
+ none: false
83
89
  requirements:
84
- - - ">="
90
+ - - ! '>='
85
91
  - !ruby/object:Gem::Version
86
92
  version: '0'
93
+ segments:
94
+ - 0
95
+ hash: 4235098473398822064
87
96
  required_rubygems_version: !ruby/object:Gem::Requirement
97
+ none: false
88
98
  requirements:
89
- - - ">="
99
+ - - ! '>='
90
100
  - !ruby/object:Gem::Version
91
101
  version: '0'
102
+ segments:
103
+ - 0
104
+ hash: 4235098473398822064
92
105
  requirements: []
93
106
  rubyforge_project:
94
- rubygems_version: 2.4.5
107
+ rubygems_version: 1.8.23.2
95
108
  signing_key:
96
- specification_version: 4
109
+ specification_version: 3
97
110
  summary: Easily generate and verify AES encrypted HMAC based authentication tokens
98
- test_files:
99
- - spec/acceptance/generate_spec.rb
100
- - spec/acceptance/verify_spec.rb
101
- - spec/bit_packing_spec.rb
102
- - spec/fernet_spec.rb
103
- - spec/secret_spec.rb
104
- - spec/spec_helper.rb
105
- - spec/token_spec.rb
111
+ test_files: []
checksums.yaml DELETED
@@ -1,7 +0,0 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 8306def467a28bb3eeda6f4eb57c0dcc0b6f73a2
4
- data.tar.gz: 3f124ffeff277310fb3df669d78f4e41c26cdb4d
5
- SHA512:
6
- metadata.gz: c3954ecff3c25ff7142d950303206b6a437705537fdf3add03b66d4e8489aecbcd217c99927a6ce147ba08e3907dd6fa9ebdf91146cf353ca18d5a34230da158
7
- data.tar.gz: b8fb5061d5d37d287ec20fedf5df2cdd44dd103ae3d91df746037b51e8e8fa714670c48fd85abb6735ed0d4b7be46867eb5db7cb09ae3103061abcf253019907
data/.gitignore DELETED
@@ -1,19 +0,0 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- pkg
13
- rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
17
- tmp
18
- .rbenv-version
19
- .ruby-version
@@ -1,3 +0,0 @@
1
- [submodule "spec/fernet-spec"]
2
- path = spec/fernet-spec
3
- url = git://github.com/kr/fernet-spec.git
@@ -1,16 +0,0 @@
1
- --- !ruby/object:RDoc::Options
2
- encoding: UTF-8
3
- static_path: []
4
- rdoc_include:
5
- - .
6
- charset: UTF-8
7
- exclude:
8
- hyperlink_all: false
9
- line_numbers: false
10
- main_page:
11
- markup: tomdoc
12
- show_hash: false
13
- tab_width: 8
14
- title:
15
- visibility: :protected
16
- webcvs:
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --color
2
- --format progress
@@ -1,8 +0,0 @@
1
- language: ruby
2
-
3
- rvm:
4
- - "1.9.3"
5
- - "1.9.2"
6
- - "2.0.0"
7
-
8
- script: bundle exec rspec -b spec
data/Gemfile DELETED
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- # Specify your gem's dependencies in fernet.gemspec
4
- gemspec
data/Rakefile DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env rake
2
- require "bundler/gem_tasks"
@@ -1,20 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- require File.expand_path('../lib/fernet/version', __FILE__)
3
-
4
- Gem::Specification.new do |gem|
5
- gem.authors = ["Harold Giménez"]
6
- gem.email = ["harold.gimenez@gmail.com"]
7
- gem.description = %q{Delicious HMAC Digest(if) authentication and AES-128-CBC encryption}
8
- gem.summary = %q{Easily generate and verify AES encrypted HMAC based authentication tokens}
9
- gem.homepage = ""
10
-
11
- gem.files = `git ls-files`.split($\)
12
- gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
- gem.name = "fernet"
15
- gem.require_paths = ["lib"]
16
- gem.version = Fernet::VERSION
17
-
18
- gem.add_runtime_dependency "valcro", "0.1"
19
- gem.add_development_dependency "rspec"
20
- end
@@ -1,27 +0,0 @@
1
- require 'spec_helper'
2
- require 'fernet'
3
- require 'json'
4
- require 'base64'
5
-
6
- describe Fernet::Generator do
7
- it 'generates tokens according to the spec' do
8
- path = File.expand_path(
9
- './../fernet-spec/generate.json', File.dirname(__FILE__)
10
- )
11
- generate_json = JSON.parse(File.read(path))
12
- generate_json.each do |test_data|
13
- message = test_data['src']
14
- iv = test_data['iv'].pack("C*")
15
- secret = test_data['secret']
16
- now = DateTime.parse(test_data['now']).to_time
17
- expected_token = test_data['token']
18
-
19
- generator = Fernet::Generator.new(secret: secret,
20
- message: message,
21
- iv: iv,
22
- now: now)
23
-
24
- expect(generator.generate).to eq(expected_token)
25
- end
26
- end
27
- end
@@ -1,52 +0,0 @@
1
- require 'spec_helper'
2
- require 'fernet'
3
- require 'json'
4
- require 'base64'
5
-
6
- describe Fernet::Verifier do
7
- it 'verifies tokens according to the spec' do
8
- path = File.expand_path(
9
- './../fernet-spec/verify.json', File.dirname(__FILE__)
10
- )
11
- verify_json = JSON.parse(File.read(path))
12
-
13
- verify_json.each do |test_data|
14
- token = test_data['token']
15
- ttl = test_data['ttl_sec']
16
- now = DateTime.parse(test_data['now']).to_time
17
- secret = test_data['secret']
18
- message = test_data['src']
19
-
20
- verifier = Fernet::Verifier.new(token: token,
21
- secret: secret,
22
- now: now,
23
- ttl: ttl)
24
- expect(
25
- verifier.message
26
- ).to eq(message)
27
- end
28
- end
29
-
30
- context 'invalid tokens' do
31
- path = File.expand_path(
32
- './../fernet-spec/invalid.json', File.dirname(__FILE__)
33
- )
34
- invalid_json = JSON.parse(File.read(path))
35
- invalid_json.each do |test_data|
36
- it "detects #{test_data['desc']}" do
37
- token = test_data['token']
38
- ttl = test_data['ttl_sec']
39
- now = DateTime.parse(test_data['now']).to_time
40
- secret = test_data['secret']
41
-
42
- verifier = Fernet::Verifier.new(token: token,
43
- secret: secret,
44
- now: now,
45
- ttl: ttl)
46
-
47
- expect { verifier.message }.to raise_error(Fernet::Token::InvalidToken)
48
- end
49
- end
50
- end
51
-
52
- end
@@ -1,36 +0,0 @@
1
- require 'spec_helper'
2
- require 'fernet/bit_packing'
3
-
4
- describe Fernet::BitPacking do
5
- VALUE_TO_BYTES = {
6
- 0x0000000000000000 => [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
7
- 0x00000000000000FF => [ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF ],
8
- 0x000000FF00000000 => [ 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00 ],
9
- 0x00000000FF000000 => [ 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00 ],
10
- 0xFF00000000000000 => [ 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ],
11
- 0xFFFFFFFFFFFFFFFF => [ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ]
12
- }
13
-
14
- def self.pretty(bytea)
15
- "0x#{bytea.map { |b| sprintf("%.2x", b) }.join}"
16
- end
17
-
18
- def self.bytestr(bytea)
19
- bytea.map(&:chr).join
20
- end
21
-
22
- VALUE_TO_BYTES.each do |value, bytes|
23
- pretty_bytes = pretty(bytes).rjust(20)
24
- pretty_val = value.to_s.rjust(20)
25
- bytestr = bytestr(bytes)
26
- it "encodes #{pretty_val} to #{pretty_bytes}" do
27
- expect(Fernet::BitPacking.pack_int64_bigendian(value)).to eq(bytestr)
28
- end
29
-
30
- # N.B.: we have two extra spaces in the spec description for
31
- # aligned formatting w.r.t. the 'encode' specs
32
- it "decodes #{pretty_bytes} to #{pretty_val}" do
33
- expect(Fernet::BitPacking.unpack_int64_bigendian(bytestr)).to eq(value)
34
- end
35
- end
36
- end
@@ -1,75 +0,0 @@
1
- require 'spec_helper'
2
- require 'fernet'
3
-
4
- describe Fernet do
5
- after { Fernet::Configuration.run }
6
-
7
- let(:secret) { 'JrdICDH6x3M7duQeM8dJEMK4Y5TkBIsYDw1lPy35RiY=' }
8
- let(:bad_secret) { 'badICDH6x3M7duQeM8dJEMK4Y5TkBIsYDw1lPy35RiY=' }
9
-
10
- it 'can verify tokens it generates' do
11
- token = Fernet.generate(secret, 'harold@heroku.com')
12
-
13
- verifier = Fernet.verifier(secret, token)
14
- expect(verifier).to be_valid
15
- expect(verifier.message).to eq('harold@heroku.com')
16
- end
17
-
18
- it 'fails with a bad secret' do
19
- token = Fernet.generate(secret, 'harold@heroku.com')
20
-
21
- verifier = Fernet.verifier(bad_secret, token)
22
- expect(verifier.valid?).to eq(false)
23
- expect {
24
- verifier.message
25
- }.to raise_error Fernet::Token::InvalidToken
26
- end
27
-
28
- it 'fails if the token is too old' do
29
- token = Fernet.generate(secret, 'harold@heroku.com', now: (Time.now - 61))
30
-
31
- verifier = Fernet.verifier(secret, token)
32
- expect(verifier.valid?).to eq(false)
33
- end
34
-
35
- it 'can ignore TTL enforcement' do
36
- Fernet::Configuration.run do |config|
37
- config.enforce_ttl = true
38
- end
39
-
40
- token = Fernet.generate(secret, 'harold@heroku.com')
41
-
42
- verifier = Fernet.verifier(secret, token, enforce_ttl: false,
43
- now: Time.now + 9999)
44
- expect(verifier.valid?).to eq(true)
45
- end
46
-
47
- it 'can ignore TTL enforcement via global config' do
48
- Fernet::Configuration.run do |config|
49
- config.enforce_ttl = false
50
- end
51
-
52
- token = Fernet.generate(secret, 'harold@heroku.com')
53
-
54
- verifier = Fernet.verifier(secret, token, now: Time.now + 999999)
55
- expect(verifier.valid?).to eq(true)
56
- end
57
-
58
- it 'does not send the message in plain text' do
59
- token = Fernet.generate(secret, 'password1')
60
-
61
- expect(Base64.urlsafe_decode64(token)).not_to match /password1/
62
- end
63
-
64
- it 'allows overriding enforce_ttl on a verifier' do
65
- Fernet::Configuration.run do |config|
66
- config.enforce_ttl = true
67
- config.ttl = 0
68
- end
69
- token = Fernet.generate(secret, 'password1')
70
- verifier = Fernet.verifier(secret, token, now: Time.now + 999999)
71
- verifier.enforce_ttl = false
72
- expect(verifier.valid?).to eq(true)
73
- expect(verifier.message).to eq('password1')
74
- end
75
- end
@@ -1,35 +0,0 @@
1
- require 'spec_helper'
2
- require 'fernet/secret'
3
-
4
- describe Fernet::Secret do
5
- it "can resolve a URL safe base64 encoded 32 byte string" do
6
- resolves_input(Base64.urlsafe_encode64("A"*16 + "B"*16))
7
- end
8
-
9
- it "can resolve a base64 encoded 32 byte string" do
10
- resolves_input(Base64.encode64("A"*16 + "B"*16))
11
- end
12
-
13
- it "can resolve a 32 byte string without encoding" do
14
- resolves_input("A"*16 + "B"*16)
15
- end
16
-
17
- it "fails loudly when an invalid secret is provided" do
18
- secret = Base64.urlsafe_encode64("bad")
19
- expect do
20
- Fernet::Secret.new(secret)
21
- end.to raise_error(Fernet::Secret::InvalidSecret)
22
- end
23
-
24
- def resolves_input(input)
25
- secret = Fernet::Secret.new(input)
26
-
27
- expect(
28
- secret.signing_key
29
- ).to eq("A"*16)
30
-
31
- expect(
32
- secret.encryption_key
33
- ).to eq("B"*16)
34
- end
35
- end
@@ -1,20 +0,0 @@
1
- # This file was generated by the `rspec --init` command. Conventionally, all
2
- # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
- # Require this file using `require "spec_helper"` to ensure that it is only
4
- # loaded once.
5
- #
6
- # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
- RSpec.configure do |config|
8
- config.run_all_when_everything_filtered = true
9
- config.filter_run :focus
10
-
11
- # Run specs in random order to surface order dependencies. If you find an
12
- # order dependency and want to debug it, you can fix the order by providing
13
- # the seed, which is printed after each run.
14
- # --seed 1234
15
- config.order = 'random'
16
-
17
- config.expect_with :rspec do |c|
18
- c.syntax = :expect
19
- end
20
- end
@@ -1,106 +0,0 @@
1
- require 'spec_helper'
2
- require 'fernet'
3
- require 'json'
4
-
5
- describe Fernet::Token, 'validation' do
6
- let(:secret) { 'odN/0Yu+Pwp3oIvvG8OiE5w4LsLrqfWYRb3knQtSyKI=' }
7
- it 'is invalid with a bad MAC signature' do
8
- generated = Fernet::Token.generate(secret: secret,
9
- message: 'hello')
10
-
11
- bogus_hmac = "1" * 32
12
- allow(Fernet::Encryption).to receive(:hmac_digest).and_return(bogus_hmac)
13
-
14
- token = Fernet::Token.new(generated.to_s, secret: secret)
15
-
16
- expect(token.valid?).to eq(false)
17
- expect(token.errors[:signature]).to include("does not match")
18
- end
19
-
20
- it 'is invalid if too old' do
21
- generated = Fernet::Token.generate(secret: secret,
22
- message: 'hello',
23
- now: Time.now - 61)
24
- token = Fernet::Token.new(generated.to_s, enforce_ttl: true,
25
- ttl: 60,
26
- secret: secret)
27
- expect(token.valid?).to eq(false)
28
- expect(token.errors[:issued_timestamp]).to include("is too far in the past: token expired")
29
- end
30
-
31
- it 'is invalid with a large clock skew' do
32
- generated = Fernet::Token.generate(secret: secret,
33
- message: 'hello',
34
- now: Time.at(Time.now.to_i + 61))
35
- token = Fernet::Token.new(generated.to_s, secret: secret)
36
-
37
- expect(token.valid?).to eq(false)
38
- expect(token.errors[:issued_timestamp]).to include("is too far in the future")
39
- end
40
-
41
- it 'is invalid with bad base64' do
42
- token = Fernet::Token.new('bad', secret: secret)
43
-
44
- expect(token.valid?).to eq(false)
45
- expect(token.errors[:token]).to include("invalid base64")
46
- end
47
-
48
- it 'is invalid with an unknown token version' do
49
- invalid1 = Fernet::Token.generate(message: 'message', version: 0x00, secret: secret)
50
- invalid2 = Fernet::Token.generate(message: 'message', version: 0x81, secret: secret)
51
- valid = Fernet::Token.generate(message: 'message', secret: secret)
52
-
53
- [invalid1, invalid2].each do |token|
54
- expect(token.valid?).to eq(false)
55
- expect(token.errors[:version]).to include("is unknown")
56
- end
57
- expect(valid.valid?).to eq(true)
58
- end
59
-
60
- it 'is invalid with bad base64 encodings' do
61
- token = Fernet::Token.generate(message: 'message', secret: secret)
62
- invalid = Fernet::Token.new("\n#{token}", secret: secret)
63
-
64
- ["\n#{token}", "#{token} ", "#{token}+",
65
- token.to_s.gsub(/(.)$/, "1"),
66
- token.to_s.gsub(/(.)$/, "+"),
67
- token.to_s.gsub(/(.)$/, "\\"),
68
- ].each do |invalid_string|
69
- invalid = Fernet::Token.new(invalid_string, secret: secret)
70
- expect(invalid.valid?).to be(false)
71
- end
72
- end
73
- end
74
-
75
- describe Fernet::Token, 'message' do
76
- let(:secret) { 'odN/0Yu+Pwp3oIvvG8OiE5w4LsLrqfWYRb3knQtSyKI=' }
77
- it 'refuses to decrypt if invalid' do
78
- generated = Fernet::Token.generate(secret: secret,
79
- message: 'hello',
80
- now: Time.now + 61)
81
- token = Fernet::Token.new(generated.to_s, secret: secret)
82
-
83
- !token.valid? or raise "invalid token"
84
-
85
- expect {
86
- token.message
87
- }.to raise_error Fernet::Token::InvalidToken,
88
- /issued_timestamp is too far in the future/
89
- end
90
-
91
- it 'gives back the original message in plain text' do
92
- token = Fernet::Token.generate(secret: secret,
93
- message: 'hello')
94
- token.valid? or raise "invalid token"
95
-
96
- expect(token.message).to eq('hello')
97
- end
98
-
99
- it 'correctly handles an empty message' do
100
- token = Fernet::Token.generate(secret: secret,
101
- message: '')
102
- token.valid? or raise "invalid token"
103
-
104
- expect(token.message).to eq('')
105
- end
106
- end