コード例 #1
0
    def download_rfile(self, session, tid, user_id, file_id):
        rfile, rtip = session.query(models.ReceiverFile, models.ReceiverTip) \
                             .filter(models.ReceiverFile.id == file_id,
                                     models.ReceiverFile.receivertip_id == models.ReceiverTip.id,
                                     models.ReceiverTip.receiver_id == user_id,
                                     models.ReceiverTip.internaltip_id == models.InternalTip.id,
                                     models.InternalTip.tid == tid).one()

        if not rfile:
            raise errors.ModelNotFound(models.ReceiverFile)

        log.debug("Download of file %s by receiver %s (%d)" %
                  (rfile.internalfile_id, rtip.receiver_id, rfile.downloads))

        rfile.last_access = datetime_now()
        rfile.downloads += 1

        return serializers.serialize_rfile(session, tid,
                                           rfile), rtip.crypto_tip_prv_key
コード例 #2
0
ファイル: wbtip.py プロジェクト: vondrakk/GlobaLeaks
def create_message(store, wbtip_id, receiver_id, request):
    rtip_id, internaltip = store.find(
        (models.ReceiverTip.id, models.InternalTip),
        models.ReceiverTip.internaltip_id == wbtip_id,
        models.InternalTip.id == wbtip_id,
        models.ReceiverTip.receiver_id == receiver_id).one()

    if rtip_id is None:
        raise errors.ModelNotFound(models.ReceiverTip)

    internaltip.update_date = internaltip.wb_last_access = datetime_now()

    msg = models.Message()
    msg.content = request['content']
    msg.receivertip_id = rtip_id
    msg.type = u'whistleblower'
    store.add(msg)

    return serialize_message(store, msg)
コード例 #3
0
def create_message(session, tid, wbtip_id, receiver_id, request):
    rtip_id, internaltip = session.query(models.ReceiverTip.id, models.InternalTip) \
                                  .filter(models.ReceiverTip.internaltip_id == wbtip_id,
                                          models.InternalTip.id == wbtip_id,
                                          models.ReceiverTip.receiver_id == receiver_id,
                                          models.InternalTip.tid == tid).one_or_none()

    if rtip_id is None:
        raise errors.ModelNotFound(models.ReceiverTip)

    internaltip.update_date = internaltip.wb_last_access = datetime_now()

    msg = models.Message()
    msg.content = request['content']
    msg.receivertip_id = rtip_id
    msg.type = u'whistleblower'
    session.add(msg)
    session.flush()

    return serialize_message(session, msg)
コード例 #4
0
ファイル: submission.py プロジェクト: qertoip/GlobaLeaks
def db_create_submission(session, tid, request, token, client_using_tor):
    if not request['receivers']:
        raise errors.InputValidationError("need at least one recipient")

    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 = db_archive_questionnaire_schema(session, steps)

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

    itip.progressive = db_assign_submission_progressive(session, tid)

    itip.additional_questionnaire_id = context.additional_questionnaire_id

    if context.tip_timetolive > 0:
        itip.expiration_date = get_expiration(context.tip_timetolive)

    # 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.
    itip.total_score = request['total_score']

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

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

    x = session.query(models.Field, models.FieldAttr.value) \
               .filter(models.Field.template_id == u'whistleblower_identity',
                       models.Field.step_id == models.Step.id,
                       models.Step.questionnaire_id == context.questionnaire_id,
                       models.FieldAttr.field_id == models.Field.id,
                       models.FieldAttr.name == u'visibility_subject_to_authorization').one_or_none()

    whistleblower_identity = None
    can_access_whistleblower_identity = True

    if x:
        whistleblower_identity = x[0]
        can_access_whistleblower_identity = not x[1]

    itip.enable_whistleblower_identity = whistleblower_identity is not None

    itip.preview = extract_answers_preview(steps, answers)

    session.add(itip)
    session.flush()

    receipt = GCE.generate_receipt()
    receipt_salt = State.tenant_cache[tid].receipt_salt

    wbtip = models.WhistleblowerTip()
    wbtip.id = itip.id
    wbtip.tid = tid
    wbtip.hash_alg = GCE.HASH
    wbtip.receipt_hash = GCE.hash_password(receipt, receipt_salt)

    crypto_is_available = State.tenant_cache[1].encryption

    if crypto_is_available:
        users_count = session.query(models.User) \
                             .filter(models.User.id.in_(request['receivers']),
                                     models.User.crypto_prv_key != b'').count()

        crypto_is_available = users_count == len(request['receivers'])

    if crypto_is_available:
        crypto_tip_prv_key, itip.crypto_tip_pub_key = GCE.generate_keypair()
        wb_key = GCE.derive_key(receipt.encode(), receipt_salt)
        wb_prv_key, wb_pub_key = GCE.generate_keypair()
        wbtip.crypto_prv_key = GCE.symmetric_encrypt(wb_key, wb_prv_key)
        wbtip.crypto_pub_key = wb_pub_key
        wbtip.crypto_tip_prv_key = GCE.asymmetric_encrypt(
            wb_pub_key, crypto_tip_prv_key)

    if itip.enable_whistleblower_identity and request[
            'identity_provided'] and answers[whistleblower_identity.id]:
        wbi = answers[whistleblower_identity.id][0]
        answers[whistleblower_identity.id] = ''

        if crypto_is_available:
            wbi = base64.b64encode(
                GCE.asymmetric_encrypt(itip.crypto_tip_pub_key,
                                       json.dumps(wbi).encode())).decode()

        db_set_internaltip_data(session, itip.id, 'identity_provided', True,
                                False)
        db_set_internaltip_data(session, itip.id, 'whistleblower_identity',
                                wbi, crypto_is_available)

    if crypto_is_available:
        answers = base64.b64encode(
            GCE.asymmetric_encrypt(itip.crypto_tip_pub_key,
                                   json.dumps(answers).encode())).decode()
    else:
        db_save_questionnaire_answers(session, tid, itip.id, answers)

    db_set_internaltip_answers(session, itip.id, questionnaire_hash, answers,
                               crypto_is_available)

    session.add(wbtip)

    for filedesc in token.uploaded_files:
        new_file = models.InternalFile()
        new_file.tid = tid
        new_file.encrypted = crypto_is_available
        new_file.name = filedesc['name']
        new_file.description = ""
        new_file.content_type = filedesc['type']
        new_file.size = filedesc['size']
        new_file.internaltip_id = itip.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")

    for user in session.query(models.User).filter(
            models.User.id.in_(request['receivers'])):
        if not crypto_is_available and not user.pgp_key_public and not State.tenant_cache[
                tid].allow_unencrypted:
            continue

        _tip_key = b''
        if crypto_is_available:
            _tip_key = GCE.asymmetric_encrypt(user.crypto_pub_key,
                                              crypto_tip_prv_key)

        db_create_receivertip(session, user, itip,
                              can_access_whistleblower_identity, _tip_key)

    return {'receipt': receipt}
