rack_encrypted_cookie 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 23f35d46ff17b90a24e7af57a88ccc537c6313cc
4
+ data.tar.gz: 2f9efc7904c1716376024d167aeffd377edabb35
5
+ SHA512:
6
+ metadata.gz: 2f2eca097ad9d4cbd671ec96dda484f539cfbc2c163e3e7ae3e8e4ae1161bac7f6e3223d9ca23869989d2a81a655b248ee6c73a64be74cf52eb174d8527087f1
7
+ data.tar.gz: 5c7db236e99c36ebba040b4532d5c8f9a37130b54c2082235d900ce42306a2cdeaa5652c70fb1770790fa03e849beba31316f9fdd2662ed134241ca2b7109062
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+ require 'rack/session/cookie'
3
+ require 'openssl'
4
+ require 'base64'
5
+
6
+ module Rack
7
+ module Session
8
+ class EncryptedCookie < Cookie #:nodoc:
9
+ def initialize(app, options = {})
10
+ super
11
+ @salt = options.fetch(:salt, 'encrypted cookie')
12
+ @signed_salt = options.fetch(:signed_salt, 'signed encrypted cookie')
13
+ @iterations = options.fetch(:iterations, 1024)
14
+ @key_size = options.fetch(:key_size, 64)
15
+ @cipher = OpenSSL::Cipher::Cipher.new(options.fetch(:cipher, 'AES-256-CBC'))
16
+ @cipher_secrets = @secrets.map { |secret| generate_key(secret, @salt) }
17
+ @secrets.map! { |secret| generate_key(secret, @signed_salt) }
18
+ end
19
+
20
+ private
21
+
22
+ def unpacked_cookie_data(request)
23
+ request.fetch_header(RACK_SESSION_UNPACKED_COOKIE_DATA) do |k|
24
+ session_data = request.cookies[@key]
25
+
26
+ if !@secrets.empty? && session_data
27
+ digest, session_data = session_data.reverse.split('--', 2)
28
+ digest&.reverse!
29
+ session_data&.reverse!
30
+ session_data = nil unless digest_match?(session_data, digest)
31
+ end
32
+
33
+ if !@cipher_secrets.empty? && session_data
34
+ encrypted_data, iv = ::Base64.strict_decode64(session_data).split('--').map! { |v| ::Base64.strict_decode64(v) }
35
+
36
+ @cipher_secrets.each do |cipher_secret|
37
+ @cipher.decrypt
38
+ @cipher.key = cipher_secret
39
+ @cipher.iv = iv
40
+ begin
41
+ session_data = @cipher.update(encrypted_data) << @cipher.final
42
+ break
43
+ rescue OpenSSL::Cipher::CipherError
44
+ next
45
+ end
46
+ end
47
+ end
48
+ request.set_header(k, coder.decode(session_data) || {})
49
+ end
50
+ end
51
+
52
+ def write_session(req, session_id, session, _options)
53
+ session = session.merge('session_id' => session_id)
54
+ session_data = coder.encode(session)
55
+
56
+ if @cipher_secrets.first
57
+ @cipher.encrypt
58
+ @cipher.key = @cipher_secrets.first
59
+ iv = @cipher.random_iv
60
+ encrypted_data = @cipher.update(session_data) << @cipher.final
61
+ blob = "#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}"
62
+ session_data = ::Base64.strict_encode64(blob)
63
+ end
64
+
65
+ if @secrets.first
66
+ session_data << "--#{generate_hmac(session_data, @secrets.first)}"
67
+ end
68
+
69
+ if session_data.size > (4096 - @key.size)
70
+ req.get_header(RACK_ERRORS).puts('Warning! Rack::Session::Cookie data size exceeds 4K.')
71
+ nil
72
+ else
73
+ session_data
74
+ end
75
+ end
76
+
77
+ def generate_key(secret, salt)
78
+ OpenSSL::PKCS5.pbkdf2_hmac_sha1(secret, salt, @iterations, @key_size)
79
+ end
80
+ end
81
+ end
82
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack_encrypted_cookie
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jian Weihang
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-12-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Rack middleware for signed encrypted session cookie.
70
+ email: tonytonyjan@gmail.com
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files: []
74
+ files:
75
+ - lib/rack/session/encrypted_cookie.rb
76
+ homepage:
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 2.3.0
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.6.4
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: Rack middleware for signed encrypted session cookie.
100
+ test_files: []