 
 ;; Cookie sessions
 
-
+; Random secret key
+(def *session-secret-key* (gen-uuid))
+
+(defn- session-hmac
+  "Calculate a HMAC for a marshalled session"
+  [cookie-data]
+  (hmac *session-secret-key* "HmacSHA256" cookie-data))
+
+(defmethod create-session :cookie [_] {})
+
+(defmethod session-cookie :cookie
+  [_ _ session]
+  (let [cookie-data (marshal session)]
+    (if (> (count cookie-data) 4000)
+      (throwf "Session data exceeds 4K")
+      (str cookie-data "--" (session-hmac cookie-data)))))
+
+(defmethod read-session :cookie
+  [_ data]
+  (let [[session mac] (.split data "--")]
+    (if (= mac (session-hmac session))
+      (unmarshal session))))
+
+; Do nothing for write or destroy
+(defmethod write-session :cookie [_ _])
+(defmethod destroy-session :cookie [_ _])
 
 ;; Session middleware
 
 (defn- get-request-session
   "Retrieve the session using the 'session-id' cookie in the request."
   [request]
-  (if-let [session-id (-> request :cookies :session-id)]
+  (if-let [session-id (-> request :cookies :session)]
     (read-session *session-store* session-id)))
 
 (defn- assoc-request-session

  "Remove the session from the session store."
  (fn [type session] type))

(defmulti set-session-cookie
  "Add the session cookie to the given response."
  (fn [type response session] type))

;; Default implementations of create-session and set-session-cookie


(defn- get-response-session
  "Retrieve the current session from the response map."
  [request response]
  (if-let [id (-> request :session :id)]
    (assoc (:session response) :id id)
    (:session response)))

(defn- set-session-cookie
  "Set the session cookie on the response."
  [request response session]
  (let [new?   (:new-session? request)
        cookie (session-cookie *session-store* new? session)
        update (set-cookie :session cookie)]
    (update-response {} response update)))

(defn with-session
  "Wrap a handler in a session."
