Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update master #2744

Merged
merged 7 commits into from
Sep 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading