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 conditional passwordless flow #13655

Merged
merged 38 commits into from
Feb 1, 2023

Conversation

Beamanator
Copy link
Contributor

@Beamanator Beamanator commented Dec 16, 2022

Ready for tests / review! 👍

Details

Adding the ability to show the new "Passwordless" flow if the user is in the Passwordless beta (so we can do a slow ish, smart rollout)

Fixed Issues

$ https://github.com/Expensify/Expensify/issues/249360

Tests

To add an account to the Passwordless beta:

  1. Open https://www.expensify.com.dev/_support/beta
  2. Set $allBetasEnabled = false;
  3. Set $toggledBetas = ['passwordless'];

To make the account not be on the passwordless beta:

  1. In App, go to src/libs/Permissions.js and make the function canUsePasswordlessLogins have return false;
  2. In Web-E, go to lib/BetaManager.php and make sure $allBetasEnabled is set to false

With an unvalidated account, on the Passwordless beta

  1. Enter your login into the signin page
  2. Verify you see this Magic code form with the "It's always great to see a new face around here" welcome text:

Screenshot 2023-01-10 at 12 48 30 PM

  1. Click "Didn't receive a magic code?" then enter 000000, then click "Sign in"
  2. Verify you were logged in successfully
  3. (You might have to unthrottle your account to be able to sign in & to reset the magic code)

With a validated account, on the Passwordless beta

  1. Enter your login into the signin page
  2. Verify you see this Magic code form (with the appropriate welcome text):

Screenshot 2023-01-10 at 12 57 49 PM

  1. Click "Didn't receive a magic code?", enter 000000 into the form, then click "Sign in"
  2. Verify you can sign in successfully

With a validated account on the Passwordless beta with 2FA required

  1. Enter your login into the signin page
  2. Verify you see this Magic code form with the above welcome text
  3. Click "Didn't receive a magic code?", enter 000000 into the form, then click "Sign in"
  4. Verify you see the 2FA input:

Screenshot 2023-01-24 at 3 14 31 PM

  1. Enter your 2FA code, click "Sign in"
  2. Verify you sign in successfully

With an unvalidated account, not on the Passwordless beta

  1. Enter new email address in Signin form
  2. Verify you see this magic link text:

Screenshot 2023-01-10 at 12 31 10 PM

  1. Click "Resend Link", verify you get an email with a old magic link
    • Note: To send the email in dev, you should run php script/notifyall.php from your VM
    • Screenshot 2023-01-10 at 12 36 30 PM
  2. Click the magic link, verify you can now enter a password & sign in

With a validated account, not on the Passwordless beta

  1. Enter your login into the signin page
  2. Verify you see the Password signin form:

Screenshot 2023-01-10 at 12 29 36 PM

  1. Click "Forgot", verify you get an email with the old magic link text:
    • Note: To send the email in dev, you should run php script/notifyall.php from your VM
    • Screenshot 2023-01-10 at 12 36 30 PM
  2. Don't click the link, just try signing in with your password
  3. Verify you can sign in with the password

With a validated account not on the Passwordless beta with 2FA required

  1. Enter your login into the signin page
  2. Verify you see the old password signin form
  3. Enter your password then click "Sign in"
  4. Verify you see the 2FA input:

Screenshot 2023-01-24 at 3 11 30 PM

  1. Enter your 2FA code, click "Sign in"
  2. Verify you sign in successfully

In all tests:

  • Verify that no errors appear in the JS console

Offline tests

None of the above flows should work offline, as the signin flows all require being online.

Verify if you try to sign in while offline, you're unable (the signin button should be disabled)

QA Steps

Similar as above, but will need an internal employee to add the accounts to passwordless beta on staging

To add an account to the Passwordless beta:

  1. Open BetaManager
  2. Enter the account you want to add to the beta
  3. Select passwordless beta
  4. Click "Add multiple users"

In all tests:

  • Verify that no errors appear in the JS console

