about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEric Bailey <git@esb.lol>2024-03-09 10:35:23 -0600
committerGitHub <noreply@github.com>2024-03-09 10:35:23 -0600
commit594958c6dc2a69155c19bcd108f19fe9c64f98be (patch)
tree72180011d9d227f24c3eb47df79bd5567357c718
parentaad8c080eda81ad96875c817420d719a8c80874f (diff)
downloadvoidsky-594958c6dc2a69155c19bcd108f19fe9c64f98be.tar.zst
Fix RSS URLs treated as internal (#3156)
* Fix RSS URLs treated as internal

* Add utils to patch relative RSS external links

* modify router to support multiple paths

---------

Co-authored-by: Hailey <me@haileyok.com>
-rw-r--r--src/lib/routes/router.ts10
-rw-r--r--src/lib/strings/url-helpers.ts24
-rw-r--r--src/routes.ts2
-rw-r--r--src/state/preferences/in-app-browser.tsx9
4 files changed, 40 insertions, 5 deletions
diff --git a/src/lib/routes/router.ts b/src/lib/routes/router.ts
index 00defaeda..8c8be3739 100644
--- a/src/lib/routes/router.ts
+++ b/src/lib/routes/router.ts
@@ -2,9 +2,15 @@ import {RouteParams, Route} from './types'
 
 export class Router {
   routes: [string, Route][] = []
-  constructor(description: Record<string, string>) {
+  constructor(description: Record<string, string | string[]>) {
     for (const [screen, pattern] of Object.entries(description)) {
-      this.routes.push([screen, createRoute(pattern)])
+      if (typeof pattern === 'string') {
+        this.routes.push([screen, createRoute(pattern)])
+      } else {
+        pattern.forEach(subPattern => {
+          this.routes.push([screen, createRoute(subPattern)])
+        })
+      }
     }
   }
 
diff --git a/src/lib/strings/url-helpers.ts b/src/lib/strings/url-helpers.ts
index 7729e4a38..820311e4e 100644
--- a/src/lib/strings/url-helpers.ts
+++ b/src/lib/strings/url-helpers.ts
@@ -3,6 +3,8 @@ import {BSKY_SERVICE} from 'lib/constants'
 import TLDs from 'tlds'
 import psl from 'psl'
 
+export const BSKY_APP_HOST = 'https://bsky.app'
+
 export function isValidDomain(str: string): boolean {
   return !!TLDs.find(tld => {
     let i = str.lastIndexOf(tld)
@@ -67,8 +69,21 @@ export function isBskyAppUrl(url: string): boolean {
   return url.startsWith('https://bsky.app/')
 }
 
+export function isRelativeUrl(url: string): boolean {
+  return /^\/[^/]/.test(url)
+}
+
+export function isBskyRSSUrl(url: string): boolean {
+  return (
+    (url.startsWith('https://bsky.app/') || isRelativeUrl(url)) &&
+    /\/rss\/?$/.test(url)
+  )
+}
+
 export function isExternalUrl(url: string): boolean {
-  return !isBskyAppUrl(url) && url.startsWith('http')
+  const external = !isBskyAppUrl(url) && url.startsWith('http')
+  const rss = isBskyRSSUrl(url)
+  return external || rss
 }
 
 export function isBskyPostUrl(url: string): boolean {
@@ -149,7 +164,7 @@ export function linkRequiresWarning(uri: string, label: string) {
   const labelDomain = labelToDomain(label)
 
   // If the uri started with a / we know it is internal.
-  if (uri.startsWith('/')) {
+  if (isRelativeUrl(uri)) {
     return false
   }
 
@@ -222,3 +237,8 @@ export function splitApexDomain(hostname: string): [string, string] {
     hostnamep.domain,
   ]
 }
+
+export function createBskyAppAbsoluteUrl(path: string): string {
+  const sanitizedPath = path.replace(BSKY_APP_HOST, '').replace(/^\/+/, '')
+  return `${BSKY_APP_HOST.replace(/\/$/, '')}/${sanitizedPath}`
+}
diff --git a/src/routes.ts b/src/routes.ts
index 3fc908b48..5c263fd6f 100644
--- a/src/routes.ts
+++ b/src/routes.ts
@@ -12,7 +12,7 @@ export const router = new Router({
   ModerationModlists: '/moderation/modlists',
   ModerationMutedAccounts: '/moderation/muted-accounts',
   ModerationBlockedAccounts: '/moderation/blocked-accounts',
-  Profile: '/profile/:name',
+  Profile: ['/profile/:name', '/profile/:name/rss'],
   ProfileFollowers: '/profile/:name/followers',
   ProfileFollows: '/profile/:name/follows',
   ProfileList: '/profile/:name/lists/:rkey',
diff --git a/src/state/preferences/in-app-browser.tsx b/src/state/preferences/in-app-browser.tsx
index 4f033db65..2398f1f81 100644
--- a/src/state/preferences/in-app-browser.tsx
+++ b/src/state/preferences/in-app-browser.tsx
@@ -5,6 +5,11 @@ import * as WebBrowser from 'expo-web-browser'
 import {isNative} from '#/platform/detection'
 import {useModalControls} from '../modals'
 import {usePalette} from 'lib/hooks/usePalette'
+import {
+  isBskyRSSUrl,
+  isRelativeUrl,
+  createBskyAppAbsoluteUrl,
+} from 'lib/strings/url-helpers'
 
 type StateContext = persisted.Schema['useInAppBrowser']
 type SetContext = (v: persisted.Schema['useInAppBrowser']) => void
@@ -57,6 +62,10 @@ export function useOpenLink() {
 
   const openLink = React.useCallback(
     (url: string, override?: boolean) => {
+      if (isBskyRSSUrl(url) && isRelativeUrl(url)) {
+        url = createBskyAppAbsoluteUrl(url)
+      }
+
       if (isNative && !url.startsWith('mailto:')) {
         if (override === undefined && enabled === undefined) {
           openModal({