Skip to content
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
33 changes: 15 additions & 18 deletions src/apify/_proxy_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,9 @@ def __init__(
self._country_code = country_code

async def initialize(self) -> None:
"""Load the Apify Proxy password if the API token is provided and check access to Apify Proxy and proxy groups.
"""Check if using proxy, if so, check the access.

Load the Apify Proxy password from API (only if not passed to constructor or through env var).

Only called if Apify Proxy configuration is used. Also checks if country has access to Apify Proxy groups
if the country code is provided.
Expand All @@ -187,7 +189,17 @@ async def initialize(self) -> None:
`ProxyConfiguration` instance instead of calling this manually.
"""
if self._uses_apify_proxy:
await self._maybe_fetch_password()
if not self._password:
await self._maybe_fetch_password()
if not self._password:
raise ValueError(
'Apify Proxy password must be provided using the "password" constructor argument '
f'or the "{ApifyEnvVars.PROXY_PASSWORD}" environment variable. '
f'You can also provide your Apify token via the "${ApifyEnvVars.TOKEN}" environment variable, '
f'so that the SDK can fetch the proxy password from Apify API, '
f'when not provided through constructor or ${ApifyEnvVars.PROXY_PASSWORD}.'
)

await self._check_access()

async def new_proxy_info(
Expand Down Expand Up @@ -255,22 +267,7 @@ async def _maybe_fetch_password(self) -> None:
user_info = await self._apify_client.user().get()
if user_info:
password = user_info['proxy']['password']

if self._password:
if self._password != password:
logger.warning(
'The Apify Proxy password you provided belongs to a different user than the Apify '
'token you are using. Are you sure this is correct?'
)
else:
self._password = password

if not self._password:
raise ValueError(
'Apify Proxy password must be provided using the "password" constructor argument '
f'or the "{ApifyEnvVars.PROXY_PASSWORD}" environment variable. If you add '
f'the "{ApifyEnvVars.TOKEN}" environment variable, the password will be automatically inferred.'
)
self._password = password

async def _check_access(self) -> None:
proxy_status_url = f'{self._configuration.proxy_status_url}/?format=json'
Expand Down
30 changes: 30 additions & 0 deletions tests/unit/test_proxy_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,36 @@ async def test_initialize_with_manual_password(monkeypatch: pytest.MonkeyPatch,
assert proxy_configuration.is_man_in_the_middle is False


async def test_initialize_prefering_password_from_env_over_calling_api(
monkeypatch: pytest.MonkeyPatch,
respx_mock: MockRouter,
patched_apify_client: ApifyClientAsync,
) -> None:
dummy_proxy_status_url = 'http://dummy-proxy-status-url.com'
monkeypatch.setenv(ApifyEnvVars.PROXY_STATUS_URL.value, dummy_proxy_status_url)
monkeypatch.setenv(ApifyEnvVars.PROXY_PASSWORD.value, DUMMY_PASSWORD)

respx_mock.get(dummy_proxy_status_url).mock(
httpx.Response(
200,
json={
'connected': True,
'connectionError': None,
'isManInTheMiddle': False,
},
)
)

proxy_configuration = ProxyConfiguration()

await proxy_configuration.initialize()

assert proxy_configuration._password == DUMMY_PASSWORD
assert proxy_configuration.is_man_in_the_middle is False

assert len(patched_apify_client.calls['user']['get']) == 0 # type: ignore[attr-defined]


@pytest.mark.skip(reason='There are issues with log propagation to caplog, see issue #462.')
async def test_initialize_with_manual_password_different_than_user_one(
monkeypatch: pytest.MonkeyPatch,
Expand Down