PR Author Checklist

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for the expected offline behavior in the Offline steps section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
    • I tested this PR with a High Traffic account against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • iOS / native
    • Android / native
    • iOS / Safari
    • Android / Chrome
    • MacOS / Chrome
    • MacOS / Desktop
  • I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
  • I followed proper code patterns (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick)
    • I verified that comments were added to code that is not self explanatory
    • I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
    • I verified any copy / text shown in the product is localized by adding it to src/languages/* files and using the translation method
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • I verified any copy / text that was added to the app is correct English and approved by marketing by adding the Waiting for Copy label for a copy review on the original GH to get the correct copy.
    • I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I followed the guidelines as stated in the Review Guidelines
  • I tested other components that can be impacted by my changes (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar are working as expected)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.js or at the top of the file that uses the constant) are defined as such
  • I verified that if a function's arguments changed that all usages have also been updated correctly
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately and each prop has a /** comment above it */
    • The file is named correctly
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(themeColors.componentBG)
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • I have checked off every checkbox in the PR author checklist, including those that don't apply to this PR.

Screenshots/Videos

Web

On Passwordless beta

Unvalidated Validated, no 2FA required Validated, 2FA required
Screenshot 2023-01-10 at 12 48 30 PM Screenshot 2023-01-10 at 12 57 49 PM Screenshot 2023-01-24 at 3 14 31 PM

Not on Passwordless beta

Unvalidated Validated, no 2FA required Validated, 2FA required
Screenshot 2023-01-10 at 12 31 10 PM Screenshot 2023-01-10 at 12 29 36 PM Screenshot 2023-01-24 at 3 11 30 PM
Mobile Web - Chrome

On Passwordless beta

Unvalidated Validated, no 2FA required Validated, 2FA required
Screenshot 2023-01-24 at 3 40 15 PM Screenshot 2023-01-24 at 3 39 36 PM Screenshot 2023-01-24 at 3 39 44 PM

Not on Passwordless beta

Unvalidated Validated, no 2FA required Validated, 2FA required
Screenshot 2023-01-24 at 3 40 31 PM Screenshot 2023-01-24 at 3 40 46 PM Screenshot 2023-01-24 at 3 40 53 PM
Mobile Web - Safari

On Passwordless beta

Unvalidated Validated, no 2FA required Validated, 2FA required
Screenshot 2023-01-24 at 3 49 23 PM Screenshot 2023-01-24 at 3 49 37 PM Screenshot 2023-01-24 at 3 49 49 PM

Not on Passwordless beta

Unvalidated Validated, no 2FA required Validated, 2FA required
Screenshot 2023-01-24 at 3 50 29 PM Screenshot 2023-01-24 at 3 50 16 PM Screenshot 2023-01-24 at 3 50 06 PM
Desktop

On Passwordless beta

Unvalidated Validated, no 2FA required Validated, 2FA required
Screenshot 2023-01-24 at 3 26 47 PM Screenshot 2023-01-24 at 3 23 57 PM Screenshot 2023-01-24 at 3 26 18 PM

Not on Passwordless beta

Unvalidated Validated, no 2FA required Validated, 2FA required
Screenshot 2023-01-24 at 3 27 14 PM Screenshot 2023-01-24 at 3 27 37 PM Screenshot 2023-01-24 at 3 27 44 PM
iOS

On Passwordless beta

Unvalidated Validated, no 2FA required Validated, 2FA required
Screenshot 2023-01-24 at 3 48 43 PM Screenshot 2023-01-24 at 3 48 34 PM Screenshot 2023-01-24 at 3 48 22 PM

Not on Passwordless beta

Unvalidated Validated, no 2FA required Validated, 2FA required
Screenshot 2023-01-24 at 3 47 41 PM Screenshot 2023-01-24 at 3 47 52 PM Screenshot 2023-01-24 at 3 48 00 PM
Android

On Passwordless beta

Unvalidated Validated, no 2FA required Validated, 2FA required
Screenshot 2023-01-24 at 3 38 05 PM Screenshot 2023-01-24 at 3 38 20 PM Screenshot 2023-01-24 at 3 38 37 PM

Not on Passwordless beta

Unvalidated Validated, no 2FA required Validated, 2FA required
Screenshot 2023-01-24 at 3 37 28 PM Screenshot 2023-01-24 at 3 37 02 PM Screenshot 2023-01-24 at 3 37 12 PM

