Example #1
0
def donate():
    counter_file = os.path.join(home_path(), 'warden/counter.json')
    templateData = {
        "title": "Support this Software",
        "current_app": current_app
    }
    return (render_template('warden/warden_thanks.html', **templateData))
Example #2
0
def pickle_it(action='load', filename=None, data=None):
    logging.info(f"Pickle {action} file: {filename}")
    from warden_modules import home_path
    filename = 'warden/' + filename
    filename = os.path.join(home_path(), filename)
    if action == 'delete':
        try:
            os.remove(filename)
            return ('deleted')
        except Exception:
            return ('failed')

    if action == 'load':
        try:
            with open(filename, 'rb') as handle:
                ld = pickle.load(handle)
                logging.info(f"Loaded: Pickle {action} file: {filename}")
                return (ld)
        except Exception as e:
            logging.warning(
                f"Error: Pickle {action} file: {filename} error:{e}")
            return ("file not found")
    else:
        with open(filename, 'wb') as handle:
            pickle.dump(data, handle, protocol=pickle.HIGHEST_PROTOCOL)
            logging.info(f"Saved: Pickle {action} file: {filename}")
            return ("saved")
Example #3
0
def donated():
    counter_file = os.path.join(home_path(),
                                'warden/counter.json')
    templateData = {"title": "Thank You!", "donated": donate_check(), "current_app": current_app}
    with open(counter_file, 'w') as fp:
        json.dump("donated", fp)
    return (render_template('warden/warden_thanks.html', **templateData))
Example #4
0
def donate_check():
    counter_file = os.path.join(home_path(),
                                'warden/counter.json')
    donated = False
    try:
        with open(counter_file) as data_file:
            json_all = json.loads(data_file.read())
        if json_all == "donated":
            donated = True
    except Exception:
        donated = False
    return (donated)
Example #5
0
def start_hidden_service(app):
    if app.controller is None:
        return
    app.controller.reconnect()
    key_path = os.path.abspath(os.path.join(home_path(), ".tor_service_key"))

    app.tor_service_id = None

    if not os.path.exists(key_path):
        service = app.controller.create_ephemeral_hidden_service(
            {app.tor_port: app.port}, await_publication=True)
        app.tor_service_id = service.service_id
        print("* Started a new hidden service with the address of %s.onion" %
              app.tor_service_id)

        with open(key_path, "w") as key_file:
            key_file.write("%s:%s" %
                           (service.private_key_type, service.private_key))
    else:
        with open(key_path) as key_file:
            key_type, key_content = key_file.read().split(":", 1)

        try:
            service = app.controller.create_ephemeral_hidden_service(
                {app.tor_port: app.port},
                key_type=key_type,
                key_content=key_content,
                await_publication=True,
            )
            app.tor_service_id = service.service_id
            print("")
            print(success("✅ Resumed %s.onion" % app.tor_service_id))
            from utils import pickle_it
            pickle_it('save', 'onion_address.pkl',
                      app.tor_service_id + '.onion')
            print("")
        except Exception:
            pass

    try:
        # save address to file
        if app.save_tor_address_to is not None:
            with open(app.save_tor_address_to, "w") as f:
                f.write("%s.onion" % app.tor_service_id)
        app.tor_service_id = app.tor_service_id
        from utils import pickle_it
        pickle_it('save', 'onion_address.pkl', app.tor_service_id + '.onion')
        app.tor_enabled = True
    except Exception:
        pass
Example #6
0
def tor_services():
    action = request.args.get("action")
    if action == 'start':
        current_app.settings['SERVER']['onion_server'] = 'True'
        update_config()
        from stem.control import Controller
        from urllib.parse import urlparse
        current_app.tor_port = current_app.settings['SERVER'].getint('onion_port')
        current_app.port = current_app.settings['SERVER'].getint('port')
        from warden_modules import home_path
        toraddr_file = os.path.join(home_path(), "onion.txt")
        current_app.save_tor_address_to = toraddr_file
        proxy_url = "socks5h://localhost:9050"
        tor_control_port = ""
        try:
            tor_control_address = urlparse(proxy_url).netloc.split(":")[0]
            if tor_control_address == "localhost":
                tor_control_address = "127.0.0.1"
            current_app.controller = Controller.from_port(
                address=tor_control_address,
                port=int(tor_control_port)
                if tor_control_port
                else "default",
            )
        except Exception:
            current_app.controller = None
        from tor import start_hidden_service
        start_hidden_service(current_app)

        flash(f"Started Tor Hidden Services at {current_app.tor_service_id}.onion", "success")
    if action == 'stop':
        current_app.settings['SERVER']['onion_server'] = 'False'
        update_config()
        from tor import stop_hidden_services
        stop_hidden_services(current_app)
        flash("Stopped Tor Hidden Services", "warning")
    return render_template("warden/tor.html",
                           title="Tor Hidden Services",
                           current_app=current_app)
Example #7
0
def historical_prices(ticker, fx='USD', source=None):
    '''
    RETURNS a DF with
        columns={
                'close': 'close',
                'open': 'open',
                'high': 'high',
                'low': 'low',
                'volume': 'volume'
        }
    '''

    ticker = ticker.replace(' ', '')

    if source and type(source) != list:
        raise TypeError("source has to be a list of strings - can be one string inside a list")

    try:
        source_list = mapping[ticker]
    except KeyError:
        source_list = [
            'cryptocompare',
            'twelvedata',
            'alphavantage_currency',
            'alphavantage_global',
            'fmp'
        ]

    from pricing_engine.alphavantage import historical as aa_historical
    from pricing_engine.cryptocompare import historical as cc_historical
    from pricing_engine.fmp import historical as fmp_historical
    from pricing_engine.twelvedata import historical as td_historical

    results = pd.DataFrame()
    # Gets from each source
    for src in source_list:
        # Try to load file if exists
        filename = (ticker + "_" + fx + ".price")
        # Check if file was updated today
        from warden_modules import home_path
        file_check = os.path.join(home_path(), 'warden/' + filename)
        # Try to read from file and check how recent it is
        try:
            today = datetime.now().date()
            filetime = datetime.fromtimestamp(os.path.getctime(file_check))
            if filetime.date() == today:
                df = pd.read_pickle(file_check)
                return (df)
        except Exception:
            pass

        if src == 'alphavantage_currency':
            results = aa_historical(ticker, function='DIGITAL_CURRENCY_DAILY')
        if src == 'alphavantage_global':
            results = aa_historical(ticker, function='TIME_SERIES_DAILY_ADJUSTED')
        if src == 'alphavantage_fx':
            results = aa_historical(ticker, function='FX_DAILY')
        if src == 'cryptocompare':
            results = cc_historical(ticker)
        if src == 'fmp':
            results = fmp_historical(ticker)
        if src == 'twelvedata':
            results = td_historical(ticker)
        # Check if data is valid
        if not results.empty:
            # Include fx column and convert to currency if needed
            if fx != 'USD':
                # Get a currency df
                df_fx = aa_historical(fx, function='FX_DAILY')
                df_fx.index = pd.to_datetime(df_fx.index)
                df_fx = df_fx.loc[~df_fx.index.duplicated(keep='first')]
                df_fx = df_fx.rename(columns={'close': 'fx_close'})
                df_fx = df_fx[['fx_close']]
                df_fx['fx_close'] = pd.to_numeric(df_fx.fx_close,
                                                  errors='coerce')
                df_fx['fx_close'] = 1 / df_fx['fx_close']

                # Merge the two dfs:
                results.index = pd.to_datetime(results.index)
                results = results.loc[~results.index.duplicated(keep='first')]
                merge_df = pd.merge(results, df_fx, on='date', how='inner')
                merge_df['close'] = merge_df['close'].astype(float)
                merge_df['close_converted'] = merge_df['close'] * merge_df[
                    'fx_close']

                results = merge_df

            else:
                results['fx_close'] = 1
                results['close_converted'] = pd.to_numeric(results.close,
                                                           errors='coerce')

            results.index = results.index.astype('datetime64[ns]')
            # Save this file to be used during the same day instead of calling API
            pickle_it(action='save', filename=filename, data=results)
            # save metadata as well
            metadata = {
                'source': src,
                'last_update': datetime.utcnow()
            }
            filemeta = (ticker + "_" + fx + ".meta")
            pickle_it(action='save', filename=filemeta, data=metadata)

            return (results)
        else:
            logging.info(f"Source {src} does not return any data for {ticker}. Trying other sources.")
    if results.empty:
        logging.warning(f"Could not retrieve a df for {ticker} from any source")

    return (results)
Example #8
0
def init_app(app):
    from ansi_management import (warning, success, error)
    from utils import (create_config, runningInDocker)
    from config import Config
    from connections import tor_request
    warnings.filterwarnings('ignore')

    # Load config.ini into app
    # --------------------------------------------
    # Read Global Variables from warden.config(s)
    # Can be accessed like a dictionary like:
    # app.settings['PORTFOLIO']['RENEW_NAV']
    # --------------------------------------------
    config_file = Config.config_file
    app.warden_status = {}

    # Check for internet connection
    internet_ok = internet_connected()
    if internet_ok is True:
        print(success("✅ Internet Connection"))
    else:
        print(
            error(
                "[!] WARden needs internet connection. Check your connection.")
        )
        print(warning("[!] Exiting"))
        exit()

    # Config
    config_settings = configparser.ConfigParser()
    if os.path.isfile(config_file):
        config_settings.read(config_file)
        app.warden_status['initial_setup'] = False
        print(
            success(
                "✅ Config Loaded from config.ini - edit it for customization"
            ))
    else:
        print(
            error(
                "  Config File could not be loaded, created a new one with default values..."
            ))
        create_config(config_file)
        config_settings.read(config_file)
        app.warden_status['initial_setup'] = True

    table_error = False
    try:
        # create empty instance of LoginManager
        app.login_manager = LoginManager()
    except sqlite3.OperationalError:
        table_error = True

    # Create empty instance of SQLAlchemy
    app.db = SQLAlchemy()
    app.db.init_app(app)
    # Import models so tables are created
    from models import Trades, User, AccountInfo, TickerInfo, SpecterInfo
    app.db.create_all()

    #  There was an initial error on getting users
    #  probably because tables were not created yet.
    # The above create_all should have solved it so try again.
    if table_error:
        # create empty instance of LoginManager
        app.login_manager = LoginManager()

    # If login required - go to login:
    app.login_manager.login_view = "warden.login"
    # To display messages - info class (Bootstrap)
    app.login_manager.login_message_category = "secondary"
    app.login_manager.init_app(app)

    # Create empty instance of messagehandler
    from message_handler import MessageHandler
    app.message_handler = MessageHandler()
    app.message_handler.clean_all()

    # Get Version
    print("")
    try:
        version_file = Config.version_file
        with open(version_file, 'r') as file:
            current_version = file.read().replace('\n', '')
    except Exception:
        current_version = 'unknown'
    with app.app_context():
        app.version = current_version

    # Check if there are any users on database, if not, needs initial setup
    users = User.query.all()
    if users == []:
        app.warden_status['initial_setup'] = True

    # Check for Cryptocompare API Keys
    print("")
    check_cryptocompare()
    print("")

    print(f"[i] Running WARden version: {current_version}")
    app.warden_status['running_version'] = current_version

    # CHECK FOR UPGRADE
    repo_url = 'https://api.github.com/repos/pxsocs/warden/releases'
    try:
        github_version = tor_request(repo_url).json()[0]['tag_name']
    except Exception:
        github_version = None

    app.warden_status['github_version'] = github_version

    if github_version:
        print(f"[i] Newest WARden version available: {github_version}")
        parsed_github = version.parse(github_version)
        parsed_version = version.parse(current_version)

        app.warden_status['needs_upgrade'] = False
        if parsed_github > parsed_version:
            print(warning("  [i] Upgrade Available"))
            app.warden_status['needs_upgrade'] = True
        if parsed_github == parsed_version:
            print(success("✅ You are running the latest version"))
    else:
        print(warning("[!] Could not check GitHub for updates"))

    print("")
    # Check if config.ini exists
    with app.app_context():
        app.settings = config_settings
    with app.app_context():
        try:
            from utils import fxsymbol
            app.fx = fxsymbol(config_settings['PORTFOLIO']['base_fx'], 'all')
        except KeyError:  # Problem with this config, reset
            print(error("  [!] Config File needs to be rebuilt"))
            print("")
            create_config(config_file)

    # TOR Server through Onion Address --
    # USE WITH CAUTION - ONION ADDRESSES CAN BE EXPOSED!
    # WARden needs to implement authentication (coming soon)
    if app.settings['SERVER'].getboolean('onion_server'):
        from stem.control import Controller
        from urllib.parse import urlparse
        app.tor_port = app.settings['SERVER'].getint('onion_port')
        app.port = app.settings['SERVER'].getint('port')
        from warden_modules import home_path
        toraddr_file = os.path.join(home_path(), "onion.txt")
        app.save_tor_address_to = toraddr_file
        proxy_url = "socks5h://localhost:9050"
        tor_control_port = ""
        try:
            tor_control_address = urlparse(proxy_url).netloc.split(":")[0]
            if tor_control_address == "localhost":
                tor_control_address = "127.0.0.1"
            app.controller = Controller.from_port(
                address=tor_control_address,
                port=int(tor_control_port) if tor_control_port else "default",
            )
        except Exception:
            app.controller = None
        from tor import start_hidden_service
        start_hidden_service(app)

    from routes import warden
    from errors.handlers import errors
    from api.routes import api
    from csv_routes.routes import csv_routes
    from user_routes.routes import user_routes
    from simulator.routes import simulator
    app.register_blueprint(warden)
    app.register_blueprint(errors)
    app.register_blueprint(api)
    app.register_blueprint(csv_routes)
    app.register_blueprint(user_routes)
    app.register_blueprint(simulator)

    # Prepare app to receive Specter Server info
    # For the first load, just get a saved file if available
    # The background jobs will update later
    with app.app_context():
        from specter_importer import Specter
        app.specter = Specter()
        app.specter.refresh_txs(load=True)
        app.downloading = False

    with app.app_context():
        app.runningInDocker = runningInDocker()

    with app.app_context():
        app.tor = create_tor()

    # Check if home folder exists, if not create
    home = str(Path.home())
    home_path = os.path.join(home, 'warden/')
    try:
        os.makedirs(os.path.dirname(home_path))
    except Exception:
        pass

    # Start Schedulers
    from backgroundjobs import (background_settings_update,
                                background_specter_update,
                                background_scan_network,
                                background_specter_health,
                                background_mempool_seeker)

    def bk_su():
        with app.app_context():
            background_specter_update()

    def bk_stu():
        with app.app_context():
            background_settings_update()

    def bk_scan():
        with app.app_context():
            background_scan_network()

    def bk_specter_health():
        with app.app_context():
            background_specter_health()

    def bk_mempool_health():
        with app.app_context():
            background_mempool_seeker()

    app.scheduler = BackgroundScheduler()
    app.scheduler.add_job(bk_su, 'interval', seconds=1)
    app.scheduler.add_job(bk_stu, 'interval', seconds=1)
    app.scheduler.add_job(bk_scan, 'interval', seconds=1)
    app.scheduler.add_job(bk_specter_health, 'interval', seconds=1)
    app.scheduler.add_job(bk_mempool_health, 'interval', seconds=1)
    app.scheduler.start()
    print(success("✅ Background jobs running"))
    print("")
    app.app_context().push()

    print(success("✅ Application startup is complete"))

    return app
Example #9
0
def warden_page():
    # For now pass only static positions, will update prices and other
    # data through javascript after loaded. This improves load time
    # and refresh speed.
    # Get positions and prepare df for delivery

    try:
        df = positions()
    except Exception:
        flash("Seems like transactions may be downloading... Check Specter Transactions for status.", "warning")
        return redirect(url_for("warden.newtrade"))

    if df.empty:
        flash("No Transactions Found. You can start by including a transaction below. You may also Connect to Specter or import a CSV file.", "info")
        return redirect(url_for("warden.newtrade"))

    if df.index.name != 'trade_asset_ticker':
        df.set_index('trade_asset_ticker', inplace=True)
    df = df[df['is_currency'] == 0].sort_index(ascending=True)
    df = df.to_dict(orient='index')

    # Create a custody DF
    transactions = transactions_fx()
    custody_df = transactions.groupby(["trade_account", "trade_asset_ticker"
                                       ])[["trade_quantity"]].sum()

    # Open Counter, increment, send data
    counter_file = os.path.join(home_path(),
                                'warden/counter.json')
    donated = False
    try:
        with open(counter_file) as data_file:
            json_all = json.loads(data_file.read())
        if json_all == "donated":
            donated = True
        else:
            counter = int(json_all)
            counter += 1
            if counter == 25:
                flash(
                    "Looks like you've been using the app frequently. " +
                    "Awesome! Consider donating.", "info")
            if counter == 50:
                flash(
                    "Open Source software is transparent and free. " +
                    "Support it. Make a donation.", "info")
            if counter == 200:
                flash(
                    "Looks like you are a frequent user of the WARden. " +
                    "Have you donated?", "info")
            if counter >= 1000:
                flash(
                    "You've opened this page 1,000 times or more. " +
                    "Really! Time to make a donation?", "danger")
            with open(counter_file, 'w') as fp:
                json.dump(counter, fp)

    except Exception:
        # File wasn't found. Create start at zero
        if not donated:
            flash(
                "Welcome. Consider making a donation " +
                "to support this software.", "info")
            counter = 0
            with open(counter_file, 'w') as fp:
                json.dump(counter, fp)

    meta = warden_metadata()

    # Sort the wallets by balance
    sorted_wallet_list = []
    try:
        for wallet in current_app.specter.wallet_alias_list():
            wallet_df = meta['full_df'].loc[meta['full_df']['wallet_alias'] == wallet]
            if wallet_df.empty:
                balance = 0
            else:
                balance = wallet_df['amount'].sum()
            sorted_wallet_list.append((wallet, balance))

        sorted_wallet_list = sorted(sorted_wallet_list, reverse=True, key=itemgetter(1))
        sorted_wallet_list = [i[0] for i in sorted_wallet_list]
        wallets_exist = True
    except Exception:
        wallets_exist = False

    from api.routes import alert_activity
    if not current_app.downloading:
        activity = alert_activity()
    else:
        activity = False

    templateData = {
        "title": "Portfolio Dashboard",
        "warden_metadata": meta,
        "portfolio_data": df,
        "FX": current_app.settings['PORTFOLIO']['base_fx'],
        "donated": donated,
        "alerts": activity,
        "current_app": current_app,
        "sorted_wallet_list": sorted_wallet_list,
        "wallets_exist": wallets_exist,
        "custody_df": custody_df
    }
    return (render_template('warden/warden.html', **templateData))
Example #10
0
 def test_paths(self):
     print("Checking that current and home paths can be returned...")
     print(f"Current Path: {current_path()}")
     print(f"Home Path: {home_path()}")
     self.assertIsNotNone(current_path())
     self.assertIsNotNone(home_path())