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 signInWithNewPassword GraphQL API #291

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

henry0715-dev
Copy link
Contributor

Close #14

Changed sign-in GraphQL API logic.

  • Returns Err if last_signin_time of account is None.

Copy link

codecov bot commented Aug 29, 2024

Codecov Report

Attention: Patch coverage is 98.62543% with 4 lines in your changes missing coverage. Please review.

Project coverage is 66.87%. Comparing base (6506e95) to head (a743b94).

Files with missing lines Patch % Lines
src/graphql/account.rs 98.62% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #291      +/-   ##
==========================================
+ Coverage   66.21%   66.87%   +0.66%     
==========================================
  Files          68       68              
  Lines       13011    13259     +248     
==========================================
+ Hits         8615     8867     +252     
+ Misses       4396     4392       -4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

CHANGELOG.md Outdated
@@ -68,6 +68,9 @@ Versioning](https://semver.org/spec/v2.0.0.html).
- Added a `language` field to the `Account`. Consequently, the `account` and
`accountList` API responses now include this field. The `insertAccount` and
`updateAccount` GraphQL API endpoints are also updated to support the field.
- Added `common_sign-in_logic` to handle `sign-in` GraphQL API logic.
Copy link
Contributor

Choose a reason for hiding this comment

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

This is not necessary because the method is not for users.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll delete it.

src/graphql/account.rs Outdated Show resolved Hide resolved
Comment on lines 290 to 292
/// - Authenticates with the given username and password.
/// - If the `last_signin_time` value of the `account` is `None`, the operation will fail, and
/// it should be guided to call common_sign_in_logic.
Copy link
Contributor

@sehkone sehkone Aug 29, 2024

Choose a reason for hiding this comment

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

Since this is an open method to users, we need to fulfill the Rust documentation according to the convention

@henry0715-dev henry0715-dev force-pushed the henry/sign-in-with-new-password branch 2 times, most recently from ed652fa to 97ffb90 Compare August 29, 2024 07:08
/// }"#
/// ```
///
/// # Returns
Copy link
Contributor

Choose a reason for hiding this comment

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

We usually don't mention returning values in a separate section. You can refer to the standard library to check how to write the Rust documentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll delete it.

Copy link
Contributor

Choose a reason for hiding this comment

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

If you deleted that part, that’s not what I meant. I just wanted to say that the return values should be mentioned according to the Rust documentation convention, like this:

///
/// Returns blah blah blah
///
  • The title, # Returns, is not necessary.
  • The sentence starts with Returns, a third-person singular verb.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll be careful.

@@ -420,6 +400,96 @@ impl AccountMutation {
}
}