@Beamanator Beamanator self-assigned this Dec 16, 2022
src/languages/es.js Outdated Show resolved Hide resolved
Copy link
Contributor

@mollfpr mollfpr left a comment

Choose a reason for hiding this comment

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

Test well on all platforms! Although, I still can't resend the magic code, and the email I received with the invalidated account is a magic link, not the magic code.

Checklist #13655 (comment).

Yugi Thumb

@melvin-bot
Copy link

melvin-bot bot commented Jan 31, 2023

🎯 @mollfpr, thanks for reviewing and testing this PR! 🎉

An E/App issue has been created to issue payment here: #14717.

@NikkiWines
Copy link
Contributor

the email I received with the invalidated account is a magic link, not the magic code.

@mollfpr what do you mean by this? Do you have a screenshot of the notification you received?

@mollfpr
Copy link
Contributor

mollfpr commented Jan 31, 2023

@NikkiWines Sign up with a new unvalidated account on password less will show the validation form, but the email I receive is a link to set the password.

C6E9D87B-5DF9-406A-BD1E-0F6571E71A09

@NikkiWines
Copy link
Contributor

Hmm that should definitely be a different notification 🤔 will investigate

@NikkiWines
Copy link
Contributor

@mollfpr if you use luthfi.ufi14+unvalidated@gmail.com to sign in do you get a notification that has a "magic link" and "magic code"? Essentially, do you only get the old notification when you're signing up with a new login (that isn't on the beta)?

@mollfpr
Copy link
Contributor

mollfpr commented Feb 1, 2023

Yes, I got the notification that it has a magic link and magic code.

Essentially, do you only get the old notification when you're signing up with a new login (that isn't on the beta)?

Yes! I probably mixed up with the dev environment, where it’s open to all beta permission.

@NikkiWines
Copy link
Contributor

Ok, perfect, then I think we're all good

@NikkiWines NikkiWines merged commit e1c554a into main Feb 1, 2023
@NikkiWines NikkiWines deleted the beaman-addConditionalPasswordlessFlow branch February 1, 2023 02:42
@OSBotify
Copy link
Contributor

OSBotify commented Feb 1, 2023

✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 1, 2023

Performance Comparison Report 📊

Significant Changes To Duration

There are no entries

Meaningless Changes To Duration

Show entries
Name Duration
App start TTI 684.047 ms → 709.755 ms (+25.709 ms, +3.8%)
App start runJsBundle 193.969 ms → 195.406 ms (+1.438 ms, +0.7%)
App start nativeLaunch 19.148 ms → 19.594 ms (+0.446 ms, +2.3%)
App start regularAppStart 0.014 ms → 0.015 ms (+0.001 ms, +7.3%)
Open Search Page TTI 611.556 ms → 607.282 ms (-4.274 ms, -0.7%)
Show details
Name Duration
App start TTI Baseline
Mean: 684.047 ms
Stdev: 32.128 ms (4.7%)
Runs: 620.6605229999404 631.3479919999372 631.6222349999007 636.0200169999152 643.2710009999573 646.1957590000238 649.4609489999712 653.8795449999161 655.6119460000191 657.1900130000431 659.6552540000994 684.2080930001102 684.5939279999584 689.5832720000762 689.9229580000974 690.7969080000184 691.3803369998932 696.7556549999863 697.3002879999112 698.2085339999758 699.3823909999337 699.4518869998865 704.6877450000029 706.9209980000742 712.0980799999088 713.2937759999186 716.5356580000371 716.7159059999976 718.940431999974 725.8780169999227 731.3422530000098 736.5822640000843

Current
Mean: 709.755 ms
Stdev: 28.188 ms (4.0%)
Runs: 657.9528439999558 661.935754999984 674.4475539999548 678.1265600000042 681.8538250001147 682.600921999896 684.4759670000058 685.4149629999883 685.4218270001002 687.5474310000427 692.7974549999926 693.0290620001033 696.5314849999268 704.0519199999981 704.8443720000796 712.4414480000269 713.1140970000997 718.4193740000483 718.5056390000973 721.0610380000435 721.0803390000947 721.7521869998891 723.0331180000212 724.8540860000066 729.8613970000297 730.7328260000795 734.621412999928 738.3171880000737 739.3427919999231 750.850076999981 763.9163069999777 779.2371090000961
App start runJsBundle Baseline
Mean: 193.969 ms
Stdev: 21.496 ms (11.1%)
Runs: 161 164 166 167 169 170 170 174 175 175 180 183 183 186 190 196 196 198 198 202 205 207 207 207 209 210 218 220 221 229 234 237

Current
Mean: 195.406 ms
Stdev: 18.138 ms (9.3%)
Runs: 164 168 172 175 176 177 179 180 182 184 185 187 187 189 191 192 194 197 199 199 200 201 205 206 210 214 216 218 220 221 223 242
App start nativeLaunch Baseline
Mean: 19.148 ms
Stdev: 0.848 ms (4.4%)
Runs: 18 18 18 18 18 18 19 19 19 19 19 19 19 19 19 19 19 19 19 20 20 20 20 20 20 21 21

Current
Mean: 19.594 ms
Stdev: 1.617 ms (8.3%)
Runs: 17 17 18 18 18 18 18 18 19 19 19 19 19 19 19 19 19 19 19 20 20 20 20 21 21 21 21 22 22 22 22 24
App start regularAppStart Baseline
Mean: 0.014 ms
Stdev: 0.001 ms (6.4%)
Runs: 0.012410000199452043 0.01261399989016354 0.012776999967172742 0.013223999878391623 0.013428000034764409 0.013549999799579382 0.01359100011177361 0.013630999950692058 0.013753000181168318 0.01383400009945035 0.013835000107064843 0.013875000178813934 0.013956999871879816 0.014119000174105167 0.014160999795421958 0.014283000025898218 0.01432300009764731 0.01432300009764731 0.01436399994418025 0.014445000095292926 0.014728999929502606 0.014730000169947743 0.014810999855399132 0.014811000088229775 0.014973999932408333 0.015055999858304858 0.015137000009417534 0.015461999922990799 0.015828999923542142 0.015868999995291233 0.016235000221058726

Current
Mean: 0.015 ms
Stdev: 0.001 ms (5.4%)
Runs: 0.014038000022992492 0.014160000020638108 0.014282000018283725 0.014404000015929341 0.014485999941825867 0.014607000164687634 0.014648000011220574 0.014688999857753515 0.014689000090584159 0.0147299999371171 0.014770000008866191 0.014770000008866191 0.0148930000141263 0.014973999932408333 0.015055000083521008 0.01509599993005395 0.015096000162884593 0.015381000004708767 0.015381000004708767 0.015381000004708767 0.015461999922990799 0.015503000002354383 0.015584999928250909 0.015625 0.015949999913573265 0.01603199983946979 0.016112999990582466 0.016315999906510115 0.01647999999113381 0.01660200022161007 0.016927000135183334 0.017537000123411417
Open Search Page TTI Baseline
Mean: 611.556 ms
Stdev: 25.732 ms (4.2%)
Runs: 579.4684250000864 579.8629560000263 583.0244960000273 583.3431400000118 585.2923999999184 587.8105879998766 588.3535980000161 590.3263350001071 593.8645839998499 595.4840899999253 595.8102220001165 598.341878999956 599.284750000108 600.083049000008 602.1590990000404 608.8513599999715 610.2100420000497 610.5859369998798 612.0322269999888 616.1624760001432 617.7807620000094 619.1378580001183 625.4609779999591 626.8481040000916 628.3551439999137 630.155436999863 633.918050999986 645.341999999946 664.6189780000132 668.0688079998363 678.1999109999742

Current
Mean: 607.282 ms
Stdev: 19.058 ms (3.1%)
Runs: 575.43660500017 579.3757730000652 583.2621260001324 585.2099619999062 587.3936360001098 589.0110269999132 589.0820730000269 595.1188560000155 595.9373780000024 596.425414999947 598.7510180000681 599.7789310000371 601.8031820000615 601.8751629998442 602.431396999862 602.6889650002122 605.662597999908 606.4457199999597 606.5208340000827 606.8054609999526 608.0661619999446 613.3534339999314 615.890340999933 622.0621340000071 623.5926520000212 624.7279060001019 625.579264999833 626.7557779999916 629.5008139999118 630.7895100000314 636.9816900000442 666.698200999992

