-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Conflicts: lib/camping/ar/session.rb
- Loading branch information
Showing
1 changed file
with
70 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# == About camping/session.rb | ||
# | ||
# This file contains two modules which supply basic sessioning to your Camping app. | ||
# Again, we're dealing with a pretty little bit of code: approx. 60 lines. | ||
# | ||
# * Camping::Models::Session is a module which adds a single <tt>sessions</tt> table | ||
# to your database. | ||
# * Camping::Session is a module which you will mix into your application (or into | ||
# specific controllers which require sessions) to supply a <tt>@state</tt> variable | ||
# you can use in controllers and views. | ||
# | ||
# For a basic tutorial, see the *Getting Started* section of the Camping::Session module. | ||
#require 'camping' | ||
require 'base64' | ||
require 'digest/sha2' | ||
|
||
module Camping | ||
# The Camping::Session module is designed to be mixed into your application or into specific | ||
# controllers which require sessions. This module defines a <tt>service</tt> method which | ||
# intercepts all requests handed to those controllers. | ||
# | ||
# == Getting Started | ||
# | ||
# To get sessions working for your application: | ||
# | ||
# 1. <tt>require 'camping/session'</tt> | ||
# 2. Mixin the module: <tt>module YourApp; include Camping::Session end</tt> | ||
# 3. Define a secret (and keep it secret): <tt>module YourApp; @@state_secret = "SECRET!"; end</tt> | ||
# 4. Throughout your application, use the <tt>@state</tt> var like a hash to store your application's data. | ||
# | ||
# == A Few Notes | ||
# | ||
# * The session is stored in a cookie. Look in <tt>@cookies.identity</tt>. | ||
# * Session data is only saved if it has changed. | ||
module Session | ||
# This <tt>service</tt> method, when mixed into controllers, intercepts requests | ||
# and wraps them with code to start and close the session. If a session isn't found | ||
# in the cookie it is created. The <tt>@state</tt> variable is set and if it changes, | ||
# it is saved back into the cookie. | ||
def service(*a) | ||
if @cookies.identity | ||
blob, secure_hash = @cookies.identity.to_s.split(':', 2) | ||
blob = Base64.decode64(blob) | ||
data = Marshal.restore(blob) | ||
data = {} unless secure_blob_hasher(blob).strip == secure_hash.strip | ||
else | ||
blob = '' | ||
data = {} | ||
end | ||
|
||
app = self.class.name.gsub(/^(\w+)::.+$/, '\1') | ||
@state = (data[app] ||= Camping::H[]) | ||
hash_before = blob.hash | ||
return super(*a) | ||
ensure | ||
data[app] = @state | ||
blob = Marshal.dump(data) | ||
unless hash_before == blob.hash | ||
secure_hash = secure_blob_hasher(blob) | ||
content = Base64.encode64(blob).gsub("\n", '').strip + ':' + secure_hash | ||
raise "The session contains to much data" if content.length > 4096 | ||
@response.set_cookie("identity", content) | ||
end | ||
end | ||
|
||
def secure_blob_hasher(data) | ||
Digest::SHA256.hexdigest(self.class.module_eval('@@state_secret') + data) | ||
end | ||
end | ||
end |