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

use a-z for sms mfa index #925 #929

Merged
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Unreleased

- fix: use a-z for sms mfa index to disambiguate with mfa code with leading zeros [#925](https://github.com/icloud-photos-downloader/icloud_photos_downloader/issues/925)

## 1.23.0 (2024-07-25)

- feature: update webui and allow to cancel and resume sync
Expand Down
59 changes: 48 additions & 11 deletions src/icloudpd/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,35 +131,72 @@ def request_2fa(icloud: PyiCloudService, logger: logging.Logger) -> None:
"""Request two-factor authentication."""
devices = icloud.get_trusted_phone_numbers()
devices_count = len(devices)
device_index_alphabet = "abcdefghijklmnopqrstuvwxyz"
if devices_count > 0:
if devices_count > 99:
if devices_count > len(device_index_alphabet):
logger.error("Too many trusted devices for authentication")
sys.exit(1)

for i, device in enumerate(devices):
print(f" {i}: {device.obfuscated_number}")
print(f" {device_index_alphabet[i]}: {device.obfuscated_number}")

index_str = f"..{devices_count - 1}" if devices_count > 1 else ""
code: int = click.prompt(
f"Please enter two-factor authentication code or device index (0{index_str}) to send SMS with a code",
type=click.IntRange(0, 999999),
)
index_str = f"..{device_index_alphabet[devices_count - 1]}" if devices_count > 1 else ""
index_or_code: str = ""
while True:
index_or_code = (
click.prompt(
f"Please enter two-factor authentication code or device index ({device_index_alphabet[0]}{index_str}) to send SMS with a code",
)
.strip()
.lower()
)

if index_or_code == "":
click.echo("Empty string. Try again")
continue

if len(index_or_code) == 1:
if index_or_code in device_index_alphabet:
if device_index_alphabet.index(index_or_code) > devices_count - 1:
click.echo(
f"Invalid index, should be {device_index_alphabet[0]}{index_str}. Try again"
)
continue
else:
break
else:
click.echo(
f"Invalid index, should be {device_index_alphabet[0]}{index_str}. Try again"
)
continue

if len(index_or_code) == 6:
if index_or_code.isdigit():
break
else:
click.echo("Invalid code, should be six digits. Try again")
continue

click.echo(
f"Should be index {device_index_alphabet[0]}{index_str} or six-digit code. Try again"
)

if code < devices_count:
if index_or_code in device_index_alphabet:
# need to send code
device = devices[code]
device_index = device_index_alphabet.index(index_or_code)
device = devices[device_index]
if not icloud.send_2fa_code_sms(device.id):
logger.error("Failed to send two-factor authentication code")
sys.exit(1)
code = click.prompt(
code: int = click.prompt(
"Please enter two-factor authentication code that you received over SMS",
type=click.IntRange(0, 999999),
)
if not icloud.validate_2fa_code_sms(device.id, code):
logger.error("Failed to verify two-factor authentication code")
sys.exit(1)
else:
if not icloud.validate_2fa_code(str(code)):
if not icloud.validate_2fa_code(index_or_code):
logger.error("Failed to verify two-factor authentication code")
sys.exit(1)
else:
Expand Down
12 changes: 8 additions & 4 deletions tests/test_authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,14 @@ def test_password_prompt_2sa(self) -> None:
[
"--username",
"jdoe@gmail.com",
"--password",
"password1",
"--no-progress-bar",
"--cookie-directory",
cookie_dir,
"--auth-only",
],
input="password1\n0\n654321\n",
input="0\n654321\n",
)
self.assertIn("DEBUG Authenticating...", self._caplog.text)
self.assertIn(
Expand Down Expand Up @@ -217,21 +219,23 @@ def test_password_prompt_2fa(self) -> None:
[
"--username",
"jdoe@gmail.com",
"--password",
"password1",
"--no-progress-bar",
"--cookie-directory",
cookie_dir,
"--auth-only",
],
input="password1\n654321\n",
input="654321\n",
)
self.assertIn("DEBUG Authenticating...", self._caplog.text)
self.assertIn(
"INFO Two-factor authentication is required",
self._caplog.text,
)
self.assertIn(" 0: (***) ***-**81", result.output)
self.assertIn(" a: (***) ***-**81", result.output)
self.assertIn(
"Please enter two-factor authentication code or device index (0) to send SMS with a code: 654321",
"Please enter two-factor authentication code or device index (a) to send SMS with a code: 654321",
result.output,
)
self.assertIn(
Expand Down
2 changes: 1 addition & 1 deletion tests/test_two_step_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ def test_2fa_flow_valid_code(self) -> None:
self._caplog.text,
)
self.assertIn(
"Please enter two-factor authentication code or device index (0) to send SMS with a code: 654321",
"Please enter two-factor authentication code or device index (a) to send SMS with a code: 654321",
result.output,
)
self.assertIn(
Expand Down
Loading