diff --git a/main.py b/main.py index de20e24..faec9d0 100644 --- a/main.py +++ b/main.py @@ -8,6 +8,7 @@ from concurrent.futures import ThreadPoolExecutor, as_completed from threading import Thread from flask import Flask, jsonify, request from waitress import serve +from functools import wraps import time import datetime import json @@ -18,7 +19,7 @@ import os def load_keys_from_db(file_name: str) -> list: ''' - Load valid API keys + Load valid API keys to a set Parameters ---------- @@ -37,7 +38,7 @@ def load_keys_from_db(file_name: str) -> list: data = database_cursor.fetchall() database_connection.close() - valid_keys = [line[1] for line in data] + valid_keys = {line[1] for line in data} return valid_keys @@ -126,8 +127,21 @@ def main(): earn_api = Flask(__name__) +#Helper functions +def require_api_key(func): + ''' + Validates API key + ''' + @wraps(func) + def wrapper(*args, **kwargs): + key = request.headers.get("X-API-KEY") + if not key or key not in valid_keys: + return jsonify({'Error': 'API key not valid'}), 401 + return func(*args, **kwargs) + return wrapper @earn_api.route("/get_global_status", methods=['GET']) +@require_api_key def get_global_status(): ''' GET request @@ -136,26 +150,25 @@ def get_global_status(): None ''' - if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: - response = {} - for item in earners: - response[str(item.connector)] = {"currency": item.get_currency(), - "trading_balance": item.get_trading_balance(), - "earning_balance": item.get_earning_balance(), - "is_paused": item.get_is_paused(), - "step_size": item.get_step_size(), - "percentage": item.get_percentage(), - "minimum_amount_in_trading_account": item.get_minimum_amount_in_trading_account(), - "time_between_subscriptions": item.get_time_between_subscriptions(), - "time_between_redemptions": item.get_time_between_redemptions(), - "last_subscription": item.get_last_subscription(), - "last_redemption": item.get_last_redemption()} - response["uptime"] = time.time() - start_time - return jsonify(response) - return jsonify({'Error': 'API key not valid'}), 401 + response = {} + for item in earners: + response[str(item.connector)] = {"currency": item.get_currency(), + "trading_balance": item.get_trading_balance(), + "earning_balance": item.get_earning_balance(), + "is_paused": item.get_is_paused(), + "step_size": item.get_step_size(), + "percentage": item.get_percentage(), + "minimum_amount_in_trading_account": item.get_minimum_amount_in_trading_account(), + "time_between_subscriptions": item.get_time_between_subscriptions(), + "time_between_redemptions": item.get_time_between_redemptions(), + "last_subscription": item.get_last_subscription(), + "last_redemption": item.get_last_redemption()} + response["uptime"] = time.time() - start_time + return jsonify(response) @earn_api.route("/toggle_pause", methods=['POST']) +@require_api_key def toggle_pause(): ''' GET request @@ -163,25 +176,23 @@ def toggle_pause(): Parameters: broker: str ''' - - if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: - valid_brokers = [str(item.connector) for item in earners] - if request.json is None: - return jsonify({'Error': 'request.json is None'}) - broker = request.json["broker"] - if broker is None: - return jsonify({'Error': 'broker is None'}) - if broker not in valid_brokers: - return jsonify({'Error': 'broker not valid'}) - for item in earners: - if str(item.connector)==broker: - item.toggle_pause() - return jsonify({'Status': item.get_is_paused()}) - return jsonify({'Error': 'broker not found'}) - return jsonify({'Error': 'API key not valid'}), 401 + + if request.json is None: + return jsonify({'Error': 'request.json is None'}) + broker = request.json["broker"] + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_broker_list: + return jsonify({'Error': 'broker not valid'}) + for item in earners: + if str(item.connector)==broker: + item.toggle_pause() + return jsonify({'Status': item.get_is_paused()}) + return jsonify({'Error': 'broker not found'}) @earn_api.route("/get_step_size", methods=["GET"]) +@require_api_key def get_step_size(): ''' GET request @@ -189,242 +200,216 @@ def get_step_size(): Parameters: broker: str ''' - - if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: - valid_brokers = [str(item.connector) for item in earners] - broker = request.args.get("broker") - if broker is None: - return jsonify({'Error': 'broker is None'}) - if broker not in valid_brokers: - return jsonify({'Error': 'broker not valid'}) - for item in earners: - if str(item.connector)==broker: - return jsonify({'step_size': item.get_step_size()}) - return jsonify({'Error': 'broker not found'}) - return jsonify({'Error': 'API key not valid'}), 401 + + broker = request.args.get("broker") + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_broker_list: + return jsonify({'Error': 'broker not valid'}) + for item in earners: + if str(item.connector)==broker: + return jsonify({'step_size': item.get_step_size()}) + return jsonify({'Error': 'broker not found'}) @earn_api.route("/set_step_size", methods=["POST"]) -def set_step_size(): - if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: - valid_brokers = [str(item.connector) for item in earners] - if request.json is None: - return jsonify({'Error': 'request.json is None'}) - broker = request.json["broker"] - new_step_size = request.json["new_step_size"] - if broker is None: - return jsonify({'Error': 'broker is None'}) - if broker not in valid_brokers: - return jsonify({'Error': 'broker not valid'}) - if new_step_size is None: - return jsonify({'Error': 'new_step_size is None'}) - for item in earners: - if str(item.connector)==broker: - item.set_step_size(new_step_size) - return jsonify({'step_size': new_step_size}) - return jsonify({'Error': 'broker not found'}) - return jsonify({'Error': 'API key not valid'}), 401 +@require_api_key +def set_step_size(): + if request.json is None: + return jsonify({'Error': 'request.json is None'}) + broker = request.json["broker"] + new_step_size = request.json["new_step_size"] + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_broker_list: + return jsonify({'Error': 'broker not valid'}) + if new_step_size is None: + return jsonify({'Error': 'new_step_size is None'}) + for item in earners: + if str(item.connector)==broker: + item.set_step_size(new_step_size) + return jsonify({'step_size': new_step_size}) + return jsonify({'Error': 'broker not found'}) -@earn_api.route("/get_percentage", methods=["GET"]) +@earn_api.route("/get_percentage", methods=["GET"]) +@require_api_key def get_percentage(): - if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: - valid_brokers = [str(item.connector) for item in earners] - broker = request.args.get("broker") - if broker is None: - return jsonify({'Error': 'broker is None'}) - if broker not in valid_brokers: - return jsonify({'Error': 'broker not valid'}) - for item in earners: - if str(item.connector)==broker: - return jsonify({'percentage': item.get_percentage()}) - return jsonify({'Error': 'broker not found'}) - return jsonify({'Error': 'API key not valid'}), 401 + broker = request.args.get("broker") + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_broker_list: + return jsonify({'Error': 'broker not valid'}) + for item in earners: + if str(item.connector)==broker: + return jsonify({'percentage': item.get_percentage()}) + return jsonify({'Error': 'broker not found'}) @earn_api.route("/set_percentage", methods=["POST"]) -def set_percentage(): - if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: - valid_brokers = [str(item.connector) for item in earners] - if request.json is None: - return jsonify({'Error': 'request.json is None'}) - broker = request.json["broker"] - new_percentage = request.json["new_percentage"] - if broker is None: - return jsonify({'Error': 'broker is None'}) - if broker not in valid_brokers: - return jsonify({'Error': 'broker not valid'}) - if new_percentage is None: - return jsonify({'Error': 'new_step_size is None'}) - for item in earners: - if str(item.connector)==broker: - item.set_percentage(new_percentage) - return jsonify({'percentage': new_percentage}) - return jsonify({'Error': 'broker not found'}) - return jsonify({'Error': 'API key not valid'}), 401 +@require_api_key +def set_percentage(): + if request.json is None: + return jsonify({'Error': 'request.json is None'}) + broker = request.json["broker"] + new_percentage = request.json["new_percentage"] + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_broker_list: + return jsonify({'Error': 'broker not valid'}) + if new_percentage is None: + return jsonify({'Error': 'new_step_size is None'}) + for item in earners: + if str(item.connector)==broker: + item.set_percentage(new_percentage) + return jsonify({'percentage': new_percentage}) + return jsonify({'Error': 'broker not found'}) -@earn_api.route("/get_time_between_subscriptions", methods=["GET"]) -def get_time_between_subscriptions(): - if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: - valid_brokers = [str(item.connector) for item in earners] - broker = request.args.get("broker") - if broker is None: - return jsonify({'Error': 'broker is None'}) - if broker not in valid_brokers: - return jsonify({'Error': 'broker not valid'}) - for item in earners: - if str(item.connector)==broker: - return jsonify({'time_between_subscriptions': item.get_time_between_subscriptions()}) - return jsonify({'Error': 'broker not found'}) - return jsonify({'Error': 'API key not valid'}), 401 +@earn_api.route("/get_time_between_subscriptions", methods=["GET"]) +@require_api_key +def get_time_between_subscriptions(): + broker = request.args.get("broker") + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_broker_list: + return jsonify({'Error': 'broker not valid'}) + for item in earners: + if str(item.connector)==broker: + return jsonify({'time_between_subscriptions': item.get_time_between_subscriptions()}) + return jsonify({'Error': 'broker not found'}) @earn_api.route("/set_time_between_subscriptions", methods=["POST"]) +@require_api_key def set_time_between_subscriptions(): - if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: - valid_brokers = [str(item.connector) for item in earners] - if request.json is None: - return jsonify({'Error': 'request.json is None'}) - broker = request.json["broker"] - new_time_between_subscriptions = request.json["new_time_between_subscriptions"] - if broker is None: - return jsonify({'Error': 'broker is None'}) - if broker not in valid_brokers: - return jsonify({'Error': 'broker not valid'}) - if new_time_between_subscriptions is None: - return jsonify({'Error': 'new_step_size is None'}) - for item in earners: - if str(item.connector)==broker: - item.set_time_between_subscriptions(new_time_between_subscriptions) - return jsonify({'time_between_subscriptions': new_time_between_subscriptions}) - return jsonify({'Error': 'broker not found'}) - return jsonify({'Error': 'API key not valid'}), 401 + if request.json is None: + return jsonify({'Error': 'request.json is None'}) + broker = request.json["broker"] + new_time_between_subscriptions = request.json["new_time_between_subscriptions"] + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_broker_list: + return jsonify({'Error': 'broker not valid'}) + if new_time_between_subscriptions is None: + return jsonify({'Error': 'new_step_size is None'}) + for item in earners: + if str(item.connector)==broker: + item.set_time_between_subscriptions(new_time_between_subscriptions) + return jsonify({'time_between_subscriptions': new_time_between_subscriptions}) + return jsonify({'Error': 'broker not found'}) @earn_api.route("/get_time_between_redemptions", methods=["GET"]) +@require_api_key def get_time_between_redemptions(): - if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: - valid_brokers = [str(item.connector) for item in earners] - broker = request.args.get("broker") - if broker is None: - return jsonify({'Error': 'broker is None'}) - if broker not in valid_brokers: - return jsonify({'Error': 'broker not valid'}) - for item in earners: - if str(item.connector)==broker: - return jsonify({'time_between_redemptions': item.get_time_between_redemptions()}) - return jsonify({'Error': 'broker not found'}) - return jsonify({'Error': 'API key not valid'}), 401 + broker = request.args.get("broker") + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_broker_list: + return jsonify({'Error': 'broker not valid'}) + for item in earners: + if str(item.connector)==broker: + return jsonify({'time_between_redemptions': item.get_time_between_redemptions()}) + return jsonify({'Error': 'broker not found'}) @earn_api.route("/set_time_between_redemptions", methods=["POST"]) +@require_api_key def set_time_between_redemptions(): - if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: - valid_brokers = [str(item.connector) for item in earners] - if request.json is None: - return jsonify({'Error': 'request.json is None'}) - broker = request.json["broker"] - new_time_between_redemptions = request.json["new_time_between_redemptions"] - if broker is None: - return jsonify({'Error': 'broker is None'}) - if broker not in valid_brokers: - return jsonify({'Error': 'broker not valid'}) - if new_time_between_redemptions is None: - return jsonify({'Error': 'new_step_size is None'}) - for item in earners: - if str(item.connector)==broker: - item.set_time_between_redemptions(new_time_between_redemptions) - return jsonify({'time_between_redemptions': new_time_between_redemptions}) - return jsonify({'Error': 'broker not found'}) - return jsonify({'Error': 'API key not valid'}), 401 + if request.json is None: + return jsonify({'Error': 'request.json is None'}) + broker = request.json["broker"] + new_time_between_redemptions = request.json["new_time_between_redemptions"] + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_broker_list: + return jsonify({'Error': 'broker not valid'}) + if new_time_between_redemptions is None: + return jsonify({'Error': 'new_step_size is None'}) + for item in earners: + if str(item.connector)==broker: + item.set_time_between_redemptions(new_time_between_redemptions) + return jsonify({'time_between_redemptions': new_time_between_redemptions}) + return jsonify({'Error': 'broker not found'}) @earn_api.route("/get_minimum_amount_in_trading_account", methods=["GET"]) +@require_api_key def get_minimum_amount_in_trading_account(): - if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: - valid_brokers = [str(item.connector) for item in earners] - broker = request.args.get("broker") - if broker is None: - return jsonify({'Error': 'broker is None'}) - if broker not in valid_brokers: - return jsonify({'Error': 'broker not valid'}) - for item in earners: - if str(item.connector)==broker: - return jsonify({'minimum_amount_in_trading_account': item.get_minimum_amount_in_trading_account()}) - return jsonify({'Error': 'broker not found'}) - return jsonify({'Error': 'API key not valid'}), 401 + broker = request.args.get("broker") + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_broker_list: + return jsonify({'Error': 'broker not valid'}) + for item in earners: + if str(item.connector)==broker: + return jsonify({'minimum_amount_in_trading_account': item.get_minimum_amount_in_trading_account()}) + return jsonify({'Error': 'broker not found'}) @earn_api.route("/set_minimum_amount_in_trading_account", methods=["POST"]) +@require_api_key def set_minimum_amount_in_trading_account(): - if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: - valid_brokers = [str(item.connector) for item in earners] - broker = request.json["broker"] - new_minimum_amount_in_trading_account = request.json["new_minimum_amount_in_trading_account"] - if broker is None: - return jsonify({'Error': 'broker is None'}) - if broker not in valid_brokers: - return jsonify({'Error': 'broker not valid'}) - if new_minimum_amount_in_trading_account is None: - return jsonify({'Error': 'new_step_size is None'}) - for item in earners: - if str(item.connector)==broker: - item.set_minimum_amount_in_trading_account(new_minimum_amount_in_trading_account) - return jsonify({'minimum_amount_in_trading_account': new_minimum_amount_in_trading_account}) - return jsonify({'Error': 'broker not found'}) - return jsonify({'Error': 'API key not valid'}), 401 + broker = request.json["broker"] + new_minimum_amount_in_trading_account = request.json["new_minimum_amount_in_trading_account"] + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_broker_list: + return jsonify({'Error': 'broker not valid'}) + if new_minimum_amount_in_trading_account is None: + return jsonify({'Error': 'new_step_size is None'}) + for item in earners: + if str(item.connector)==broker: + item.set_minimum_amount_in_trading_account(new_minimum_amount_in_trading_account) + return jsonify({'minimum_amount_in_trading_account': new_minimum_amount_in_trading_account}) + return jsonify({'Error': 'broker not found'}) @earn_api.route("/get_last_subscription", methods=["GET"]) +@require_api_key def get_last_subscription(): - if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: - valid_brokers = [str(item.connector) for item in earners] - broker = request.args.get("broker") - if broker is None: - return jsonify({'Error': 'broker is None'}) - if broker not in valid_brokers: - return jsonify({'Error': 'broker not valid'}) - for item in earners: - if str(item.connector)==broker: - return jsonify({'last_subscription': item.get_last_subscription()}) - return jsonify({'Error': 'broker not found'}) - return jsonify({'Error': 'API key not valid'}), 401 + broker = request.args.get("broker") + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_broker_list: + return jsonify({'Error': 'broker not valid'}) + for item in earners: + if str(item.connector)==broker: + return jsonify({'last_subscription': item.get_last_subscription()}) + return jsonify({'Error': 'broker not found'}) @earn_api.route("/get_last_redemption", methods=["GET"]) +@require_api_key def get_last_redemption(): - if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: - valid_brokers = [str(item.connector) for item in earners] - broker = request.args.get("broker") - if broker is None: - return jsonify({'Error': 'broker is None'}) - if broker not in valid_brokers: - return jsonify({'Error': 'broker not valid'}) - for item in earners: - if str(item.connector)==broker: - return jsonify({'last_redemption': item.get_last_redemption()}) - return jsonify({'Error': 'broker not found'}) - return jsonify({'Error': 'API key not valid'}), 401 + broker = request.args.get("broker") + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_broker_list: + return jsonify({'Error': 'broker not valid'}) + for item in earners: + if str(item.connector)==broker: + return jsonify({'last_redemption': item.get_last_redemption()}) + return jsonify({'Error': 'broker not found'}) @earn_api.route("/get_total_balance", methods=["GET"]) +@require_api_key def get_total_balance(): - if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: - valid_brokers = [str(item.connector) for item in earners] - broker = request.args.get("broker") - if broker is None: - return jsonify({'Error': 'broker is None'}) - if broker not in valid_brokers: - return jsonify({'Error': 'broker not valid'}) - for item in earners: - if str(item.connector)==broker: - return jsonify({'trading_balance': item.get_trading_balance(), 'earning_balance': item.get_earning_balance()}) - return jsonify({'Error': 'broker not found'}) - return jsonify({'Error': 'API key not valid'}), 401 + broker = request.args.get("broker") + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_broker_list: + return jsonify({'Error': 'broker not valid'}) + for item in earners: + if str(item.connector)==broker: + return jsonify({'trading_balance': item.get_trading_balance(), 'earning_balance': item.get_earning_balance()}) + return jsonify({'Error': 'broker not found'}) @earn_api.route("/subscribe", methods=["POST"]) +@require_api_key def subscribe(): ''' args: @@ -432,32 +417,30 @@ def subscribe(): amount: amount to subscribe force_pause: True or False ''' - if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: - valid_brokers = [str(item.connector) for item in earners] - if request.json is None: - return jsonify({'Error': 'request.json is None'}) - broker = request.json["broker"] - amount = request.json["amount"] - force_pause = False - if "force_pause" in request.json: - force_pause = request.json["force_pause"] - if broker is None: - return jsonify({'Error': 'broker is None'}) - if broker not in valid_brokers: - return jsonify({'Error': 'broker not valid'}) - if amount is None: - return jsonify({'Error': 'amount is None'}) - if force_pause is None: - return jsonify({'Error': 'force_pause is None'}) - for item in earners: - if str(item.connector)==broker: - subscription = item.subscribe(amount, force_pause=force_pause) - return jsonify({'Success': str(subscription)}) - return jsonify({'Error': 'broker not found'}) - return jsonify({'Error': 'API key not valid'}), 401 + if request.json is None: + return jsonify({'Error': 'request.json is None'}) + broker = request.json["broker"] + amount = request.json["amount"] + force_pause = False + if "force_pause" in request.json: + force_pause = request.json["force_pause"] + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_broker_list: + return jsonify({'Error': 'broker not valid'}) + if amount is None: + return jsonify({'Error': 'amount is None'}) + if force_pause is None: + return jsonify({'Error': 'force_pause is None'}) + for item in earners: + if str(item.connector)==broker: + subscription = item.subscribe(amount, force_pause=force_pause) + return jsonify({'Success': str(subscription)}) + return jsonify({'Error': 'broker not found'}) @earn_api.route("/redeem", methods=["POST"]) +@require_api_key def redeem(): ''' args: @@ -465,29 +448,27 @@ def redeem(): amount: amount to redeem force_pause: True or False ''' - if "X-API-KEY" in request.headers and request.headers.get("X-API-KEY") in valid_keys: - valid_brokers = [str(item.connector) for item in earners] - if request.json is None: - return jsonify({'Error': 'request.json is None'}) - broker = request.json["broker"] - amount = request.json["amount"] - force_pause = False - if "force_pause" in request.json: - force_pause = request.json["force_pause"] - if broker is None: - return jsonify({'Error': 'broker is None'}) - if broker not in valid_brokers: - return jsonify({'Error': 'broker not valid'}) - if amount is None: - return jsonify({'Error': 'amount is None'}) - if force_pause is None: - return jsonify({'Error': 'force_pause is None'}) - for item in earners: - if str(item.connector)==broker: - redemption = item.redeem(amount, force_pause=force_pause) - return jsonify({'Success': str(redemption)}) - return jsonify({'Error': 'broker not found'}) - return jsonify({'Error': 'API key not valid'}), 401 + if request.json is None: + return jsonify({'Error': 'request.json is None'}) + broker = request.json["broker"] + amount = request.json["amount"] + force_pause = False + if "force_pause" in request.json: + force_pause = request.json["force_pause"] + if broker is None: + return jsonify({'Error': 'broker is None'}) + if broker not in valid_broker_list: + return jsonify({'Error': 'broker not valid'}) + if amount is None: + return jsonify({'Error': 'amount is None'}) + if force_pause is None: + return jsonify({'Error': 'force_pause is None'}) + for item in earners: + if str(item.connector)==broker: + redemption = item.redeem(amount, force_pause=force_pause) + return jsonify({'Success': str(redemption)}) + return jsonify({'Error': 'broker not found'}) + def run_API(port): @@ -525,6 +506,9 @@ if __name__=="__main__": for item in config["exchanges"]: earners.append(earner(connectors[item], config["exchanges"][item])) + #Valid broker list + valid_broker_list = [str(item.connector) for item in earners] + #Load valid API keys valid_keys = load_keys_from_db("keys/api_credentials.db")