diff --git a/lib/camping/session.rb b/lib/camping/session.rb
new file mode 100644
index 0000000..731102b
--- /dev/null
+++ b/lib/camping/session.rb
@@ -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 sessions 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 @state 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 service method which
+# intercepts all requests handed to those controllers.
+#
+# == Getting Started
+#
+# To get sessions working for your application:
+#
+# 1. require 'camping/session'
+# 2. Mixin the module: module YourApp; include Camping::Session end
+# 3. Define a secret (and keep it secret): module YourApp; @@state_secret = "SECRET!"; end
+# 4. Throughout your application, use the @state var like a hash to store your application's data.
+#
+# == A Few Notes
+#
+# * The session is stored in a cookie. Look in @cookies.identity.
+# * Session data is only saved if it has changed.
+module Session
+ # This service 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 @state 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