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)
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
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}