Skip to content

Commit 725edd0

Browse files
committed
Merge pull request #4 from mmerickel/refactor/split-pickle-from-encryption
split pickle from encryption
2 parents aa1de0f + 2010279 commit 725edd0

File tree

8 files changed

+42
-23
lines changed

8 files changed

+42
-23
lines changed

CHANGES.rst

+4-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ Changelog
44
0.2 (unreleased)
55
----------------
66

7-
- TBD
8-
7+
- Split the ``EncryptingPickleSerializer`` into ``EncryptedSerializer``
8+
with a default dependency on ``pyramid.session.PickleSerializer`` allowing
9+
alternative serializers to be used with the encryption interface.
10+
See https://github.com/Pylons/pyramid_nacl_session/pull/4
911

1012
0.1 (2015-11-23)
1113
----------------

CONTRIBUTORS.txt

+2
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,5 @@ Contributors
104104
------------
105105

106106
- Tres Seaver, 2015/11/16
107+
108+
- Michael Merickel, 2015/11/23

docs/_static/.keep

Whitespace-only changes.

docs/conf.py

+5
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@
3131
'sphinx.ext.intersphinx',
3232
]
3333

34+
# Looks for objects in external projects
35+
intersphinx_mapping = {
36+
'pyramid': ('http://docs.pylonsproject.org/projects/pyramid/en/latest/', None),
37+
}
38+
3439
# Add any paths that contain templates here, relative to this directory.
3540
templates_path = ['_templates']
3641

docs/usage.rst

+4-4
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ Use the generated secret to configure a session factory:
2020
.. code-block:: python
2121
2222
from pyramid.session import BaseCookieSessionFactory
23-
from pyramid_nacl_session import EncryptingPickleSerializer
23+
from pyramid_nacl_session import EncryptedSerializer
2424
2525
def includeme(config):
26-
serializer = EncryptingPickleSerializer(SECRET)
26+
serializer = EncryptedSerializer(SECRET)
2727
factory = BaseCookieSessionFactory(serializer) # other config ad lib.
2828
config.set_session_factory(factory)
2929
@@ -53,12 +53,12 @@ construct and register a session factory:
5353
5454
import binascii
5555
from pyramid.session import BaseCookieSessionFactory
56-
from pyramid_nacl_session import EncryptingPickleSerializer
56+
from pyramid_nacl_session import EncryptedSerializer
5757
5858
def includeme(config):
5959
hex_secret = config.settings['yourapp.session_secret'].strip()
6060
secret = binascii.unhexlify(hex_secret)
61-
serializer = EncryptingPickleSerializer(secret)
61+
serializer = EncryptedSerializer(secret)
6262
factory = BaseCookieSessionFactory(serializer) # other config ad lib.
6363
config.set_session_factory(factory)
6464

pyramid_nacl_session/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ def _export(thing):
44
Also, shuts pyflakes up about unused import.
55
"""
66

7-
from .serializer import EncryptingPickleSerializer
8-
_export(EncryptingPickleSerializer)
7+
from .serializer import EncryptedSerializer
8+
_export(EncryptedSerializer)
99
from .scripts import generate_secret
1010
_export(generate_secret)

pyramid_nacl_session/serializer.py

+20-10
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,34 @@
33

44
from nacl.secret import SecretBox
55
from nacl.utils import random
6-
from pyramid.compat import pickle
6+
from pyramid.session import PickleSerializer
77

88

9-
class EncryptingPickleSerializer(object):
10-
"""Encrypt pickled session state using PyNaCl.
9+
class EncryptedSerializer(object):
10+
"""Encrypt session state using PyNaCl.
1111
1212
:type secret: bytes
1313
:param secret: a 32-byte random secret for encrypting/decrypting the
1414
pickled session state.
15+
:param serializer:
16+
An object with two methods: ``loads`` and ``dumps``. The ``loads``
17+
method should accept bytes and return a Python object. The ``dumps``
18+
method should accept a Python object and return bytes. A ``ValueError``
19+
should be raised for malformed inputs. Default: ``None``, which will
20+
use :class:`pyramid.session.PickleSerializer`.
1521
"""
16-
def __init__(self, secret):
22+
def __init__(self, secret, serializer=None):
1723
if len(secret) != SecretBox.KEY_SIZE:
1824
raise ValueError(
19-
"Secret should be a random bytes string of length %d"
20-
% SecretBox.KEY_SIZE)
25+
"Secret should be a random bytes string of length %d" %
26+
SecretBox.KEY_SIZE)
2127
self.box = SecretBox(secret)
2228

29+
if serializer is None:
30+
serializer = PickleSerializer()
31+
32+
self.serializer = serializer
33+
2334
def loads(self, encrypted_state):
2435
"""Decrypt session state.
2536
@@ -31,7 +42,7 @@ def loads(self, encrypted_state):
3142
``session_state`` to :meth:`dumps`.
3243
"""
3344
payload = self.box.decrypt(urlsafe_b64decode(encrypted_state))
34-
return pickle.loads(payload)
45+
return self.serializer.loads(payload)
3546

3647
def dumps(self, session_state):
3748
"""Encrypt session state.
@@ -42,7 +53,6 @@ def dumps(self, session_state):
4253
:rtype: bytes
4354
:returns: the encrypted session state
4455
"""
45-
pickled = pickle.dumps(session_state)
56+
cstruct = self.serializer.dumps(session_state)
4657
nonce = random(SecretBox.NONCE_SIZE)
47-
return urlsafe_b64encode(self.box.encrypt(pickled, nonce))
48-
58+
return urlsafe_b64encode(self.box.encrypt(cstruct, nonce))

pyramid_nacl_session/tests/test_serializer.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import unittest
22

33

4-
class EncryptingPickleSerializerTests(unittest.TestCase):
4+
class EncryptedSerializerTests(unittest.TestCase):
55

66
def _getTargetClass(self):
7-
from ..serializer import EncryptingPickleSerializer
8-
return EncryptingPickleSerializer
7+
from ..serializer import EncryptedSerializer
8+
return EncryptedSerializer
99

1010
def _makeOne(self, *args, **kw):
1111
return self._getTargetClass()(*args, **kw)
@@ -20,7 +20,7 @@ def test_dumps(self):
2020
SECRET = 'SEEKRIT!' * 4 # 32 bytes
2121
NONCE = b'\x01' * 24
2222
APPSTRUCT = {'foo': 'bar'}
23-
PICKLED = pickle.dumps(APPSTRUCT)
23+
PICKLED = pickle.dumps(APPSTRUCT, pickle.HIGHEST_PROTOCOL)
2424
_base64_called = []
2525
def _base64_encode(what):
2626
_base64_called.append(what)
@@ -42,7 +42,7 @@ def test_loads(self):
4242
SECRET = 'SEEKRIT!' * 4 # 32 bytes
4343
NONCE = b'\x01' * 24
4444
APPSTRUCT = {'foo': 'bar'}
45-
PICKLED = pickle.dumps(APPSTRUCT)
45+
PICKLED = pickle.dumps(APPSTRUCT, pickle.HIGHEST_PROTOCOL)
4646
CIPHERTEXT = PICKLED + b':' + NONCE
4747
_base64_called = []
4848
def _base64_decode(what):

0 commit comments

Comments
 (0)