-
Notifications
You must be signed in to change notification settings - Fork 58
fix(auth): limit the sign-out toast message to a known allowlist #8037
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
Open
yhabib
wants to merge
5
commits into
main
Choose a base branch
from
fix/logout-msg-allowlist
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 4 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
0080ad3
fix(auth): limit the sign-out message in the url to an allowlist
yhabib 6ba71be
test(auth): add an e2e spec for the sign-out message allowlist
yhabib c1ce87b
test(auth): make the url assertions in the sign-out msg tests real
yhabib 60f6e98
fix(auth): clean a bare level url param with no msg
yhabib 3e25ff3
fix(auth): strip a pre-existing level param when writing msg to url
yhabib File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| import { AppPo } from "$tests/page-objects/App.page-object"; | ||
| import { PlaywrightPageObjectElement } from "$tests/page-objects/playwright.page-object"; | ||
| import { signInWithNewUser, step } from "$tests/utils/e2e.test-utils"; | ||
| import { expect, test, type Page } from "@playwright/test"; | ||
|
|
||
| // The global expect timeout is 0, which means "wait forever", so every poll | ||
| // below sets its own timeout. | ||
| const POLL_TIMEOUT = 30_000; | ||
|
|
||
| // Playwright cannot import en.json here, so the texts are copied. | ||
| // "error.missing_identity" in frontend/src/lib/i18n/en.json. | ||
| const missingIdentityText = | ||
| "The operation cannot be executed without any identity."; | ||
| // "warning.auth_sign_out" in frontend/src/lib/i18n/en.json. | ||
| const authSignOutText = | ||
| "You have been logged out because your session has expired."; | ||
|
|
||
| const craftedMsg = "Send your ICP to this address to recover your account"; | ||
|
|
||
| // initAppAuth deletes both parameters on every page load. | ||
| const waitForCleanUrl = async (page: Page) => { | ||
| await expect | ||
| .poll(() => new URL(page.url()).searchParams.get("msg"), { | ||
| timeout: POLL_TIMEOUT, | ||
| }) | ||
| .toBeNull(); | ||
| expect(new URL(page.url()).searchParams.get("level")).toBeNull(); | ||
| }; | ||
|
yhabib marked this conversation as resolved.
|
||
|
|
||
| const getToastMessages = (appPo: AppPo): Promise<string[]> => | ||
| appPo.getToastsPo().getMessages(); | ||
|
|
||
| const getToastClasses = (appPo: AppPo): Promise<string[] | null> => | ||
| appPo.getToastsPo().getToastPo().root.getClasses(); | ||
|
|
||
| test("Test the msg url parameter", async ({ page }) => { | ||
| const appPo = new AppPo(PlaywrightPageObjectElement.fromPage(page)); | ||
|
|
||
| await step("A msg that is not in the allowlist shows no toast"); | ||
| await page.goto( | ||
| `/accounts?msg=${encodeURIComponent(craftedMsg)}&level=error` | ||
| ); | ||
| await appPo.getSignInPo().waitFor(); | ||
| await waitForCleanUrl(page); | ||
| expect(await getToastMessages(appPo)).toEqual([]); | ||
|
|
||
| await step("A msg in the allowlist shows its own text and its own level"); | ||
| await page.goto("/accounts?msg=error.missing_identity&level=success"); | ||
| await appPo.getSignInPo().waitFor(); | ||
| await expect | ||
| .poll(() => getToastMessages(appPo), { timeout: POLL_TIMEOUT }) | ||
| .toEqual([missingIdentityText]); | ||
| // The url asked for "success". The app owns the level, so the toast is an | ||
| // error. | ||
| expect(await getToastClasses(appPo)).toContain("error"); | ||
| expect(await getToastClasses(appPo)).not.toContain("success"); | ||
| await waitForCleanUrl(page); | ||
| }); | ||
|
|
||
| test("Test the toast after an automatic sign out", async ({ | ||
| page: page1, | ||
| context, | ||
| }) => { | ||
| await page1.goto("/accounts"); | ||
| await expect(page1).toHaveTitle("Account | Network Nervous System"); | ||
| const appPo1 = new AppPo(PlaywrightPageObjectElement.fromPage(page1)); | ||
|
|
||
| const page2 = await context.newPage(); | ||
| await page2.goto("/accounts"); | ||
| await expect(page2).toHaveTitle("Account | Network Nervous System"); | ||
| const appPo2 = new AppPo(PlaywrightPageObjectElement.fromPage(page2)); | ||
|
|
||
| await signInWithNewUser({ page: page1, context }); | ||
| await appPo1.getAccountsPo().waitFor(); | ||
|
|
||
| await page2.reload(); | ||
| await appPo2.getAccountsPo().waitFor(); | ||
|
|
||
| await step("Sign out in the first tab"); | ||
| await appPo1.getAccountMenuPo().openMenu(); | ||
| await appPo1.getAccountMenuPo().clickLogout(); | ||
| await appPo1.getSignInPo().waitFor(); | ||
|
|
||
| await step("The second tab shows the session expiry toast"); | ||
| // The auth worker of the second tab sees the missing delegation, calls | ||
| // logout with "warning.auth_sign_out" and reloads the page. | ||
| await appPo2.getSignInPo().waitFor(); | ||
| await expect | ||
| .poll(() => getToastMessages(appPo2), { timeout: POLL_TIMEOUT }) | ||
| .toContain(authSignOutText); | ||
| expect(await getToastClasses(appPo2)).toContain("warn"); | ||
| await waitForCleanUrl(page2); | ||
| }); | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.