From 4c641b0fb2f619d92a8f0f6ec7a4e85ef6936abe Mon Sep 17 00:00:00 2001 From: Gusted Date: Mon, 3 Mar 2025 18:05:01 +0000 Subject: [PATCH] feat: improve incorrect `ROOT_URL` warning (#7103) - In the case that the `ROOT_URL` does not match the site a person is visiting Forgejo gives zero guarantees that any of the functionality will still work. - Make the error i18n, use `local_next`. - Reflect in the error that the any part of the application can break, don't be specific - it is plain wrong and should not be used. - Always check for this case on the login page. This was previously only the case if OAuth2 was enabled, but this code was checking for elements that are always present on the login page regardless if the OAuth2 was enabled or not. Technically nothing changed, but reading the code it is now more clear when this check is being run. - Add E2E testing. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7103 Reviewed-by: Otto Reviewed-by: 0ko <0ko@noreply.codeberg.org> Co-authored-by: Gusted Co-committed-by: Gusted --- options/locale_next/locale_en-US.json | 3 ++- templates/base/head_script.tmpl | 1 + tests/e2e/login.test.e2e.ts | 33 +++++++++++++++++++++++++++ web_src/js/features/common-global.js | 4 ++-- web_src/js/features/user-auth.js | 7 ++++-- web_src/js/index.js | 3 ++- 6 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 tests/e2e/login.test.e2e.ts diff --git a/options/locale_next/locale_en-US.json b/options/locale_next/locale_en-US.json index cc06102c46..23e35af318 100644 --- a/options/locale_next/locale_en-US.json +++ b/options/locale_next/locale_en-US.json @@ -12,5 +12,6 @@ "one": "wants to merge %[1]d commit from %[2]s into %[3]s", "other": "wants to merge %[1]d commits from %[2]s into %[3]s" }, - "search.milestone_kind": "Search milestones..." + "search.milestone_kind": "Search milestones...", + "incorrect_root_url": "This Forgejo instance is configured to be served on \"%s\". You are currently viewing Forgejo through a different URL, which may cause parts of the application to break. The canonical URL is controlled by Forgejo admins via the ROOT_URL setting in the app.ini." } diff --git a/templates/base/head_script.tmpl b/templates/base/head_script.tmpl index 22e08e9c8f..d2774010b6 100644 --- a/templates/base/head_script.tmpl +++ b/templates/base/head_script.tmpl @@ -42,6 +42,7 @@ If you introduce mistakes in it, Gitea JavaScript code wouldn't run correctly. modal_confirm: {{ctx.Locale.Tr "modal.confirm"}}, modal_cancel: {{ctx.Locale.Tr "modal.cancel"}}, more_items: {{ctx.Locale.Tr "more_items"}}, + incorrect_root_url: {{ctx.Locale.Tr "incorrect_root_url" AppUrl}}, }, }; {{/* in case some pages don't render the pageData, we make sure it is an object to prevent null access */}} diff --git a/tests/e2e/login.test.e2e.ts b/tests/e2e/login.test.e2e.ts new file mode 100644 index 0000000000..1ffa0b2e5d --- /dev/null +++ b/tests/e2e/login.test.e2e.ts @@ -0,0 +1,33 @@ +// Copyright 2025 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: GPL-3.0-or-later + +// @watch start +// templates/user/auth/** +// web_src/js/features/user-** +// web_src/js/features/common-global.js +// @watch end + +import {expect} from '@playwright/test'; +import {test, save_visual, test_context} from './utils_e2e.ts'; + +test('Mismatched ROOT_URL', async ({browser}) => { + const context = await test_context(browser); + const page = await context.newPage(); + + // Ugly hack to override the appUrl of `window.config`. + await page.addInitScript(() => { + setInterval(() => { + if (window.config) { + window.config.appUrl = 'https://example.com'; + } + }, 1); + }); + + const response = await page.goto('/user/login'); + expect(response?.status()).toBe(200); + + await save_visual(page); + const globalError = page.locator('.js-global-error'); + await expect(globalError).toContainText('This Forgejo instance is configured to be served on '); + await expect(globalError).toContainText('You are currently viewing Forgejo through a different URL, which may cause parts of the application to break. The canonical URL is controlled by Forgejo admins via the ROOT_URL setting in the app.ini.'); +}); diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js index b05f6e07fe..7848a14b66 100644 --- a/web_src/js/features/common-global.js +++ b/web_src/js/features/common-global.js @@ -458,6 +458,6 @@ export function checkAppUrl() { if (curUrl.startsWith(appUrl) || `${curUrl}/` === appUrl) { return; } - showGlobalErrorMessage(`Your ROOT_URL in app.ini is "${appUrl}", it's unlikely matching the site you are visiting. -Mismatched ROOT_URL config causes wrong URL links for web UI/mail content/webhook notification/OAuth2 sign-in.`); + + showGlobalErrorMessage(i18n.incorrect_root_url); } diff --git a/web_src/js/features/user-auth.js b/web_src/js/features/user-auth.js index a871ac471c..64519037c7 100644 --- a/web_src/js/features/user-auth.js +++ b/web_src/js/features/user-auth.js @@ -5,8 +5,6 @@ export function initUserAuthOauth2() { if (!outer) return; const inner = document.getElementById('oauth2-login-navigator-inner'); - checkAppUrl(); - for (const link of outer.querySelectorAll('.oauth-login-link')) { link.addEventListener('click', () => { inner.classList.add('tw-invisible'); @@ -20,3 +18,8 @@ export function initUserAuthOauth2() { }); } } + +export function initUserAuth() { + if (!document.querySelector('.user.signin')) return; + checkAppUrl(); +} diff --git a/web_src/js/index.js b/web_src/js/index.js index 6797617414..7d44b9ff56 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -24,7 +24,7 @@ import {initFindFileInRepo} from './features/repo-findfile.js'; import {initCommentContent, initMarkupContent} from './markup/content.js'; import {initPdfViewer} from './render/pdf.js'; -import {initUserAuthOauth2} from './features/user-auth.js'; +import {initUserAuthOauth2, initUserAuth} from './features/user-auth.js'; import { initRepoIssueDue, initRepoIssueReferenceRepositorySearch, @@ -184,6 +184,7 @@ onDomReady(() => { initUserAuthOauth2(); initUserAuthWebAuthn(); initUserAuthWebAuthnRegister(); + initUserAuth(); initRepoDiffView(); initPdfViewer(); initScopedAccessTokenCategories();