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
         |