<commit_before>"""
FormWizard class -- implements a multi-page form, validating between each
step and storing the form's state as HTML hidden fields so that no state is
stored on the server side.
"""

import cPickle as pickle

from django import forms
from django.conf import settings
from django.contrib.formtools.utils import security_hash, form_hmac
from django.http import Http404
from django.shortcuts import render_to_response
from django.template.context import RequestContext
from django.utils.crypto import constant_time_compare
from django.utils.hashcompat import md5_constructor
from django.utils.translation import ugettext_lazy as _
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_protect


class FormWizard(object):
    # The HTML (and POST data) field name for the "step" variable.
    step_field_name="wizard_step"

    # METHODS SUBCLASSES SHOULDN'T OVERRIDE ###################################

    def __init__(self, form_list, initial=None):
        """
        Start a new wizard with a list of forms.

        form_list should be a list of Form classes (not instances).
        """
        self.form_list = form_list[:]
        self.initial = initial or {}

        # Dictionary of extra template context variables.
        self.extra_context = {}

        # A zero-based counter keeping track of which step we're in.
        self.step = 0

    def __repr__(self):
        return "step: %d\nform_list: %s\ninitial_data: %s" % (self.step, self.form_list, self.initial)

    def get_form(self, step, data=None):
        "Helper method that returns the Form instance for the given step."
        return self.form_list[step](data, prefix=self.prefix_for_step(step), initial=self.initial.get(step, None))

    def num_steps(self):
        "Helper method that returns the number of steps."
        # You might think we should just set "self.num_steps = len(form_list)"
        # in __init__(), but this calculation needs to be dynamic, because some
        # hook methods might alter self.form_list.
        return len(self.form_list)

    def _check_security_hash(self, token, request, form):
        expected = self.security_hash(request, form)
        if constant_time_compare(token, expected):
            return True
        else:
            # Fall back to Django 1.2 method, for compatibility with forms that
            # are in the middle of being used when the upgrade occurs. However,
            # we don't want to do this fallback if a subclass has provided their
            # own security_hash method - because they might have implemented a
            # more secure method, and this would punch a hole in that.

            # PendingDeprecationWarning <- left here to remind us that this
            # compatibility fallback should be removed in Django 1.5
            FormWizard_expected = FormWizard.security_hash(self, request, form)
            if expected == FormWizard_expected:
                # They didn't override security_hash, do the fallback:
                old_expected = security_hash(request, form)
                return constant_time_compare(token, old_expected)
            else:
                return False

    @method_decorator(csrf_protect)
    def __call__(self, request, *args, **kwargs):
        """
        Main method that does all the hard work, conforming to the Django view
        interface.
        """
        if 'extra_context' in kwargs:
            self.extra_context.update(kwargs['extra_context'])
        current_step = self.determine_step(request, *args, **kwargs)
        self.parse_params(request, *args, **kwargs)

        # Sanity check.
        if current_step >= self.num_steps():
            raise Http404('Step %s does not exist' % current_step)

        # Process the current step. If it's valid, go to the next step or call
        # done(), depending on whether any steps remain.
        if request.method == 'POST':
            form = self.get_form(current_step, request.POST)
        else:
            form = self.get_form(current_step)

        if form.is_valid():
            # Validate all the forms. If any of them fail validation, that
            # must mean the validator relied on some other input, such as
            # an external Web site.

            # It is also possible that validation might fail under certain
            # attack situations: an attacker might be able to bypass previous
            # stages, and generate correct security hashes for all the
            # skipped stages by virtue of:
            #  1) having filled out an identical form which doesn't have the
            #     validation (and does something different at the end),
            #  2) or having filled out a previous version of the same form
            #     which had some validation missing,
            #  3) or previously having filled out the form when they had
            #     more privileges than they do now.
            #
            # Since the hashes only take into account values, and not other
            # other validation the form might do, we must re-do validation
            # now for security reasons.
            current_form_list = [self.get_form(i, request.POST) for i in range(current_step)]

            for i, f in enumerate(current_form_list):
                if not self._check_security_hash(request.POST.get("hash_%d" % i, ''), request, f):
                    return self.render_hash_failure(request, i)

                if not f.is_valid():
                    return self.render_revalidation_failure(request, i, f)
                else:
                    self.process_step(request, f, i)

            # Now progress to processing this step:
            self.process_step(request, form, current_step)
            next_step = current_step + 1

            if current_step == self.num_steps():
                return self.done(request, final_form_list)
            else:
                form = self.get_form(next_step)
                self.step = current_step = next_step

        return self.render(form, request, current_step)

    def render(self, form, request, step, context=None):
        "Renders the given Form object, returning an HttpResponse."
        old_data = request.POST
        prev_fields = []
        if old_data:
            hidden = forms.HiddenInput()<commit_msg>Fixed bug and test failure introducted in [14290]<commit_after>"""
FormWizard class -- implements a multi-page form, validating between each
step and storing the form's state as HTML hidden fields so that no state is
stored on the server side.
"""

