コード例 #1
0
ファイル: state.py プロジェクト: zshell/GlobaLeaks
    def schedule_exception_email(self, exception_text, *args):
        from globaleaks.transactions import schedule_email

        if not hasattr(self.tenant_cache[1], 'notification'):
            log.err(
                "Error: Cannot send mail exception before complete initialization."
            )
            return

        if self.exceptions_email_count >= self.settings.exceptions_email_hourly_limit:
            return

        exception_text = (exception_text % args) if args else exception_text

        sha256_hash = sha256(bytes(exception_text))

        if sha256_hash not in self.exceptions:
            self.exceptions[sha256_hash] = 0

        self.exceptions[sha256_hash] += 1
        if self.exceptions[sha256_hash] > 5:
            log.err(
                "Exception mail suppressed for (%s) [reason: threshold exceeded]",
                sha256_hash)
            return

        self.exceptions_email_count += 1

        mail_subject = "GlobaLeaks Exception"
        delivery_list = self.tenant_cache[
            1].notification.exception_delivery_list

        if self.settings.devel_mode:
            mail_subject += " [%s]" % self.settings.developer_name
            delivery_list = [("*****@*****.**",
                              '')]

        mail_body = bytes("Platform: %s (%s)\nVersion: %s\n\n%s" \
                          % (self.tenant_cache[1].hostname,
                             self.tenant_cache[1].onionservice,
                             __version__,
                             exception_text))

        for mail_address, pgp_key_public in delivery_list:
            # Opportunisticly encrypt the mail body. NOTE that mails will go out
            # unencrypted if one address in the list does not have a public key set.
            if pgp_key_public:
                pgpctx = PGPContext(self.settings.tmp_path)
                fingerprint = pgpctx.load_key(pgp_key_public)['fingerprint']
                mail_body = pgpctx.encrypt_message(fingerprint, mail_body)

            # avoid waiting for the notification to send and instead rely on threads to handle it
            schedule_email(1, mail_address, mail_subject, mail_body)
コード例 #2
0
    def proof_of_work_valid(self, request_answer):
        """
        :param resolved_proof_of_work: a string, that has to be an integer
        :return:
        """
        HASH_ENDS_WITH = b'00'

        resolved = "%s%d" % (self.proof_of_work['question'], request_answer)
        x = sha256(resolved.encode())
        if not x.endswith(HASH_ENDS_WITH):
            log.debug("Failed proof of work validation: expected '%s' at the end of the hash %s (seeds %s + %d)",
                      HASH_ENDS_WITH, x, self.proof_of_work['question'], request_answer)
            return

        log.debug("Successful proof of work validation! got '%s' at the end of the hash %s (seeds %s + %d)",
                  HASH_ENDS_WITH, x, self.proof_of_work['question'], request_answer)

        self.proof_of_work['solved'] = True
コード例 #3
0
def db_create_submission(session, tid, request, uploaded_files, client_using_tor):
    answers = request['answers']

    context, questionnaire = session.query(models.Context, models.Questionnaire) \
                                    .filter(models.Context.id == request['context_id'],
                                            models.Questionnaire.id == models.Context.questionnaire_id,
                                            models.Questionnaire.tid.in_(set([1, tid]))).one_or_none()
    if not context:
        raise errors.ModelNotFound(models.Context)

    steps = db_get_questionnaire(session, tid, questionnaire.id, None)['steps']
    questionnaire_hash = text_type(sha256(json.dumps(steps)))
    db_archive_questionnaire_schema(session, steps, questionnaire_hash)

    submission = models.InternalTip()
    submission.tid = tid
    submission.status = db_get_id_for_system_status(session, tid, 'new')

    submission.progressive = db_assign_submission_progressive(session, tid)

    if context.tip_timetolive > 0:
        submission.expiration_date = get_expiration(context.tip_timetolive)
    else:
        submission.expiration_date = datetime_never()

    # this is get from the client as it the only possibility possible
    # that would fit with the end to end submission.
    # the score is only an indicator and not a critical information so we can accept to
    # be fooled by the malicious user.
    submission.total_score = request['total_score']

    # The status https is used to keep track of the security level adopted by the whistleblower
    submission.https = not client_using_tor

    submission.context_id = context.id
    submission.enable_two_way_comments = context.enable_two_way_comments
    submission.enable_two_way_messages = context.enable_two_way_messages
    submission.enable_attachments = context.enable_attachments

    whistleblower_identity = session.query(models.Field) \
                                    .filter(models.Field.template_id == u'whistleblower_identity',
                                            models.Field.step_id == models.Step.id,
                                            models.Step.questionnaire_id == context.questionnaire_id).one_or_none()

    submission.enable_whistleblower_identity = whistleblower_identity is not None

    if submission.enable_whistleblower_identity and request['identity_provided']:
        submission.identity_provided = True
        submission.identity_provided_date = datetime_now()

    submission.questionnaire_hash = questionnaire_hash
    submission.preview = extract_answers_preview(steps, answers)

    session.add(submission)
    session.flush()

    receipt = text_type(generateRandomReceipt())

    wbtip = models.WhistleblowerTip()
    wbtip.id = submission.id
    wbtip.tid = submission.tid
    wbtip.receipt_hash = hash_password(receipt, State.tenant_cache[tid].receipt_salt)
    session.add(wbtip)

    db_save_questionnaire_answers(session, tid, submission.id, answers)

    for filedesc in uploaded_files:
        new_file = models.InternalFile()
        new_file.tid = tid
        new_file.name = filedesc['name']
        new_file.description = ""
        new_file.content_type = filedesc['type']
        new_file.size = filedesc['size']
        new_file.internaltip_id = submission.id
        new_file.submission = filedesc['submission']
        new_file.filename = filedesc['filename']
        session.add(new_file)
        log.debug("=> file associated %s|%s (%d bytes)",
                  new_file.name, new_file.content_type, new_file.size)

    if context.maximum_selectable_receivers > 0 and \
                    len(request['receivers']) > context.maximum_selectable_receivers:
        raise errors.InputValidationError("selected an invalid number of recipients")

    rtips_count = 0
    for receiver, user in session.query(models.Receiver, models.User) \
                                 .filter(models.Receiver.id.in_(request['receivers']),
                                         models.ReceiverContext.receiver_id == models.Receiver.id,
                                         models.ReceiverContext.context_id == context.id,
                                         models.User.id == models.Receiver.id,
                                         models.UserTenant.user_id == models.User.id,
                                         models.UserTenant.tenant_id == tid):
        if user.pgp_key_public or State.tenant_cache[tid].allow_unencrypted:
            db_create_receivertip(session, receiver, submission)
            rtips_count += 1

    if rtips_count == 0:
        raise errors.InputValidationError("need at least one recipient")

    log.debug("The finalized submission had created %d models.ReceiverTip(s)", rtips_count)

    return {'receipt': receipt}