async fn common_sign_in_logic(
Copy link
Contributor

Choose a reason for hiding this comment

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

This method doesn't seem to behave consistently. Its behavior depends on is_update_password, which is the only differing argument between the two callers. In other words, this method is not the common part between the two callers. When we extract the common part, it should be identical across all participants.

Copy link
Contributor

Choose a reason for hiding this comment

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

If there were any reason to keep this, it should have at least a different name rather than "common".

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What do you think of the function name below?

sign_in_logic_by_update_password

Copy link
Contributor

Choose a reason for hiding this comment

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

It would be better to explicitly outline the process in both methods, sign_in and sign_in_with_new_password.

I suggest the following pseudocode:

sign_in
- Check the password
- Check if there was no previous sign-in
- Check the IP address
- Check the number of parallel sessions
- Sign in

sign_in_with_new_password
- Check the password
- Check the IP address
- Check the number of parallel sessions
- Change the password
- Sign in

While revealing this skeleton in both methods, we need to extract the common parts as separate methods.

Copy link
Contributor

Choose a reason for hiding this comment

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

I want to point out we need to check the password first. The information about whether the user is signing in for the first time or again, whether the number of sessions exceeds the limit, or whether the IP address is valid, is so confidential that it should not be accessible to anyone who has not provided the correct password. The original code was not properly implemented in this regard.

Copy link
Contributor

Choose a reason for hiding this comment

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

While revealing this skeleton in both methods, we need to extract the common parts as separate methods.

The common part might involve validating the IP address and the number of sessions.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I considered splitting the function because it is responsible for so many functions, but there is a lot of overlap, so we made it into one function.
As you mentioned above, we will refactor the checking part by splitting it into functions and calling them.

@henry0715-dev henry0715-dev force-pushed the henry/sign-in-with-new-password branch 3 times, most recently from a5c9935 to 5548e55 Compare August 30, 2024 05:03
@@ -641,6 +742,7 @@ fn initial_credential() -> anyhow::Result<types::Account> {
None,
None,
)?;
initial_account.update_last_signin_time();
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you explain why you put this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the part set to satisfy the existing test case.
There is also a part where admin/admin does not affect the part you are currently using when running for the first time.
In the future, I thought of the expected behavior of creating a new account after logging in with the admin account, and requesting password change when attempting to log in with the created account.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't quite understand. Could you elaborate on what you answered?

Copy link
Contributor

Choose a reason for hiding this comment

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

This initial_credential seems to create the first admin account and immediately set its sign-in time. This makes it pointless to alter sign_in to check the last sign-in time. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This part has been restored to its original state.

CHANGELOG.md Outdated
@@ -68,6 +68,7 @@ Versioning](https://semver.org/spec/v2.0.0.html).
- Added a `language` field to the `Account`. Consequently, the `account` and
`accountList` API responses now include this field. The `insertAccount` and
`updateAccount` GraphQL API endpoints are also updated to support the field.
- Added `signInWithNewPassword` GraphQL API for signing in with a new password.
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a new API, so should be included in the section "Added".

Copy link
Contributor

Choose a reason for hiding this comment

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

Since the signIn has been changed, it should be documented.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll change it.

@henry0715-dev henry0715-dev force-pushed the henry/sign-in-with-new-password branch 2 times, most recently from e72ae31 to 6ebe11b Compare September 2, 2024 01:39
CHANGELOG.md Outdated
@@ -68,6 +69,7 @@ Versioning](https://semver.org/spec/v2.0.0.html).
- Added a `language` field to the `Account`. Consequently, the `account` and
`accountList` API responses now include this field. The `insertAccount` and
`updateAccount` GraphQL API endpoints are also updated to support the field.
- Added logic to check the `lastSigninTime` value in the `signIn` GraphQL API.
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we need to document how the new logic works, as well as the fact that it has changed, because in this case, the new behavior is the primary concern for users.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added content.

Copy link
Contributor

Choose a reason for hiding this comment

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

The key point is that this API rejects a user's access if it is their first attempt. Therefore, it's not enough to simply mention checking the lastSigninTime. Additionally, the word "logic" seems unnecessary. I suggest:

  • Changed the signIn to reject the first sign-in attempt unless it is done through the new signInWithNewPassword API.

In this case, "Changed" or "Updated" is preferred over "Added" because the behavior of the API has actually changed from the user's perspective. Also, the word "reject" or any similar one should be included to convey the key point.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I will delete the explanation below and change it to the sentence you suggested.
"Apply a requirement for a password change upon the initial signIn."

@henry0715-dev henry0715-dev force-pushed the henry/sign-in-with-new-password branch 2 times, most recently from e4320fd to acbb168 Compare September 2, 2024 02:41
@sehkone
Copy link
Contributor

sehkone commented Sep 2, 2024

When reseting the admin's password, we need to reset the last_signin_time as well.

@henry0715-dev henry0715-dev force-pushed the henry/sign-in-with-new-password branch 2 times, most recently from fb6cc77 to 17d7dc0 Compare September 3, 2024 06:18
Comment on lines 312 to 318
/// ```ignore
/// r#"mutation {
/// signInWithNewPassword(username: "user", password: "pw", newPassword: "pw2") {
/// token
/// }
/// }"#
/// ```
Copy link
Contributor

Choose a reason for hiding this comment

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

We don't need to present the signatures of GraphQL APIs in the code because users can not only infer them on their own but also check them in the GraphQL playground.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll delete it.

Comment on lines 309 to 310
/// If the `signIn` GraphQL API response is the error message "a password change is
/// required to proceed", you can call the `signInWithNewPassword` GraphQL API.
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think this part is necessary because it seems to repeat what was mentioned right above.

Copy link
Contributor

Choose a reason for hiding this comment

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

The part I think is unnecessary:

/// If the `signIn` GraphQL API response is the error message "a password change is
/// required to proceed", you can call the `signInWithNewPassword` GraphQL API.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll delete it.

///
/// # Errors
///
/// An error message (`String`) if any of the checks fail or an error occurs during the process.
Copy link
Contributor

Choose a reason for hiding this comment

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

I suggest:

/// # Errors
///
/// Returns `Err` if the password is invalid, this is the first sign-in attempt, the access doesn't originate from a permitted IP address, or the number of sessions exceeds the maximum limit.

The style where the sentence starts with a third-person singular verb is a convention in Rust documentation. Additionally, it would be better to specify exactly the cases where errors occur.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll change it.

@sophie-cluml
Copy link
Contributor

@sehkone I know we are still in pr-review stage for this PR, but I think merging PR would require implement new UX flow and design in the client side. So I would like to suggest in advance, that we might merge this PR after we release the upcoming review-web version.

@sehkone
Copy link
Contributor

sehkone commented Sep 3, 2024

@sehkone I know we are still in pr-review stage for this PR, but I think merging PR would require implement new UX flow and design in the client side. So I would like to suggest in advance, that we might merge this PR after we release the upcoming review-web version.

Yes. I won't merge this until what is required is done.

Close #14

Changed `sign-in` GraphQL API logic.
- Returns `Err` if `last_signin_time` of `account` is `None`.
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.

첫 로그인 시 계정 비밀번호 변경을 위한 새로운 GraphQL mutation 구현
3 participants