encookie 0.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 84167f668043958eead4609ed8af9aac231f59bb
4
+ data.tar.gz: d93981c2c83e486aff8f7b8b0f291a9e533e1348
5
+ SHA512:
6
+ metadata.gz: 1487a5f3d2dd9a31201ef7c6a6ec31e5dd4f0e28b34f0233d7917e11239f90fd3ab91432ad80d4160b6eb86a29a1b1f41e0feecf91f74d9dbc23a9a3dc345715
7
+ data.tar.gz: d90f0bc9724a1ad6fa90763654225b063c26ed10a741838085689a1f83f7f49d4cfebacc7d7a5e64e68b0b268ce781f17f1473b60dee11b9b58a37cfc91d0bda
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ .idea
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.0
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in encookie.gemspec
4
+ gemspec
@@ -0,0 +1,28 @@
1
+ # Encookie
2
+
3
+ `encookie` is a Ruby gem that provides a Rack session middleware implementation.
4
+ This implementation stores all data in the HTTP cookies - like `Rack::Session::Cookie`,
5
+ but also encrypts the contents of the cookies so it cannot be read by the user.
6
+
7
+ Encryption **and** authentication is provided by OpenSSL's `aes-128-gcm` cipher.
8
+ This means that there is no need for a separate MAC step or a second key.
9
+
10
+ ## Usage
11
+
12
+ ```ruby
13
+ # Gemfile
14
+ gem 'encookie'
15
+
16
+ # config.ru
17
+ require 'encookie'
18
+ key = ['7881e46e1e40484756485019038703c2'].pack 'H*'
19
+ use Rack::Session::Encookie, key: key
20
+
21
+ # app.rb
22
+ get '/' do
23
+ session[:yourdata] = 'super secret persistent data'
24
+ end
25
+ ````
26
+
27
+ Bug reports and pull requests are welcome on GitHub at https://github.com/glassechidna/encookie.
28
+
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'encookie'
5
+ spec.version = '0.0.1'
6
+ spec.authors = ['Aidan Steele']
7
+ spec.email = ['aidan.steele@glassechidna.com.au']
8
+
9
+ spec.summary = %q{Write a short summary, because Rubygems requires one.}
10
+ # spec.homepage = 'TODO: Put your gem's website or public repo URL here.'
11
+
12
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
13
+ spec.bindir = 'exe'
14
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
15
+ spec.require_paths = ['lib']
16
+
17
+ spec.add_development_dependency 'bundler', '~> 1.10'
18
+ spec.add_development_dependency 'rake', '~> 10.0'
19
+
20
+ spec.add_dependency 'rack'
21
+ spec.add_dependency 'multi_json'
22
+ end
@@ -0,0 +1,7 @@
1
+ require 'rack'
2
+ require 'openssl'
3
+ require 'multi_json'
4
+ require 'base64'
5
+
6
+ require 'encookie/cryptor'
7
+ require 'encookie/cookie'
@@ -0,0 +1,66 @@
1
+ module Rack
2
+ module Session
3
+ class Encookie
4
+ def initialize(app, options={})
5
+ @app = app
6
+ @name = options[:name] || 'rack.session'
7
+ @key = options[:key]
8
+ @default_options = { domain: nil, path: '/'}.merge(options)
9
+ fail 'A secret is required' unless @key
10
+ end
11
+
12
+ def call(env)
13
+ load_session env
14
+ status, headers, body = @app.call env
15
+ commit_session env, status, headers, body
16
+ end
17
+
18
+ def load_session(env)
19
+ request = Rack::Request.new env
20
+ env['rack.session.options'] = @default_options.dup
21
+
22
+ cookieval = request.cookies[@name]
23
+ enc = cookieval_to_encrypted cookieval
24
+ json = ::Encookie::Cryptor.decrypt ciphertext: enc.ciphertext, key: @key, iv: enc.iv, auth_tag: enc.auth_tag
25
+ session_data = MultiJson.load json, symbolize_keys: true
26
+
27
+ env['rack.session'] = session_data
28
+ rescue
29
+ env['rack.session'] = Hash.new
30
+ end
31
+
32
+ def commit_session(env, status, headers, body)
33
+ options = env['rack.session.options']
34
+
35
+ session_data = env['rack.session']
36
+ json = MultiJson.dump session_data
37
+ enc = ::Encookie::Cryptor.encrypt plaintext: json, key: @key
38
+ cookieval = encrypted_to_cookieval enc
39
+
40
+ if session_data.size > (4096 - @name.size)
41
+ env['rack.errors'].puts 'Warning! Rack::Session::Cookie data size exceeds 4K. Content dropped.'
42
+ else
43
+ cookie = Hash.new
44
+ cookie[:value] = cookieval
45
+ cookie[:expires] = Time.now + options[:expire_after] unless options[:expire_after].nil?
46
+ Utils.set_cookie_header! headers, @name, cookie.merge(options)
47
+ end
48
+
49
+ [status, headers, body]
50
+ end
51
+
52
+ def encrypted_to_cookieval(encrypted)
53
+ combined = encrypted.iv + encrypted.auth_tag + encrypted.ciphertext
54
+ Base64.urlsafe_encode64 combined
55
+ end
56
+
57
+ def cookieval_to_encrypted(cookieval)
58
+ combined = Base64.urlsafe_decode64 cookieval
59
+ iv = combined[0..11]
60
+ auth_tag = combined[12..27]
61
+ ciphertext = combined[28..-1]
62
+ ::Encookie::Cryptor::Encrypted.new ciphertext, iv, auth_tag
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,26 @@
1
+ module Encookie
2
+ class Cryptor
3
+ Encrypted = Struct.new(:ciphertext, :iv, :auth_tag)
4
+
5
+ def self.encrypt(plaintext:, key:)
6
+ cipher = OpenSSL::Cipher.new 'aes-128-gcm'
7
+ cipher.encrypt
8
+ cipher.key = key
9
+ iv = cipher.random_iv
10
+ cipher.auth_data = ''
11
+ ciphertext = cipher.update(plaintext) + cipher.final
12
+ auth_tag = cipher.auth_tag
13
+ Encrypted.new(ciphertext, iv, auth_tag)
14
+ end
15
+
16
+ def self.decrypt(ciphertext:, key:, iv:, auth_tag:)
17
+ cipher = OpenSSL::Cipher.new 'aes-128-gcm'
18
+ cipher.decrypt
19
+ cipher.key = key
20
+ cipher.iv = iv
21
+ cipher.auth_tag = auth_tag
22
+ cipher.auth_data = ''
23
+ cipher.update(ciphertext) + cipher.final
24
+ end
25
+ end
26
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: encookie
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Aidan Steele
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-06-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rack
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
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: multi_json
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description:
70
+ email:
71
+ - aidan.steele@glassechidna.com.au
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".travis.yml"
78
+ - Gemfile
79
+ - README.md
80
+ - Rakefile
81
+ - encookie.gemspec
82
+ - lib/encookie.rb
83
+ - lib/encookie/cookie.rb
84
+ - lib/encookie/cryptor.rb
85
+ homepage:
86
+ licenses: []
87
+ metadata: {}
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 2.4.5.1
105
+ signing_key:
106
+ specification_version: 4
107
+ summary: Write a short summary, because Rubygems requires one.
108
+ test_files: []