Example #1
0
def enable_disable_languages(store, request):
    cur_enabled_langs = EnabledLanguage.list(store)
    new_enabled_langs = [unicode(y) for y in request['languages_enabled']]

    if len(new_enabled_langs) < 1:
        raise errors.InvalidInputFormat("No languages enabled!")

    if request['default_language'] not in new_enabled_langs:
        raise errors.InvalidInputFormat(
            "Invalid lang code for chosen default_language")

    appdata = None
    for lang_code in new_enabled_langs:
        if lang_code not in LANGUAGES_SUPPORTED_CODES:
            raise errors.InvalidInputFormat("Invalid lang code: %s" %
                                            lang_code)
        if lang_code not in cur_enabled_langs:
            if appdata is None:
                appdata = load_appdata()
            log.debug("Adding a new lang %s" % lang_code)
            EnabledLanguage.add_new_lang(store, lang_code, appdata)

    to_remove = list(set(cur_enabled_langs) - set(new_enabled_langs))

    if len(to_remove):
        users = store.find(models.User, In(models.User.language, to_remove))
        for user in users:
            user.language = request['default_language']

        EnabledLanguage.remove_old_langs(store, to_remove)
Example #2
0
def enable_disable_languages(store, request):
    cur_enabled_langs = EnabledLanguage.get_all_strings(store)
    new_enabled_langs = [unicode(y) for y in request['languages_enabled']]

    if len(new_enabled_langs) < 1:
        raise errors.InvalidInputFormat("No languages enabled!")

    if request['default_language'] not in new_enabled_langs:
        raise errors.InvalidInputFormat(
            "Invalid lang code for chosen default_language")

    appdata = None
    for lang_code in new_enabled_langs:
        if lang_code not in LANGUAGES_SUPPORTED_CODES:
            raise errors.InvalidInputFormat("Invalid lang code: %s" %
                                            lang_code)
        if lang_code not in cur_enabled_langs:
            if appdata is None:
                appdata = load_appdata()
            log.debug("Adding a new lang %s" % lang_code)
            EnabledLanguage.add_new_lang(store, lang_code, appdata)

    for lang_code in cur_enabled_langs:
        if lang_code not in new_enabled_langs:
            EnabledLanguage.remove_old_lang(store, lang_code)
Example #3
0
def db_create_context(store, request, language):
    """
    Creates a new context from the request of a client.

    We associate to the context the list of receivers and if the receiver is
    not valid we raise a ReceiverIdNotFound exception.

    Args:
        (dict) the request containing the keys to set on the model.

    Returns:
        (dict) representing the configured context
    """
    receivers = request.get('receivers', [])
    steps = request.get('steps', [])

    fill_localized_keys(request, models.Context.localized_strings, language)

    context = models.Context(request)

    # Integrity checks related on name (need to exists, need to be unique)
    # are performed only using the default language at the moment (XXX)
    try:
        context_name = request['name'][language]
    except Exception as excep:
        raise errors.InvalidInputFormat("language %s do not provide name: %s" %
                                        (language, excep))
    if len(context_name) < 1:
        log.err("Invalid request: name is an empty string")
        raise errors.InvalidInputFormat(
            "Context name is missing (1 char required)")

    if request['select_all_receivers']:
        if request['maximum_selectable_receivers']:
            log.debug(
                "Resetting maximum_selectable_receivers (%d) because 'select_all_receivers' is True"
                % request['maximum_selectable_receivers'])
        request['maximum_selectable_receivers'] = 0

    # tip_timetolive to be converted in seconds since hours and days
    context.tip_timetolive = acquire_context_timetolive(
        int(request['tip_timetolive']))

    c = store.add(context)

    for receiver_id in receivers:
        receiver = models.Receiver.get(store, receiver_id)
        if not receiver:
            log.err("Creation error: unexistent context can't be associated")
            raise errors.ReceiverIdNotFound
        c.receivers.add(receiver)

    if steps:
        db_create_steps(store, c.id, steps, language)
    else:
        db_setup_default_steps(store, c.id)

    log.debug("Created context %s (using %s)" % (context_name, language))

    return admin_serialize_context(store, context, language)
Example #4
0
def import_receivers(store, submission, receiver_id_list):
    context = submission.context

    if not len(receiver_id_list):
        raise errors.SubmissionValidationFailure(
            "needed almost one receiver selected [1]")

    if context.maximum_selectable_receivers and \
                    len(receiver_id_list) > context.maximum_selectable_receivers:
        raise errors.InvalidInputFormat(
            "provided an invalid number of receivers")

    for receiver in store.find(models.Receiver,
                               In(models.Receiver.id, receiver_id_list)):
        if context not in receiver.contexts:
            raise errors.InvalidInputFormat(
                "forged receiver selection, you fuzzer! <:")

        if not GLSettings.memory_copy.allow_unencrypted and receiver.user.pgp_key_status != u'enabled':
            raise errors.SubmissionValidationFailure(
                "the platform does not allow selection of receivers with encryption disabled"
            )
            continue

        submission.receivers.add(receiver)

        log.debug("+receiver [%s] In tip (%s) #%d" % \
                  (receiver.user.name, submission.id, submission.receivers.count() ))
    if submission.receivers.count() == 0:
        raise errors.SubmissionValidationFailure(
            "needed almost one receiver selected [2]")
Example #5
0
def associate_field(store, field, step=None, fieldgroup=None):
    """
    Associate a field to a specified step or fieldgroup

    :param store: the store on which perform queries.
    """
    if step:
        if field.is_template:
            raise errors.InvalidInputFormat(
                "Cannot associate a field template to a step")

        step.children.add(field)

    if fieldgroup:
        if field.is_template != fieldgroup.is_template:
            raise errors.InvalidInputFormat(
                "Cannot associate field templates with fields")

        ancestors = set(fieldtree_ancestors(store, field.id))

        if field.id in [field.template_id, fieldgroup.id] or \
           field.template_id == fieldgroup.id or \
           field.template_id in ancestors or \
           fieldgroup.id in ancestors:
            raise errors.InvalidInputFormat(
                "Provided field association would cause recursion loop")

        fieldgroup.children.add(field)
Example #6
0
def dict_v(_self, attr, value):
    """
    Validate dict content, every key, if unicode, have not to
    overcome the generic length limit.
    """
    if not value:
        return {}

    if not isinstance(value, dict):
        raise errors.InvalidInputFormat("(%s) dict expected" % attr)

    for key, subvalue in value.iteritems():
        if isinstance(subvalue, str):
            subvalue = unicode(subvalue)

        if isinstance(subvalue, unicode):
            if len(subvalue) > GLSettings.memory_copy.maximum_textsize:
                raise errors.InvalidInputFormat("In dict %s the key %s" \
                                                "overcome length limit of %d" % (attr, key,
                                                                                 GLSettings.memory_copy.maximum_textsize))

        if isinstance(subvalue, dict):
            dict_v(_self, attr, subvalue)

    return value
Example #7
0
def associate_field(store, field, template=None, step=None, fieldgroup=None):
    """
    Associate a field to a specified step or fieldgroup

    :param store: the store on which perform queries
    :param field: the field to be associated
    :param template: the template to which bind the field
    :param step: the step to which associate the field
    :param fieldgroup: the fieldgroup to which associate the field
    """
    if template:
        if field.instance != 'reference':
             raise errors.InvalidInputFormat("Only fields of kind reference can be binded to a template")

        field.template_id = template.id

    if step:
        if field.instance == 'template':
            raise errors.InvalidInputFormat("Cannot associate a field template to a step")

        step.children.add(field)

    if fieldgroup:
        if field.instance == 'template' and fieldgroup.instance != 'template':
            raise errors.InvalidInputFormat("Cannot associate field template to a field")

        ancestors = set(fieldtree_ancestors(store, fieldgroup.id))

        if field.id == fieldgroup.id or field.id in ancestors:
            raise errors.InvalidInputFormat("Provided field association would cause recursion loop")

        fieldgroup.children.add(field)
Example #8
0
def import_receivers(store, submission, receiver_id_list):
    context = submission.context

    if not len(receiver_id_list):
        log.err("Receivers required to be selected, not empty")
        raise errors.SubmissionValidationFailure("needed almost one receiver selected")

    if context.maximum_selectable_receivers and \
                    len(receiver_id_list) > context.maximum_selectable_receivers:
        raise errors.InvalidInputFormat("provided an invalid number of receivers")

    for receiver in store.find(Receiver, In(Receiver.id, receiver_id_list)):
        if context not in receiver.contexts:
            raise errors.InvalidInputFormat("forged receiver selection, you fuzzer! <:")

        try:
            if not GLSettings.memory_copy.allow_unencrypted and \
                            receiver.pgp_key_status != u'enabled':
                log.err("Encrypted only submissions are supported. Cannot select [%s]" % receiver.id)
                continue
            submission.receivers.add(receiver)
        except Exception as excep:
            log.err("Receiver %s can't be assigned to the tip [%s]" % (receiver.id, excep))
            continue

        log.debug("+receiver [%s] In tip (%s) #%d" % \
                  (receiver.name, submission.id, submission.receivers.count() ))
    if submission.receivers.count() == 0:
        log.err("Receivers required to be selected, not empty")
        raise errors.SubmissionValidationFailure("needed at least one receiver selected [2]")
