Update trusted hosts, allow `#`, and add more tests (#3232)

* Update trusted hosts, allow `#`, and add more tests

* update comments
zio/stable
Hailey 2024-03-19 12:01:54 -07:00 committed by GitHub
parent 5b4b8e47d9
commit 5e0a6a12ff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 64 additions and 12 deletions

View File

@ -4,6 +4,7 @@ import {
linkRequiresWarning, linkRequiresWarning,
isPossiblyAUrl, isPossiblyAUrl,
splitApexDomain, splitApexDomain,
isTrustedUrl,
} from '../../../src/lib/strings/url-helpers' } from '../../../src/lib/strings/url-helpers'
describe('linkRequiresWarning', () => { describe('linkRequiresWarning', () => {
@ -74,6 +75,10 @@ describe('linkRequiresWarning', () => {
// bad uri inputs, default to true // bad uri inputs, default to true
['', '', true], ['', '', true],
['example.com', 'example.com', true], ['example.com', 'example.com', true],
['/profile', 'Username', false],
['#', 'Show More', false],
['https://docs.bsky.app', 'https://docs.bsky.app', false],
['https://bsky.app/compose/intent?text=test', 'Compose a post', false],
] ]
it.each(cases)( it.each(cases)(
@ -139,3 +144,36 @@ describe('splitApexDomain', () => {
}, },
) )
}) })
describe('isTrustedUrl', () => {
const cases = [
['#', true],
['#profile', true],
['/', true],
['/profile', true],
['/profile/', true],
['/profile/bob.test', true],
['https://bsky.app', true],
['https://bsky.app/', true],
['https://bsky.app/profile/bob.test', true],
['https://www.bsky.app', true],
['https://www.bsky.app/', true],
['https://docs.bsky.app', true],
['https://bsky.social', true],
['https://bsky.social/blog', true],
['https://blueskyweb.xyz', true],
['https://blueskyweb.zendesk.com', true],
['http://bsky.app', true],
['http://bsky.social', true],
['http://blueskyweb.xyz', true],
['http://blueskyweb.zendesk.com', true],
['https://google.com', false],
['https://docs.google.com', false],
['https://google.com/#', false],
]
it.each(cases)('given input uri %p, returns %p', (str, expected) => {
const output = isTrustedUrl(str)
expect(output).toEqual(expected)
})
})

View File

@ -4,6 +4,23 @@ import TLDs from 'tlds'
import psl from 'psl' import psl from 'psl'
export const BSKY_APP_HOST = 'https://bsky.app' export const BSKY_APP_HOST = 'https://bsky.app'
const BSKY_TRUSTED_HOSTS = [
'bsky.app',
'bsky.social',
'blueskyweb.xyz',
'blueskyweb.zendesk.com',
...(__DEV__ ? ['localhost:19006', 'localhost:8100'] : []),
]
/*
* This will allow any BSKY_TRUSTED_HOSTS value by itself or with a subdomain.
* It will also allow relative paths like /profile as well as #.
*/
const TRUSTED_REGEX = new RegExp(
`^(http(s)?://(([\\w-]+\\.)?${BSKY_TRUSTED_HOSTS.join(
'|([\\w-]+\\.)?',
)})|/|#)`,
)
export function isValidDomain(str: string): boolean { export function isValidDomain(str: string): boolean {
return !!TLDs.find(tld => { return !!TLDs.find(tld => {
@ -86,6 +103,10 @@ export function isExternalUrl(url: string): boolean {
return external || rss return external || rss
} }
export function isTrustedUrl(url: string): boolean {
return TRUSTED_REGEX.test(url)
}
export function isBskyPostUrl(url: string): boolean { export function isBskyPostUrl(url: string): boolean {
if (isBskyAppUrl(url)) { if (isBskyAppUrl(url)) {
try { try {
@ -163,8 +184,8 @@ export function feedUriToHref(url: string): string {
export function linkRequiresWarning(uri: string, label: string) { export function linkRequiresWarning(uri: string, label: string) {
const labelDomain = labelToDomain(label) const labelDomain = labelToDomain(label)
// If the uri started with a / we know it is internal. // We should trust any relative URL or a # since we know it links to internal content
if (isRelativeUrl(uri)) { if (isRelativeUrl(uri) || uri === '#') {
return false return false
} }
@ -176,18 +197,11 @@ export function linkRequiresWarning(uri: string, label: string) {
} }
const host = urip.hostname.toLowerCase() const host = urip.hostname.toLowerCase()
// Hosts that end with bsky.app or bsky.social should be trusted by default. if (isTrustedUrl(uri)) {
if ( // if this is a link to internal content, warn if it represents itself as a URL to another app
host.endsWith('bsky.app') ||
host.endsWith('bsky.social') ||
host.endsWith('blueskyweb.xyz')
) {
// if this is a link to internal content,
// warn if it represents itself as a URL to another app
return !!labelDomain && labelDomain !== host && isPossiblyAUrl(labelDomain) return !!labelDomain && labelDomain !== host && isPossiblyAUrl(labelDomain)
} else { } else {
// if this is a link to external content, // if this is a link to external content, warn if the label doesnt match the target
// warn if the label doesnt match the target
if (!labelDomain) { if (!labelDomain) {
return true return true
} }