-
Notifications
You must be signed in to change notification settings - Fork 247
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
fix(auth): handle missing or empty signUpOptions #627
fix(auth): handle missing or empty signUpOptions #627
Conversation
@Jordan-Nelson Since the null safety branch will eventually be merged into master, I wonder if it would make sense to just fix THAT branch - that way we won't have to do duplicate work and release multiple times? |
@haverchuck I was thinking that originally as well, but I don't think it will lead to much duplication or additional releases. The changes on the dart side were so minimal that I think bringing this into the NS branch should be pretty easy. And I don't think we have to do a release of the NS branch just for this since its an issue in the latest non NS release as well. |
Since integration tests are not running in CI yet, here are screenshots of the tests passing on iOS and Android. Note that these were run with #637 pulled in. |
Codecov Report
@@ Coverage Diff @@
## master #627 +/- ##
==========================================
+ Coverage 69.36% 69.41% +0.04%
==========================================
Files 262 262
Lines 8604 8631 +27
Branches 353 353
==========================================
+ Hits 5968 5991 +23
- Misses 2504 2508 +4
Partials 132 132
Flags with carried forward coverage won't be shown. Click here to find out more.
|
456990d
to
f3450e5
Compare
…fix/209-handle-missing-signUpOptions
@@ -13,13 +13,12 @@ | |||
* permissions and limitations under the License. | |||
*/ | |||
|
|||
|
|||
|
|||
class SignUpOptions { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not just make this abstract? https://github.com/aws-amplify/amplify-flutter/pull/697/files#diff-634553a25cf511114cd3409bd3324f52178d09bc6467715a52d9f78e8e1e4b8c
And set a default value on Cognito? https://github.com/aws-amplify/amplify-flutter/pull/697/files#diff-67c9b0e8dc3d1ab4a486c06096d4b78d5eaffb25ec1639a42b7f292dde25a6d2R58
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only actual changes in the file are lines 19 and 20. The rest are auto formatting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(the change seems reasonable, it just isn't related to the PR)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah my bad! Sorry I misread the diff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Had some suggestions but
- I don't see anything functionally wrong
- Many suggestions are nitpicking on existing code
So lgtm overall 🚀
var authUserAttributes: MutableList<AuthUserAttribute> = mutableListOf(); | ||
var validationData = rawOptions["validationData"] as? MutableMap<String, String>; | ||
private fun formatOptions(rawOptions: HashMap<String, *>?): AWSCognitoAuthSignUpOptions { | ||
val options = AWSCognitoAuthSignUpOptions.builder() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Is it convention to do this? Imo it's clearer to name this variable optionsBuilder
unless the entire build chain is part of the assignment.
private fun formatOptions(rawOptions: HashMap<String, *>?): AWSCognitoAuthSignUpOptions { | ||
val options = AWSCognitoAuthSignUpOptions.builder() | ||
if (rawOptions != null) { | ||
val authUserAttributes: MutableList<AuthUserAttribute> = mutableListOf() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
val authUserAttributes: MutableList<AuthUserAttribute> = mutableListOf() |
attributeData.forEach { (key, value) -> | ||
val attribute = createAuthUserAttribute(key, value) | ||
authUserAttributes.add(attribute) | ||
} | ||
options.userAttributes(authUserAttributes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: More concise and arguably clearer with added benefit of not creating a list at all if attributeData
is null
attributeData.forEach { (key, value) -> | |
val attribute = createAuthUserAttribute(key, value) | |
authUserAttributes.add(attribute) | |
} | |
options.userAttributes(authUserAttributes) | |
val authUserAttributes: List<AuthUserAttribute> = attributeData.map { (key, value) -> | |
createAuthUserAttribute(key, value) | |
} | |
options.userAttributes(authUserAttributes) |
import 'utils/mock_data.dart'; | ||
import 'utils/setup_utils.dart'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤩
if (options != null) { | ||
pendingRequest['options'] = options!.serializeAsMap(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we remove nulls on line 32, could we just keep line 29 the way it was but will the null-aware access?
'options': options?.serializeAsMap()
private func createOptions(options: Dictionary<String, Any>?) -> AuthSignUpRequest.Options? { | ||
if (options == nil) { | ||
return nil | ||
} | ||
var formattedAttributes: Array<AuthUserAttribute> = Array() | ||
if (options!["userAttributes"] is Dictionary<String, String>) { | ||
let rawAttributes: Dictionary<String, Any> = options!["userAttributes"] as! Dictionary<String, String> | ||
for attr in rawAttributes { | ||
formattedAttributes.append(createAuthUserAttribute(key: attr.key, value: attr.value as! String)) | ||
} | ||
} | ||
return AuthSignUpRequest.Options(userAttributes: formattedAttributes) | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible for the initial guard clause to just be
if (!(options?["userAttributes"] is Dictionary<String, String>)) {
return nil
}
// rest of function without if condition
It would reduce some of the nesting and improve readability if so. I think it'd also make it possible to just assign a mapped array directly to formattedAttributes
similar to my kotlin suggestion above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right. I am going to make this update. I think I was mimicking what I had done on the Android side. However, on Android the nested if statements has a purpose since options
can contain userAttributes and/or validationData. On iOS we aren't doing anything with the validationData. That seems like it might be a bug.
@haverchuck It doesn't seem like there is any way to include "validationData" in the sign up request in amplify-ios. Amplify-flutter seems to just be ignoring that value on iOS. On Android validationData is part of the AWSCognitoAuthSignUpOptions
that gets included in the request. Is that a known platform discrepancy?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Jordan-Nelson Yeah - this is something we need to fix. It is related to the clientmetadata work that Hui and myself have implemented piecemeal. In this case, android and ios should be able to handle both validationData and clientMetadata attributes.
This doesn't need to be part of this PR.
let rawAttributes: Dictionary<String, Any> = options["userAttributes"] as! Dictionary<String, String> | ||
var formattedAttributes: Array<AuthUserAttribute> = Array() | ||
for attr in rawAttributes { | ||
formattedAttributes.append(createAuthUserAttribute(key: attr.key, value: attr.value as! String)) | ||
} | ||
return formattedAttributes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Could simplify this I think
let rawAttributes: Dictionary<String, Any> = options["userAttributes"] as! Dictionary<String, String> | |
var formattedAttributes: Array<AuthUserAttribute> = Array() | |
for attr in rawAttributes { | |
formattedAttributes.append(createAuthUserAttribute(key: attr.key, value: attr.value as! String)) | |
} | |
return formattedAttributes | |
let rawAttributes: Dictionary<String, Any> = options["userAttributes"] as! Dictionary<String, String> | |
return rawAttributes.map { attr in | |
createAuthUserAttribute(key: attr.key, value: attr.value as! String) | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couple of cleanup nits but lgtm
Issue #, if available: #292
Description of changes:
For a standard username based auth (where email is a required attribute), if a consumer omits options, user attributes, or just the email attribute they will receive and InvalidParameterException.
For an email based auth (where email is the username) omitting any of these fields/values will not cause an error.
Test scenarios
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.