Example #9
0
def update_notification(store,
                        request,
                        language=GLSetting.memory_copy.default_language):

    try:
        notif = store.find(Notification).one()
    except Exception as excep:
        log.err("Database error or application error: %s" % excep)
        raise excep

    mo = structures.Rosetta()
    mo.acquire_request(language, request, Notification)
    for attr in mo.get_localized_attrs():
        request[attr] = mo.get_localized_dict(attr)

    if request['security'] in Notification._security_types:
        notif.security = request['security']
    else:
        log.err("Invalid request: Security option not recognized")
        log.debug("Invalid Security value: %s" % request['security'])
        raise errors.InvalidInputFormat("Security selection not recognized")

    try:
        notif.update(request)
    except Exception as dberror:
        log.err("Unable to update Notification: %s" % dberror)
        raise errors.InvalidInputFormat(dberror)

    if request['disable'] != GLSetting.notification_temporary_disable:
        log.msg("Switching notification mode: was %s and now is %s" %
                ("DISABLE" if GLSetting.notification_temporary_disable else
                 "ENABLE", "DISABLE" if request['disable'] else "ENABLE"))
        GLSetting.notification_temporary_disable = request['disable']

    return admin_serialize_notification(notif, language)
Example #10
0
 def _on_request_body(self, data):
     try:
         self._request.body = data
         content_type = self._request.headers.get("Content-Type", "")
         if self._request.method in ("POST", "PATCH", "PUT"):
             if content_type.startswith(
                     "application/x-www-form-urlencoded"
             ) and self.content_length < GLSetting.www_form_urlencoded_maximum_size:
                 arguments = parse_qs_bytes(native_str(self._request.body))
                 for name, values in arguments.iteritems():
                     values = [v for v in values if v]
                     if values:
                         self._request.arguments.setdefault(
                             name, []).extend(values)
             elif content_type.startswith(
                     "application/x-www-form-urlencoded"):
                 raise errors.InvalidInputFormat(
                     "content type application/x-www-form-urlencoded not supported"
                 )
             elif content_type.startswith("multipart/form-data"):
                 raise errors.InvalidInputFormat(
                     "content type multipart/form-data not supported")
         self.request_callback(self._request)
     except Exception as exception:
         log.msg("Malformed HTTP request from %s: %s" %
                 (self._remote_ip, exception))
         log.exception(exception)
         if self._request:
             self._request.finish()
         if self.transport:
             self.transport.loseConnection()
Example #11
0
def update_field(store, field_id, request, language):
    """
    Update the specified field with the details.
    raises :class:`globaleaks.errors.FieldIdNotFound` if the field does
    not exist.

    :param store: the store on which perform queries.
    :param: field_id: the field_id of the field to update
    :param: request: the field definition dict
    :param: language: the language of the field definition dict
    :return: a serialization of the object
    """
    errmsg = 'Invalid or not existent field ids in request.'

    is_template, step_id, fieldgroup_id = field_integrity_check(request)

    field = models.Field.get(store, field_id)
    try:
        if not field:
            raise errors.InvalidInputFormat(errmsg)

        fill_localized_keys(request, models.Field.localized_strings, language)

        field.update(request)

        # children handling:
        #  - old children are cleared
        #  - new provided childrens are evaluated and added
        children = request['children']
        if children and field.type != 'fieldgroup':
            raise errors.InvalidInputFormat(
                "children can be associated only to fields of type fieldgroup")

        ancestors = set(fieldtree_ancestors(store, field.id))

        field.children.clear()
        for c in children:
            child = models.Field.get(store, c['id'])
            # check child do exists and graph is not recursive
            if not child or child.id == field.id or child.id in ancestors:
                raise errors.InvalidInputFormat(errmsg)

            # remove current step/field fieldgroup/field association
            disassociate_field(store, child.id)

            field.children.add(child)

        db_update_options(store, field.id, request['options'], language)

        # remove current step/field fieldgroup/field association
        disassociate_field(store, field_id)

        associate_field(store, field, step_id, fieldgroup_id)

    except Exception as dberror:
        log.err('Unable to update field: {e}'.format(e=dberror))
        raise errors.InvalidInputFormat(dberror)

    return anon_serialize_field(store, field, language)
Example #12
0
def import_receivers(store, submission, receiver_id_list, required=False):
    context = submission.context

    # Clean the previous list of selected Receiver
    for prevrec in submission.receivers:
        try:
            submission.receivers.remove(prevrec)
        except Exception as excep:
            log.err(
                "Unable to remove receiver from Tip, before new reassignment")
            raise excep

    # and now clean the received list and import the new Receiver set.
    receiver_id_list = set(receiver_id_list)

    if required and (not len(receiver_id_list)):
        log.err("Receivers required to be selected, not empty")
        raise errors.SubmissionFailFields(
            "Needed almost one Receiver selected")

    if context.maximum_selectable_receivers and \
                    len(receiver_id_list) > context.maximum_selectable_receivers:
        raise errors.InvalidInputFormat(
            "Provided an invalid number of Receivers")

    for receiver_id in receiver_id_list:
        try:
            receiver = store.find(Receiver,
                                  Receiver.id == unicode(receiver_id)).one()
        except Exception as excep:
            log.err("Receiver requested (%s) can't be found: %s" %
                    (receiver_id, excep))
            raise errors.ReceiverIdNotFound

        if context not in receiver.contexts:
            raise errors.InvalidInputFormat(
                "Forged receiver selection, you fuzzer! <:")

        try:
            if not GLSetting.memory_copy.allow_unencrypted and \
                    receiver.gpg_key_status != u'enabled':
                log.err(
                    "Encrypted only submissions are supported. Cannot select [%s]"
                    % receiver_id)
                continue
            submission.receivers.add(receiver)
        except Exception as excep:
            log.err("Receiver %s can't be assigned to the tip [%s]" %
                    (receiver_id, excep))
            continue

        log.debug("+receiver [%s] In tip (%s) #%d" %\
                (receiver.name, submission.id, submission.receivers.count() ) )

    if required and submission.receivers.count() == 0:
        log.err("Receivers required to be selected, not empty")
        raise errors.SubmissionFailFields(
            "Needed at least one Receiver selected [2]")
