diff --git a/test/Django-2.1.15/django/exceptions.py b/test/Django-2.1.15/django/exceptions.py new file mode 100644 index 0000000..0e85397 --- /dev/null +++ b/test/Django-2.1.15/django/exceptions.py @@ -0,0 +1,183 @@ +""" +Global Django exception and warning classes. +""" + + +class FieldDoesNotExist(Exception): + """The requested model field does not exist""" + pass + + +class AppRegistryNotReady(Exception): + """The django.apps registry is not populated yet""" + pass + + +class ObjectDoesNotExist(Exception): + """The requested object does not exist""" + silent_variable_failure = True + + +class MultipleObjectsReturned(Exception): + """The query returned multiple objects when only one was expected.""" + pass + + +class SuspiciousOperation(Exception): + """The user did something suspicious""" + + +class SuspiciousMultipartForm(SuspiciousOperation): + """Suspect MIME request in multipart form data""" + pass + + +class SuspiciousFileOperation(SuspiciousOperation): + """A Suspicious filesystem operation was attempted""" + pass + + +class DisallowedHost(SuspiciousOperation): + """HTTP_HOST header contains invalid value""" + pass + + +class DisallowedRedirect(SuspiciousOperation): + """Redirect to scheme not in allowed list""" + pass + + +class TooManyFieldsSent(SuspiciousOperation): + """ + The number of fields in a GET or POST request exceeded + settings.DATA_UPLOAD_MAX_NUMBER_FIELDS. + """ + pass + + +class RequestDataTooBig(SuspiciousOperation): + """ + The size of the request (excluding any file uploads) exceeded + settings.DATA_UPLOAD_MAX_MEMORY_SIZE. + """ + pass + + +class PermissionDenied(Exception): + """The user did not have permission to do that""" + pass + + +class ViewDoesNotExist(Exception): + """The requested view does not exist""" + pass + + +class MiddlewareNotUsed(Exception): + """This middleware is not used in this server configuration""" + pass + + +class ImproperlyConfigured(Exception): + """Django is somehow improperly configured""" + pass + + +class FieldError(Exception): + """Some kind of problem with a model field.""" + pass + + +NON_FIELD_ERRORS = '__all__' + + +class ValidationError(Exception): + """An error while validating data.""" + def __init__(self, message, code=None, params=None): + """ + The `message` argument can be a single error, a list of errors, or a + dictionary that maps field names to lists of errors. What we define as + an "error" can be either a simple string or an instance of + ValidationError with its message attribute set, and what we define as + list or dictionary can be an actual `list` or `dict` or an instance + of ValidationError with its `error_list` or `error_dict` attribute set. + """ + super().__init__(message, code, params) + + if isinstance(message, ValidationError): + if hasattr(message, 'error_dict'): + message = message.error_dict + elif not hasattr(message, 'message'): + message = message.error_list + else: + message, code, params = message.message, message.code, message.params + + if isinstance(message, dict): + self.error_dict = {} + for field, messages in message.items(): + if not isinstance(messages, ValidationError): + messages = ValidationError(messages) + self.error_dict[field] = messages.error_list + + elif isinstance(message, list): + self.error_list = [] + for message in message: + # Normalize plain strings to instances of ValidationError. + if not isinstance(message, ValidationError): + message = ValidationError(message) + if hasattr(message, 'error_dict'): + self.error_list.extend(sum(message.error_dict.values(), [])) + else: + self.error_list.extend(message.error_list) + + else: + self.message = message + self.code = code + self.params = params + self.error_list = [self] + + @property + def message_dict(self): + # Trigger an AttributeError if this ValidationError + # doesn't have an error_dict. + getattr(self, 'error_dict') + + return dict(self) + + @property + def messages(self): + if hasattr(self, 'error_dict'): + return sum(dict(self).values(), []) + return list(self) + + def update_error_dict(self, error_dict): + if hasattr(self, 'error_dict'): + for field, error_list in self.error_dict.items(): + error_dict.setdefault(field, []).extend(error_list) + else: + error_dict.setdefault(NON_FIELD_ERRORS, []).extend(self.error_list) + return error_dict + + def __iter__(self): + if hasattr(self, 'error_dict'): + for field, errors in self.error_dict.items(): + yield field, list(ValidationError(errors)) + else: + for error in self.error_list: + message = error.message + if error.params: + message %= error.params + yield str(message) + + def __str__(self): + if hasattr(self, 'error_dict'): + return repr(dict(self)) + return repr(list(self)) + + def __repr__(self): + return 'ValidationError(%s)' % self + + +class EmptyResultSet(Exception): + """A database query predicate is impossible.""" + pass diff --git a/test/Django-2.1.15/django/paginator.py b/test/Django-2.1.15/django/paginator.py new file mode 100644 index 0000000..4af80a2 --- /dev/null +++ b/test/Django-2.1.15/django/paginator.py @@ -0,0 +1,187 @@ +import collections.abc +import warnings +from math import ceil + +from django.utils.functional import cached_property +from django.utils.translation import gettext_lazy as _ + + +class UnorderedObjectListWarning(RuntimeWarning): + pass + + +class InvalidPage(Exception): + pass + + +class PageNotAnInteger(InvalidPage): + pass + + +class EmptyPage(InvalidPage): + pass + + +class Paginator: + + def __init__(self, object_list, per_page, orphans=0, + allow_empty_first_page=True): + self.object_list = object_list + self._check_object_list_is_ordered() + self.per_page = int(per_page) + self.orphans = int(orphans) + self.allow_empty_first_page = allow_empty_first_page + + def validate_number(self, number): + """Validate the given 1-based page number.""" + try: + if isinstance(number, float) and not number.is_integer(): + raise ValueError + number = int(number) + except (TypeError, ValueError): + raise PageNotAnInteger(_('That page number is not an integer')) + if number < 1: + raise EmptyPage(_('That page number is less than 1')) + if number > self.num_pages: + if number == 1 and self.allow_empty_first_page: + pass + else: + raise EmptyPage(_('That page contains no results')) + return number + + def get_page(self, number): + """ + Return a valid page, even if the page argument isn't a number or isn't + in range. + """ + try: + number = self.validate_number(number) + except PageNotAnInteger: + number = 1 + except EmptyPage: + number = self.num_pages + return self.page(number) + + def page(self, number): + """Return a Page object for the given 1-based page number.""" + number = self.validate_number(number) + bottom = (number - 1) * self.per_page + top = bottom + self.per_page + if top + self.orphans >= self.count: + top = self.count + return self._get_page(self.object_list[bottom:top], number, self) + + def _get_page(self, *args, **kwargs): + """ + Return an instance of a single page. + + This hook can be used by subclasses to use an alternative to the + standard :cls:`Page` object. + """ + return Page(*args, **kwargs) + + @cached_property + def count(self): + """Return the total number of objects, across all pages.""" + try: + return self.object_list.count() + except (AttributeError, TypeError): + # AttributeError if object_list has no count() method. + # TypeError if object_list.count() requires arguments + # (i.e. is of type list). + return len(self.object_list) + + @cached_property + def num_pages(self): + """Return the total number of pages.""" + if self.count == 0 and not self.allow_empty_first_page: + return 0 + hits = max(1, self.count - self.orphans) + return ceil(hits / self.per_page) + + @property + def page_range(self): + """ + Return a 1-based range of pages for iterating through within + a template for loop. + """ + return range(1, self.num_pages + 1) + + def _check_object_list_is_ordered(self): + """ + Warn if self.object_list is unordered (typically a QuerySet). + """ + ordered = getattr(self.object_list, 'ordered', None) + if ordered is not None and not ordered: + obj_list_repr = ( + '{} {}'.format(self.object_list.model, self.object_list.__class__.__name__) + if hasattr(self.object_list, 'model') + else '{!r}'.format(self.object_list) + ) + warnings.warn( + 'Pagination may yield inconsistent results with an unordered ' + 'object_list: {}.'.format(obj_list_repr), + UnorderedObjectListWarning, + stacklevel=3 + ) + + +QuerySetPaginator = Paginator # For backwards-compatibility. + + +class Page(collections.abc.Sequence): + + def __init__(self, object_list, number, paginator): + self.object_list = object_list + self.number = number + self.paginator = paginator + + def __repr__(self): + return '' % (self.number, self.paginator.num_pages) + + def __len__(self): + return len(self.object_list) + + def __getitem__(self, index): + if not isinstance(index, (int, slice)): + raise TypeError + # The object_list is converted to a list so that if it was a QuerySet + # it won't be a database hit per __getitem__. + if not isinstance(self.object_list, list): + self.object_list = list(self.object_list) + return self.object_list[index] + + def has_next(self): + return self.number < self.paginator.num_pages + + def has_previous(self): + return self.number > 1 + + def has_other_pages(self): + return self.has_previous() or self.has_next() + + def next_page_number(self): + return self.paginator.validate_number(self.number + 1) + + def previous_page_number(self): + return self.paginator.validate_number(self.number - 1) + + def start_index(self): + """ + Return the 1-based index of the first object on this page, + relative to total objects in the paginator. + """ + # Special case, return zero if no items. + if self.paginator.count == 0: + return 0 + return (self.paginator.per_page * (self.number - 1)) + 1 + + def end_index(self): + """ + Return the 1-based index of the last object on this page, + relative to total objects found (hits). + """ + # Special case for the last page because there can be orphans. + if self.number == self.paginator.num_pages: + return self.paginator.count + return self.number * self.paginator.per_page diff --git a/test/Django-2.1.15/django/signals.py b/test/Django-2.1.15/django/signals.py new file mode 100644 index 0000000..5d9618d --- /dev/null +++ b/test/Django-2.1.15/django/signals.py @@ -0,0 +1,6 @@ +from django.dispatch import Signal + +request_started = Signal(providing_args=["environ"]) +request_finished = Signal() +got_request_exception = Signal(providing_args=["request"]) +setting_changed = Signal(providing_args=["setting", "value", "enter"]) diff --git a/test/Django-2.1.15/django/signing.py b/test/Django-2.1.15/django/signing.py new file mode 100644 index 0000000..1e92838 --- /dev/null +++ b/test/Django-2.1.15/django/signing.py @@ -0,0 +1,198 @@ +""" +Functions for creating and restoring url-safe signed JSON objects. + +The format used looks like this: + +>>> signing.dumps("hello") +'ImhlbGxvIg:1QaUZC:YIye-ze3TTx7gtSv422nZA4sgmk' + +There are two components here, separated by a ':'. The first component is a +URLsafe base64 encoded JSON of the object passed to dumps(). The second +component is a base64 encoded hmac/SHA1 hash of "$first_component:$secret" + +signing.loads(s) checks the signature and returns the deserialized object. +If the signature fails, a BadSignature exception is raised. + +>>> signing.loads("ImhlbGxvIg:1QaUZC:YIye-ze3TTx7gtSv422nZA4sgmk") +'hello' +>>> signing.loads("ImhlbGxvIg:1QaUZC:YIye-ze3TTx7gtSv422nZA4sgmk-modified") +... +BadSignature: Signature failed: ImhlbGxvIg:1QaUZC:YIye-ze3TTx7gtSv422nZA4sgmk-modified + +You can optionally compress the JSON prior to base64 encoding it to save +space, using the compress=True argument. This checks if compression actually +helps and only applies compression if the result is a shorter string: + +>>> signing.dumps(list(range(1, 20)), compress=True) +'.eJwFwcERACAIwLCF-rCiILN47r-GyZVJsNgkxaFxoDgxcOHGxMKD_T7vhAml:1QaUaL:BA0thEZrp4FQVXIXuOvYJtLJSrQ' + +The fact that the string is compressed is signalled by the prefixed '.' at the +start of the base64 JSON. + +There are 65 url-safe characters: the 64 used by url-safe base64 and the ':'. +These functions make use of all of them. +""" + +import base64 +import datetime +import json +import re +import time +import zlib + +from django.conf import settings +from django.utils import baseconv +from django.utils.crypto import constant_time_compare, salted_hmac +from django.utils.encoding import force_bytes +from django.utils.module_loading import import_string + +_SEP_UNSAFE = re.compile(r'^[A-z0-9-_=]*$') + + +class BadSignature(Exception): + """Signature does not match.""" + pass + + +class SignatureExpired(BadSignature): + """Signature timestamp is older than required max_age.""" + pass + + +def b64_encode(s): + return base64.urlsafe_b64encode(s).strip(b'=') + + +def b64_decode(s): + pad = b'=' * (-len(s) % 4) + return base64.urlsafe_b64decode(s + pad) + + +def base64_hmac(salt, value, key): + return b64_encode(salted_hmac(salt, value, key).digest()).decode() + + +def get_cookie_signer(salt='django.core.signing.get_cookie_signer'): + Signer = import_string(settings.SIGNING_BACKEND) + key = force_bytes(settings.SECRET_KEY) # SECRET_KEY may be str or bytes. + return Signer(b'django.http.cookies' + key, salt=salt) + + +class JSONSerializer: + """ + Simple wrapper around json to be used in signing.dumps and + signing.loads. + """ + def dumps(self, obj): + return json.dumps(obj, separators=(',', ':')).encode('latin-1') + + def loads(self, data): + return json.loads(data.decode('latin-1')) + + +def dumps(obj, key=None, salt='django.core.signing', serializer=JSONSerializer, compress=False): + """ + Return URL-safe, hmac/SHA1 signed base64 compressed JSON string. If key is + None, use settings.SECRET_KEY instead. + + If compress is True (not the default), check if compressing using zlib can + save some space. Prepend a '.' to signify compression. This is included + in the signature, to protect against zip bombs. + + Salt can be used to namespace the hash, so that a signed string is + only valid for a given namespace. Leaving this at the default + value or re-using a salt value across different parts of your + application without good cause is a security risk. + + The serializer is expected to return a bytestring. + """ + data = serializer().dumps(obj) + + # Flag for if it's been compressed or not + is_compressed = False + + if compress: + # Avoid zlib dependency unless compress is being used + compressed = zlib.compress(data) + if len(compressed) < (len(data) - 1): + data = compressed + is_compressed = True + base64d = b64_encode(data).decode() + if is_compressed: + base64d = '.' + base64d + return TimestampSigner(key, salt=salt).sign(base64d) + + +def loads(s, key=None, salt='django.core.signing', serializer=JSONSerializer, max_age=None): + """ + Reverse of dumps(), raise BadSignature if signature fails. + + The serializer is expected to accept a bytestring. + """ + # TimestampSigner.unsign() returns str but base64 and zlib compression + # operate on bytes. + base64d = TimestampSigner(key, salt=salt).unsign(s, max_age=max_age).encode() + decompress = base64d[:1] == b'.' + if decompress: + # It's compressed; uncompress it first + base64d = base64d[1:] + data = b64_decode(base64d) + if decompress: + data = zlib.decompress(data) + return serializer().loads(data) + + +class Signer: + + def __init__(self, key=None, sep=':', salt=None): + # Use of native strings in all versions of Python + self.key = key or settings.SECRET_KEY + self.sep = sep + if _SEP_UNSAFE.match(self.sep): + raise ValueError( + 'Unsafe Signer separator: %r (cannot be empty or consist of ' + 'only A-z0-9-_=)' % sep, + ) + self.salt = salt or '%s.%s' % (self.__class__.__module__, self.__class__.__name__) + + def signature(self, value): + return base64_hmac(self.salt + 'signer', value, self.key) + + def sign(self, value): + return '%s%s%s' % (value, self.sep, self.signature(value)) + + def unsign(self, signed_value): + if self.sep not in signed_value: + raise BadSignature('No "%s" found in value' % self.sep) + value, sig = signed_value.rsplit(self.sep, 1) + if constant_time_compare(sig, self.signature(value)): + return value + raise BadSignature('Signature "%s" does not match' % sig) + + +class TimestampSigner(Signer): + + def timestamp(self): + return baseconv.base62.encode(int(time.time())) + + def sign(self, value): + value = '%s%s%s' % (value, self.sep, self.timestamp()) + return super().sign(value) + + def unsign(self, value, max_age=None): + """ + Retrieve original value and check it wasn't signed more + than max_age seconds ago. + """ + result = super().unsign(value) + value, timestamp = result.rsplit(self.sep, 1) + timestamp = baseconv.base62.decode(timestamp) + if max_age is not None: + if isinstance(max_age, datetime.timedelta): + max_age = max_age.total_seconds() + # Check timestamp is not older than max_age + age = time.time() - timestamp + if age > max_age: + raise SignatureExpired( + 'Signature age %s > %s seconds' % (age, max_age)) + return value