Skip to content

Commit

Permalink
Merge pull request #2744 from Drakkar-Software/dev
Browse files Browse the repository at this point in the history
Update master
  • Loading branch information
GuillaumeDSM authored Sep 8, 2024
2 parents b034427 + caf7912 commit 622f126
Show file tree
Hide file tree
Showing 31 changed files with 249 additions and 31 deletions.
38 changes: 31 additions & 7 deletions additional_tests/exchanges_tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import octobot_commons.constants as commons_constants
import octobot_commons.asyncio_tools as asyncio_tools
import octobot_commons.os_util as os_util
import octobot_commons.configuration as configuration
import octobot_commons.tests.test_config as test_config
import octobot_trading.api as trading_api
import octobot_trading.exchanges as exchanges
Expand Down Expand Up @@ -61,15 +62,18 @@ def get_name(self):


@contextlib.asynccontextmanager
async def get_authenticated_exchange_manager(exchange_name, exchange_tentacle_name, config=None,
credentials_exchange_name=None, market_filter=None):
async def get_authenticated_exchange_manager(
exchange_name, exchange_tentacle_name, config=None,
credentials_exchange_name=None, market_filter=None,
use_invalid_creds=False
):
credentials_exchange_name = credentials_exchange_name or exchange_name
_load_exchange_creds_env_variables_if_necessary()
config = {**test_config.load_test_config(), **config} if config else test_config.load_test_config()
if exchange_name not in config[commons_constants.CONFIG_EXCHANGES]:
config[commons_constants.CONFIG_EXCHANGES][exchange_name] = {}
config[commons_constants.CONFIG_EXCHANGES][exchange_name].update(_get_exchange_auth_details(
credentials_exchange_name
credentials_exchange_name, use_invalid_creds
))
exchange_type = config[commons_constants.CONFIG_EXCHANGES][exchange_name].get(
commons_constants.CONFIG_EXCHANGE_TYPE, exchanges.get_default_exchange_type(exchange_name))
Expand Down Expand Up @@ -129,15 +133,35 @@ def _load_exchange_creds_env_variables_if_necessary():
LOADED_EXCHANGE_CREDS_ENV_VARIABLES = True


def _get_exchange_auth_details(exchange_name):
return {
def _get_exchange_auth_details(exchange_name, use_invalid_creds):
config = {
commons_constants.CONFIG_EXCHANGE_KEY:
_get_exchange_credential_from_env(exchange_name, commons_constants.CONFIG_EXCHANGE_KEY),
commons_constants.CONFIG_EXCHANGE_SECRET:
_get_exchange_credential_from_env(exchange_name, commons_constants.CONFIG_EXCHANGE_SECRET),
commons_constants.CONFIG_EXCHANGE_SECRET: _get_exchange_credential_from_env(
exchange_name, commons_constants.CONFIG_EXCHANGE_SECRET
),
commons_constants.CONFIG_EXCHANGE_PASSWORD:
_get_exchange_credential_from_env(exchange_name, commons_constants.CONFIG_EXCHANGE_PASSWORD),
}
if use_invalid_creds:
_invalidate(config)
return config


def _invalidate(exchange_config: dict):
# try to invalidate key while returning a "plausible" value to avoid signature / parsing issues
decoded = configuration.decrypt_element_if_possible(
commons_constants.CONFIG_EXCHANGE_KEY, exchange_config, None
)
updated_decoded = decoded
for numb in range(9):
if str(numb) in decoded:
number_index = decoded.index(str(numb))
updated_decoded = f"{decoded[:number_index]}{numb + 1}{decoded[number_index+1:]}"
break
if updated_decoded == decoded:
raise ValueError("No number to invalid api key")
exchange_config[commons_constants.CONFIG_EXCHANGE_KEY] = configuration.encrypt(updated_decoded).decode()


def _get_exchange_credential_from_env(exchange_name, cred_suffix):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,17 @@ async def inner_test_get_account_id(self):
with pytest.raises(NotImplementedError):
await self.exchange_manager.exchange.get_account_id()

async def test_invalid_api_key_error(self):
with pytest.raises(trading_errors.AuthenticationError):
created_exchange = mock.Mock()
async with self.local_exchange_manager(use_invalid_creds=True):
created_exchange()
# should fail
await self.get_portfolio()
raise AssertionError("Did not raise")
# ensure self.local_exchange_manager did not raise
created_exchange.assert_called_once()

async def test_get_api_key_permissions(self):
async with self.local_exchange_manager():
await self.inner_test_get_api_key_permissions()
Expand Down Expand Up @@ -735,7 +746,7 @@ async def get_price(self, symbol=None):
))

@contextlib.asynccontextmanager
async def local_exchange_manager(self, market_filter=None, identifiers_suffix=None):
async def local_exchange_manager(self, market_filter=None, identifiers_suffix=None, use_invalid_creds=False):
try:
exchange_tentacle_name = self.EXCHANGE_TENTACLE_NAME or self.EXCHANGE_NAME.capitalize()
credentials_exchange_name = self.CREDENTIALS_EXCHANGE_NAME or self.EXCHANGE_NAME
Expand All @@ -746,7 +757,8 @@ async def local_exchange_manager(self, market_filter=None, identifiers_suffix=No
exchange_tentacle_name,
self.get_config(),
credentials_exchange_name=credentials_exchange_name,
market_filter=market_filter
market_filter=market_filter,
use_invalid_creds=use_invalid_creds,
) as exchange_manager:
self.exchange_manager = exchange_manager
yield
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_ascendex.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ async def test_get_account_id(self):
# pass if not implemented
pass

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
# pass if not implemented
pass
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_binance.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ async def test_get_portfolio_with_market_filter(self):
async def test_get_account_id(self):
await super().test_get_account_id()

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
await super().test_get_api_key_permissions()

Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_binance_futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ async def test_get_portfolio_with_market_filter(self):
async def test_get_account_id(self):
await super().test_get_account_id()

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
# pass if not implemented
pass
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_bingx.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ async def test_get_portfolio_with_market_filter(self):
async def test_get_account_id(self):
await super().test_get_account_id()

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
await super().test_get_api_key_permissions()

Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_bitget.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ async def test_get_account_id(self):
# pass if not implemented
pass

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
# pass if not implemented
pass
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_bitmart.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ async def test_get_account_id(self):
# pass if not implemented
pass

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
# pass if not implemented
pass
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_bybit.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ async def test_get_account_id(self):
# pass if not implemented
pass

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
# pass if not implemented
pass
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_bybit_futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ async def test_get_account_id(self):
# pass if not implemented
pass

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
# pass if not implemented
pass
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_coinbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ async def test_get_portfolio_with_market_filter(self):
async def test_get_account_id(self):
await super().test_get_account_id()

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
await super().test_get_api_key_permissions()

Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_coinex.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ async def test_get_account_id(self):
# pass if not implemented
pass

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
# pass if not implemented
pass
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_cryptocom.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ async def test_get_account_id(self):
# pass if not implemented
pass

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
# pass if not implemented
pass
Expand Down
4 changes: 4 additions & 0 deletions additional_tests/exchanges_tests/test_gateio.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ async def test_get_account_id(self):
# pass if not implemented
pass

async def test_invalid_api_key_error(self):
# await super().test_invalid_api_key_error() # raises Request timeout
pass

