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

Add rudimentary 2FA support #11

Closed
wants to merge 2 commits into from

Conversation

tinyvoice
Copy link

Logs in, checks for 2FA window, inputs one-time-code; finishes login; See https://github.com/crepererum/tatutanatata/issues/10

@tinyvoice tinyvoice mentioned this pull request Jan 17, 2023
Copy link
Member

@crepererum crepererum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, esp. considering that you don't have much Rust experience (needs a CI check though). Thanks a lot :)

Comment on lines +22 to +23
#[clap(long, default_value_t = 0.to_string(), env = "TUTANOTA_CLI_ONETIMECODE")]
onetimecode: String,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#[clap(long, default_value_t = 0.to_string(), env = "TUTANOTA_CLI_ONETIMECODE")]
onetimecode: String,
#[clap(long, env = "TUTANOTA_CLI_ONETIMECODE")]
onetimecode: Option<String>,

Should be optional. clap will default this to None and not complain if the env var (or the CLI parameter) is missing.

Comment on lines +65 to +93
// loggedin tracks if timeout loop exited due to successful login or due to 2FA detection
let mut loggedin = false;

// Check if login successful or if 2FA required (Cancel button appears)
tokio::time::timeout(Duration::from_secs(20), async {
loop {
if has_new_email_button(webdriver)
.await
.context("search new-email button")?
{
loggedin = true;
return Ok::<_, anyhow::Error>(()); // Login successful
}
else if has_cancel_button(webdriver)
.await
.context("search cancel button")?
{
// Cancel button present means 2FA needed
enter_onetimecode(&onetimecode, webdriver)
.await
.context("entering one-time-code and finishing login")?;
return Ok::<_, anyhow::Error>(()); // 2FA entered, logging in...
}

tokio::time::sleep(Duration::from_secs(1)).await;
}
})
.await
.context("wait for one-time-code or login")??;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// loggedin tracks if timeout loop exited due to successful login or due to 2FA detection
let mut loggedin = false;
// Check if login successful or if 2FA required (Cancel button appears)
tokio::time::timeout(Duration::from_secs(20), async {
loop {
if has_new_email_button(webdriver)
.await
.context("search new-email button")?
{
loggedin = true;
return Ok::<_, anyhow::Error>(()); // Login successful
}
else if has_cancel_button(webdriver)
.await
.context("search cancel button")?
{
// Cancel button present means 2FA needed
enter_onetimecode(&onetimecode, webdriver)
.await
.context("entering one-time-code and finishing login")?;
return Ok::<_, anyhow::Error>(()); // 2FA entered, logging in...
}
tokio::time::sleep(Duration::from_secs(1)).await;
}
})
.await
.context("wait for one-time-code or login")??;
// Check if login successful or if 2FA required (Cancel button appears)
let loggedin = tokio::time::timeout(Duration::from_secs(20), async {
loop {
if has_new_email_button(webdriver)
.await
.context("search new-email button")?
{
// Login successful
return Ok::<_, anyhow::Error>(true);
}
else if has_cancel_button(webdriver)
.await
.context("search cancel button")?
{
// Cancel button present means 2FA needed
enter_onetimecode(&onetimecode, webdriver)
.await
.context("entering one-time-code and finishing login")?;
// 2FA entered, logging in...
return Ok::<_, anyhow::Error>(false);
}
tokio::time::sleep(Duration::from_secs(1)).await;
}
})
.await
.context("wait for one-time-code or login")??;

This is slightly more "Rusty".

```

Note: You can leave the `ONETIMECODE` variable as displayed above even if your account does not have 2FA, or you can remove that line from your `.env` file.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the "make it optional" change I've proposed below, the user normally doesn't need it. In general I think editing the file for every single action is a bit cumbersome, so I would pass the code via CLI and instead of mentioning it here, add a subsection add the end of the "usage" section:

### 2FA
If you use 2 factor authentication (2FA), you need to pass the one-time-code to tatutanatata. This can either be done via a CLI parameter (`--onetimecode=000000`) or via a new entry within the `.env` file (`TUTANOTA_CLI_ONETIMECODE=000000`).

Technically there's even a third way: passing the env variable directly (i.e. env TUTANOTA_CLI_ONETIMECODE=000000 cargo run ...) but techy users that know env variables probably also understand .env files and the fact that the only reflect/set env variables.

@eveetc
Copy link

eveetc commented Jul 26, 2023

Just checking in, will this still be merged into the main repo? :)
Thanks for your work!

@crepererum
Copy link
Member

I think merging this doesn't provide much at the moment before someone fixes #44, i.e. adjusts the code to the recent UI changes.

@crepererum
Copy link
Member

I totally rewrote this tool to no longer use a webdriver but directly use the upstream protocol. 2FA would need a redesign to work with the new approach.

@crepererum crepererum closed this Mar 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants