Skip to content

Commit

Permalink
Merge pull request #2720 from Drakkar-Software/dev
Browse files Browse the repository at this point in the history
Dev merge
  • Loading branch information
GuillaumeDSM authored Aug 25, 2024
2 parents aaec1d1 + 2bb3c49 commit 9d2c2ed
Show file tree
Hide file tree
Showing 12 changed files with 130 additions and 21 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

*It is strongly advised to perform an update of your tentacles after updating OctoBot. (start.py tentacles --install --all)*

## [2.0.4] - 2024-08-25
### Added
- [BitMart] The BitMart exchange is now officially supported
- [GridTrading] Fund redispatch delay config
### Updated
- [WebInterface] Improve portfolio history display and make it more flexible
- [Webhook] Make error messages easier to understand
- [CCXT] update to ccxt 4.3.85
- [Community] Fix community authentication related issues
### Fixed
- [GridTrading] Fixed grid reset issues when funds redispatch is enabled
- [MEXC] Fixed MEXC traded pairs fetching issues
- [OKX] Fixed leveraging parsing issues
- [WebInterface] Fixed order cancel UI issues
- [Configuration] Fixed recovery file related iss

## [2.0.3] - 2024-08-03
### Added
- [IndexTradingMode]: Default profile, intra-day, real time update option and custom content
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# OctoBot [2.0.3](https://github.com/Drakkar-Software/OctoBot/blob/master/CHANGELOG.md)
# OctoBot [2.0.4](https://github.com/Drakkar-Software/OctoBot/blob/master/CHANGELOG.md)
[![PyPI](https://img.shields.io/pypi/v/OctoBot.svg?logo=pypi)](https://pypi.org/project/OctoBot)
[![Downloads](https://pepy.tech/badge/octobot/month)](https://pepy.tech/project/octobot)
[![Dockerhub](https://img.shields.io/docker/pulls/drakkarsoftware/octobot.svg?logo=docker)](https://hub.docker.com/r/drakkarsoftware/octobot)
Expand Down
4 changes: 4 additions & 0 deletions additional_tests/supabase_backend_tests/.env.template
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ SUPABASE_BACKEND_KEY=

SUPABASE_BACKEND_CLIENT_1_EMAIL=
SUPABASE_BACKEND_CLIENT_1_PASSWORD=
SUPABASE_BACKEND_CLIENT_1_AUTH_KEY=

SUPABASE_BACKEND_CLIENT_2_EMAIL=
SUPABASE_BACKEND_CLIENT_2_PASSWORD=

SUPABASE_BACKEND_CLIENT_3_EMAIL=
SUPABASE_BACKEND_CLIENT_3_PASSWORD=

SUPABASE_BACKEND_SERVICE_KEY=
4 changes: 4 additions & 0 deletions additional_tests/supabase_backend_tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,10 @@ def get_backend_client_creds(identifier):
os.getenv(f"SUPABASE_BACKEND_CLIENT_{identifier}_PASSWORD")


def get_backend_client_auth_key(identifier):
return os.getenv(f"SUPABASE_BACKEND_CLIENT_{identifier}_AUTH_KEY")


def _get_backend_service_key():
return os.getenv(f"SUPABASE_BACKEND_SERVICE_KEY")

Expand Down
50 changes: 49 additions & 1 deletion additional_tests/supabase_backend_tests/test_user_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
import octobot.community as community
import octobot.community.supabase_backend.enums as supabase_backend_enums
from additional_tests.supabase_backend_tests import authenticated_client_1, authenticated_client_2, \
admin_client, anon_client, get_backend_api_creds, skip_if_no_service_key
admin_client, anon_client, get_backend_api_creds, skip_if_no_service_key, get_backend_client_creds, \
get_backend_client_auth_key


# All test coroutines will be treated as marked.
Expand Down Expand Up @@ -114,3 +115,50 @@ async def test_sign_in_with_otp_token(authenticated_client_1, skip_if_no_service
finally:
if supabase_client:
await supabase_client.aclose()


async def test_sign_in_with_auth_token():
# create new client
backend_url, backend_key = get_backend_api_creds()
email, _ = get_backend_client_creds(1)

config = commons_configuration.Configuration("", "")
config.config = {}
supabase_client = None
try:
supabase_client = community.CommunitySupabaseClient(
backend_url,
backend_key,
community.ASyncConfigurationStorage(config)
)
saved_session = "saved_session"
await supabase_client.auth._storage.set_item(supabase_client.auth._storage_key, saved_session)
# wrong configs
with pytest.raises(authentication.AuthenticationError):
await supabase_client.get_otp_with_auth_key("", "")
with pytest.raises(authentication.AuthenticationError):
await supabase_client.get_otp_with_auth_key(None, "")
with pytest.raises(authentication.AuthenticationError):
await supabase_client.get_otp_with_auth_key(email, None)
with pytest.raises(authentication.AuthenticationError):
await supabase_client.get_otp_with_auth_key(email, "1234")
assert await supabase_client.auth._storage.get_item(supabase_client.auth._storage_key) == saved_session
token = await supabase_client.get_otp_with_auth_key(email, get_backend_client_auth_key(1))
# ensure token is valid

await supabase_client.sign_in_with_otp_token(token)
# save session has been updated
updated_session = await supabase_client.auth._storage.get_item(supabase_client.auth._storage_key)
assert updated_session != saved_session

# ensure new supabase_client is bound to the same user as the previous client
user = await supabase_client.get_user()
assert user[supabase_backend_enums.UserKeys.EMAIL.value] == email

# already consumed token
with pytest.raises(authentication.AuthenticationError):
await supabase_client.sign_in_with_otp_token(token)
assert await supabase_client.auth._storage.get_item(supabase_client.auth._storage_key) == updated_session
finally:
if supabase_client:
await supabase_client.aclose()
2 changes: 1 addition & 1 deletion octobot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@

PROJECT_NAME = "OctoBot"
AUTHOR = "Drakkar-Software"
VERSION = "2.0.3" # major.minor.revision
VERSION = "2.0.4" # major.minor.revision
LONG_VERSION = f"{VERSION}"
25 changes: 17 additions & 8 deletions octobot/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
#
# You should have received a copy of the GNU General Public
# License along with OctoBot. If not, see <https://www.gnu.org/licenses/>.
import time
import argparse
import os
import sys
Expand Down Expand Up @@ -189,13 +188,23 @@ async def _get_authenticated_community_if_possible(config, logger):
community_auth = octobot_community.CommunityAuthentication.create(config)
try:
if not community_auth.is_initialized():
if constants.IS_CLOUD_ENV and constants.USER_ACCOUNT_EMAIL and constants.USER_PASSWORD_TOKEN:
try:
await community_auth.login(
constants.USER_ACCOUNT_EMAIL, None, password_token=constants.USER_PASSWORD_TOKEN
)
except authentication.AuthenticationError as err:
logger.debug(f"Password token auth failure ({err}). Trying with saved session.")
if constants.IS_CLOUD_ENV:
if constants.USER_ACCOUNT_EMAIL and constants.USER_AUTH_KEY:
try:
logger.debug("Attempting auth key authentication")
await community_auth.login(
constants.USER_ACCOUNT_EMAIL, None, auth_key=constants.USER_AUTH_KEY
)
except authentication.AuthenticationError as err:
logger.debug(f"Auth key auth failure ({err}). Trying other methods if available.")
if constants.USER_ACCOUNT_EMAIL and constants.USER_PASSWORD_TOKEN:
try:
logger.debug("Attempting password token authentication")
await community_auth.login(
constants.USER_ACCOUNT_EMAIL, None, password_token=constants.USER_PASSWORD_TOKEN
)
except authentication.AuthenticationError as err:
logger.debug(f"Password token auth failure ({err}). Trying with saved session.")
if not community_auth.is_initialized():
# try with saved credentials if any
has_tentacles = tentacles_manager_api.is_tentacles_architecture_valid()
Expand Down
18 changes: 15 additions & 3 deletions octobot/community/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ def __init__(self, config=None, backend_url=None, backend_key=None, use_as_singl
self.user_account = community_user_account.CommunityUserAccount()
self.public_data = community_public_data.CommunityPublicData()
self.successfully_fetched_tentacles_package_urls = False
self.silent_auth = False
self._community_feed = None

self.initialized_event = None
Expand Down Expand Up @@ -305,11 +306,20 @@ def can_authenticate(self):
def must_be_authenticated_through_authenticator(self):
return constants.IS_CLOUD_ENV

async def login(self, email, password, password_token=None, minimal=False):
async def login(
self,
email: str,
password: typing.Optional[str],
password_token: typing.Optional[str] = None,
auth_key: typing.Optional[str] = None,
minimal: bool = False
):
self._ensure_email(email)
self._ensure_community_url()
self._reset_tokens()
with self._login_process():
if auth_key and not password_token:
password_token = await self.supabase_client.get_otp_with_auth_key(email, auth_key)
if password_token:
await self.supabase_client.sign_in_with_otp_token(password_token)
else:
Expand All @@ -331,7 +341,8 @@ async def register(self, email, password):
await self.on_signed_in()

async def on_signed_in(self, minimal=False):
self.logger.info(f"Signed in as {self.get_logged_in_email()}")
if not self.silent_auth:
self.logger.info(f"Signed in as {self.get_logged_in_email()}")
await self._initialize_account(minimal=minimal)

async def _update_account_metadata(self, metadata_update):
Expand Down Expand Up @@ -669,7 +680,8 @@ async def _restore_previous_session(self):
# will raise on failure
await self.supabase_client.restore_session()
await self._on_account_updated()
self.logger.info(f"Signed in as {self.get_logged_in_email()}")
if not self.silent_auth:
self.logger.info(f"Signed in as {self.get_logged_in_email()}")
return self.is_logged_in()

@contextlib.asynccontextmanager
Expand Down
6 changes: 3 additions & 3 deletions octobot/community/errors_upload/sentry_tracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ def init_sentry_tracker():
"""
Will upload errors to octobot.constants.ERROR_TRACKER_DSN if its value is set
"""
logger = octobot_commons.logging.get_logger(__name__)
logger = octobot_commons.logging.get_logger("sentry_tracker")
if not octobot.constants.ERROR_TRACKER_DSN:
logger.debug(f"Skipping error tracker: error tracker dsn is '{octobot.constants.ERROR_TRACKER_DSN}'")
logger.debug(f"Error tracker disabled")
return
environment = "cloud" if octobot.constants.IS_CLOUD_ENV else "self hosted"
app_name = f"{octobot.constants.PROJECT_NAME} open source"
Expand Down Expand Up @@ -72,7 +72,7 @@ def init_sentry_tracker():
def flush_tracker():
if octobot.constants.ERROR_TRACKER_DSN:
delay = 2
octobot_commons.logging.get_logger(__name__).info(f"Flushing trackers: shutting down in {delay} seconds ...")
octobot_commons.logging.get_logger("sentry_tracker").info(f"Flushing trackers: shutting down in {delay} seconds ...")
sentry_sdk.flush()
# let trackers upload errors
time.sleep(delay)
Expand Down
19 changes: 17 additions & 2 deletions octobot/community/supabase_backend/community_supabase_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import logging
import httpx
import uuid
import json

import aiohttp
import gotrue.errors
Expand Down Expand Up @@ -211,8 +212,22 @@ async def get_user(self) -> dict:
raise errors.EmailValidationRequiredError(err) from err
raise authentication.AuthenticationError(f"Please re-login to your OctoBot account: {err}") from err

def sync_get_user(self) -> dict:
return self.auth.get_user().user.model_dump()
async def get_otp_with_auth_key(self, user_email: str, auth_key: str) -> str:
try:
resp = await self.functions.invoke(
"create-auth-token",
{
"headers": {
"User-Auth-Token": auth_key
},
"body": {
"user_email": user_email
},
}
)
return json.loads(resp)["token"]
except Exception:
raise authentication.AuthenticationError(f"Invalid auth key authentication details")

async def fetch_bot(self, bot_id) -> dict:
try:
Expand Down
1 change: 1 addition & 0 deletions octobot/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
USE_BETA_EARLY_ACCESS = os_util.parse_boolean_environment_var("USE_BETA_EARLY_ACCESS", "false")
USER_ACCOUNT_EMAIL = os.getenv("USER_ACCOUNT_EMAIL", "")
USER_PASSWORD_TOKEN = os.getenv("USER_PASSWORD_TOKEN", None)
USER_AUTH_KEY = os.getenv("USER_AUTH_KEY", None)
COMMUNITY_BOT_ID = os.getenv("COMMUNITY_BOT_ID", "")
IS_DEMO = os_util.parse_boolean_environment_var("IS_DEMO", "False")
IS_CLOUD_ENV = os_util.parse_boolean_environment_var("IS_CLOUD_ENV", "false")
Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Drakkar-Software requirements
OctoBot-Commons==1.9.54
OctoBot-Trading==2.4.100
OctoBot-Commons==1.9.55
OctoBot-Trading==2.4.103
OctoBot-Evaluators==1.9.5
OctoBot-Tentacles-Manager==2.9.16
OctoBot-Services==1.6.17
Expand Down

0 comments on commit 9d2c2ed

Please sign in to comment.