From fc4e6e7e4b87210af541d1038d3e041871d9621f Mon Sep 17 00:00:00 2001 From: Virgile <78490891+V-Gira@users.noreply.github.com> Date: Fri, 6 Sep 2024 17:36:08 +0200 Subject: [PATCH] chore: allow support for appended URL paths [WPB-10937] (#18013) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: allow end user to set all url paths (WPB-4676) (#16774) * fix: allow end user to set all url paths (WPB-4676) * add new urls in env variables to config * remove hard coded path from externalRoutes util * update components using the externalRoutes util * update missing components * remove unused path * rename subpath to url_path * expose external urls instead of get methods * add JS doc to methods appending UTM parameters * Apply suggestions from code review Co-authored-by: Przemysław Jóźwik --------- Co-authored-by: Virgile Co-authored-by: Przemysław Jóźwik * chore: bump default config to 0.31.22 [WPB-10937] --------- Co-authored-by: Virgile Co-authored-by: Przemysław Jóźwik --- app-config/package.json | 4 +- server/config/client.config.ts | 19 +++- server/config/env.ts | 17 +++ .../Message/DecryptErrorMessage.tsx | 4 +- .../components/Modals/UserModal/UserModal.tsx | 3 +- .../components/userDevices/DeviceList.tsx | 3 +- .../components/userDevices/NoDevicesFound.tsx | 4 +- src/script/externalRoute.ts | 107 +++++++----------- src/script/main/app.ts | 4 +- .../panels/preferences/AboutPreferences.tsx | 8 +- .../AccountSecuritySection.tsx | 12 +- 11 files changed, 91 insertions(+), 94 deletions(-) diff --git a/app-config/package.json b/app-config/package.json index 81ea2182a2c..0c982f45cee 100644 --- a/app-config/package.json +++ b/app-config/package.json @@ -1,6 +1,6 @@ { "dependencies": { - "wire-web-config-default-master": "https://github.com/wireapp/wire-web-config-wire#v0.31.21-0", - "wire-web-config-default-staging": "https://github.com/wireapp/wire-web-config-default#v0.31.20" + "wire-web-config-default-master": "https://github.com/wireapp/wire-web-config-wire#v0.31.22", + "wire-web-config-default-staging": "https://github.com/wireapp/wire-web-config-default#v0.31.22" } } diff --git a/server/config/client.config.ts b/server/config/client.config.ts index a7c58878b34..a1e54b7e5a0 100644 --- a/server/config/client.config.ts +++ b/server/config/client.config.ts @@ -77,27 +77,36 @@ export function generateConfig(params: ConfigGeneratorParams, env: Env) { MOBILE_BASE: env.URL_MOBILE_BASE, PRICING: env.URL_PRICING, PRIVACY_POLICY: env.URL_PRIVACY_POLICY, + URL_PATH: { + CREATE_TEAM: env.URL_PATH_CREATE_TEAM, + MANAGE_SERVICES: env.URL_PATH_MANAGE_SERVICES, + MANAGE_TEAM: env.URL_PATH_MANAGE_TEAM, + PASSWORD_RESET: env.URL_PATH_PASSWORD_RESET, + }, SUPPORT: { BUG_REPORT: env.URL_SUPPORT_BUG_REPORT, CALLING: env.URL_SUPPORT_CALLING, CAMERA_ACCESS_DENIED: env.URL_SUPPORT_CAMERA_ACCESS_DENIED, CONTACT: env.URL_SUPPORT_CONTACT, + DECRYPT_ERROR: env.URL_SUPPORT_DECRYPT_ERROR, DEVICE_ACCESS_DENIED: env.URL_SUPPORT_DEVICE_ACCESS_DENIED, DEVICE_NOT_FOUND: env.URL_SUPPORT_DEVICE_NOT_FOUND, + E2EI_VERIFICATION: env.URL_SUPPORT_E2EI_VERIFICATION, EMAIL_EXISTS: env.URL_SUPPORT_EMAIL_EXISTS, + FEDERATION_STOP: env.URL_SUPPORT_FEDERATION_STOP, HISTORY: env.URL_SUPPORT_HISTORY, INDEX: env.URL_SUPPORT_INDEX, + LEARN_MORE_ABOUT_GUEST_LINKS: env.URL_LEARN_MORE_ABOUT_GUEST_LINKS, LEGAL_HOLD_BLOCK: env.URL_SUPPORT_LEGAL_HOLD_BLOCK, MICROPHONE_ACCESS_DENIED: env.URL_SUPPORT_MICROPHONE_ACCESS_DENIED, MLS_LEARN_MORE: env.URL_SUPPORT_MLS_LEARN_MORE, - PRIVACY_VERIFY_FINGERPRINT: env.URL_SUPPORT_PRIVACY_VERIFY_FINGERPRINT, - SCREEN_ACCESS_DENIED: env.URL_SUPPORT_SCREEN_ACCESS_DENIED, - LEARN_MORE_ABOUT_GUEST_LINKS: env.URL_LEARN_MORE_ABOUT_GUEST_LINKS, NON_FEDERATING_INFO: env.URL_SUPPORT_NON_FEDERATING_INFO, OAUTH_LEARN_MORE: env.URL_SUPPORT_OAUTH_LEARN_MORE, OFFLINE_BACKEND: env.URL_SUPPORT_OFFLINE_BACKEND, - FEDERATION_STOP: env.URL_SUPPORT_FEDERATION_STOP, - E2EI_VERIFICATION: env.URL_SUPPORT_E2EI_VERIFICATION, + PRIVACY_UNVERIFIED_USERS: env.URL_SUPPORT_PRIVACY_UNVERIFIED_USERS, + PRIVACY_VERIFY_FINGERPRINT: env.URL_SUPPORT_PRIVACY_VERIFY_FINGERPRINT, + PRIVACY_WHY: env.URL_SUPPORT_PRIVACY_WHY, + SCREEN_ACCESS_DENIED: env.URL_SUPPORT_SCREEN_ACCESS_DENIED, }, TEAMS_BASE: env.URL_TEAMS_BASE, TEAMS_CREATE: env.URL_TEAMS_CREATE, diff --git a/server/config/env.ts b/server/config/env.ts index 93a54c84be4..0e2861b2602 100644 --- a/server/config/env.ts +++ b/server/config/env.ts @@ -215,6 +215,16 @@ export type Env = { /** Sets the host URL for the website, e.g. https://wire.com */ URL_WEBSITE_BASE: string; + /** Sets paths to append to a base URL */ + URL_PATH_CREATE_TEAM: string; + + URL_PATH_MANAGE_SERVICES: string; + + URL_PATH_MANAGE_TEAM: string; + + URL_PATH_PASSWORD_RESET: string; + + /** Sets Support URLs to specific pages */ URL_SUPPORT_INDEX: string; URL_SUPPORT_BUG_REPORT: string; @@ -252,8 +262,15 @@ export type Env = { URL_SUPPORT_OFFLINE_BACKEND: string; URL_SUPPORT_FEDERATION_STOP: string; + URL_SUPPORT_E2EI_VERIFICATION: string; + URL_SUPPORT_DECRYPT_ERROR: string; + + URL_SUPPORT_PRIVACY_UNVERIFIED_USERS: string; + + URL_SUPPORT_PRIVACY_WHY: string; + URL_WHATS_NEW: string; /** Content Security Policy diff --git a/src/script/components/MessagesList/Message/DecryptErrorMessage.tsx b/src/script/components/MessagesList/Message/DecryptErrorMessage.tsx index 16a1aa3aab9..ec4593b4c7e 100644 --- a/src/script/components/MessagesList/Message/DecryptErrorMessage.tsx +++ b/src/script/components/MessagesList/Message/DecryptErrorMessage.tsx @@ -20,7 +20,7 @@ import React, {useState} from 'react'; import {Icon} from 'Components/Icon'; -import {getDecryptErrorUrl} from 'src/script/externalRoute'; +import {Config} from 'src/script/Config'; import {MotionDuration} from 'src/script/motion/MotionDuration'; import {t} from 'Util/LocalizerUtil'; import {splitFingerprint} from 'Util/StringUtil'; @@ -36,7 +36,7 @@ export interface DecryptErrorMessageProps { const DecryptErrorMessage: React.FC = ({message, onClickResetSession}) => { const [isResettingSession, setIsResettingSession] = useState(false); - const link = getDecryptErrorUrl(); + const link = Config.getConfig().URL.SUPPORT.DECRYPT_ERROR; const caption = message.isIdentityChanged ? t('conversationUnableToDecrypt2', message.user().name(), { '/highlight': '', diff --git a/src/script/components/Modals/UserModal/UserModal.tsx b/src/script/components/Modals/UserModal/UserModal.tsx index 761580bf7a3..b6b4df5bd43 100644 --- a/src/script/components/Modals/UserModal/UserModal.tsx +++ b/src/script/components/Modals/UserModal/UserModal.tsx @@ -31,7 +31,6 @@ import {ModalComponent} from 'Components/ModalComponent'; import {EnrichedFields} from 'Components/panel/EnrichedFields'; import {UserActions} from 'Components/panel/UserActions'; import {UserDetails} from 'Components/panel/UserDetails'; -import {getPrivacyUnverifiedUsersUrl} from 'src/script/externalRoute'; import {useKoSubscribableChildren} from 'Util/ComponentUtil'; import {handleKeyDown} from 'Util/KeyboardUtil'; import {replaceLink, t} from 'Util/LocalizerUtil'; @@ -117,7 +116,7 @@ export const UnverifiedUserWarning: React.FC = ({use css={{fontSize: 'var(--font-size-medium)', margin: '0 0.2em'}} variant={LinkVariant.PRIMARY} targetBlank - href={getPrivacyUnverifiedUsersUrl()} + href={Config.getConfig().URL.SUPPORT.PRIVACY_UNVERIFIED_USERS} > {t('modalUserLearnMore')} diff --git a/src/script/components/userDevices/DeviceList.tsx b/src/script/components/userDevices/DeviceList.tsx index dce2baf5e77..a0dc7c891ce 100644 --- a/src/script/components/userDevices/DeviceList.tsx +++ b/src/script/components/userDevices/DeviceList.tsx @@ -30,7 +30,6 @@ import {DeviceCard} from './DeviceCard'; import type {ClientEntity} from '../../client/ClientEntity'; import {Config} from '../../Config'; import type {User} from '../../entity/User'; -import {getPrivacyWhyUrl} from '../../externalRoute'; interface DeviceListProps { clickOnDevice: (client: ClientEntity) => void; @@ -52,7 +51,7 @@ const DeviceList: React.FC = ({user, getDeviceIdentity, noPaddi diff --git a/src/script/components/userDevices/NoDevicesFound.tsx b/src/script/components/userDevices/NoDevicesFound.tsx index 5322967200b..831ee2b3c3b 100644 --- a/src/script/components/userDevices/NoDevicesFound.tsx +++ b/src/script/components/userDevices/NoDevicesFound.tsx @@ -26,7 +26,7 @@ import {t} from 'Util/LocalizerUtil'; import {Config} from '../../Config'; import type {User} from '../../entity/User'; -import {getPrivacyPolicyUrl} from '../../externalRoute'; +import {externalUrl} from '../../externalRoute'; interface NoDevicesFoundProps { noPadding: boolean; @@ -48,7 +48,7 @@ const NoDevicesFound: React.FC = ({user, noPadding}) => {

diff --git a/src/script/externalRoute.ts b/src/script/externalRoute.ts index e391e909bcb..737bfe6a093 100644 --- a/src/script/externalRoute.ts +++ b/src/script/externalRoute.ts @@ -20,79 +20,55 @@ import {currentLanguage} from './auth/localeConfig'; import {Config} from './Config'; -const env = window.wire.env; - -export const URL = { - ACCOUNT: env.URL?.ACCOUNT_BASE, - PRIVACY_POLICY: env.URL?.PRIVACY_POLICY, - SUPPORT: env.URL?.SUPPORT.INDEX, - TEAM_SETTINGS: env.URL?.TEAMS_BASE, - TERMS_OF_USE_PERSONAL: env.URL?.TERMS_OF_USE_PERSONAL, - TERMS_OF_USE_TEAMS: env.URL?.TERMS_OF_USE_TEAMS, - WEBAPP: { - INTERNAL: 'https://wire-webapp-staging.wire.com', - PRODUCTION: env.APP_BASE || 'https://app.wire.com', - STAGING: 'https://wire-webapp-staging.zinfra.io', - }, - WEBSITE: env.URL?.WEBSITE_BASE, -}; - -export const URL_PATH = { - CREATE_TEAM: '/create-team/', - DECRYPT_ERROR_1: '/articles/207948115', - DECRYPT_ERROR_2: '/privacy/error-2/', - MANAGE_SERVICES: '/services/', - MANAGE_TEAM: '/login/', - PASSWORD_RESET: '/forgot/', - PRIVACY_HOW: '/privacy/how/', - PRIVACY_UNVERIFIED_USERS: '/articles/202857164', - PRIVACY_WHY: '/articles/207859815', - SUPPORT_USERNAME: '/support/username/', -} as const; +const URL = Config.getConfig().URL; const getTeamSettingsUrl = (path: string = '', utmSource?: string): string | undefined => { const query = utmSource ? `?utm_source=${utmSource}&utm_term=desktop` : ''; - const teamSettingsUrl = `${URL.TEAM_SETTINGS}${path}${query}`; - return URL.TEAM_SETTINGS ? teamSettingsUrl : undefined; + const teamSettingsUrl = `${URL.TEAMS_BASE}${path}${query}`; + return URL.TEAMS_BASE ? teamSettingsUrl : undefined; }; -export const getWebsiteUrl = (path: string = '', pkCampaign?: string): string | undefined => { - if (URL.WEBSITE) { +const getWebsiteUrl = (path: string = '', pkCampaign?: string): string | undefined => { + if (URL.WEBSITE_BASE) { const query = pkCampaign ? `?pk_campaign=${pkCampaign}&pk_kwd=desktop` : ''; - const websiteUrl = `${URL.WEBSITE}${path}${query}`; - return addLocaleToUrl(URL.WEBSITE ? websiteUrl : undefined); + const websiteUrl = `${URL.WEBSITE_BASE}${path}${query}`; + return addLocaleToUrl(websiteUrl); } return undefined; }; -const getHelpCenterUrl = (path: (typeof URL_PATH)[keyof typeof URL_PATH]) => { - if (URL.SUPPORT) { - const helpcenterUrl = `${URL.SUPPORT}${path}`; - return addLocaleToHelpCenterUrl(URL.SUPPORT ? helpcenterUrl : undefined); - } - return undefined; +const getAccountPagesUrl = (path: string = ''): string | undefined => { + return URL.ACCOUNT_BASE ? `${URL.ACCOUNT_BASE}${path}` : undefined; }; -export const getAccountPagesUrl = (path: string = ''): string | undefined => { - const accountPagesUrl = `${URL.ACCOUNT}${path}`; - return URL.ACCOUNT ? accountPagesUrl : undefined; -}; +const getPrivacyPolicyUrl = (): string | undefined => addLocaleToUrl(URL.PRIVACY_POLICY || undefined); +const getTermsOfUsePersonalUrl = (): string | undefined => addLocaleToUrl(URL.TERMS_OF_USE_PERSONAL || undefined); +const getTermsOfUseTeamUrl = (): string | undefined => addLocaleToUrl(URL.TERMS_OF_USE_TEAMS || undefined); -export const getPrivacyPolicyUrl = (): string => addLocaleToUrl(URL.PRIVACY_POLICY || undefined); -export const getTermsOfUsePersonalUrl = (): string => addLocaleToUrl(URL.TERMS_OF_USE_PERSONAL || undefined); -export const getTermsOfUseTeamUrl = (): string => addLocaleToUrl(URL.TERMS_OF_USE_TEAMS || undefined); +/** + * Retrieves the URL for managing services with optional UTM parameters. + * UTM parameters are used in online marketing to track the effectiveness of campaigns. + * + * @param utmSource - Optional. The source of the UTM parameters. + * @returns The URL for managing services with optional UTM parameters. + */ +export const getManageServicesUrl = (utmSource?: string): string | undefined => + getTeamSettingsUrl(URL.URL_PATH.MANAGE_SERVICES, utmSource); -export const getManageServicesUrl = (utmSource?: string): string => - getTeamSettingsUrl(URL_PATH.MANAGE_SERVICES, utmSource); -export const getManageTeamUrl = (utmSource?: string): string => getTeamSettingsUrl(URL_PATH.MANAGE_TEAM, utmSource); +/** + * Retrieves the URL for managing team settings with optional UTM parameters. + * UTM parameters are used in online marketing to track the effectiveness of campaigns. + * + * @param utmSource - Optional. The source of the UTM parameters. + * @returns The URL for managing team settings with optional UTM parameters. + */ +export const getManageTeamUrl = (utmSource?: string): string | undefined => + getTeamSettingsUrl(URL.URL_PATH.MANAGE_TEAM, utmSource); -export const getCreateTeamUrl = (): string => - Config.getConfig().FEATURE.ENABLE_ACCOUNT_REGISTRATION && `${Config.getConfig().URL.TEAMS_BASE}/register/email`; -export const getDecryptErrorUrl = (): string => getHelpCenterUrl(URL_PATH.DECRYPT_ERROR_1); -export const getPrivacyUnverifiedUsersUrl = (): string => getHelpCenterUrl(URL_PATH.PRIVACY_UNVERIFIED_USERS); -export const getPrivacyWhyUrl = (): string => getHelpCenterUrl(URL_PATH.PRIVACY_WHY); +const getCreateTeamUrl = (): string | undefined => + Config.getConfig().FEATURE.ENABLE_ACCOUNT_REGISTRATION ? `${URL.TEAMS_BASE}${URL.URL_PATH.CREATE_TEAM}` : undefined; -export const addLocaleToUrl = (url?: string): string => { +export const addLocaleToUrl = (url?: string): string | undefined => { if (!url) { return undefined; } @@ -101,14 +77,11 @@ export const addLocaleToUrl = (url?: string): string => { return url.replace(Config.getConfig().URL.WEBSITE_BASE, `${Config.getConfig().URL.WEBSITE_BASE}/${websiteLanguage}`); }; -const addLocaleToHelpCenterUrl = (url?: string): string => { - if (!url) { - return undefined; - } - const language = currentLanguage().slice(0, 2); - const websiteLanguage = language == 'de' ? language : 'en-us'; - return url.replace( - `${Config.getConfig().URL.SUPPORT.INDEX}`, - `${Config.getConfig().URL.SUPPORT.INDEX}/hc/${websiteLanguage}`, - ); +export const externalUrl = { + createTeam: getCreateTeamUrl(), + passwordReset: getAccountPagesUrl(URL.URL_PATH?.PASSWORD_RESET), + privacyPolicy: getPrivacyPolicyUrl(), + termsOfUsePersonnal: getTermsOfUsePersonalUrl(), + termsOfUseTeam: getTermsOfUseTeamUrl(), + website: getWebsiteUrl(), }; diff --git a/src/script/main/app.ts b/src/script/main/app.ts index 0768374052f..55cd9aed548 100644 --- a/src/script/main/app.ts +++ b/src/script/main/app.ts @@ -82,7 +82,7 @@ import {ServiceMiddleware} from '../event/preprocessor/ServiceMiddleware'; import {FederationEventProcessor} from '../event/processor/FederationEventProcessor'; import {GiphyRepository} from '../extension/GiphyRepository'; import {GiphyService} from '../extension/GiphyService'; -import {getWebsiteUrl} from '../externalRoute'; +import {externalUrl} from '../externalRoute'; import {IntegrationRepository} from '../integration/IntegrationRepository'; import {IntegrationService} from '../integration/IntegrationService'; import {startNewVersionPolling} from '../lifecycle/newVersionHandler'; @@ -819,7 +819,7 @@ export class App { const isLeavingGuestRoom = isTemporaryGuestReason && this.repository.user['userState'].self()?.isTemporaryGuest(); if (isLeavingGuestRoom) { - const websiteUrl = getWebsiteUrl(); + const websiteUrl = externalUrl.website; if (websiteUrl) { return window.location.replace(websiteUrl); diff --git a/src/script/page/MainContent/panels/preferences/AboutPreferences.tsx b/src/script/page/MainContent/panels/preferences/AboutPreferences.tsx index 5c5474093bb..f61050ce6af 100644 --- a/src/script/page/MainContent/panels/preferences/AboutPreferences.tsx +++ b/src/script/page/MainContent/panels/preferences/AboutPreferences.tsx @@ -31,7 +31,7 @@ import {PreferencesSection} from './components/PreferencesSection'; import {Config} from '../../../../Config'; import {User} from '../../../../entity/User'; -import {getPrivacyPolicyUrl, getTermsOfUsePersonalUrl, getTermsOfUseTeamUrl, URL} from '../../../../externalRoute'; +import {externalUrl} from '../../../../externalRoute'; interface AboutPreferencesProps { selfUser: User; @@ -42,12 +42,12 @@ const AboutPreferences: React.FC = ({selfUser, teamState const inTeam = teamState.isInTeam(selfUser); const config = Config.getConfig(); const desktopConfig = Config.getDesktopConfig(); - const websiteUrl = URL.WEBSITE; - const privacyPolicyUrl = getPrivacyPolicyUrl(); + const websiteUrl = externalUrl.website; + const privacyPolicyUrl = externalUrl.privacyPolicy; const termsOfUseUrl = useMemo(() => { if (selfUser) { - return inTeam ? getTermsOfUseTeamUrl() : getTermsOfUsePersonalUrl(); + return inTeam ? externalUrl.termsOfUseTeam : externalUrl.termsOfUsePersonnal; } return ''; }, [selfUser, inTeam]); diff --git a/src/script/page/MainContent/panels/preferences/accountPreferences/AccountSecuritySection.tsx b/src/script/page/MainContent/panels/preferences/accountPreferences/AccountSecuritySection.tsx index 71803f933b7..abcb64139ad 100644 --- a/src/script/page/MainContent/panels/preferences/accountPreferences/AccountSecuritySection.tsx +++ b/src/script/page/MainContent/panels/preferences/accountPreferences/AccountSecuritySection.tsx @@ -30,10 +30,9 @@ import {WebAppEvents} from '@wireapp/webapp-events'; import {PrimaryModal} from 'Components/Modals/PrimaryModal'; import {useKoSubscribableChildren} from 'Util/ComponentUtil'; import {t} from 'Util/LocalizerUtil'; -import {safeWindowOpen} from 'Util/SanitizationUtil'; import {User} from '../../../../../entity/User'; -import {getAccountPagesUrl, getCreateTeamUrl, getManageTeamUrl, URL_PATH} from '../../../../../externalRoute'; +import {externalUrl, getManageTeamUrl} from '../../../../../externalRoute'; import {TeamState} from '../../../../../team/TeamState'; import {AppLockState} from '../../../../../user/AppLockState'; import {FEATURES, hasAccessToFeature} from '../../../../../user/UserPermission'; @@ -53,7 +52,7 @@ const AccountSecuritySection: React.FC = ({ appLockState = container.resolve(AppLockState), teamState = container.resolve(TeamState), }) => { - const createTeamUrl = getCreateTeamUrl(); + const createTeamUrl = externalUrl.createTeam; const manageTeamUrl = getManageTeamUrl('client_settings'); const {teamRole} = useKoSubscribableChildren(selfUser, ['teamRole']); const {isAppLockActivated} = useKoSubscribableChildren(appLockState, ['isAppLockActivated']); @@ -82,7 +81,8 @@ const AccountSecuritySection: React.FC = ({ safeWindowOpen(manageTeamUrl)} + href={manageTeamUrl} + targetBlank data-uie-name="do-manage-team" type="button" > @@ -110,8 +110,8 @@ const AccountSecuritySection: React.FC = ({ safeWindowOpen(getAccountPagesUrl(URL_PATH.PASSWORD_RESET))} + href={externalUrl.passwordReset} + targetBlank title={t('tooltipPreferencesPassword')} data-uie-name="do-reset-password" type="button"