1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
# -*- coding: UTF-8 -*-
require 'securerandom'
module Zorglub
class Node
@sessions = {}
class << self
attr_reader :sessions
end
def session
@session ||= SessionHash.new @request, @response, Node.sessions, app.opt(:session_options)
end
end
class SessionHash < Hash
def initialize req, resp, sessions, options
@request = req
@response = resp
@sessions = sessions
@sid = nil
@options = options
super()
end
def [] key
load_data!
super key
end
def has_key? key
load_data!
super key
end
alias :key? :has_key?
alias :include? :has_key?
def []= key, value
load_data!
super key, value
end
def clear
load_data!
# @response.delete_cookie @options[:key]
# @sessions.delete @sid
# @sid = nil
super
end
def to_hash
load_data!
h = {}.replace(self)
h.delete_if { |k,v| v.nil? }
h
end
def update hash
load_data!
super stringify_keys(hash)
end
def delete key
load_data!
super key
end
def inspect
if loaded?
super
else
"#<#{self.class}:0x#{self.object_id.to_s(16)} not yet loaded>"
end
end
def exists?
( loaded? ? @sessions.has_key?(@sid) : false )
end
def loaded?
not @sid.nil?
end
def empty?
load_data!
super
end
private
def load_data!
return if loaded?
if @options[:enabled]
sid = @request.cookies[@options[:key]]
if sid.nil?
sid = generate_sid!
@response.set_cookie @options[:key], sid
end
replace @sessions[sid] ||={}
@sessions[sid] = self
@sid = sid
end
end
def stringify_keys other
hash = {}
other.each do |key, value|
hash[key] = value
end
hash
end
def generate_sid!
begin sid = sid_algorithm end while @sessions.has_key? sid
sid
end
begin
require 'securerandom'
# Using SecureRandom, optional length.
# SecureRandom is available since Ruby 1.8.7.
# For Ruby versions earlier than that, you can require the uuidtools gem,
# which has a drop-in replacement for SecureRandom.
def sid_algorithm; SecureRandom.hex(@options[:sid_len]); end
rescue LoadError
require 'openssl'
# Using OpenSSL::Random for generation, this is comparable in performance
# with stdlib SecureRandom and also allows for optional length, it should
# have the same behaviour as the SecureRandom::hex method of the
# uuidtools gem.
def sid_algorithm
OpenSSL::Random.random_bytes(@options[:sid_len] / 2).unpack('H*')[0]
end
rescue LoadError
# Digest::SHA2::hexdigest produces a string of length 64, although
# collisions are not very likely, the entropy is still very low and
# length is not optional.
#
# Replacing it with OS-provided random data would take a lot of code and
# won't be as cross-platform as Ruby.
def sid_algorithm
entropy = [ srand, rand, Time.now.to_f, rand, $$, rand, object_id ]
Digest::SHA2.hexdigest(entropy.join)
end
end
end
end
|