コード例 #5
0
ファイル: __init__.py プロジェクト: yashodhank/GlobaLeaks
def db_get(store, model, *args, **kwargs):
    ret = store.find(model, *args, **kwargs).one()
    if ret is None:
        raise errors.ModelNotFound(model)

    return ret
コード例 #6
0
def db_create_submission(session, tid, request, token, 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)

    if not request['receivers']:
        raise errors.InputValidationError("The submission should involve at least one recipient")

    if context.maximum_selectable_receivers > 0 and \
        len(request['receivers']) > context.maximum_selectable_receivers:
        raise errors.InputValidationError("The number of recipients selected exceed the configured limit")

    steps = db_get_questionnaire(session, tid, questionnaire.id, None)['steps']
    questionnaire_hash = db_archive_questionnaire_schema(session, steps)
    preview = extract_answers_preview(steps, answers)

    itip = models.InternalTip()
    itip.tid = tid
    itip.status = 'new'

    itip.progressive = db_assign_submission_progressive(session, tid)

    itip.additional_questionnaire_id = context.additional_questionnaire_id

    if context.tip_timetolive > 0:
        itip.expiration_date = get_expiration(context.tip_timetolive)

    # Evaluate the score level
    itip.total_score = request['total_score']

    # The status https is used to keep track of the security level adopted by the whistleblower
    itip.https = not client_using_tor
    itip.mobile = request['mobile']

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

    x = session.query(models.Field, models.FieldAttr.value) \
               .filter(models.Field.template_id == 'whistleblower_identity',
                       models.Field.step_id == models.Step.id,
                       models.Step.questionnaire_id == context.questionnaire_id,
                       models.FieldAttr.field_id == models.Field.id,
                       models.FieldAttr.name == 'visibility_subject_to_authorization').one_or_none()

    whistleblower_identity = None
    can_access_whistleblower_identity = True

    if x:
        whistleblower_identity = x[0]
        can_access_whistleblower_identity = not x[1]

    itip.enable_whistleblower_identity = whistleblower_identity is not None

    session.add(itip)
    session.flush()

    crypto_is_available = State.tenant_cache[tid].encryption

    # Evaluate if encryption is available
    if crypto_is_available:
        users_count = session.query(models.User) \
                             .filter(models.User.id.in_(request['receivers']),
                                     models.User.crypto_prv_key != b'').count()

        crypto_is_available = users_count == len(request['receivers'])

        if crypto_is_available:
            crypto_tip_prv_key, itip.crypto_tip_pub_key = GCE.generate_keypair()

    # Evaluate if the whistleblower tip should be generated
    if ((not State.tenant_cache[tid].enable_scoring_system) or
        (context.score_threshold_receipt == 0) or
        (context.score_threshold_receipt == 1 and itip.total_score >= 2) or
        (context.score_threshold_receipt == 2 and itip.total_score == 3)):
        receipt = GCE.generate_receipt()
        receipt_salt = State.tenant_cache[tid].receipt_salt
        wbtip = models.WhistleblowerTip()
        wbtip.id = itip.id
        wbtip.tid = tid
        wbtip.hash_alg = 'ARGON2'
        wbtip.receipt_hash = GCE.hash_password(receipt, receipt_salt)

        # Evaluate if the whistleblower tip should be encrypted
        if crypto_is_available:
            crypto_tip_prv_key, itip.crypto_tip_pub_key = GCE.generate_keypair()
            wb_key = GCE.derive_key(receipt.encode(), receipt_salt)
            wb_prv_key, wb_pub_key = GCE.generate_keypair()
            wbtip.crypto_prv_key = GCE.symmetric_encrypt(wb_key, wb_prv_key)
            wbtip.crypto_pub_key = wb_pub_key
            wbtip.crypto_tip_prv_key = GCE.asymmetric_encrypt(wb_pub_key, crypto_tip_prv_key)

        session.add(wbtip)
    else:
        receipt = ''

    # Apply special handling to the whistleblower identity question
    if itip.enable_whistleblower_identity and request['identity_provided'] and answers[whistleblower_identity.id]:
        if crypto_is_available:
            wbi = base64.b64encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, json.dumps(answers[whistleblower_identity.id][0]).encode())).decode()
        else:
            wbi = answers[whistleblower_identity.id][0]

        answers[whistleblower_identity.id] = ''

        db_set_internaltip_data(session, itip.id, 'whistleblower_identity', wbi)

    if crypto_is_available:
        preview = base64.b64encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, json.dumps(preview).encode())).decode()
        answers = base64.b64encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, json.dumps(answers).encode())).decode()

    itip.preview = preview

    db_set_internaltip_answers(session, itip.id, questionnaire_hash, answers)

    db_save_answers_subject_to_stats(session, tid, itip.id, answers)

    for uploaded_file in token.uploaded_files:
        if uploaded_file['id'] in request['removed_files']:
            continue

        if crypto_is_available:
            for k in ['name', 'type', 'size']:
                uploaded_file[k] = base64.b64encode(GCE.asymmetric_encrypt(itip.crypto_tip_pub_key, uploaded_file[k]))

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

    tip_count = 0

    for user in session.query(models.User).filter(models.User.id.in_(request['receivers'])):
        _tip_key = b''
        if crypto_is_available:
            _tip_key = GCE.asymmetric_encrypt(user.crypto_pub_key, crypto_tip_prv_key)

        db_create_receivertip(session, user, itip, can_access_whistleblower_identity, _tip_key)

        tip_count +=1

    if not tip_count:
        raise errors.InputValidationError("Unable to deliver the submission to at least one recipient")

    return {
        'receipt': receipt,
        'score': itip.total_score
    }