import cPickle as pickle

from django import forms
from django.conf import settings
from django.contrib.formtools.utils import security_hash, form_hmac
from django.http import Http404
from django.shortcuts import render_to_response
from django.template.context import RequestContext
from django.utils.crypto import constant_time_compare
from django.utils.hashcompat import md5_constructor
from django.utils.translation import ugettext_lazy as _
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_protect


class FormWizard(object):
    # The HTML (and POST data) field name for the "step" variable.
    step_field_name="wizard_step"

    # METHODS SUBCLASSES SHOULDN'T OVERRIDE ###################################

    def __init__(self, form_list, initial=None):
        """
        Start a new wizard with a list of forms.

        form_list should be a list of Form classes (not instances).
        """
        self.form_list = form_list[:]
        self.initial = initial or {}

        # Dictionary of extra template context variables.
        self.extra_context = {}

        # A zero-based counter keeping track of which step we're in.
        self.step = 0

    def __repr__(self):
        return "step: %d\nform_list: %s\ninitial_data: %s" % (self.step, self.form_list, self.initial)

    def get_form(self, step, data=None):
        "Helper method that returns the Form instance for the given step."
        return self.form_list[step](data, prefix=self.prefix_for_step(step), initial=self.initial.get(step, None))

    def num_steps(self):
        "Helper method that returns the number of steps."
        # You might think we should just set "self.num_steps = len(form_list)"
        # in __init__(), but this calculation needs to be dynamic, because some
        # hook methods might alter self.form_list.
        return len(self.form_list)

    def _check_security_hash(self, token, request, form):
        expected = self.security_hash(request, form)
        if constant_time_compare(token, expected):
            return True
        else:
            # Fall back to Django 1.2 method, for compatibility with forms that
            # are in the middle of being used when the upgrade occurs. However,
            # we don't want to do this fallback if a subclass has provided their
            # own security_hash method - because they might have implemented a
            # more secure method, and this would punch a hole in that.

            # PendingDeprecationWarning <- left here to remind us that this
            # compatibility fallback should be removed in Django 1.5
            FormWizard_expected = FormWizard.security_hash(self, request, form)
            if expected == FormWizard_expected:
                # They didn't override security_hash, do the fallback:
                old_expected = security_hash(request, form)
                return constant_time_compare(token, old_expected)
            else:
                return False

    @method_decorator(csrf_protect)
    def __call__(self, request, *args, **kwargs):
        """
        Main method that does all the hard work, conforming to the Django view
        interface.
        """
        if 'extra_context' in kwargs:
            self.extra_context.update(kwargs['extra_context'])
        current_step = self.determine_step(request, *args, **kwargs)
        self.parse_params(request, *args, **kwargs)

        # Sanity check.
        if current_step >= self.num_steps():
            raise Http404('Step %s does not exist' % current_step)

        # Process the current step. If it's valid, go to the next step or call
        # done(), depending on whether any steps remain.
        if request.method == 'POST':
            form = self.get_form(current_step, request.POST)
        else:
            form = self.get_form(current_step)

        if form.is_valid():
            # Validate all the forms. If any of them fail validation, that
            # must mean the validator relied on some other input, such as
            # an external Web site.

            # It is also possible that validation might fail under certain
            # attack situations: an attacker might be able to bypass previous
            # stages, and generate correct security hashes for all the
            # skipped stages by virtue of:
            #  1) having filled out an identical form which doesn't have the
            #     validation (and does something different at the end),
            #  2) or having filled out a previous version of the same form
            #     which had some validation missing,
            #  3) or previously having filled out the form when they had
            #     more privileges than they do now.
            #
            # Since the hashes only take into account values, and not other
            # other validation the form might do, we must re-do validation
            # now for security reasons.
            current_form_list = [self.get_form(i, request.POST) for i in range(current_step)]

            for i, f in enumerate(current_form_list):
                if not self._check_security_hash(request.POST.get("hash_%d" % i, ''), request, f):
                    return self.render_hash_failure(request, i)

                if not f.is_valid():
                    return self.render_revalidation_failure(request, i, f)
                else:
                    self.process_step(request, f, i)

            # Now progress to processing this step:
            self.process_step(request, form, current_step)
            next_step = current_step + 1

            if next_step == self.num_steps():
                return self.done(request, current_form_list)
            else:
                form = self.get_form(next_step)
                self.step = current_step = next_step

        return self.render(form, request, current_step)

    def render(self, form, request, step, context=None):
        "Renders the given Form object, returning an HttpResponse."
        old_data = request.POST
        prev_fields = []
        if old_data:
            hidden = forms.HiddenInput()
{'fraction_non_alphanumeric': 0.07543323139653414, 'fraction_numerical': 0.002901278130635929, 'mean_word_length': 2.368726888536714, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1989071', 'n_tokens_mistral': 3364, 'n_tokens_neox': 3219, 'n_words': 1238}