encrypted_cookie 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
Binary file
data/Manifest CHANGED
@@ -1,4 +1,7 @@
1
+ Manifest
2
+ README.markdown
1
3
  Rakefile
2
- encrypted_cookie_spec.rb
4
+ encrypted_cookie.gemspec
3
5
  lib/encrypted_cookie.rb
4
- Manifest
6
+ spec/encrypted_cookie_spec.rb
7
+ test/demo.rb
File without changes
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
  require 'rake'
3
3
  require 'echoe'
4
4
 
5
- Echoe.new('encrypted_cookie', '0.0.1') do |p|
5
+ Echoe.new('encrypted_cookie', '0.0.2') do |p|
6
6
  p.description = "Encrypted session cookies for Rack"
7
7
  p.url = "http://github.com/cvonkleist/encrypted_cookie"
8
8
  p.author = "Christian von Kleist"
@@ -2,18 +2,18 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{encrypted_cookie}
5
- s.version = "0.0.1"
5
+ s.version = "0.0.2"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Christian von Kleist"]
9
9
  s.cert_chain = ["/home/cvk/.gemcert/gem-public_cert.pem"]
10
- s.date = %q{2011-03-01}
10
+ s.date = %q{2011-03-02}
11
11
  s.description = %q{Encrypted session cookies for Rack}
12
12
  s.email = %q{cvonkleist at-a-place-called gmail.com}