コード例 #7
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}
コード例 #8
0
ファイル: submission.py プロジェクト: yashodhank/GlobaLeaks
def db_create_submission(store, request, uploaded_files, client_using_tor):
    answers = request['answers']

    context, questionnaire = store.find(
        (models.Context, models.Questionnaire),
        models.Context.id == request['context_id'],
        models.Questionnaire.id == models.Context.questionnaire_id).one()
    if not context:
        raise errors.ModelNotFound(models.Context)

    steps = db_get_questionnaire(store, questionnaire.id, None)['steps']
    questionnaire_hash = unicode(sha256(json.dumps(steps)))

    submission = models.InternalTip()

    submission.progressive = db_assign_submission_progressive(store)

    if context.tip_timetolive > -1:
        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 tor2web is used to keep track of the security level adopted by the whistleblower
    submission.tor2web = 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
    submission.enable_whistleblower_identity = questionnaire.enable_whistleblower_identity

    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)

    store.add(submission)

    db_archive_questionnaire_schema(store, steps, questionnaire_hash)
    db_save_questionnaire_answers(store, submission.id, answers)

    for filedesc in uploaded_files:
        new_file = models.InternalFile()
        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.file_path = filedesc['path']
        store.add(new_file)
        log.debug("=> file associated %s|%s (%d bytes)", new_file.name,
                  new_file.content_type, new_file.size)

    receipt = db_create_whistleblowertip(store, submission)

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

    rtips_count = 0
    for receiver, user, in store.find(
        (models.Receiver, models.User),
            In(models.Receiver.id, request['receivers']),
            models.ReceiverContext.receiver_id == models.Receiver.id,
            models.ReceiverContext.context_id == context.id,
            models.User.id == models.Receiver.id):
        if user.pgp_key_public or GLSettings.memory_copy.allow_unencrypted:
            db_create_receivertip(store, receiver, submission)
            rtips_count += 1

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

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

    return {'receipt': receipt}