Private GIT

Skip to content
Snippets Groups Projects
Commit 78c8b5e1 authored by Dustyn Gibson's avatar Dustyn Gibson
Browse files

Remove pyOpenSSL from libs. Cryptography is only needed if you use pyOpenSSL...

Remove pyOpenSSL from libs. Cryptography is only needed if you use pyOpenSSL 0.14 or newer. Instead `pip install pyopenssl==0.13.1`
parent 75583553
No related branches found
No related tags found
No related merge requests found
Showing
with 22 additions and 13642 deletions
...@@ -8,7 +8,7 @@ branches: ...@@ -8,7 +8,7 @@ branches:
- develop - develop
install: install:
- pip install cheetah cryptography - pip install cheetah pyopenssl==0.13.1
before_script: before_script:
- chmod +x ./tests/all_tests.py - chmod +x ./tests/all_tests.py
......
...@@ -64,7 +64,15 @@ else: ...@@ -64,7 +64,15 @@ else:
try: try:
import cryptography import cryptography
except ImportError: except ImportError:
print("SNI is disabled when the cryptography module is missing. You may encounter SSL errors!") try:
from OpenSSL.version import __version__ as pyOpenSSL_Version
if int(pyOpenSSL_Version.replace('.', '')[:3]) > 13:
raise ImportError
except ImportError:
print('\nSNI is disabled with pyOpenSSL >= 0.14 when the cryptography module is missing,\n' +
'you will encounter SSL errors with HTTPS! To fix this issue:\n' +
'pip install pyopenssl==0.13.1 (easy) or pip install cryptography (pita)')
import locale import locale
import datetime import datetime
......
This diff is collapsed.
This diff is collapsed.
# Copyright (C) AB Strakt
# See LICENSE for details.
"""
pyOpenSSL - A simple wrapper around the OpenSSL library
"""
from OpenSSL import rand, crypto, SSL
from OpenSSL.version import __version__
__all__ = [
'rand', 'crypto', 'SSL', 'tsafe', '__version__']
from warnings import warn
import sys
from six import PY3, binary_type, text_type
from cryptography.hazmat.bindings.openssl.binding import Binding
binding = Binding()
ffi = binding.ffi
lib = binding.lib
def text(charp):
"""
Get a native string type representing of the given CFFI ``char*`` object.
:param charp: A C-style string represented using CFFI.
:return: :class:`str`
"""
if not charp:
return ""
return native(ffi.string(charp))
def exception_from_error_queue(exception_type):
"""
Convert an OpenSSL library failure into a Python exception.
When a call to the native OpenSSL library fails, this is usually signalled
by the return value, and an error code is stored in an error queue
associated with the current thread. The err library provides functions to
obtain these error codes and textual error messages.
"""
errors = []
while True:
error = lib.ERR_get_error()
if error == 0:
break
errors.append((
text(lib.ERR_lib_error_string(error)),
text(lib.ERR_func_error_string(error)),
text(lib.ERR_reason_error_string(error))))
raise exception_type(errors)
def native(s):
"""
Convert :py:class:`bytes` or :py:class:`unicode` to the native
:py:class:`str` type, using UTF-8 encoding if conversion is necessary.
:raise UnicodeError: The input string is not UTF-8 decodeable.
:raise TypeError: The input is neither :py:class:`bytes` nor
:py:class:`unicode`.
"""
if not isinstance(s, (binary_type, text_type)):
raise TypeError("%r is neither bytes nor unicode" % s)
if PY3:
if isinstance(s, binary_type):
return s.decode("utf-8")
else:
if isinstance(s, text_type):
return s.encode("utf-8")
return s
def path_string(s):
"""
Convert a Python string to a :py:class:`bytes` string identifying the same
path and which can be passed into an OpenSSL API accepting a filename.
:param s: An instance of :py:class:`bytes` or :py:class:`unicode`.
:return: An instance of :py:class:`bytes`.
"""
if isinstance(s, binary_type):
return s
elif isinstance(s, text_type):
return s.encode(sys.getfilesystemencoding())
else:
raise TypeError("Path must be represented as bytes or unicode string")
if PY3:
def byte_string(s):
return s.encode("charmap")
else:
def byte_string(s):
return s
# A marker object to observe whether some optional arguments are passed any
# value or not.
UNSPECIFIED = object()
_TEXT_WARNING = (
text_type.__name__ + " for {0} is no longer accepted, use bytes"
)
def text_to_bytes_and_warn(label, obj):
"""
If ``obj`` is text, emit a warning that it should be bytes instead and try
to convert it to bytes automatically.
:param str label: The name of the parameter from which ``obj`` was taken
(so a developer can easily find the source of the problem and correct
it).
:return: If ``obj`` is the text string type, a ``bytes`` object giving the
UTF-8 encoding of that text is returned. Otherwise, ``obj`` itself is
returned.
"""
if isinstance(obj, text_type):
warn(
_TEXT_WARNING.format(label),
category=DeprecationWarning,
stacklevel=3
)
return obj.encode('utf-8')
return obj
This diff is collapsed.
"""
PRNG management routines, thin wrappers.
See the file RATIONALE for a short explanation of why this module was written.
"""
from functools import partial
from six import integer_types as _integer_types
from OpenSSL._util import (
ffi as _ffi,
lib as _lib,
exception_from_error_queue as _exception_from_error_queue,
path_string as _path_string)
class Error(Exception):
"""
An error occurred in an `OpenSSL.rand` API.
"""
_raise_current_error = partial(_exception_from_error_queue, Error)
_unspecified = object()
_builtin_bytes = bytes
def bytes(num_bytes):
"""
Get some random bytes as a string.
:param num_bytes: The number of bytes to fetch
:return: A string of random bytes
"""
if not isinstance(num_bytes, _integer_types):
raise TypeError("num_bytes must be an integer")
if num_bytes < 0:
raise ValueError("num_bytes must not be negative")
result_buffer = _ffi.new("char[]", num_bytes)
result_code = _lib.RAND_bytes(result_buffer, num_bytes)
if result_code == -1:
# TODO: No tests for this code path. Triggering a RAND_bytes failure
# might involve supplying a custom ENGINE? That's hard.
_raise_current_error()
return _ffi.buffer(result_buffer)[:]
def add(buffer, entropy):
"""
Add data with a given entropy to the PRNG
:param buffer: Buffer with random data
:param entropy: The entropy (in bytes) measurement of the buffer
:return: None
"""
if not isinstance(buffer, _builtin_bytes):
raise TypeError("buffer must be a byte string")
if not isinstance(entropy, int):
raise TypeError("entropy must be an integer")
# TODO Nothing tests this call actually being made, or made properly.
_lib.RAND_add(buffer, len(buffer), entropy)
def seed(buffer):
"""
Alias for rand_add, with entropy equal to length
:param buffer: Buffer with random data
:return: None
"""
if not isinstance(buffer, _builtin_bytes):
raise TypeError("buffer must be a byte string")
# TODO Nothing tests this call actually being made, or made properly.
_lib.RAND_seed(buffer, len(buffer))
def status():
"""
Retrieve the status of the PRNG
:return: True if the PRNG is seeded enough, false otherwise
"""
return _lib.RAND_status()
def egd(path, bytes=_unspecified):
"""
Query an entropy gathering daemon (EGD) for random data and add it to the
PRNG. I haven't found any problems when the socket is missing, the function
just returns 0.
:param path: The path to the EGD socket
:param bytes: (optional) The number of bytes to read, default is 255
:returns: The number of bytes read (NB: a value of 0 isn't necessarily an
error, check rand.status())
"""
if not isinstance(path, _builtin_bytes):
raise TypeError("path must be a byte string")
if bytes is _unspecified:
bytes = 255
elif not isinstance(bytes, int):
raise TypeError("bytes must be an integer")
return _lib.RAND_egd_bytes(path, bytes)
def cleanup():
"""
Erase the memory used by the PRNG.
:return: None
"""
# TODO Nothing tests this call actually being made, or made properly.
_lib.RAND_cleanup()
def load_file(filename, maxbytes=_unspecified):
"""
Seed the PRNG with data from a file
:param filename: The file to read data from (``bytes`` or ``unicode``).
:param maxbytes: (optional) The number of bytes to read, default is to read
the entire file
:return: The number of bytes read
"""
filename = _path_string(filename)
if maxbytes is _unspecified:
maxbytes = -1
elif not isinstance(maxbytes, int):
raise TypeError("maxbytes must be an integer")
return _lib.RAND_load_file(filename, maxbytes)
def write_file(filename):
"""
Save PRNG state to a file
:param filename: The file to write data to (``bytes`` or ``unicode``).
:return: The number of bytes written
"""
filename = _path_string(filename)
return _lib.RAND_write_file(filename)
# TODO There are no tests for screen at all
def screen():
"""
Add the current contents of the screen to the PRNG state. Availability:
Windows.
:return: None
"""
_lib.RAND_screen()
if getattr(_lib, 'RAND_screen', None) is None:
del screen
# TODO There are no tests for the RAND strings being loaded, whatever that
# means.
_lib.ERR_load_RAND_strings()
# Copyright (C) Jean-Paul Calderone
# See LICENSE for details.
"""
Package containing unit tests for :py:mod:`OpenSSL`.
"""
This diff is collapsed.
# Copyright (c) Frederick Dean
# See LICENSE for details.
"""
Unit tests for :py:obj:`OpenSSL.rand`.
"""
from unittest import main
import os
import stat
import sys
from OpenSSL.test.util import NON_ASCII, TestCase, b
from OpenSSL import rand
class RandTests(TestCase):
def test_bytes_wrong_args(self):
"""
:py:obj:`OpenSSL.rand.bytes` raises :py:obj:`TypeError` if called with the wrong
number of arguments or with a non-:py:obj:`int` argument.
"""
self.assertRaises(TypeError, rand.bytes)
self.assertRaises(TypeError, rand.bytes, None)
self.assertRaises(TypeError, rand.bytes, 3, None)
def test_insufficientMemory(self):
"""
:py:obj:`OpenSSL.rand.bytes` raises :py:obj:`MemoryError` if more bytes
are requested than will fit in memory.
"""
self.assertRaises(MemoryError, rand.bytes, sys.maxsize)
def test_bytes(self):
"""
Verify that we can obtain bytes from rand_bytes() and
that they are different each time. Test the parameter
of rand_bytes() for bad values.
"""
b1 = rand.bytes(50)
self.assertEqual(len(b1), 50)
b2 = rand.bytes(num_bytes=50) # parameter by name
self.assertNotEqual(b1, b2) # Hip, Hip, Horay! FIPS complaince
b3 = rand.bytes(num_bytes=0)
self.assertEqual(len(b3), 0)
exc = self.assertRaises(ValueError, rand.bytes, -1)
self.assertEqual(str(exc), "num_bytes must not be negative")
def test_add_wrong_args(self):
"""
When called with the wrong number of arguments, or with arguments not of
type :py:obj:`str` and :py:obj:`int`, :py:obj:`OpenSSL.rand.add` raises :py:obj:`TypeError`.
"""
self.assertRaises(TypeError, rand.add)
self.assertRaises(TypeError, rand.add, b("foo"), None)
self.assertRaises(TypeError, rand.add, None, 3)
self.assertRaises(TypeError, rand.add, b("foo"), 3, None)
def test_add(self):
"""
:py:obj:`OpenSSL.rand.add` adds entropy to the PRNG.
"""
rand.add(b('hamburger'), 3)
def test_seed_wrong_args(self):
"""
When called with the wrong number of arguments, or with a non-:py:obj:`str`
argument, :py:obj:`OpenSSL.rand.seed` raises :py:obj:`TypeError`.
"""
self.assertRaises(TypeError, rand.seed)
self.assertRaises(TypeError, rand.seed, None)
self.assertRaises(TypeError, rand.seed, b("foo"), None)
def test_seed(self):
"""
:py:obj:`OpenSSL.rand.seed` adds entropy to the PRNG.
"""
rand.seed(b('milk shake'))
def test_status_wrong_args(self):
"""
:py:obj:`OpenSSL.rand.status` raises :py:obj:`TypeError` when called with any
arguments.
"""
self.assertRaises(TypeError, rand.status, None)
def test_status(self):
"""
:py:obj:`OpenSSL.rand.status` returns :py:obj:`True` if the PRNG has sufficient
entropy, :py:obj:`False` otherwise.
"""
# It's hard to know what it is actually going to return. Different
# OpenSSL random engines decide differently whether they have enough
# entropy or not.
self.assertTrue(rand.status() in (1, 2))
def test_egd_wrong_args(self):
"""
:py:obj:`OpenSSL.rand.egd` raises :py:obj:`TypeError` when called with the wrong
number of arguments or with arguments not of type :py:obj:`str` and :py:obj:`int`.
"""
self.assertRaises(TypeError, rand.egd)
self.assertRaises(TypeError, rand.egd, None)
self.assertRaises(TypeError, rand.egd, "foo", None)
self.assertRaises(TypeError, rand.egd, None, 3)
self.assertRaises(TypeError, rand.egd, "foo", 3, None)
def test_egd_missing(self):
"""
:py:obj:`OpenSSL.rand.egd` returns :py:obj:`0` or :py:obj:`-1` if the
EGD socket passed to it does not exist.
"""
result = rand.egd(self.mktemp())
expected = (-1, 0)
self.assertTrue(
result in expected,
"%r not in %r" % (result, expected))
def test_egd_missing_and_bytes(self):
"""
:py:obj:`OpenSSL.rand.egd` returns :py:obj:`0` or :py:obj:`-1` if the
EGD socket passed to it does not exist even if a size argument is
explicitly passed.
"""
result = rand.egd(self.mktemp(), 1024)
expected = (-1, 0)
self.assertTrue(
result in expected,
"%r not in %r" % (result, expected))
def test_cleanup_wrong_args(self):
"""
:py:obj:`OpenSSL.rand.cleanup` raises :py:obj:`TypeError` when called with any
arguments.
"""
self.assertRaises(TypeError, rand.cleanup, None)
def test_cleanup(self):
"""
:py:obj:`OpenSSL.rand.cleanup` releases the memory used by the PRNG and returns
:py:obj:`None`.
"""
self.assertIdentical(rand.cleanup(), None)
def test_load_file_wrong_args(self):
"""
:py:obj:`OpenSSL.rand.load_file` raises :py:obj:`TypeError` when called the wrong
number of arguments or arguments not of type :py:obj:`str` and :py:obj:`int`.
"""
self.assertRaises(TypeError, rand.load_file)
self.assertRaises(TypeError, rand.load_file, "foo", None)
self.assertRaises(TypeError, rand.load_file, None, 1)
self.assertRaises(TypeError, rand.load_file, "foo", 1, None)
def test_write_file_wrong_args(self):
"""
:py:obj:`OpenSSL.rand.write_file` raises :py:obj:`TypeError` when called with the
wrong number of arguments or a non-:py:obj:`str` argument.
"""
self.assertRaises(TypeError, rand.write_file)
self.assertRaises(TypeError, rand.write_file, None)
self.assertRaises(TypeError, rand.write_file, "foo", None)
def _read_write_test(self, path):
"""
Verify that ``rand.write_file`` and ``rand.load_file`` can be used.
"""
# Create the file so cleanup is more straightforward
with open(path, "w"):
pass
try:
# Write random bytes to a file
rand.write_file(path)
# Verify length of written file
size = os.stat(path)[stat.ST_SIZE]
self.assertEqual(1024, size)
# Read random bytes from file
rand.load_file(path)
rand.load_file(path, 4) # specify a length
finally:
# Cleanup
os.unlink(path)
def test_bytes_paths(self):
"""
Random data can be saved and loaded to files with paths specified as
bytes.
"""
path = self.mktemp()
path += NON_ASCII.encode(sys.getfilesystemencoding())
self._read_write_test(path)
def test_unicode_paths(self):
"""
Random data can be saved and loaded to files with paths specified as
unicode.
"""
path = self.mktemp().decode('utf-8') + NON_ASCII
self._read_write_test(path)
if __name__ == '__main__':
main()
This diff is collapsed.
# Copyright (C) Jean-Paul Calderone
# See LICENSE for details.
"""
Unit tests for :py:obj:`OpenSSL.tsafe`.
"""
from OpenSSL.SSL import TLSv1_METHOD, Context
from OpenSSL.tsafe import Connection
from OpenSSL.test.util import TestCase
class ConnectionTest(TestCase):
"""
Tests for :py:obj:`OpenSSL.tsafe.Connection`.
"""
def test_instantiation(self):
"""
:py:obj:`OpenSSL.tsafe.Connection` can be instantiated.
"""
# The following line should not throw an error. This isn't an ideal
# test. It would be great to refactor the other Connection tests so
# they could automatically be applied to this class too.
Connection(Context(TLSv1_METHOD), None)
from OpenSSL._util import exception_from_error_queue, lib
from OpenSSL.test.util import TestCase
class ErrorTests(TestCase):
"""
Tests for handling of certain OpenSSL error cases.
"""
def test_exception_from_error_queue_nonexistent_reason(self):
"""
:py:func:`exception_from_error_queue` raises ``ValueError`` when it
encounters an OpenSSL error code which does not have a reason string.
"""
lib.ERR_put_error(lib.ERR_LIB_EVP, 0, 1112, b"", 10)
exc = self.assertRaises(ValueError, exception_from_error_queue, ValueError)
self.assertEqual(exc.args[0][0][2], "")
# Copyright (C) Jean-Paul Calderone
# Copyright (C) Twisted Matrix Laboratories.
# See LICENSE for details.
"""
Helpers for the OpenSSL test suite, largely copied from
U{Twisted<http://twistedmatrix.com/>}.
"""
import shutil
import traceback
import os, os.path
from tempfile import mktemp
from unittest import TestCase
import sys
from six import PY3
from OpenSSL._util import exception_from_error_queue
from OpenSSL.crypto import Error
try:
import memdbg
except Exception:
class _memdbg(object): heap = None
memdbg = _memdbg()
from OpenSSL._util import ffi, lib, byte_string as b
# This is the UTF-8 encoding of the SNOWMAN unicode code point.
NON_ASCII = b("\xe2\x98\x83").decode("utf-8")
class TestCase(TestCase):
"""
:py:class:`TestCase` adds useful testing functionality beyond what is available
from the standard library :py:class:`unittest.TestCase`.
"""
def run(self, result):
run = super(TestCase, self).run
if memdbg.heap is None:
return run(result)
# Run the test as usual
before = set(memdbg.heap)
run(result)
# Clean up some long-lived allocations so they won't be reported as
# memory leaks.
lib.CRYPTO_cleanup_all_ex_data()
lib.ERR_remove_thread_state(ffi.NULL)
after = set(memdbg.heap)
if not after - before:
# No leaks, fast succeed
return
if result.wasSuccessful():
# If it passed, run it again with memory debugging
before = set(memdbg.heap)
run(result)
# Clean up some long-lived allocations so they won't be reported as
# memory leaks.
lib.CRYPTO_cleanup_all_ex_data()
lib.ERR_remove_thread_state(ffi.NULL)
after = set(memdbg.heap)
self._reportLeaks(after - before, result)
def _reportLeaks(self, leaks, result):
def format_leak(p):
stacks = memdbg.heap[p]
# Eventually look at multiple stacks for the realloc() case. For
# now just look at the original allocation location.
(size, python_stack, c_stack) = stacks[0]
stack = traceback.format_list(python_stack)[:-1]
# c_stack looks something like this (interesting parts indicated
# with inserted arrows not part of the data):
#
# /home/exarkun/Projects/pyOpenSSL/branches/use-opentls/__pycache__/_cffi__x89095113xb9185b9b.so(+0x12cf) [0x7fe2e20582cf]
# /home/exarkun/Projects/cpython/2.7/python(PyCFunction_Call+0x8b) [0x56265a]
# /home/exarkun/Projects/cpython/2.7/python() [0x4d5f52]
# /home/exarkun/Projects/cpython/2.7/python(PyEval_EvalFrameEx+0x753b) [0x4d0e1e]
# /home/exarkun/Projects/cpython/2.7/python() [0x4d6419]
# /home/exarkun/Projects/cpython/2.7/python() [0x4d6129]
# /home/exarkun/Projects/cpython/2.7/python(PyEval_EvalFrameEx+0x753b) [0x4d0e1e]
# /home/exarkun/Projects/cpython/2.7/python(PyEval_EvalCodeEx+0x1043) [0x4d3726]
# /home/exarkun/Projects/cpython/2.7/python() [0x55fd51]
# /home/exarkun/Projects/cpython/2.7/python(PyObject_Call+0x7e) [0x420ee6]
# /home/exarkun/Projects/cpython/2.7/python(PyEval_CallObjectWithKeywords+0x158) [0x4d56ec]
# /home/exarkun/.local/lib/python2.7/site-packages/cffi-0.5-py2.7-linux-x86_64.egg/_cffi_backend.so(+0xe96e) [0x7fe2e38be96e]
# /usr/lib/x86_64-linux-gnu/libffi.so.6(ffi_closure_unix64_inner+0x1b9) [0x7fe2e36ad819]
# /usr/lib/x86_64-linux-gnu/libffi.so.6(ffi_closure_unix64+0x46) [0x7fe2e36adb7c]
# /lib/x86_64-linux-gnu/libcrypto.so.1.0.0(CRYPTO_malloc+0x64) [0x7fe2e1cef784] <------ end interesting
# /lib/x86_64-linux-gnu/libcrypto.so.1.0.0(lh_insert+0x16b) [0x7fe2e1d6a24b] .
# /lib/x86_64-linux-gnu/libcrypto.so.1.0.0(+0x61c18) [0x7fe2e1cf0c18] .
# /lib/x86_64-linux-gnu/libcrypto.so.1.0.0(+0x625ec) [0x7fe2e1cf15ec] .
# /lib/x86_64-linux-gnu/libcrypto.so.1.0.0(DSA_new_method+0xe6) [0x7fe2e1d524d6] .
# /lib/x86_64-linux-gnu/libcrypto.so.1.0.0(DSA_generate_parameters+0x3a) [0x7fe2e1d5364a] <------ begin interesting
# /home/exarkun/Projects/opentls/trunk/tls/c/__pycache__/_cffi__x305d4698xb539baaa.so(+0x1f397) [0x7fe2df84d397]
# /home/exarkun/Projects/cpython/2.7/python(PyCFunction_Call+0x8b) [0x56265a]
# /home/exarkun/Projects/cpython/2.7/python() [0x4d5f52]
# /home/exarkun/Projects/cpython/2.7/python(PyEval_EvalFrameEx+0x753b) [0x4d0e1e]
# /home/exarkun/Projects/cpython/2.7/python() [0x4d6419]
# ...
#
# Notice the stack is upside down compared to a Python traceback.
# Identify the start and end of interesting bits and stuff it into the stack we report.
saved = list(c_stack)
# Figure the first interesting frame will be after a the cffi-compiled module
while c_stack and '/__pycache__/_cffi__' not in c_stack[-1]:
c_stack.pop()
# Figure the last interesting frame will always be CRYPTO_malloc,
# since that's where we hooked in to things.
while c_stack and 'CRYPTO_malloc' not in c_stack[0] and 'CRYPTO_realloc' not in c_stack[0]:
c_stack.pop(0)
if c_stack:
c_stack.reverse()
else:
c_stack = saved[::-1]
stack.extend([frame + "\n" for frame in c_stack])
stack.insert(0, "Leaked (%s) at:\n")
return "".join(stack)
if leaks:
unique_leaks = {}
for p in leaks:
size = memdbg.heap[p][-1][0]
new_leak = format_leak(p)
if new_leak not in unique_leaks:
unique_leaks[new_leak] = [(size, p)]
else:
unique_leaks[new_leak].append((size, p))
memdbg.free(p)
for (stack, allocs) in unique_leaks.iteritems():
allocs_accum = []
for (size, pointer) in allocs:
addr = int(ffi.cast('uintptr_t', pointer))
allocs_accum.append("%d@0x%x" % (size, addr))
allocs_report = ", ".join(sorted(allocs_accum))
result.addError(
self,
(None, Exception(stack % (allocs_report,)), None))
def tearDown(self):
"""
Clean up any files or directories created using :py:meth:`TestCase.mktemp`.
Subclasses must invoke this method if they override it or the
cleanup will not occur.
"""
if False and self._temporaryFiles is not None:
for temp in self._temporaryFiles:
if os.path.isdir(temp):
shutil.rmtree(temp)
elif os.path.exists(temp):
os.unlink(temp)
try:
exception_from_error_queue(Error)
except Error:
e = sys.exc_info()[1]
if e.args != ([],):
self.fail("Left over errors in OpenSSL error queue: " + repr(e))
def assertIsInstance(self, instance, classOrTuple, message=None):
"""
Fail if C{instance} is not an instance of the given class or of
one of the given classes.
@param instance: the object to test the type (first argument of the
C{isinstance} call).
@type instance: any.
@param classOrTuple: the class or classes to test against (second
argument of the C{isinstance} call).
@type classOrTuple: class, type, or tuple.
@param message: Custom text to include in the exception text if the
assertion fails.
"""
if not isinstance(instance, classOrTuple):
if message is None:
suffix = ""
else:
suffix = ": " + message
self.fail("%r is not an instance of %s%s" % (
instance, classOrTuple, suffix))
def failUnlessIn(self, containee, container, msg=None):
"""
Fail the test if :py:data:`containee` is not found in :py:data:`container`.
:param containee: the value that should be in :py:class:`container`
:param container: a sequence type, or in the case of a mapping type,
will follow semantics of 'if key in dict.keys()'
:param msg: if msg is None, then the failure message will be
'%r not in %r' % (first, second)
"""
if containee not in container:
raise self.failureException(msg or "%r not in %r"
% (containee, container))
return containee
assertIn = failUnlessIn
def assertNotIn(self, containee, container, msg=None):
"""
Fail the test if C{containee} is found in C{container}.
@param containee: the value that should not be in C{container}
@param container: a sequence type, or in the case of a mapping type,
will follow semantics of 'if key in dict.keys()'
@param msg: if msg is None, then the failure message will be
'%r in %r' % (first, second)
"""
if containee in container:
raise self.failureException(msg or "%r in %r"
% (containee, container))
return containee
failIfIn = assertNotIn
def assertIs(self, first, second, msg=None):
"""
Fail the test if :py:data:`first` is not :py:data:`second`. This is an
obect-identity-equality test, not an object equality
(i.e. :py:func:`__eq__`) test.
:param msg: if msg is None, then the failure message will be
'%r is not %r' % (first, second)
"""
if first is not second:
raise self.failureException(msg or '%r is not %r' % (first, second))
return first
assertIdentical = failUnlessIdentical = assertIs
def assertIsNot(self, first, second, msg=None):
"""
Fail the test if :py:data:`first` is :py:data:`second`. This is an
obect-identity-equality test, not an object equality
(i.e. :py:func:`__eq__`) test.
:param msg: if msg is None, then the failure message will be
'%r is %r' % (first, second)
"""
if first is second:
raise self.failureException(msg or '%r is %r' % (first, second))
return first
assertNotIdentical = failIfIdentical = assertIsNot
def failUnlessRaises(self, exception, f, *args, **kwargs):
"""
Fail the test unless calling the function :py:data:`f` with the given
:py:data:`args` and :py:data:`kwargs` raises :py:data:`exception`. The
failure will report the traceback and call stack of the unexpected
exception.
:param exception: exception type that is to be expected
:param f: the function to call
:return: The raised exception instance, if it is of the given type.
:raise self.failureException: Raised if the function call does
not raise an exception or if it raises an exception of a
different type.
"""
try:
result = f(*args, **kwargs)
except exception:
inst = sys.exc_info()[1]
return inst
except:
raise self.failureException('%s raised instead of %s'
% (sys.exc_info()[0],
exception.__name__,
))
else:
raise self.failureException('%s not raised (%r returned)'
% (exception.__name__, result))
assertRaises = failUnlessRaises
_temporaryFiles = None
def mktemp(self):
"""
Pathetic substitute for twisted.trial.unittest.TestCase.mktemp.
"""
if self._temporaryFiles is None:
self._temporaryFiles = []
temp = b(mktemp(dir="."))
self._temporaryFiles.append(temp)
return temp
# Other stuff
def assertConsistentType(self, theType, name, *constructionArgs):
"""
Perform various assertions about :py:data:`theType` to ensure that it is a
well-defined type. This is useful for extension types, where it's
pretty easy to do something wacky. If something about the type is
unusual, an exception will be raised.
:param theType: The type object about which to make assertions.
:param name: A string giving the name of the type.
:param constructionArgs: Positional arguments to use with :py:data:`theType` to
create an instance of it.
"""
self.assertEqual(theType.__name__, name)
self.assertTrue(isinstance(theType, type))
instance = theType(*constructionArgs)
self.assertIdentical(type(instance), theType)
class EqualityTestsMixin(object):
"""
A mixin defining tests for the standard implementation of C{==} and C{!=}.
"""
def anInstance(self):
"""
Return an instance of the class under test. Each call to this method
must return a different object. All objects returned must be equal to
each other.
"""
raise NotImplementedError()
def anotherInstance(self):
"""
Return an instance of the class under test. Each call to this method
must return a different object. The objects must not be equal to the
objects returned by C{anInstance}. They may or may not be equal to
each other (they will not be compared against each other).
"""
raise NotImplementedError()
def test_identicalEq(self):
"""
An object compares equal to itself using the C{==} operator.
"""
o = self.anInstance()
self.assertTrue(o == o)
def test_identicalNe(self):
"""
An object doesn't compare not equal to itself using the C{!=} operator.
"""
o = self.anInstance()
self.assertFalse(o != o)
def test_sameEq(self):
"""
Two objects that are equal to each other compare equal to each other
using the C{==} operator.
"""
a = self.anInstance()
b = self.anInstance()
self.assertTrue(a == b)
def test_sameNe(self):
"""
Two objects that are equal to each other do not compare not equal to
each other using the C{!=} operator.
"""
a = self.anInstance()
b = self.anInstance()
self.assertFalse(a != b)
def test_differentEq(self):
"""
Two objects that are not equal to each other do not compare equal to
each other using the C{==} operator.
"""
a = self.anInstance()
b = self.anotherInstance()
self.assertFalse(a == b)
def test_differentNe(self):
"""
Two objects that are not equal to each other compare not equal to each
other using the C{!=} operator.
"""
a = self.anInstance()
b = self.anotherInstance()
self.assertTrue(a != b)
def test_anotherTypeEq(self):
"""
The object does not compare equal to an object of an unrelated type
(which does not implement the comparison) using the C{==} operator.
"""
a = self.anInstance()
b = object()
self.assertFalse(a == b)
def test_anotherTypeNe(self):
"""
The object compares not equal to an object of an unrelated type (which
does not implement the comparison) using the C{!=} operator.
"""
a = self.anInstance()
b = object()
self.assertTrue(a != b)
def test_delegatedEq(self):
"""
The result of comparison using C{==} is delegated to the right-hand
operand if it is of an unrelated type.
"""
class Delegate(object):
def __eq__(self, other):
# Do something crazy and obvious.
return [self]
a = self.anInstance()
b = Delegate()
self.assertEqual(a == b, [b])
def test_delegateNe(self):
"""
The result of comparison using C{!=} is delegated to the right-hand
operand if it is of an unrelated type.
"""
class Delegate(object):
def __ne__(self, other):
# Do something crazy and obvious.
return [self]
a = self.anInstance()
b = Delegate()
self.assertEqual(a != b, [b])
# The type name expected in warnings about using the wrong string type.
if PY3:
WARNING_TYPE_EXPECTED = "str"
else:
WARNING_TYPE_EXPECTED = "unicode"
from OpenSSL import SSL
_ssl = SSL
del SSL
import threading
_RLock = threading.RLock
del threading
class Connection:
def __init__(self, *args):
self._ssl_conn = _ssl.Connection(*args)
self._lock = _RLock()
for f in ('get_context', 'pending', 'send', 'write', 'recv', 'read',
'renegotiate', 'bind', 'listen', 'connect', 'accept',
'setblocking', 'fileno', 'shutdown', 'close', 'get_cipher_list',
'getpeername', 'getsockname', 'getsockopt', 'setsockopt',
'makefile', 'get_app_data', 'set_app_data', 'state_string',
'sock_shutdown', 'get_peer_certificate', 'get_peer_cert_chain', 'want_read',
'want_write', 'set_connect_state', 'set_accept_state',
'connect_ex', 'sendall'):
exec("""def %s(self, *args):
self._lock.acquire()
try:
return self._ssl_conn.%s(*args)
finally:
self._lock.release()\n""" % (f, f))
# Copyright (C) AB Strakt
# Copyright (C) Jean-Paul Calderone
# See LICENSE for details.
"""
pyOpenSSL - A simple wrapper around the OpenSSL library
"""
__version__ = '0.15.1'
...@@ -26,7 +26,7 @@ Video File Manager for TV Shows, It watches for new episodes of your favorite sh ...@@ -26,7 +26,7 @@ Video File Manager for TV Shows, It watches for new episodes of your favorite sh
-[Mobile](http://imgur.com/a/WPyG6) -[Mobile](http://imgur.com/a/WPyG6)
## Dependencies ## Dependencies
To run SickRage from source you will need Python 2.6+ and Cheetah 2.1.0+. To run SickRage from source you will need Python 2.6+, Cheetah 2.1.0+, and PyOpenSSL 0.13.1 or lower.
## Forums ## Forums
Any questions or setup info your looking for can be found at out forums https://www.sickrage.tv Any questions or setup info your looking for can be found at out forums https://www.sickrage.tv
......
...@@ -31,13 +31,22 @@ enabled_sni = True ...@@ -31,13 +31,22 @@ enabled_sni = True
if sys.version_info < (2, 7, 9): if sys.version_info < (2, 7, 9):
try: try:
import cryptography import cryptography
except ImportError:
try:
from OpenSSL.version import __version__ as pyOpenSSL_Version
if int(pyOpenSSL_Version.replace('.', '')[:3]) > 13:
raise ImportError
except ImportError: except ImportError:
enabled_sni = False enabled_sni = False
class SNI_Tests(unittest.TestCase): class SNI_Tests(unittest.TestCase):
def test_SNI_URLS(self): def test_SNI_URLS(self):
if not enabled_sni: if not enabled_sni:
print("\nSNI is disabled when the cryptography module is missing, you may encounter SSL errors!") print('\nSNI is disabled with pyOpenSSL >= 0.14 when the cryptography module is missing,\n' +
'you will encounter SSL errors with HTTPS! To fix this issue:\n' +
'pip install pyopenssl==0.13.1 (easy) or pip install cryptography (pita)')
print
else: else:
for provider in [ torrentday, rarbg, sceneaccess ]: for provider in [ torrentday, rarbg, sceneaccess ]:
#print 'Checking ' + provider.name #print 'Checking ' + provider.name
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment