Skip to content

Commit

Permalink
Merge pull request #157 from hummingbot/feat/auth_system
Browse files Browse the repository at this point in the history
Feat/auth system
  • Loading branch information
cardosofede authored Jul 11, 2024
2 parents 1fbe59e + 61f4c57 commit 7934522
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 144 deletions.
7 changes: 3 additions & 4 deletions CONFIG.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@

from dotenv import load_dotenv


load_dotenv()

MINER_COINS = ["Algorand", "Avalanche", "DAO Maker", "Faith Tribe", "Fear", "Frontier",
"Harmony", "Hot Cross", "HUMAN Protocol", "Oddz", "Shera", "Firo",
"Vesper Finance", "Youclout", "Nimiq"]
"Harmony", "Hot Cross", "HUMAN Protocol", "Oddz", "Shera", "Firo",
"Vesper Finance", "Youclout", "Nimiq"]
MINER_EXCHANGES = ["Binance", "FTX", "Coinbase Exchange", "Huobi Global", "OKX", "KuCoin",
"Kraken", "Bybit (Spot)", "FTX.US", "Crypto.com Exchange", "Binance US",
"MEXC Global", "Gate.io", "BitMart", "Bitfinex", "AscendEX (BitMax)",
Expand All @@ -18,7 +17,7 @@
CERTIFIED_EXCHANGES = ["ascendex", "binance", "bybit", "gate.io", "hitbtc", "huobi", "kucoin", "okx", "gateway"]
CERTIFIED_STRATEGIES = ["xemm", "cross exchange market making", "pmm", "pure market making"]

AUTH_SYSTEM_ENABLED = False
AUTH_SYSTEM_ENABLED = os.getenv("AUTH_SYSTEM_ENABLED", False)

BACKEND_API_HOST = os.getenv("BACKEND_API_HOST", "127.0.0.1")
BACKEND_API_PORT = os.getenv("BACKEND_API_PORT", 8000)
13 changes: 7 additions & 6 deletions credentials.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
cookie:
expiry_days: 30
key: random_signature_key
name: random_cookie_name
credentials:
usernames:
admin:
email: [email protected]
name: Admin User
password: abc # To be replaced with hashed password: hashed_passwords = stauth.Hasher(['abc', 'def']).generate()
preauthorized: # the preferred way to add users since there is no need for manual hashing of passwords
logged_in: False
password: abc
cookie:
expiry_days: 30
key: some_signature_key # Must be string
name: some_cookie_name
pre-authorized:
emails:
- [email protected]
3 changes: 0 additions & 3 deletions frontend/pages/orchestration/credentials/app.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
from backend.services.backend_api_client import BackendAPIClient
from frontend.st_utils import initialize_st_page, get_backend_api_client
import streamlit as st


initialize_st_page(title="Credentials", icon="🔑")

# Page content
Expand Down
2 changes: 0 additions & 2 deletions frontend/pages/orchestration/instances/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
from streamlit_elements import elements, mui
from types import SimpleNamespace

from CONFIG import BACKEND_API_HOST, BACKEND_API_PORT
from frontend.components.bot_performance_card import BotPerformanceCardV2
from frontend.components.dashboard import Dashboard
from backend.services.backend_api_client import BackendAPIClient
from frontend.st_utils import initialize_st_page, get_backend_api_client

# Constants for UI layout
Expand Down
33 changes: 33 additions & 0 deletions frontend/pages/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from st_pages import Page, Section


def main_page():
return [Page("main.py", "Hummingbot Dashboard", "📊"),]


def public_pages():
return [
Section("Config Generator", "🎛️"),
Page("frontend/pages/config/pmm_simple/app.py", "PMM Simple", "👨‍🏫"),
Page("frontend/pages/config/pmm_dynamic/app.py", "PMM Dynamic", "👩‍🏫"),
Page("frontend/pages/config/dman_maker_v2/app.py", "D-Man Maker V2", "🤖"),
Page("frontend/pages/config/bollinger_v1/app.py", "Bollinger V1", "📈"),
Page("frontend/pages/config/macd_bb_v1/app.py", "MACD_BB V1", "📊"),
Page("frontend/pages/config/supertrend_v1/app.py", "SuperTrend V1", "👨‍🔬"),
Page("frontend/pages/config/xemm_controller/app.py", "XEMM Controller", "⚡️"),
Section("Data", "💾"),
Page("frontend/pages/data/download_candles/app.py", "Download Candles", "💹"),
Section("Community Pages", "👨‍👩‍👧‍👦"),
Page("frontend/pages/data/token_spreads/app.py", "Token Spreads", "🧙"),
Page("frontend/pages/data/tvl_vs_mcap/app.py", "TVL vs Market Cap", "🦉"),
]


def private_pages():
return [
Section("Bot Orchestration", "🐙"),
Page("frontend/pages/orchestration/instances/app.py", "Instances", "🦅"),
Page("frontend/pages/orchestration/launch_bot_v2/app.py", "Deploy V2", "🚀"),
Page("frontend/pages/orchestration/credentials/app.py", "Credentials", "🔑"),
Page("frontend/pages/orchestration/portfolio/app.py", "Portfolio", "💰"),
]
37 changes: 36 additions & 1 deletion frontend/st_utils.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import os.path

import streamlit_authenticator as stauth
import pandas as pd
from pathlib import Path
import inspect

import streamlit as st
from st_pages import add_page_title
import yaml
from st_pages import add_page_title, show_pages
from yaml import SafeLoader

from CONFIG import AUTH_SYSTEM_ENABLED
from frontend.pages.permissions import main_page, private_pages, public_pages


def initialize_st_page(title: str, icon: str, layout="wide", initial_sidebar_state="expanded"):
Expand Down Expand Up @@ -81,3 +87,32 @@ def get_backend_api_client():
st.error("Docker is not running. Please make sure Docker is running.")
st.stop()
return backend_api_client


def auth_system():
if not AUTH_SYSTEM_ENABLED:
show_pages(main_page() + private_pages() + public_pages())
else:
with open('credentials.yml') as file:
config = yaml.load(file, Loader=SafeLoader)
if "authenticator" not in st.session_state:
st.session_state.authenticator = stauth.Authenticate(
config['credentials'],
config['cookie']['name'],
config['cookie']['key'],
config['cookie']['expiry_days'],
config['pre-authorized']
)
st.session_state.authenticator.login()
if st.session_state["authentication_status"]:
st.session_state.authenticator.logout(location="sidebar")
st.sidebar.write(f'Welcome *{st.session_state["name"]}*')
show_pages(main_page() + private_pages() + public_pages())

else:
show_pages(main_page() + public_pages())
st.session_state.authenticator.login()
if st.session_state["authentication_status"] is False:
st.error('Username/password is incorrect')
elif st.session_state["authentication_status"] is None:
st.warning('Please enter your username and password')
141 changes: 13 additions & 128 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,134 +1,19 @@
import streamlit as st
from st_pages import Page, Section, show_pages
from streamlit_authenticator import Authenticate
from frontend.st_utils import auth_system

from CONFIG import AUTH_SYSTEM_ENABLED
from backend.utils.os_utils import read_yaml_file, dump_dict_to_yaml


def main_page():
show_pages(
[
Page("main.py", "Hummingbot Dashboard", "📊"),
Section("Bot Orchestration", "🐙"),
Page("frontend/pages/orchestration/instances/app.py", "Instances", "🦅"),
Page("frontend/pages/orchestration/launch_bot_v2/app.py", "Deploy V2", "🚀"),
Page("frontend/pages/orchestration/credentials/app.py", "Credentials", "🔑"),
Page("frontend/pages/orchestration/portfolio/app.py", "Portfolio", "💰"),
# Page("frontend/pages/orchestration/launch_bot_v2_st/app.py", "Deploy ST", "🙌"),
# Page("pages/file_manager/app.py", "File Explorer", "🗂"),
Section("Config Generator", "🎛️"),
Page("frontend/pages/config/pmm_simple/app.py", "PMM Simple", "👨‍🏫"),
Page("frontend/pages/config/pmm_dynamic/app.py", "PMM Dynamic", "👩‍🏫"),
Page("frontend/pages/config/dman_maker_v2/app.py", "D-Man Maker V2", "🤖"),
Page("frontend/pages/config/bollinger_v1/app.py", "Bollinger V1", "📈"),
Page("frontend/pages/config/macd_bb_v1/app.py", "MACD_BB V1", "📊"),
Page("frontend/pages/config/supertrend_v1/app.py", "SuperTrend V1", "👨‍🔬"),
Page("frontend/pages/config/xemm_controller/app.py", "XEMM Controller", "⚡️"),
# Page("frontend/pages/config/position_builder/app.py", "Position Builder", "🔭"),
Section("Data", "💾"),
Page("frontend/pages/data/download_candles/app.py", "Download Candles", "💹"),
# Page("pages/create/create.py", "Create", "⚔️"),
# Page("pages/optimize/optimize.py", "Optimize", "🧪"),
# Page("pages/analyze/analyze.py", "Analyze", "🔬"),
Section("Community Pages", "👨‍👩‍👧‍👦"),
# Page("frontend/pages/performance/strategy_performance/app.py", "Strategy Performance", "🚀"),
Page("frontend/pages/data/token_spreads/app.py", "Token Spreads", "🧙"),
Page("frontend/pages/data/tvl_vs_mcap/app.py", "TVL vs Market Cap", "🦉"),
]
)

# Readme Section
readme_container = st.container()
with readme_container:
st.markdown("# 📊 Hummingbot Dashboard")
st.markdown("""
Hummingbot Dashboard is an open source application that helps you create, backtest, and optimize various
types of algo trading strategies. Afterwards, you can deploy them as [Hummingbot](http://hummingbot.org)
instances in either paper or live trading mode.""")

def main():
# readme section
st.markdown("# 📊 Hummingbot Dashboard")
st.markdown("""Hummingbot Dashboard is an open source application that helps you create, backtest, and optimize
various types of algo trading strategies. Afterwards, you can deploy them as [Hummingbot](http://hummingbot.org)""")
st.write("---")
st.header("Watch the Hummingbot Dashboard Tutorial!")
st.video("https://youtu.be/7eHiMPRBQLQ?si=PAvCq0D5QDZz1h1D")
st.header("Feedback and issues")
st.write("Please give us feedback in the **#dashboard** channel of the [hummingbot discord](https://discord.gg/hummingbot)! 🙏")
st.write("If you encounter any bugs or have suggestions for improvement, please create an issue in the [hummingbot dashboard github](https://github.com/hummingbot/dashboard).")

st.header("Getting Started")

st.write(
"Watch the [Hummingbot Dashboard Tutorial playlist](https://www.youtube.com/watch?v=a-kenMqRB00) to get started!")

# Container for the videos
container = st.container()

video_titles = [
"1 - Introduction to Dashboard",
"2 - Setting up the Environment",
"3 - Managing Credentials",
"4 - Using the Master Bot Profile",
"5 - Deploying Bots and Running Strategies",
"7 - Controllers, Backtesting, and Optimization",
"8 - Deploying Best Strategies from Backtests",
"9 - Conclusions and Next Steps"
]
# List of YouTube video links
video_links = [
"https://www.youtube.com/embed/a-kenMqRB00",
"https://www.youtube.com/embed/AbezIhb6iJg",
"https://www.youtube.com/embed/VmlD_WQVe4M",
"https://www.youtube.com/embed/MPQTnlDXPno",
"https://www.youtube.com/embed/915E-C2LWdg",
"https://www.youtube.com/embed/bAi2ok7_boo",
"https://www.youtube.com/embed/BJf3ml-9JIQ",
"https://www.youtube.com/embed/ug_SSZb2HYE",
]

# Ensure the lists have the same length
assert len(video_titles) == len(video_links), "Mismatch between titles and links."

# Create a carousel-like feature
video_selection = st.selectbox("Choose a video:", options=video_titles)

# Get the index of the selected video title
selected_index = video_titles.index(video_selection)

# Display the selected video
st.video(video_links[selected_index])

st.write("---")

st.header("Feedback and Issues")

st.write("Please give us feedback in the **#dashboard** channel of the [Hummingbot Discord](https://discord.gg/hummingbot)! 🙏")

st.write("If you encounter any bugs or have suggestions for improvement, please create an issue in the [Hummingbot Dashboard Github](https://github.com/hummingbot/dashboard).")


# config = read_yaml_file("credentials.yml")
#
# if "authenticator" not in st.session_state:
# st.session_state.authenticator = Authenticate(
# config['credentials'],
# config['cookie']['name'],
# config['cookie']['key'],
# config['cookie']['expiry_days'],
# config['preauthorized']
# )

# if not AUTH_SYSTEM_ENABLED:
main_page()
# elif st.session_state["authentication_status"]:
# config["credentials"] = st.session_state.authenticator_handler.credentials
# dump_dict_to_yaml(config, "credentials.yml")
# with st.sidebar:
# st.write(f'Welcome {st.session_state["name"]}!')
# st.session_state.authenticator.logout(location='sidebar') # Updated logout call
# main_page()
# else:
# show_pages([
# Page("main.py", "Hummingbot Dashboard", "📊"),
# ])
# name, authentication_status, username = st.session_state.authenticator.login(location='main') # Updated login call
# if st.session_state["authentication_status"] == False:
# st.error('Username/password is incorrect')
# elif st.session_state["authentication_status"] == None:
# st.warning('Please enter your username and password')
# st.write("---")
# st.write("If you are pre-authorized, you can login with your pre-authorized mail!")
# st.session_state.authenticator.register_user(location='main') # Updated register user call
auth_system()
main()

0 comments on commit 7934522

Please sign in to comment.