async def test_get_api_key_permissions(self):
# pass if not implemented
pass
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_hollaex.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ async def test_get_account_id(self):
# pass if not implemented
pass

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
# pass if not implemented
pass
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_htx.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ async def test_get_account_id(self):
# pass if not implemented
pass

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
# pass if not implemented
pass
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_kucoin.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ async def test_create_and_cancel_limit_orders(self):
async def test_get_account_id(self):
await super().test_get_account_id()

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
await super().test_get_api_key_permissions()

Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_kucoin_futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ async def test_get_portfolio_with_market_filter(self):
async def test_get_account_id(self):
await super().test_get_account_id()

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
await super().test_get_api_key_permissions()

Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_mexc.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ async def test_get_account_id(self):
# pass if not implemented
pass

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
# pass if not implemented
pass
Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_okx.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ async def test_create_and_cancel_limit_orders(self):
async def test_get_account_id(self):
await super().test_get_account_id()

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
await super().test_get_api_key_permissions()

Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_okx_futures.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ async def test_get_portfolio_with_market_filter(self):
async def test_get_account_id(self):
await super().test_get_account_id()

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
await super().test_get_api_key_permissions()

Expand Down
3 changes: 3 additions & 0 deletions additional_tests/exchanges_tests/test_phemex.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ async def test_get_account_id(self):
# pass if not implemented
pass

async def test_invalid_api_key_error(self):
await super().test_invalid_api_key_error()

async def test_get_api_key_permissions(self):
# pass if not implemented
pass
Expand Down
1 change: 1 addition & 0 deletions additional_tests/supabase_backend_tests/.env.template
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ SUPABASE_BACKEND_KEY=
SUPABASE_BACKEND_CLIENT_1_EMAIL=
SUPABASE_BACKEND_CLIENT_1_PASSWORD=
SUPABASE_BACKEND_CLIENT_1_AUTH_KEY=
SUPABASE_BACKEND_CLIENT_1_EXPIRED_JWT_TOKEN=

SUPABASE_BACKEND_CLIENT_2_EMAIL=
SUPABASE_BACKEND_CLIENT_2_PASSWORD=
Expand Down
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 @@ -221,6 +221,10 @@ def get_backend_client_auth_key(identifier):
return os.getenv(f"SUPABASE_BACKEND_CLIENT_{identifier}_AUTH_KEY")


def get_backend_client_expired_jwt_token(identifier):
return os.getenv(f"SUPABASE_BACKEND_CLIENT_{identifier}_EXPIRED_JWT_TOKEN")


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

Expand Down
38 changes: 37 additions & 1 deletion additional_tests/supabase_backend_tests/test_user_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,20 @@
# 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 mock
import postgrest
import pytest

import octobot_commons.configuration as commons_configuration
import octobot_commons.authentication as authentication
import octobot.community as community
import octobot.community.supabase_backend as supabase_backend
import octobot.community.errors as community_errors
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, get_backend_client_creds, \
get_backend_client_auth_key
get_backend_client_auth_key, get_backend_client_expired_jwt_token


# All test coroutines will be treated as marked.
Expand Down Expand Up @@ -162,3 +167,34 @@ async def test_sign_in_with_auth_token():
finally:
if supabase_client:
await supabase_client.aclose()


async def test_expired_jwt_token(authenticated_client_1):
initial_email = (await authenticated_client_1.get_user())[supabase_backend_enums.UserKeys.EMAIL.value]

# refreshing session is working
await authenticated_client_1.refresh_session()
# does not raise
bots = await authenticated_client_1.fetch_bots()
assert (await authenticated_client_1.get_user())[supabase_backend_enums.UserKeys.EMAIL.value] == initial_email

# use expired jwt token
expired_jwt_token = get_backend_client_expired_jwt_token(1)

# simulate auth using this token
session = mock.Mock(access_token=expired_jwt_token)
authenticated_client_1._listen_to_auth_events(
"SIGNED_IN", session
)

# now raising "APIError: JWT expired"
with pytest.raises(postgrest.APIError):
await authenticated_client_1.fetch_bots()

# now raising "APIError: JWT expired" which is converted into community_errors.SessionTokenExpiredError
with pytest.raises(community_errors.SessionTokenExpiredError):
with supabase_backend.error_describer():
await authenticated_client_1.fetch_bots()



Loading

0 comments on commit 622f126

Please sign in to comment.