Example #13
0
    def validate_message(message, message_template):
        try:
            jmessage = json.loads(message)
        except ValueError:
            raise errors.InvalidInputFormat("Invalid JSON format")

        if BaseHandler.validate_jmessage(jmessage, message_template):
            return jmessage

        raise errors.InvalidInputFormat("Unexpected condition!?")
Example #14
0
def db_create_field(store, field_dict, language):
    """
    Create and add a new field to the store, then return the new serialized object.

    :param store: the store on which perform queries.
    :param field_dict: the field definition dict
    :param language: the language of the field definition dict
    :return: a serialization of the object
    """
    fill_localized_keys(field_dict, models.Field.localized_keys, language)

    field = models.Field(field_dict)

    if field_dict['template_id'] != '':
        field.template_id = field_dict['template_id']

    if field_dict['step_id'] != '':
        field.step_id = field_dict['step_id']

    if field_dict['fieldgroup_id'] != '':
        ancestors = set(fieldtree_ancestors(store,
                                            field_dict['fieldgroup_id']))

        if field.id == field_dict['fieldgroup_id'] or field.id in ancestors:
            raise errors.InvalidInputFormat(
                "Provided field association would cause recursion loop")

        field.fieldgroup_id = field_dict['fieldgroup_id']

    store.add(field)

    if field.template:
        # special handling of the whistleblower_identity field
        if field.template.key == 'whistleblower_identity':
            if field.step:
                if not field.step.questionnaire.enable_whistleblower_identity:
                    field.step.questionnaire.enable_whistleblower_identity = True
                else:
                    raise errors.InvalidInputFormat(
                        "Whistleblower identity field already present")
            else:
                raise errors.InvalidInputFormat(
                    "Cannot associate whistleblower identity field to a fieldgroup"
                )

    else:
        db_update_fieldattrs(store, field.id, field_dict['attrs'], language)
        db_update_fieldoptions(store, field.id, field_dict['options'],
                               language)

    for c in field_dict['children']:
        c['fieldgroup_id'] = field.id
        db_create_field(store, c, language)

    return field
Example #15
0
def db_create_field(store, field_dict, language):
    """
    Create and add a new field to the store, then return the new serialized object.

    :param store: the store on which perform queries.
    :param field_dict: the field definition dict
    :param language: the language of the field definition dict
    :return: a serialization of the object
    """
    fill_localized_keys(field_dict, models.Field.localized_keys, language)

    if field_dict.get('fieldgroup_id', ''):
        ancestors = set(fieldtree_ancestors(store,
                                            field_dict['fieldgroup_id']))

        if field_dict['id'] == field_dict['fieldgroup_id'] or field_dict[
                'id'] in ancestors:
            raise errors.InvalidInputFormat(
                "Provided field association would cause recursion loop")

    field = models.db_forge_obj(store, models.Field, field_dict)

    if field.template_id is not None:
        # special handling of the whistleblower_identity field
        if field.template_id == 'whistleblower_identity':
            if field.step_id is not None:
                questionnaire = store.find(
                    models.Questionnaire, models.Field.id == field.id,
                    models.Field.step_id == models.Step.id,
                    models.Step.questionnaire_id ==
                    models.Questionnaire.id).one()

                if questionnaire.enable_whistleblower_identity is False:
                    questionnaire.enable_whistleblower_identity = True
                else:
                    raise errors.InvalidInputFormat(
                        "Whistleblower identity field already present")
            else:
                raise errors.InvalidInputFormat(
                    "Cannot associate whistleblower identity field to a fieldgroup"
                )

    else:
        db_update_fieldattrs(store, field, field_dict.get('attrs', []),
                             language)
        db_update_fieldoptions(store, field, field_dict.get('options', []),
                               language)

    if field.instance != 'reference':
        for c in field_dict.get('children', []):
            c['fieldgroup_id'] = field.id
            db_create_field(store, c, language)

    return field
