<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -69,6 +69,14 @@ class Application(webapp.WSGIApplication):
     self.settings.update(settings)
     super(Application, self).__init__(self.url_mapping, self.settings['debug'])
 
+  def setting(self, name, feature='this feature', default=None):
+    value = self.settings.get(name)
+    if value is None and default is None:
+      raise Exception('You must define the &quot;%s&quot; setting in your application to use %s' % (name, feature))
+    elif not value is None:
+      return value
+    return default
+
 def run_appengine(application):
   from google.appengine.ext.webapp.util import run_wsgi_app
   sys.stdout = sys.stderr</diff>
      <filename>huck/web/__init__.py</filename>
    </modified>
    <modified>
      <diff>@@ -12,11 +12,15 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import base64
 import calendar
 import Cookie
 import datetime
 import email
+import hashlib
+import hmac
 import re
+import time
 
 from huck.context import utf8
 
@@ -25,6 +29,13 @@ class Cookies(object):
   def __init__(self, handler):
     self.handler = handler
 
+  def _signature(self, *parts):
+    cookie_secret = self.handler.application.setting('cookie_secret', 'secure cookies')
+    hash = hmac.new(cookie_secret, digestmod=hashlib.sha1)
+    for part in parts:
+       hash.update(part)
+    return hash.hexdigest()
+
   @property
   def list(self):
     if not hasattr(self, '_cookies'):
@@ -37,12 +48,12 @@ class Cookies(object):
     return self._cookies
 
   def clear(self, name, path='/', domain=None):
-      expires = datetime.datetime.utcnow() - datetime.timedelta(days=365)
-      self.set(name, value='', path=path, expires=expires, domain=domain)
+    expires = datetime.datetime.utcnow() - datetime.timedelta(days=365)
+    self.set(name, value='', path=path, expires=expires, domain=domain)
 
   def clear_all(self):
-      for name in self.list.iterkeys():
-        self.clear(name)
+    for name in self.list.iterkeys():
+      self.clear(name)
 
   def get(self, name, default=None):
     if name in self.list:
@@ -50,19 +61,43 @@ class Cookies(object):
     return default
 
   def set(self, name, value, domain=None, expires=None, path='/', expires_days=None):
-      name = utf8.encode(name)
-      value = utf8.encode(value)
-      if re.search(r'[\x00-\x20]', name + value):
-        raise ValueError('Invalid cookie %r: %r' % (name, value))
-      cookie = Cookie.BaseCookie()
-      cookie[name] = value
-      if domain:
-        cookie[name]['domain'] = domain
-      if expires_days is not None and not expires:
-        expires = datetime.datetime.utcnow() + datetime.timedelta(days=expires_days)
-      if expires:
-        timestamp = calendar.timegm(expires.utctimetuple())
-        cookie[name]['expires'] = email.utils.formatdate(timestamp, localtime=False, usegmt=True)
-      if path:
-        cookie[name]['path'] = path
-      self.handler.response.headers._headers.append(('Set-Cookie', cookie[name].output(header='').lstrip()))
+    name = utf8.encode(name)
+    value = utf8.encode(value)
+    if re.search(r'[\x00-\x20]', name + value):
+      raise ValueError('Invalid cookie %r: %r' % (name, value))
+    cookie = Cookie.BaseCookie()
+    cookie[name] = value
+    if domain:
+      cookie[name]['domain'] = domain
+    if expires_days is not None and not expires:
+      expires = datetime.datetime.utcnow() + datetime.timedelta(days=expires_days)
+    if expires:
+      timestamp = calendar.timegm(expires.utctimetuple())
+      cookie[name]['expires'] = email.utils.formatdate(timestamp, localtime=False, usegmt=True)
+    if path:
+      cookie[name]['path'] = path
+    self.handler.response.headers._headers.append(('Set-Cookie', cookie[name].output(header='').lstrip()))
+
+  def set_secure(self, name, value, expires_days=30, **kwargs):
+    timestamp = str(int(time.time()))
+    value = base64.b64encode(value)
+    signature = self._signature(value, timestamp)
+    value = '|'.join([value, timestamp, signature])
+    self.set(name, value, expires_days=expires_days, **kwargs)
+
+  def get_secure(self, name):
+    value = self.get(name)
+    if not value: return None
+    parts = value.split('|')
+    if len(parts) != 3: return None
+    if self._signature(parts[0], parts[1]) != parts[2]:
+      logging.warning('Invalid cookie signature %r', value)
+      return None
+    timestamp = int(parts[1])
+    if timestamp &lt; time.time() - 31 * 86400:
+      logging.warning('Expired cookie %r', value)
+      return None
+    try:
+      return base64.b64decode(parts[0])
+    except:
+      return None</diff>
      <filename>huck/web/cookies.py</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>7009626c81d135b0cd49d3c8d28bdeb4559689bd</id>
    </parent>
  </parents>
  <author>
    <name>Silas Sewell</name>
    <email>silas@sewell.ch</email>
  </author>
  <url>http://github.com/silas/huck/commit/e5212560228dc550dc87a63b6794bbec65afdb75</url>
  <id>e5212560228dc550dc87a63b6794bbec65afdb75</id>
  <committed-date>2009-11-07T12:23:06-08:00</committed-date>
  <authored-date>2009-11-07T12:23:06-08:00</authored-date>
  <message>Add secure cookies</message>
  <tree>7109eff5218b24414680409dda86f872cb8d2965</tree>
  <committer>
    <name>Silas Sewell</name>
    <email>silas@sewell.ch</email>
  </committer>
</commit>