@OSBotify
Copy link
Contributor

OSBotify commented Feb 2, 2023

🚀 Deployed to staging by https://github.com/NikkiWines in version: 1.2.64-0 🚀

platform result
🤖 android 🤖 success ✅
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

@aldo-expensify
Copy link
Contributor

I see that you can disable the passwordless login by returning false in function canUsePasswordlessLogins(betas). I didn't have to do anything on the backend. Is this because it is still on the beta and in the future a user shouldn't be able to disable it from the front end?

@Beamanator
Copy link
Contributor Author

@aldo-expensify yeah pretty much - we need to be able to show both flows for now since passwordless is still in beta, but in the future we'll definitely remove all that beta shtuff so the user will only have the passwordless flow option

@Beamanator
Copy link
Contributor Author

Tests in staging:

On Passwordless beta

Unvalidated Validated, no 2FA required Validated, 2FA required
Screenshot 2023-02-03 at 11 50 29 AM Screenshot 2023-02-03 at 11 57 34 AM Screenshot 2023-02-03 at 12 00 47 PM

Not on Passwordless beta

Unvalidated Validated, no 2FA required Validated, 2FA required
Screenshot 2023-02-03 at 11 44 06 AM Screenshot 2023-02-03 at 11 47 28 AM Screenshot 2023-02-03 at 11 49 15 AM

Possible failure:

  1. Attempt to sign in with brand new expensifail account
  2. Receive email, it should be the new magic code format but I saw the old setpassword link:
  3. Screenshot 2023-02-03 at 11 53 42 AM

Another possible failure:

  1. Sign in with account in NewDot
  2. Sign in to same account in OldDot
  3. In OldDot, enable 2FA
  4. See that NewDot page crashes
  5. Screenshot 2023-02-03 at 12 00 01 PM

@OSBotify
Copy link
Contributor

OSBotify commented Feb 4, 2023

🚀 Deployed to production by https://github.com/thienlnam in version: 1.2.64-7 🚀

platform result
🤖 android 🤖 failure ❌
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 failure ❌
🕸 web 🕸 success ✅

@OSBotify
Copy link
Contributor

OSBotify commented Feb 4, 2023

🚀 Deployed to production by https://github.com/thienlnam in version: 1.2.64-7 🚀

platform result
🤖 android 🤖 failure ❌
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

1 similar comment
@OSBotify
Copy link
Contributor

OSBotify commented Feb 4, 2023

🚀 Deployed to production by https://github.com/thienlnam in version: 1.2.64-7 🚀

platform result
🤖 android 🤖 failure ❌
🖥 desktop 🖥 success ✅
🍎 iOS 🍎 success ✅
🕸 web 🕸 success ✅

Comment on lines +72 to +82
componentDidMount() {
if (!canFocusInputOnScreenFocus() || !this.inputValidateCode || !this.props.isVisible) {
return;
}
this.inputValidateCode.focus();
}

componentDidUpdate(prevProps, prevState) {
if (!prevProps.isVisible && this.props.isVisible) {
this.inputValidateCode.focus();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

@Beamanator in componentDidUpdate we are not checking for canFocusInputOnScreenFocus should not we do so?

    componentDidUpdate(prevProps) {
        if (canFocusInputOnScreenFocus() && !prevProps.isVisible && this.props.isVisible) {
            this.inputValidateCode.focus();
        }
        ...
    }

@sobitneupane
Copy link
Contributor

We decided to disable "Didn't receive a magic code?" when user is offline. It was not considered or missed in this PR.

Issue: #19867
PR: https://github.com/Expensify/App/pull/20458/files

@sobitneupane
Copy link
Contributor

Issue: #22324

Title: "Incorrect magic code" error if click login in 2FA input page

This issue was missed and not handled in this PR.


render() {
return (
<>
Copy link
Contributor

Choose a reason for hiding this comment

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

The react fragment wrapper here caused the following issue:

Which is a Safari specific autofill popup issue that was observed by others, see this SO (comment) and #32683 (comment) breakdown for more details.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
InternalQA This pull request required internal QA
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants