mirror of
https://github.com/mattermost/mattermost.git
synced 2026-08-26 21:27:40 -05:00
MM-67387 Prevent useExternalLink from erroring on certain invalid links (#35393)
* MM-67387 Prevent useExternalLink from erroring on certain invalid links * Make check for domain in useExternalLink stricter --------- Co-authored-by: Mattermost Build <build@mattermost.com>
This commit is contained in:
co-authored by
Mattermost Build
parent
162ed1bacd
commit
baf2bcb6f5
@@ -136,9 +136,31 @@ describe('useExternalLink', () => {
|
||||
expect(firstHref).toBe(secondHref);
|
||||
expect(firstParams).toBe(secondParams);
|
||||
});
|
||||
|
||||
it('do not substitute %20 on query params', () => {
|
||||
const url = 'https://www.mattermost.com/some/url?subject=hello%20world';
|
||||
const {result: {current: [href]}} = renderHookWithContext(() => useExternalLink(url), getBaseState());
|
||||
expect(href).toContain('subject=hello%20world');
|
||||
});
|
||||
|
||||
it('do not error on invalid URLs', () => {
|
||||
const invalidUrl = 'not a valid url';
|
||||
const {result: {current: [href, queryParams]}} = renderHookWithContext(() => useExternalLink(invalidUrl), getBaseState());
|
||||
expect(href).toBe(invalidUrl);
|
||||
expect(queryParams).toEqual({});
|
||||
});
|
||||
|
||||
it('do not modify arbitrary links that happen to include mattermost.com', () => {
|
||||
const invalidUrl = 'https://example.com/mattermost.com';
|
||||
const {result: {current: [href, queryParams]}} = renderHookWithContext(() => useExternalLink(invalidUrl), getBaseState());
|
||||
expect(href).toBe(invalidUrl);
|
||||
expect(queryParams).toEqual({});
|
||||
});
|
||||
|
||||
it('do not modify mailto links on mattermost.com', () => {
|
||||
const mailtoUrl = 'mailto:support@mattermost.com';
|
||||
const {result: {current: [href, queryParams]}} = renderHookWithContext(() => useExternalLink(mailtoUrl), getBaseState());
|
||||
expect(href).toBe(mailtoUrl);
|
||||
expect(queryParams).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,6 +17,17 @@ export type ExternalLinkQueryParams = {
|
||||
userId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* useExternalLink is used when linking outside of the MM server to add extra tracking parameters when linking to any
|
||||
* page on mattermost.com (such as our docs or marketing websites). When passed any URL that isn't on mattermost.com,
|
||||
* it returns the original URL unmodified.
|
||||
*
|
||||
* @param href The external URL being linked to
|
||||
* @param location The location of the link within the app
|
||||
* @param overwriteQueryParams
|
||||
* @return {[string, Record<string, string>]} A tuple containing the URL (whether or not it was modified) and all query
|
||||
* parameters on that link (either pre-existing or added by this hook)
|
||||
*/
|
||||
export function useExternalLink(href: string, location: string = '', overwriteQueryParams: ExternalLinkQueryParams = {}): [string, Record<string, string>] {
|
||||
const userId = useSelector(getCurrentUserId);
|
||||
const config = useSelector(getConfig);
|
||||
@@ -28,11 +39,20 @@ export function useExternalLink(href: string, location: string = '', overwriteQu
|
||||
const isCloud = useSelector((state: GlobalState) => getLicense(state)?.Cloud === 'true');
|
||||
|
||||
return useMemo(() => {
|
||||
if (!href?.includes('mattermost.com') || href?.startsWith('mailto:')) {
|
||||
let parsedUrl;
|
||||
try {
|
||||
parsedUrl = new URL(href);
|
||||
} catch {
|
||||
return [href, {}];
|
||||
}
|
||||
|
||||
const parsedUrl = new URL(href);
|
||||
if (parsedUrl.hostname !== 'mattermost.com' && !parsedUrl.hostname.endsWith('.mattermost.com')) {
|
||||
return [href, {}];
|
||||
}
|
||||
|
||||
if (parsedUrl.protocol === 'mailto:') {
|
||||
return [href, {}];
|
||||
}
|
||||
|
||||
// Determine edition type (enterprise vs team)
|
||||
const isEnterpriseReady = config?.BuildEnterpriseReady === 'true';
|
||||
|
||||
Reference in New Issue
Block a user