From f6282145aa0f3412ffcfb63ffa35c38b4c024141 Mon Sep 17 00:00:00 2001 From: Osama Sayegh Date: Mon, 23 Dec 2024 07:54:53 +0300 Subject: [PATCH] FIX: Treat contact_url setting as a domain by default (#30225) This commit makes the `contact_url` in the /about page behave as an absolute URL instead of a relative one if it doesn't explicitly start with a slash or a protocol. This prevents situation where, e.g., `www.example.com` is specified in the setting and the contact URL anchor tag ends up with a `href` that navigates to `/www.example.com` instead of just `www.example.com`. We prevent this by adding 2 leading slashes `//` to `contact_url` which makes the `href` resolves to the specified `contact_url` using the same protocol as the current site's. Internal topic: t/143907. --- .../discourse/app/components/about-page.gjs | 19 ++++++- .../components/about-page-test.gjs | 56 +++++++++++++++++-- 2 files changed, 67 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/discourse/app/components/about-page.gjs b/app/assets/javascripts/discourse/app/components/about-page.gjs index 63abe5f27c7..5bccb0c9ef2 100644 --- a/app/assets/javascripts/discourse/app/components/about-page.gjs +++ b/app/assets/javascripts/discourse/app/components/about-page.gjs @@ -149,8 +149,9 @@ export default class AboutPage extends Component { const email = escape(this.args.model.contact_email || ""); if (url) { + const href = this.contactURLHref; return i18n("about.contact_info", { - contact_info: `${url}`, + contact_info: `${url}`, }); } else if (email) { return i18n("about.contact_info", { @@ -161,6 +162,20 @@ export default class AboutPage extends Component { } } + get contactURLHref() { + const url = escape(this.args.model.contact_url || ""); + + if (!url) { + return; + } + + if (url.startsWith("/") || url.match(/^\w+:/)) { + return url; + } + + return `//${url}`; + } + get siteAgeString() { const creationDate = new Date(this.args.model.site_creation_date); @@ -278,7 +293,7 @@ export default class AboutPage extends Component {

{{i18n "about.contact"}}

{{#if this.contactInfo}} -

{{htmlSafe this.contactInfo}}

+

{{htmlSafe this.contactInfo}}

{{/if}}

{{i18n "about.report_inappropriate_content"}}

{{i18n "about.site_activity"}}

diff --git a/app/assets/javascripts/discourse/tests/integration/components/about-page-test.gjs b/app/assets/javascripts/discourse/tests/integration/components/about-page-test.gjs index 3eee0b41a99..c505bf4627d 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/about-page-test.gjs +++ b/app/assets/javascripts/discourse/tests/integration/components/about-page-test.gjs @@ -11,12 +11,16 @@ function createModelObject({ moderators = [], stats = {}, }) { - return { - title, - admins, - moderators, - stats, - }; + const model = arguments[0] || {}; + return Object.assign( + { + title, + admins, + moderators, + stats, + }, + model + ); } module("Integration | Component | about-page", function (hooks) { @@ -98,4 +102,44 @@ module("Integration | Component | about-page", function (hooks) { }) ); }); + + test("contact URL", async function (assert) { + let model = createModelObject({ + contact_url: "www.example.com", + }); + + await render(); + + assert + .dom(".about__contact-info a") + .hasAttribute( + "href", + "//www.example.com", + "appends a double slash if the value doesn't start with a slash or a protocol" + ); + + model.contact_url = "/u/somebody"; + + await render(); + + assert + .dom(".about__contact-info a") + .hasAttribute( + "href", + "/u/somebody", + "doesn't append a double slash if the value starts with a slash" + ); + + model.contact_url = "https://example.com"; + + await render(); + + assert + .dom(".about__contact-info a") + .hasAttribute( + "href", + "https://example.com", + "doesn't append a double slash if the value starts with a protocol" + ); + }); });