Example #16
0
    def validate_jmessage(jmessage, message_template):
        """
        Takes a string that represents a JSON messages and checks to see if it
        conforms to the message type it is supposed to be.

        This message must be either a dict or a list. This function may be called
        recursively to validate sub-parameters that are also go GLType.

        message: the message string that should be validated

        message_type: the GLType class it should match.
        """
        if isinstance(message_template, dict):
            valid_jmessage = {}
            for key in message_template.keys():
                if key not in jmessage:
                    log.err('validate_message: key %s not in %s' %
                            (key, jmessage))
                    raise errors.InvalidInputFormat(
                        'wrong schema: missing %s' % key)
                else:
                    valid_jmessage[key] = jmessage[key]

            if GLSetting.loglevel == "DEBUG":
                # check if wrong keys are reaching the GLBackend, they are
                # stripped in the previous loop, because valid_jmessage is returned
                for double_k in jmessage.keys():
                    if double_k not in message_template.keys():
                        log.err("[!?] validate_message: key %s not expected" %
                                double_k)

            jmessage = valid_jmessage

            for key, value in message_template.iteritems():
                if not BaseHandler.validate_type(jmessage[key], value):
                    raise errors.InvalidInputFormat(
                        "REST integrity check 1, fail in %s" % key)

            for key, value in jmessage.iteritems():
                if not BaseHandler.validate_type(value, message_template[key]):
                    raise errors.InvalidInputFormat(
                        "REST integrity check 2, fail in %s" % key)

            return True

        elif isinstance(message_template, list):
            return all(
                BaseHandler.validate_type(x, message_template[0])
                for x in jmessage)

        else:
            raise errors.InvalidInputFormat(
                "invalid json massage: expected dict or list")
Example #17
0
    def sanitize_gpg_string(self, received_gpgasc):
        """
        @param received_gpgasc: A gpg armored key
        @return: Sanitized string or raise InvalidInputFormat

        This function validate the integrity of a GPG key
        """
        lines = received_gpgasc.split("\n")
        sanitized = ""

        start = 0
        if not len(lines[start]):
            start += 1

        if lines[start] != '-----BEGIN PGP PUBLIC KEY BLOCK-----':
            raise errors.InvalidInputFormat("GPG invalid format")
        else:
            sanitized += lines[start] + "\n"

        i = 0
        while i < len(lines):

            # the C language as left some archetypes in my code
            # [ITA] https://www.youtube.com/watch?v=7jI4DnRJP3k
            i += 1

            try:
                if len(lines[i]) < 2:
                    continue
            except IndexError:
                continue

            main_content = re.compile(
                r"^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$",
                re.UNICODE)
            base64only = main_content.findall(lines[i])

            if len(base64only) == 1:
                sanitized += str(base64only[0]) + "\n"

            # this GPG/PGP format it's different from the common base64 ? dunno
            if len(lines[i]) == 5 and lines[i][0] == '=':
                sanitized += str(lines[i]) + "\n"

            if lines[i] == '-----END PGP PUBLIC KEY BLOCK-----':
                sanitized += lines[i] + "\n"
                return sanitized

        raise errors.InvalidInputFormat("Malformed PGP key block")
Example #18
0
def update_step(store, step_id, request, language):
    """
    Update the specified step with the details.
    raises :class:`globaleaks.errors.StepIdNotFound` if the step does
    not exist.

    :param store: the store on which perform queries.
    :param step_id: the step_id of the step to update
    :param request: the step definition dict
    :param language: the language of the step definition dict
    :return: a serialization of the object
    """
    step = models.Step.get(store, step_id)
    try:
        if not step:
            raise errors.StepIdNotFound

        fill_localized_keys(request, models.Step.localized_strings, language)

        step.update(request)

        for child in request['children']:
            db_update_field(store, child['id'], child, language)

    except Exception as dberror:
        log.err('Unable to update step: {e}'.format(e=dberror))
        raise errors.InvalidInputFormat(dberror)

    return anon_serialize_step(store, step, language)
Example #19
0
def update_context(store, context_id, request, language):
    """
    Updates the specified context. If the key receivers is specified we remove
    the current receivers of the Context and reset set it to the new specified
    ones.
    If no such context exists raises :class:`globaleaks.errors.ContextIdNotFound`.

    Args:
        context_id:

        request:
            (dict) the request to use to set the attributes of the Context

    Returns:
            (dict) the serialized object updated
    """
    context = store.find(models.Context, models.Context.id == context_id).one()

    if not context:
        raise errors.ContextIdNotFound

    receivers = request.get('receivers', [])
    steps = request.get('steps', [])

    fill_localized_keys(request, models.Context.localized_strings, language)

    for receiver in context.receivers:
        context.receivers.remove(receiver)

    for receiver_id in receivers:
        receiver = store.find(models.Receiver,
                              models.Receiver.id == receiver_id).one()
        if not receiver:
            log.err("Update error: unexistent receiver can't be associated")
            raise errors.ReceiverIdNotFound
        context.receivers.add(receiver)

    context.tip_timetolive = acquire_context_timetolive(
        int(request['tip_timetolive']))

    if request['select_all_receivers']:
        if request['maximum_selectable_receivers']:
            log.debug(
                "Resetting maximum_selectable_receivers (%d) because 'select_all_receivers' is True"
                % request['maximum_selectable_receivers'])
        request['maximum_selectable_receivers'] = 0

    try:
        context.update(request)
    except DatabaseError as dberror:
        log.err("Unable to update context %s: %s" % (context.name, dberror))
        raise errors.InvalidInputFormat(dberror)

    if request['reset_steps']:
        db_update_steps(store, context.id, [], language)
        db_setup_default_steps(store, context.id)
    else:
        db_update_steps(store, context.id, steps, language)

    return admin_serialize_context(store, context, language)
Example #20
0
def shorttext_v(_self, _attr, value):
    """
    Validator for 'name' element, receiver, context, node, and few others
        are here checked
    """
    if isinstance(value, str):
        value = unicode(value)

    if not isinstance(value, unicode):
        raise errors.InvalidInputFormat("Name expected unicode (%s)" % value)

    if len(value) > GLSetting.memory_copy.maximum_namesize:
        raise errors.InvalidInputFormat("Name length need to be < of %d"
                                        % GLSetting.memory_copy.maximum_namesize)

    return value
Example #21
0
def verify_fields_recursively(fields, wb_fields):
    for f in fields:
        if f not in wb_fields:
            raise errors.SubmissionFailFields(
                "missing field (no structure present): %s" % f)

        if fields[f]['required'] and ('value' not in wb_fields[f]
                                      or wb_fields[f]['value'] == ''):
            raise errors.SubmissionFailFields(
                "missing required field (no value provided): %s" % f)

        if isinstance(wb_fields[f]['value'], unicode):
            if len(wb_fields[f]
                   ['value']) > GLSetting.memory_copy.maximum_textsize:
                raise errors.InvalidInputFormat(
                    "field value overcomes size limitation")

        indexed_fields = {}
        for f_c in fields[f]['children']:
            indexed_fields[f_c['id']] = copy.deepcopy(f_c)

        indexed_wb_fields = {}
        for f_c in wb_fields[f]['children']:
            indexed_wb_fields[f_c['id']] = copy.deepcopy(f_c)

        verify_fields_recursively(indexed_fields, indexed_wb_fields)

    for wbf in wb_fields:
        if wbf not in fields:
            raise errors.SubmissionFailFields("provided unexpected field %s" %
                                              wbf)
Example #22
0
def db_update_memory_variables(store):
    """
    to get fast checks, import (same) of the Node variable in GLSettings,
    this function is called every time that Node is updated.
    """
    try:
        node = store.find(models.Node).one()

        GLSettings.memory_copy.maximum_filesize = node.maximum_filesize
        GLSettings.memory_copy.maximum_namesize = node.maximum_namesize
        GLSettings.memory_copy.maximum_textsize = node.maximum_textsize

        GLSettings.memory_copy.tor2web_admin = node.tor2web_admin
        GLSettings.memory_copy.tor2web_submission = node.tor2web_submission
        GLSettings.memory_copy.tor2web_receiver = node.tor2web_receiver
        GLSettings.memory_copy.tor2web_unauth = node.tor2web_unauth

        GLSettings.memory_copy.submission_minimum_delay = node.submission_minimum_delay
        GLSettings.memory_copy.submission_maximum_ttl = node.submission_maximum_ttl

        GLSettings.memory_copy.allow_unencrypted = node.allow_unencrypted
        GLSettings.memory_copy.allow_iframes_inclusion = node.allow_iframes_inclusion

        GLSettings.memory_copy.exception_email = node.exception_email
        GLSettings.memory_copy.default_language = node.default_language
        GLSettings.memory_copy.default_timezone = node.default_timezone
        GLSettings.memory_copy.languages_enabled = node.languages_enabled

        # Email settings are copyed because they are used when an exception raises
        # and we can't go to check in the DB, because that's shall be exception source
        notif = store.find(models.Notification).one()

        GLSettings.memory_copy.notif_server = notif.server
        GLSettings.memory_copy.notif_port = notif.port
        GLSettings.memory_copy.notif_password = notif.password
        GLSettings.memory_copy.notif_username = notif.username
        GLSettings.memory_copy.notif_security = notif.security

        GLSettings.memory_copy.notification_threshold_per_hour = notif.notification_threshold_per_hour
        GLSettings.memory_copy.notification_suspension_time = notif.notification_suspension_time

        if GLSettings.developer_name:
            GLSettings.memory_copy.notif_source_name = GLSettings.developer_name
        else:
            GLSettings.memory_copy.notif_source_name = notif.source_name

        GLSettings.memory_copy.notif_source_name = notif.source_name
        GLSettings.memory_copy.notif_source_email = notif.source_email
        GLSettings.memory_copy.notif_uses_tor = notif.torify

        if GLSettings.disable_mail_notification:
            GLSettings.memory_copy.disable_receiver_notification_emails = True
            GLSettings.memory_copy.disable_admin_notification_emails = True
        else:
            GLSettings.memory_copy.disable_receiver_notification_emails = notif.disable_receivers_notification_emails
            GLSettings.memory_copy.disable_admin_notification_emails = notif.disable_admin_notification_emails

    except Exception as e:
        raise errors.InvalidInputFormat("Cannot import memory variables: %s" %
                                        e)
Example #23
0
def delete_field(store, field_id):
    """
    Delete the field object corresponding to field_id

    If the field has children, remove them as well.
    If the field is immediately attached to a step object, remove it as well.

    :param store: the store on which perform queries.
    :param field_id: the id corresponding to the field.
    :raises FieldIdNotFound: if no such field is found.
    """
    field = store.find(models.Field, models.Field.id == field_id).one()
    if not field:
        raise errors.FieldIdNotFound

    # TODO: to be uncommented upon completion of fields implementaion
    # if not field.editable:
    #     raise errors.FieldNotEditable

    if field.instance == 'template':
        if store.find(models.Field,
                      models.Field.template_id == field.id).count():
            raise errors.InvalidInputFormat(
                "Cannot remove the field template as it is used by one or more questionnaires"
            )

    if field.template:
        # special handling of the whistleblower_identity field
        if field.template.key == 'whistleblower_identity':
            if field.step is not None:
                field.step.questionnaire.enable_whistleblower_identity = False

    store.remove(field)
Example #24
0
    def get_uploaded_file(self):
        uploaded_file = self.request.body

        if not isinstance(uploaded_file, dict) or len(uploaded_file.keys()) != 5:
            raise errors.InvalidInputFormat("Expected a dict of five keys in uploaded file")

        for filekey in uploaded_file.keys():
            if filekey not in [u'body',
                               u'body_len',
                               u'content_type',
                               u'filename',
                               u'body_filepath']:
                raise errors.InvalidInputFormat(
                    "Invalid JSON key in uploaded file (%s)" % filekey)

        return uploaded_file
Example #25
0
def delete_field(store, field_id):
    """
    Delete the field object corresponding to field_id

    If the field has children, remove them as well.
    If the field is immediately attached to a step object, remove it as well.

    :param store: the store on which perform queries.
    :param field_id: the id corresponding to the field.
    """
    field = models.db_get(store, models.Field, id=field_id)

    if not field.editable:
        raise errors.FieldNotEditable

    if field.instance == 'template':
        if store.find(models.Field,
                      models.Field.template_id == field.id).count():
            raise errors.InvalidInputFormat(
                "Cannot remove the field template as it is used by one or more questionnaires"
            )

    if field.template_id == 'whistleblower_identity' and field.step_id is not None:
        store.find(
            models.Questionnaire, models.Step.id == field.step_id,
            models.Questionnaire.id == models.Step.questionnaire_id).set(
                enable_whistleblower_identity=False)

    store.remove(field)
Example #26
0
def field_integrity_check(store, field):
    """
    Preliminar validations of field descriptor in relation to:
    - step_id
    - fieldgroup_id
      template_id
    - instance type

    :param field: the field dict to be validated
    """
    template = None
    step = None
    fieldgroup = None

    if field['instance'] != 'template' and (field['step_id'] == ''
                                            and field['fieldgroup_id'] == ''):
        raise errors.InvalidInputFormat(
            "Each field should be a template or be associated to a step/fieldgroup"
        )

    if field['instance'] != 'template' and (field['step_id'] != ''
                                            and field['fieldgroup_id'] != ''):
        raise errors.InvalidInputFormat(
            "Cannot associate a field to both a step and a fieldgroup")

    if field['template_id'] != '':
        template = store.find(models.Field,
                              models.Field.id == field['template_id']).one()
        if not template:
            raise errors.FieldIdNotFound

    if field['step_id'] != '':
        step = store.find(models.Step,
                          models.Step.id == field['step_id']).one()
        if not step:
            raise errors.StepIdNotFound

    if field['fieldgroup_id'] != '':
        fieldgroup = store.find(
            models.Field, models.Field.id == field['fieldgroup_id']).one()
        if not fieldgroup:
            raise errors.FieldIdNotFound

    return field['instance'], template, step, fieldgroup
Example #27
0
def db_update_node(store, request, wizard_done, language):
    """
    Update and serialize the node infos

    :param store: the store on which perform queries.
    :param language: the language in which to localize data
    :return: a dictionary representing the serialization of the node
    """
    node = store.find(models.Node).one()

    fill_localized_keys(request, models.Node.localized_keys, language)

    # verify that the languages enabled are valid 'code' in the languages supported
    node.languages_enabled = []
    for lang_code in request['languages_enabled']:
        if lang_code in LANGUAGES_SUPPORTED_CODES:
            node.languages_enabled.append(lang_code)
        else:
            raise errors.InvalidInputFormat("Invalid lang code enabled: %s" %
                                            lang_code)

    if not len(node.languages_enabled):
        raise errors.InvalidInputFormat("Missing enabled languages")

    # enforcing of default_language usage (need to be set, need to be _enabled)
    if request['default_language']:
        if request['default_language'] not in node.languages_enabled:
            raise errors.InvalidInputFormat("Invalid lang code as default")

        node.default_language = request['default_language']

    else:
        node.default_language = node.languages_enabled[0]
        log.err("Default language not set!? fallback on %s" %
                node.default_language)

    if wizard_done:
        node.wizard_done = True

    node.update(request)

    db_refresh_memory_variables(store)

    return db_admin_serialize_node(store, language)
Example #28
0
    def get_file_upload(self):
        try:
            if len(self.request.files) != 1:
                raise errors.InvalidInputFormat(
                    "cannot accept more than a file upload at once")

            chunk_size = len(self.request.files['file'][0]['body'])
            total_file_size = int(
                self.request.arguments['flowTotalSize'][0]
            ) if 'flowTotalSize' in self.request.arguments else chunk_size
            flow_identifier = self.request.arguments['flowIdentifier'][
                0] if 'flowIdentifier' in self.request.arguments else generateRandomKey(
                    10)

            if ((chunk_size /
                 (1024 * 1024)) > GLSettings.memory_copy.maximum_filesize or
                (total_file_size /
                 (1024 * 1024)) > GLSettings.memory_copy.maximum_filesize):
                log.err("File upload request rejected: file too big")
                raise errors.FileTooBig(
                    GLSettings.memory_copy.maximum_filesize)

            if flow_identifier not in GLUploads:
                f = GLSecureTemporaryFile(GLSettings.tmp_upload_path)
                GLUploads[flow_identifier] = f
            else:
                f = GLUploads[flow_identifier]

            f.write(self.request.files['file'][0]['body'])

            if 'flowChunkNumber' in self.request.arguments and 'flowTotalChunks' in self.request.arguments:
                if self.request.arguments['flowChunkNumber'][
                        0] != self.request.arguments['flowTotalChunks'][0]:
                    return None

            uploaded_file = {}
            uploaded_file['filename'] = self.request.files['file'][0][
                'filename']
            uploaded_file['content_type'] = self.request.files['file'][0][
                'content_type']
            uploaded_file['body_len'] = total_file_size
            uploaded_file['body_filepath'] = f.filepath
            uploaded_file['body'] = f

            upload_time = time.time() - f.creation_date

            track_handler(self)

            return uploaded_file

        except errors.FileTooBig:
            raise  # propagate the exception

        except Exception as exc:
            log.err("Error while handling file upload %s" % exc)
            return None
Example #29
0
    def post(self):
        """
        This is the /login handler expecting login/password/role,
        """
        request = self.validate_message(self.request.body, requests.authDict)

        username = request['username']
        password = request['password']
        role = request['role']

        delay = random_login_delay()
        if delay:
            yield utility.deferred_sleep(delay)

        if role not in ['admin', 'wb', 'receiver']:
            raise errors.InvalidInputFormat(
                "Denied login request: invalid role requested")

        if get_tor2web_header(self.request.headers):
            if not accept_tor2web(role):
                log.err("Denied login request on Tor2web for role '%s'" % role)
                raise errors.TorNetworkRequired
            else:
                log.debug("Accepted login request on Tor2web for role '%s'" %
                          role)

        if role == 'admin':
            user_id, status, pcn = yield login_admin(username, password)

        elif role == 'wb':
            user_id = yield login_wb(password)
            status = 'enabled'
            pcn = False

        else:  # role == 'receiver'
            user_id, status, pcn = yield login_receiver(username, password)

        if user_id is False:
            GLSetting.failed_login_attempts += 1
            raise errors.InvalidAuthRequest

        session = self.generate_session(user_id, role, status)

        auth_answer = {
            'role': role,
            'session_id': session.id,
            'user_id': session.user_id,
            'session_expiration':
            int(GLSetting.sessions[session.id].getTime()),
            'status': session.user_status,
            'password_change_needed': pcn
        }

        yield self.uniform_answers_delay()
        self.write(auth_answer)
Example #30
0
def db_create_field(store, field_dict, language):
    """
    Create and add a new field to the store, then return the new serialized object.

    :param store: the store on which perform queries.
    :param field: the field definition dict
    :param language: the language of the field definition dict
    :return: a serialization of the object
    """
    _, template, step, fieldgroup = field_integrity_check(store, field_dict)

    fill_localized_keys(field_dict, models.Field.localized_keys, language)

    field = models.Field.new(store, field_dict)

    associate_field(store, field, template, step, fieldgroup)

    if field.template:
        # special handling of the whistleblower_identity field
        if field.template.key == 'whistleblower_identity':
            step = field.steps.one()
            if step:
                if not step.context.enable_whistleblower_identity:
                    step.context.enable_whistleblower_identity = True
                else:
                    raise errors.InvalidInputFormat(
                        "Whistleblower identity field already present")
            else:
                raise errors.InvalidInputFormat(
                    "Cannot associate whistleblower identity field to a fieldgroup"
                )

    else:
        db_update_fieldattrs(store, field.id, field_dict['attrs'], language)
        db_update_fieldoptions(store, field.id, field_dict['options'],
                               language)

    for c in field_dict['children']:
        c['fieldgroup_id'] = field.id
        db_create_field(store, c, language)

    return field