13
- s.extra_rdoc_files = ["lib/encrypted_cookie.rb"]
14
- s.files = ["Rakefile", "encrypted_cookie_spec.rb", "lib/encrypted_cookie.rb", "Manifest", "encrypted_cookie.gemspec"]
13
+ s.extra_rdoc_files = ["README.markdown", "lib/encrypted_cookie.rb"]
14
+ s.files = ["Manifest", "README.markdown", "Rakefile", "encrypted_cookie.gemspec", "lib/encrypted_cookie.rb", "spec/encrypted_cookie_spec.rb", "test/demo.rb"]
15
15
  s.homepage = %q{http://github.com/cvonkleist/encrypted_cookie}
16
- s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Encrypted_cookie"]
16
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Encrypted_cookie", "--main", "README.markdown"]
17
17
  s.require_paths = ["lib"]
18
18
  s.rubyforge_project = %q{encrypted_cookie}
19
19
  s.rubygems_version = %q{1.3.7}
@@ -1,27 +1,78 @@
1
1
  require 'openssl'
2
+ require 'rack/session/cookie'
2
3
 
3
4
  module Rack
4
5
  module Session
5
- class Cookie
6
- class AES
7
- def initialize(key)
8
- @key = key
6
+ class EncryptedCookie < Cookie
7
+ def initialize(app, options={})
8
+ @app = app
9
+ @key = options[:key] || "rack.session"
10
+ @secret = options[:secret]
11
+ fail "Error! A secret is required to use encrypted cookies. Do something like this:\n\nuse Rack::Session::EncryptedCookie, :secret => YOUR_VERY_LONG_VERY_RANDOM_SECRET_KEY_HERE" unless @secret
12
+ @default_options = {:domain => nil,
13
+ :path => "/",
14
+ :expire_after => nil}.merge(options)
15
+ end
16
+
17
+ def load_session(env)
18
+ request = Rack::Request.new(env)
19
+ session_data = request.cookies[@key]
20
+
21
+ if session_data
22
+ session_data = decrypt(session_data)
23
+ session_data, digest = session_data.split("--")
24
+ session_data = nil unless digest == generate_hmac(session_data)
9
25
  end
10
26
 
11
- def encode(str)
12
- aes = OpenSSL::Cipher::Cipher.new('aes-128-cbc').encrypt
13
- salt = OpenSSL::Random.random_bytes(aes.key_len)
14
- iv = OpenSSL::Random.random_bytes(aes.iv_len)
15
- [iv + (aes.update(str) << aes.final)].pack('m0')
27
+ begin
28
+ session_data = session_data.unpack("m*").first
29
+ session_data = Marshal.load(session_data)
30
+ env["rack.session"] = session_data
31
+ rescue
32
+ env["rack.session"] = Hash.new
16
33
  end
17
34
 
18
- def decode(str)
19
- str = str.unpack('m0').first
20
- aes = OpenSSL::Cipher::Cipher.new('aes-128-cbc').decrypt
21
- iv = str[0, aes.iv_len]
22
- crypted_text = str[aes.iv_len..-1]
23
- aes.update(crypted_text) << aes.final
35
+ env["rack.session.options"] = @default_options.dup
36
+ end
37
+
38
+ def commit_session(env, status, headers, body)
39
+ session_data = Marshal.dump(env["rack.session"])
40
+ session_data = [session_data].pack("m*")
41
+
42
+ session_data = "#{session_data}--#{generate_hmac(session_data)}"
43
+
44
+ session_data = encrypt(session_data)
45
+
46
+ if session_data.size > (4096 - @key.size)
47
+ env["rack.errors"].puts("Warning! Rack::Session::Cookie data size exceeds 4K. Content dropped.")
48
+ else
49
+ options = env["rack.session.options"]
50
+ cookie = Hash.new
51
+ cookie[:value] = session_data
52
+ cookie[:expires] = Time.now + options[:expire_after] unless options[:expire_after].nil?
53
+ Utils.set_cookie_header!(headers, @key, cookie.merge(options))
24
54
  end
55
+
56
+ [status, headers, body]
57
+ end
58
+
59
+ private
60
+
61
+ def encrypt(str)
62
+ aes = OpenSSL::Cipher::Cipher.new('aes-128-cbc').encrypt
63
+ aes.key = @secret
64
+ salt = OpenSSL::Random.random_bytes(aes.key_len)
65
+ iv = OpenSSL::Random.random_bytes(aes.iv_len)
66
+ [iv + (aes.update(str) << aes.final)].pack('m0')
67
+ end
68
+
69
+ def decrypt(str)
70
+ str = str.unpack('m0').first
71
+ aes = OpenSSL::Cipher::Cipher.new('aes-128-cbc').decrypt
72
+ aes.key = @secret
73
+ iv = str[0, aes.iv_len]
74
+ crypted_text = str[aes.iv_len..-1]
75
+ aes.update(crypted_text) << aes.final
25
76
  end
26
77
  end
27
78
  end
@@ -0,0 +1,95 @@
1
+ require 'rack/test'
2
+ require 'sinatra'
3
+ require 'rspec'
4
+ require 'ruby-debug'
5
+ require 'cgi'
6
+ require File.dirname(__FILE__) + '/../lib/encrypted_cookie'
7
+
8
+ include Rack::Session
9
+
10
+ RSpec.configure do |conf|
11
+ conf.include Rack::Test::Methods
12
+ end
13
+
14
+ class EncryptedApp < Sinatra::Application
15
+ use Rack::Session::EncryptedCookie, :secret => 'foo' * 10
16
+ get '/' do
17
+ "session: " + session.inspect
18
+ end
19
+ get '/set/:key/:value' do
20
+ session[params[:key]] = params[:value]
21
+ "all set"
22
+ end
23
+ end
24
+
25
+ # this app has cookie integrity protection, but not encryption
26
+ class UnencryptedApp < Sinatra::Application
27
+ use Rack::Session::Cookie, :secret => 'foo' * 10
28
+ get '/' do
29
+ "session: " + session.inspect
30
+ end
31
+ end
32
+
33
+ describe EncryptedCookie do
34
+ it 'should fail if no secret is specified' do
35
+ lambda { EncryptedCookie.new(nil) }.should raise_error(/A secret is required/)
36
+ lambda { EncryptedCookie.new(nil, :secret => 'foo') }.should_not raise_error(/A secret is required/)
37
+ end
38
+ end
39
+
40
+ describe EncryptedApp do
41
+ def app
42
+ EncryptedApp
43
+ end
44
+ it "should not include unencrypted marshal'd data" do
45
+ get '/'
46
+ last_response.body.should == 'session: {}'
47
+ last_response.headers['Set-Cookie'].should_not include("BAh7AA")
48
+ end
49
+ it "should make decryptable session data" do
50
+ get '/set/foo/bar'
51
+ last_response.body.should == 'all set'
52
+ get '/'
53
+ last_response.body.should == 'session: {"foo"=>"bar"}'
54
+ last_response.headers['Set-Cookie'].should_not include("BAh7AA")
55
+
56
+ data = last_response.headers['Set-Cookie'][/rack.session=(.*?);/, 1]
57
+ str = CGI.unescape(data).unpack('m0').first
58
+ aes = OpenSSL::Cipher::Cipher.new('aes-128-cbc').decrypt
59
+ aes.key = 'foo' * 10
60
+ iv = str[0, aes.iv_len]
61
+ crypted_text = str[aes.iv_len..-1]
62
+
63
+ plaintext = (aes.update(crypted_text) << aes.final)
64
+ base64_marshal_data, hmac = plaintext.split('--')
65
+ session_hash = Marshal.load(base64_marshal_data.unpack('m0').first)
66
+ session_hash.should == {"foo" => "bar"}
67
+ end
68
+ it "should make encrypted session data that can't be decrypted with the wrong key" do
69
+ get '/set/foo/bar'
70
+ last_response.body.should == 'all set'
71
+ get '/'
72
+ last_response.body.should == 'session: {"foo"=>"bar"}'
73
+ last_response.headers['Set-Cookie'].should_not include("BAh7AA")
74
+
75
+ data = last_response.headers['Set-Cookie'][/rack.session=(.*?);/, 1]
76
+ str = CGI.unescape(data).unpack('m0').first
77
+ aes = OpenSSL::Cipher::Cipher.new('aes-128-cbc').decrypt
78
+ aes.key = 'bar' * 10
79
+ iv = str[0, aes.iv_len]
80
+ crypted_text = str[aes.iv_len..-1]
81
+
82
+ lambda { plaintext = (aes.update(crypted_text) << aes.final) }.should raise_error("bad decrypt")
83
+ end
84
+ end
85
+
86
+ describe UnencryptedApp do
87
+ def app
88
+ UnencryptedApp
89
+ end
90
+ it "should include unencrypted marshal'd data" do
91
+ get '/'
92
+ last_response.body.should == 'session: {}'
93
+ last_response.headers['Set-Cookie'].should include("BAh7AA")
94
+ end
95
+ end
@@ -0,0 +1,15 @@
1
+ require 'sinatra'
2
+ require '../lib/encrypted_cookie'
3
+
4
+ use Rack::Session::EncryptedCookie,
5
+ :key => 'rack.session',
6
+ :secret => 'ASDFASDFASDJFsakdfji2j3oij2o3ij4l12kj3'
7
+
8
+ get '/' do
9
+ "session = " + session.inspect
10
+ end
11
+
12
+ get '/set/:data' do
13
+ session[:data] = params[:data]
14
+ redirect '/'
15
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: encrypted_cookie
3
3
  version: !ruby/object:Gem::Version
4
- hash: 29
4
+ hash: 27
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 1
10
- version: 0.0.1
9
+ - 2
10
+ version: 0.0.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Christian von Kleist
@@ -36,7 +36,7 @@ cert_chain:
36
36
  DnOM3kD7rptG2g==
37
37
  -----END CERTIFICATE-----
38
38
 
39
- date: 2011-03-01 00:00:00 -05:00
39
+ date: 2011-03-02 00:00:00 -05:00
40
40
  default_executable:
41
41
  dependencies: []
42
42
 
@@ -47,13 +47,16 @@ executables: []
47
47
  extensions: []
48
48
 
49
49
  extra_rdoc_files:
50
+ - README.markdown
50
51
  - lib/encrypted_cookie.rb
51
52
  files:
52
- - Rakefile
53
- - encrypted_cookie_spec.rb
54
- - lib/encrypted_cookie.rb
55
53
  - Manifest
54
+ - README.markdown
55
+ - Rakefile
56
56
  - encrypted_cookie.gemspec
57
+ - lib/encrypted_cookie.rb
58
+ - spec/encrypted_cookie_spec.rb
59
+ - test/demo.rb
57
60
  has_rdoc: true
58
61
  homepage: http://github.com/cvonkleist/encrypted_cookie
59
62
  licenses: []
@@ -64,6 +67,8 @@ rdoc_options:
64
67
  - --inline-source
65
68
  - --title
66
69
  - Encrypted_cookie
70
+ - --main
71
+ - README.markdown
67
72
  require_paths:
68
73
  - lib
69
74
  required_ruby_version: !ruby/object:Gem::Requirement
metadata.gz.sig CHANGED
Binary file
@@ -1,11 +0,0 @@
1
- require 'encrypted_cookie'
2
-
3
- include Rack::Session
4
-
5
- describe Cookie::AES do
6
- it 'should pass the encryption test' do
7
- a = Cookie::AES.new('foo')
8
- enc = a.encode("bar")
9
- a.decode(enc).should == 'bar'
10
- end
11
- end