コード例 #1
0
def slack_oauth_callback():
    # security: It's not possible to get here Access token. (This requests comes from users browser after redirect from
    #  Slack. Refresh token should be in cookies, but that might make problems with API calls. It's dificult to say what
    #  should be the correct behaviour. For now I'll lock it down so that the following scenario is not possible.
    #  Scenario:
    #       - Attacker generates URL using endpoint slack_redirect_to_oauth. He sends it to victim.
    #       - Victim fills out the Slack authorization form and submits it.
    #       - Attacker gets the access because he is the one who initiated the request.
    #  Now replace the work Attacker with Employee and it sounds like legit scenario.
    #  Current behaviour: The slack_redirect_to_oauth and slack_oauth_callback need to be initiated by the same user.
    #                     The slack_oauth_callback expects refresh token in cookie, can be disabled in config.

    user_id = None
    if SlackConfig.check_refresh_cookie_on_callback_endpoint:
        user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    auth_code = request.args['code']
    db_code = request.args['state']

    db_code_valid, res_or_error_msg = randomCodes.validate_code(
        db_code, randomCodes.ActivityType.SLACK, user_id)

    if not db_code_valid:
        return res_or_error_msg, 400
    res: db_models.TmpRandomCodes = res_or_error_msg

    import app.utils.notifications.slack_add_connection as notifications_slack
    ok = notifications_slack.validate_code_and_save(auth_code, res.user_id)
    if ok:
        return 'OK. Window will close in 2 seconds. <script>setTimeout(function(){ close() }, 2000);</script>', 200
    return 'fail', 500
コード例 #2
0
def api_target_by_id(target_id: int):
    user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    target = actions.get_target_from_id_if_user_can_see(target_id, user_id)
    if target is None:
        return "Target either doesn't exist or you're allowed to see it.", 400

    if request.method == 'DELETE':
        scan_order: db_models.ScanOrder = db_utils_advanced.generic_get_create_edit_from_data(
            db_schemas.ScanOrderSchema, {
                "target_id": target.id,
                "user_id": user_id
            },
            get_only=True)
        scan_order.active = False
        db_models.db.session.commit()
        db_utils.actions_on_modification(scan_order)

    scan_order = db_utils_advanced.generic_get_create_edit_from_data(
        db_schemas.ScanOrderSchema, {
            "target_id": target.id,
            "user_id": user_id
        },
        get_only=True)

    notifications = get_effective_notification_settings(user_id, target_id)

    return jsonify(
        actions.full_target_settings_to_dict(target, scan_order,
                                             notifications))
コード例 #3
0
def api_resend_validation_email():
    user_id = authentication_utils.get_user_id_from_jwt_or_exception()
    REQUEST_ERROR_MSG = "Request failed. Possible reasons:\n" \
                   "- Validation email to this email address was send less then 1 minute ago.\n"\
                   "- User did not register this email address, so there is nothing to validate.\n"

    email_to_resend_validation_email_to = json.loads(request.data).get(
        "email", "").strip()
    if len(email_to_resend_validation_email_to) == 0:
        return "No email argument provided. Aborting.", 400

    res = db_models.db.session \
        .query(db_models.TmpRandomCodes) \
        .filter(db_models.TmpRandomCodes.user_id == user_id) \
        .filter(db_models.TmpRandomCodes.activity == randomCodes.ActivityType.MAIL_VALIDATION.name) \
        .filter(db_models.TmpRandomCodes.timestamp >
                datetime_to_timestamp(time_source.time() - datetime.timedelta(minutes=1))) \
        .all()

    if res is not None:
        for x in res:
            if x.params == email_to_resend_validation_email_to:
                return REQUEST_ERROR_MSG, 400

    res = db_models.db.session \
        .query(db_models.MailConnections) \
        .filter(db_models.MailConnections.user_id == user_id) \
        .filter(db_models.MailConnections.email == email_to_resend_validation_email_to) \
        .first()

    if res is None:
        return REQUEST_ERROR_MSG, 400

    send_mail_validation(user_id, email_to_resend_validation_email_to)
    return f'ok', 200
コード例 #4
0
def api_get_basic_cert_info_for_target(target_id):
    user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    last_scan, scan_result = actions.get_last_scan_and_result(
        target_id, user_id)
    last_scan: db_models.LastScan
    scan_result: db_models.ScanResults

    if scan_result is None:
        return "Target either doesn't exist or the current user doesn't have permission to view it.", 401

    last_scanned_datetime = timestamp_to_datetime(last_scan.last_scanned)
    cert_info = scan_result.certificate_information
    verified_chain = cert_info.verified_certificate_chain_list
    certificates_in_chain: List[
        db_models.Certificate] = db_models.Certificate.select_from_list(
            verified_chain.chain)

    list_cert = certificates_in_chain[0]

    return {
        'chain_notBefore': max([x.notBefore for x in certificates_in_chain]),
        'chain_notAfter': min([x.notAfter for x in certificates_in_chain]),
        'leaf_sni': list_cert.subject_alternative_name_list,
        'leaf_subject': list_cert.subject,
        'information_fetched_on': last_scanned_datetime
    }, 200
コード例 #5
0
ファイル: scan_results.py プロジェクト: TLSInventory/backend
def api_scan_result_history_without_certs(user_id=None, x_days=30):
    if user_id is None:
        user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    res = actions.get_scan_history(user_id, x_days)

    if res is None:
        return "[]", 200

    server_info_schema = db_schemas.ServerInfoSchemaWithoutCiphers()

    res_dict = {}
    for x in res:
        try:
            res_dict[x.ScanResultsHistory.id] = {
                "timestamp": x.ScanResultsHistory.timestamp,
                "server_info": server_info_schema.dump(x.ServerInfo),
                "target_id": x.Target.id,
                "scan_result_id": x.ScanResultsSimplified.scanresult_id if x.ScanResultsSimplified else None,
            }
        except Exception as e:
            logger.error(f"{x} | {e}")
            raise

    return jsonify(res_dict)
コード例 #6
0
ファイル: scan_results.py プロジェクト: TLSInventory/backend
def api_get_users_certificate_chains(user_id=None, x_days=30):
    if user_id is None:
        user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    res = actions.get_certificate_chains(user_id, x_days)
    res_dicts: List[dict] = db_schemas.CertificateChainSchemaWithoutCertificates().dump(res, many=True)
    res_dict_of_dicts = db_schemas.convert_arr_of_dicts_to_dict_of_dicts(res_dicts)
    return jsonify(res_dict_of_dicts)
コード例 #7
0
def api_list_domain_monitoring(user_id: Optional[int] = None):
    if user_id is None:
        user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    res = db_models.db.session.query(db_models.SubdomainRescanTarget).\
        filter(db_models.SubdomainRescanTarget.subdomain_scan_user_id == user_id).all()

    res_dict = db_schemas.SubdomainRescanTargetSchema().dump(res, many=True)
    return jsonify(res_dict)
コード例 #8
0
ファイル: misc.py プロジェクト: TLSInventory/backend
def api_mail_add_or_delete():
    # this can add multiple emails at once
    user_id = authentication_utils.get_user_id_from_jwt_or_exception()
    if request.method == "POST":
        msg, status_code = mail_add(user_id, request.json.get('emails', ""))
    if request.method == "DELETE":
        msg, status_code = mail_delete(user_id, request.json.get('emails', ""))

    return msg, status_code
コード例 #9
0
def api_notification_settings(user_id=None, target_id=None):
    if user_id is None:
        user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    if target_id is not None and not actions.can_user_get_target_definition_by_id(
            target_id, user_id):
        return "Target either doesn't exist or user is not allowed to see it.", 401

    connection_lists = get_effective_notification_settings(user_id, target_id)
    return jsonify(connection_lists)
コード例 #10
0
def slack_url_to_oauth():
    user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    db_code = randomCodes.create_and_save_random_code(
        activity=randomCodes.ActivityType.SLACK,
        user_id=user_id,
        expire_in_n_minutes=10)
    import app.utils.notifications.slack_add_connection
    url = f'{app.utils.notifications.slack_add_connection.slack_endpoint_url()}&state={db_code}'
    return url, 200
コード例 #11
0
def api_get_user_targets():
    user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    # todo: the following search only looks at targets, which have scan result. This might be considered a bug. Fix?

    res = db_models.db.session \
        .query(db_models.ScanOrder, db_models.Target, db_models.LastScan, db_models.ScanResults,
               db_models.ScanResultsSimplified) \
        .outerjoin(db_models.ScanResults, db_models.LastScan.result_id == db_models.ScanResults.id) \
        .outerjoin(db_models.ScanResultsSimplified,
                   db_models.ScanResultsSimplified.scanresult_id == db_models.ScanResults.id) \
        .filter(db_models.LastScan.target_id == db_models.Target.id) \
        .filter(db_models.ScanOrder.target_id == db_models.Target.id) \
        .filter(db_models.ScanOrder.user_id == user_id) \
        .all()

    # res: List[Tuple[db_models.ScanOrder, db_models.Target, db_models.LastScan, db_models.ScanResults]]

    schema = db_schemas.TargetSchema(many=True)
    json_dict = schema.dump([x.Target for x in res])

    for obj in json_dict:
        for single_res in res:
            if obj["id"] == single_res.Target.id:
                obj["active"] = 'yes' if single_res.ScanOrder.active else 'no'

                obj["expires"] = "Not scanned yet"
                obj["grade"] = "Not scanned yet"
                if single_res.ScanResults is None:
                    continue

                if single_res.ScanResultsSimplified:
                    scan_result_simplified = single_res.ScanResultsSimplified
                else:
                    scan_result_simplified = sslyze_result_simplify.sslyze_result_simplify(
                        single_res.ScanResults)
                    # todo: consider saving the simplified result

                if scan_result_simplified:
                    if isinstance(single_res.ScanResultsSimplified.notAfter,
                                  int):
                        obj["expires"] = str(
                            timestamp_to_datetime(
                                single_res.ScanResultsSimplified.notAfter))
                    obj["grade"] = single_res.ScanResultsSimplified.grade
                    obj["grade_reasons"] = single_res.ScanResultsSimplified.grade_reasons
                    continue

    # for x in json_dict:
    #     x["grade"] = random.choice([chr(ord('A')+i) for i in range(5)])
    #     x["expires"] = datetime.date(2020, 1, 1) + datetime.timedelta(days=random.randint(10, 500))

    json_string = json.dumps(json_dict, default=str)
    # logger.debug(json_string)
    return json_string, 200
コード例 #12
0
def api_get_user_profile():
    user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    res: db_models.User = db_models.db.session \
        .query(db_models.User) \
        .get(user_id)

    return jsons.dumps({
        "username": res.username,
        "main_api_key": res.main_api_key,
        "email": res.email
    }), 200
コード例 #13
0
ファイル: scan_results.py プロジェクト: TLSInventory/backend
def api_get_users_certificates(user_id=None, x_days=30):
    if user_id is None:
        user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    # logger.debug("Start getting certificate chains")
    res_chains = actions.get_certificate_chains(user_id, x_days)

    # logger.debug("Start getting certificates")
    res_certs = actions.get_certificates(res_chains)

    # logger.debug("Start serializing certificates")
    res_dicts: List[dict] = db_schemas.CertificateSchema().dump(res_certs, many=True)
    res_dict_of_dicts = db_schemas.convert_arr_of_dicts_to_dict_of_dicts(res_dicts)
    return jsonify(res_dict_of_dicts)
コード例 #14
0
def api_set_notification_settings_raw(user_id: Optional[int] = None,
                                      target_id: Optional[int] = None):
    if user_id is None:
        user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    if target_id is not None and not actions.can_user_get_target_definition_by_id(
            target_id, user_id):
        return "Target either doesn't exist or user is not allowed to see it.", 401

    data = json.loads(request.data)
    ok = set_notification_settings_raw_single_target(user_id, target_id, data)
    if ok:
        return api_notification_settings_raw(user_id, target_id)
    return "fail", 400
コード例 #15
0
ファイル: scan_results.py プロジェクト: TLSInventory/backend
def api_get_users_scan_results_simplified(user_id=None, x_days=30):
    if user_id is None:
        user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    res = actions.get_scan_history(user_id, x_days)

    if res is None:
        return "[]", 200

    scan_results_simplified = list(map(lambda x: x.ScanResultsSimplified, res))
    scan_results_simplified2 = list(filter(lambda x: x, scan_results_simplified))
    res2: List[dict] = db_schemas.ScanResultsSimplifiedWithoutCertsSchema().dump(scan_results_simplified2, many=True)
    res_dict_of_dicts = db_schemas.convert_arr_of_dicts_to_dict_of_dicts(res2)
    return jsonify(res_dict_of_dicts)
コード例 #16
0
ファイル: misc.py プロジェクト: TLSInventory/backend
def api_slack_connection_delete(team_id: str = None, channel_id: str = None):
    user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    slack_connection: db_models.SlackConnections = db_utils_advanced.generic_get_create_edit_from_data(
        db_schemas.SlackConnectionsSchema,
        {"team_id": team_id, "channel_id": channel_id, "user_id": user_id},
        get_only=True
    )

    if slack_connection:
        db_models.db.session.delete(slack_connection)
        db_models.db.session.commit()
        return "1 deleted", 200
    return "0 deleted", 200
コード例 #17
0
def api_target():
    user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    data = json.loads(request.data)
    data["target"]["protocol"] = data.get("protocol", "HTTPS").replace(
        "TlsWrappedProtocolEnum.", "")  # todo: remove this hack
    data["target"].pop("id", None)

    target_hostnames = data["target"]["hostname"].split(";")
    target_hostnames = list(map(lambda x: x.strip(), target_hostnames))
    target_hostnames = list(filter(lambda x: len(x), target_hostnames))
    target_hostnames = list(set(target_hostnames))

    target_ids = add_targets(target_hostnames, user_id, data)

    return f'Inserted {len(target_ids)} targets', 200
コード例 #18
0
def api_enable_target_scan(target_id: int):
    user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    target = actions.get_target_from_id_if_user_can_see(target_id, user_id)
    if target is None:
        return "Target either doesn't exist or you're allowed to see it.", 400

    scan_order: db_models.ScanOrder = db_utils_advanced.generic_get_create_edit_from_data(
        db_schemas.ScanOrderSchema, {
            "target_id": target.id,
            "user_id": user_id
        },
        get_only=True)
    scan_order.active = True
    db_models.db.session.commit()
    db_utils.actions_on_modification(scan_order)
    return "ok", 200
コード例 #19
0
def api_channel_connection_delete(channel_name: str, channel_id: int):
    user_id = authentication_utils.get_user_id_from_jwt_or_exception()
    try:
        channel_db_model = CONNECTION_DB_MODELS_TYPES[channel_name]
    except KeyError:
        return "This channel doesn't exist.", 400

    existing_connection = db_models.db.session \
        .query(channel_db_model) \
        .filter(channel_db_model.user_id == user_id) \
        .filter(channel_db_model.id == channel_id) \
        .first()

    if existing_connection:
        db_models.db.session.delete(existing_connection)
        db_models.db.session.commit()

    return 'ok', 200
コード例 #20
0
def api_notification_settings_raw(user_id=None, target_id=None):
    if user_id is None:
        user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    if target_id is not None and not actions.can_user_get_target_definition_by_id(
            target_id, user_id):
        return "Target either doesn't exist or user is not allowed to see it.", 401

    res = db_models.db.session \
        .query(db_models.ConnectionStatusOverrides) \
        .filter(db_models.ConnectionStatusOverrides.user_id == user_id) \
        .filter(db_models.ConnectionStatusOverrides.target_id == target_id) \
        .first()

    pref = res.preferences if res else ""
    res2 = load_preferences_from_string(pref)

    return jsons.dumps(res2), 200
コード例 #21
0
ファイル: scan_results.py プロジェクト: TLSInventory/backend
def api_scan_results_history_v2(user_id=None, x_days=30):
    if user_id is None:
        user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    logger.debug("before API requests")
    a = api_scan_result_history_without_certs(user_id, x_days).json
    b = api_get_users_scan_results_simplified(user_id, x_days).json
    c = api_get_users_certificate_chains(user_id, x_days).json
    d = api_get_users_certificates(user_id, x_days).json
    e = get_user_targets_only(user_id)
    logger.debug("after API requests")

    new_res = convert_scan_results_to_v1(a, b, c, d, e)
    new_res_2 = sorted(new_res, key=lambda x: x["timestamp"])

    logger.debug("after conversion of scan_results for backwards compatibility")
    # return json.dumps(sorted(new_res, key=lambda x: x["timestamp"]), indent=4, sort_keys=True), 200
    return jsonify(new_res_2)
コード例 #22
0
def get_target_id(target_def=None):
    if target_def:
        data = target_def
    else:
        data = json.loads(request.data)
    # logger.warning(data)
    data["protocol"] = data.get("protocol",
                                "HTTPS").replace("TlsWrappedProtocolEnum.",
                                                 "")  # todo: remove this hack
    target = db_utils_advanced.generic_get_create_edit_from_data(
        db_schemas.TargetSchema, data, get_only=True)
    if not target:
        return "fail", 400
    user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    # validate that the user entered the target definition at least once. Protection against enumaration attack.
    if not actions.can_user_get_target_definition_by_id(target.id, user_id):
        return "fail", 400
    return jsonify({"id": target.id}), 200
コード例 #23
0
def api_get_result_for_target(target_id):
    user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    res_or_none = actions.get_last_scan_and_result(target_id, user_id)
    if res_or_none is None:
        return "Target either doesn't exist or the current user doesn't have permission to view it.", 401

    last_scan, scan_result = res_or_none

    last_scan: db_models.LastScan
    scan_result: db_models.ScanResults

    last_scanned = last_scan.last_scanned
    last_scanned_datetime = timestamp_to_datetime(last_scanned)

    scan_result_str = db_schemas.ScanResultsSchema().dumps(scan_result)

    return jsonify({
        'result': json.loads(scan_result_str),
        'time': last_scanned_datetime
    }), 200
コード例 #24
0
ファイル: misc.py プロジェクト: TLSInventory/backend
def mail_validate(db_code):
    # security: using the same trick as above, i.e. requiring valid refresh cookie. todo: maybe reconsider?
    user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    db_code_valid, res_or_error_msg = randomCodes.validate_code(db_code, randomCodes.ActivityType.MAIL_VALIDATION, user_id)

    if not db_code_valid:
        return res_or_error_msg, 400
    res: db_models.TmpRandomCodes = res_or_error_msg
    user_id_from_code = res.user_id
    validated_email = res.params

    mail_connection: db_models.MailConnections = db_utils_advanced.generic_get_create_edit_from_data(
        db_schemas.MailConnectionsSchema,
        {"email": validated_email, "user_id": user_id_from_code},
        get_only=True
    )
    if mail_connection is None:
        return "fail", 500
    mail_connection.validated = True
    db_models.db.session.delete(res)
    db_models.db.session.commit()
    return 'ok', 200
コード例 #25
0
def api_scan_result_history_choose_schema(user_id=None,
                                          x_days=30,
                                          schema_simplified=None):
    if user_id is None:
        user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    res = actions.get_scan_history(user_id, x_days)

    if res is None:
        return "[]", 200

    logger.debug("START serialization")

    schema_target = db_schemas.TargetSchema()
    if schema_simplified is None:
        schema_simplified = db_schemas.ScanResultsSimplifiedSchema()

    res_arr = []
    for x in res:
        new_dict = {
            "timestamp": None,
            "target": None,
            "result_simplified": None,
        }
        if x.ScanResultsHistory:
            new_dict["timestamp"] = x.ScanResultsHistory.timestamp
        new_dict["target"] = schema_target.dump(x.Target)
        new_dict["result_simplified"] = schema_simplified.dump(
            x.ScanResultsSimplified)
        res_arr.append(new_dict)

    # logger.debug("MID serialization")
    res_arr_sorted = sorted(res_arr, key=lambda x: x["timestamp"])
    # ret = json.dumps(res_arr_sorted), indent=3, sort_keys=True)
    # logger.debug("END serialization")
    # return ret, 200
    return jsonify(res_arr_sorted)
コード例 #26
0
def api_change_password():
    if not request.is_json:
        return jsonify({"msg": "Missing JSON in request"}), 400

    user_id = authentication_utils.get_user_id_from_jwt_or_exception()

    old_password = request.json.get('old_password', None)
    new_password = request.json.get('new_password', None)

    res: db_models.User = db_models.db.session \
        .query(db_models.User) \
        .get(user_id)

    login_msg, login_status_code = action_login(res.username, old_password)
    if login_status_code != 200:
        return login_msg, login_status_code

    if new_password is None or len(new_password) == 0:
        return jsonify({
            "msg": "Missing new password parameter."
        }), 400  # todo: consider concatenating with other error msgs

    change_ok = authentication_utils.set_user_password(res.id, new_password)
    return "ok" if change_ok else "fail", 200 if change_ok else 400
コード例 #27
0
ファイル: misc.py プロジェクト: TLSInventory/backend
def show_notification_connections(target_id=None):
    user_id = authentication_utils.get_user_id_from_jwt_or_exception()
    connection_lists = get_effective_notification_settings(user_id, target_id)
    return jsonify(connection_lists)
コード例 #28
0
def api_remove_subdomain_monitoring(target_id: int):
    user_id = authentication_utils.get_user_id_from_jwt_or_exception()
    return remove_subdomain_monitoring(target_id, user_id)
コード例 #29
0
def api_add_subdomains(target_id: int):
    user_id = authentication_utils.get_user_id_from_jwt_or_exception()
    data = request.json

    return add_subdomains(target_id, user_id, data)
コード例 #30
0
ファイル: misc.py プロジェクト: TLSInventory/backend
def api_slack_connections_get():
    user_id = authentication_utils.get_user_id_from_jwt_or_exception()
    return jsonify(list_connections_of_type(db_models.SlackConnections, user_id))