about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorHailey <me@haileyok.com>2025-02-27 13:18:30 -0800
committerGitHub <noreply@github.com>2025-02-27 13:18:30 -0800
commita2b71e3a4b786565938cef60924b27c5cd7f0660 (patch)
treeff78bc233ab5c1507b3f13f2dcbeaac96974ad07 /src
parenta3d36393a16b6219d97d2a553aa426ab108f3168 (diff)
downloadvoidsky-a2b71e3a4b786565938cef60924b27c5cd7f0660.tar.zst
tweak link handling (#7857)
Diffstat (limited to 'src')
-rw-r--r--src/components/Link.tsx14
-rw-r--r--src/components/RichText.tsx4
-rw-r--r--src/lib/hooks/useOpenLink.ts7
-rw-r--r--src/lib/strings/url-helpers.ts15
-rw-r--r--src/view/com/post-thread/PostThreadItem.tsx2
-rw-r--r--src/view/com/post/Post.tsx1
-rw-r--r--src/view/com/posts/PostFeedItem.tsx1
-rw-r--r--src/view/com/util/post-embeds/ExternalLinkEmbed.tsx1
8 files changed, 43 insertions, 2 deletions
diff --git a/src/components/Link.tsx b/src/components/Link.tsx
index 26cea5968..8bebecbc8 100644
--- a/src/components/Link.tsx
+++ b/src/components/Link.tsx
@@ -69,6 +69,11 @@ type BaseLinkProps = Pick<
    * Native-only attribute. If true, will open the share sheet on long press.
    */
   shareOnLongPress?: boolean
+
+  /**
+   * Whether the link should be opened through the redirect proxy.
+   */
+  shouldProxy?: boolean
 }
 
 export function useLink({
@@ -80,9 +85,11 @@ export function useLink({
   onLongPress: outerOnLongPress,
   shareOnLongPress,
   overridePresentation,
+  shouldProxy,
 }: BaseLinkProps & {
   displayText: string
   overridePresentation?: boolean
+  shouldProxy?: boolean
 }) {
   const navigation = useNavigationDeduped()
   const {href} = useLinkProps<AllNavigatorParams>({
@@ -118,7 +125,7 @@ export function useLink({
         })
       } else {
         if (isExternal) {
-          openLink(href, overridePresentation)
+          openLink(href, overridePresentation, shouldProxy)
         } else {
           const shouldOpenInNewTab = shouldClickOpenNewTab(e)
 
@@ -161,6 +168,7 @@ export function useLink({
       action,
       navigation,
       overridePresentation,
+      shouldProxy,
     ],
   )
 
@@ -219,6 +227,7 @@ export function Link({
   onPress: outerOnPress,
   onLongPress: outerOnLongPress,
   download,
+  shouldProxy,
   ...rest
 }: LinkProps) {
   const {href, isExternal, onPress, onLongPress} = useLink({
@@ -227,6 +236,7 @@ export function Link({
     action,
     onPress: outerOnPress,
     onLongPress: outerOnLongPress,
+    shouldProxy: shouldProxy,
   })
 
   return (
@@ -279,6 +289,7 @@ export function InlineLinkText({
   shareOnLongPress,
   disableUnderline,
   overridePresentation,
+  shouldProxy,
   ...rest
 }: InlineLinkProps) {
   const t = useTheme()
@@ -292,6 +303,7 @@ export function InlineLinkText({
     onLongPress: outerOnLongPress,
     shareOnLongPress,
     overridePresentation,
+    shouldProxy: shouldProxy,
   })
   const {
     state: hovered,
diff --git a/src/components/RichText.tsx b/src/components/RichText.tsx
index 7005d0742..d501f4287 100644
--- a/src/components/RichText.tsx
+++ b/src/components/RichText.tsx
@@ -23,6 +23,7 @@ export type RichTextProps = TextStyleProp &
     onLinkPress?: LinkProps['onPress']
     interactiveStyle?: TextStyle
     emojiMultiplier?: number
+    shouldProxyLinks?: boolean
   }
 
 export function RichText({
@@ -39,6 +40,7 @@ export function RichText({
   emojiMultiplier = 1.85,
   onLayout,
   onTextLayout,
+  shouldProxyLinks,
 }: RichTextProps) {
   const richText = React.useMemo(
     () =>
@@ -110,6 +112,7 @@ export function RichText({
             style={interactiveStyles}
             // @ts-ignore TODO
             dataSet={WORD_WRAP}
+            shouldProxy={shouldProxyLinks}
             onPress={onLinkPress}>
             {segment.text}
           </InlineLinkText>
@@ -128,6 +131,7 @@ export function RichText({
             // @ts-ignore TODO
             dataSet={WORD_WRAP}
             shareOnLongPress
+            shouldProxy={shouldProxyLinks}
             onPress={onLinkPress}
             emoji>
             {toShortUrl(segment.text)}
diff --git a/src/lib/hooks/useOpenLink.ts b/src/lib/hooks/useOpenLink.ts
index 0629656ac..a949dacc6 100644
--- a/src/lib/hooks/useOpenLink.ts
+++ b/src/lib/hooks/useOpenLink.ts
@@ -5,6 +5,7 @@ import * as WebBrowser from 'expo-web-browser'
 import {logEvent} from '#/lib/statsig/statsig'
 import {
   createBskyAppAbsoluteUrl,
+  createProxiedUrl,
   isBskyAppUrl,
   isBskyRSSUrl,
   isRelativeUrl,
@@ -23,7 +24,7 @@ export function useOpenLink() {
   const sheetWrapper = useSheetWrapper()
 
   const openLink = useCallback(
-    async (url: string, override?: boolean) => {
+    async (url: string, override?: boolean, shouldProxy?: boolean) => {
       if (isBskyRSSUrl(url) && isRelativeUrl(url)) {
         url = createBskyAppAbsoluteUrl(url)
       }
@@ -33,6 +34,10 @@ export function useOpenLink() {
           domain: toNiceDomain(url),
           url,
         })
+
+        if (shouldProxy) {
+          url = createProxiedUrl(url)
+        }
       }
 
       if (isNative && !url.startsWith('mailto:')) {
diff --git a/src/lib/strings/url-helpers.ts b/src/lib/strings/url-helpers.ts
index c44fdf7c2..bb533b12e 100644
--- a/src/lib/strings/url-helpers.ts
+++ b/src/lib/strings/url-helpers.ts
@@ -320,6 +320,21 @@ export function createBskyAppAbsoluteUrl(path: string): string {
   return `${BSKY_APP_HOST.replace(/\/$/, '')}/${sanitizedPath}`
 }
 
+export function createProxiedUrl(url: string): string {
+  let u
+  try {
+    u = URL.parse(url)
+  } catch {
+    return url
+  }
+
+  if (u?.protocol !== 'http:' && u?.protocol !== 'https:') {
+    return url
+  }
+
+  return `https://go.bsky.app/redirect?u=${url}`
+}
+
 export function isShortLink(url: string): boolean {
   return url.startsWith('https://go.bsky.app/')
 }
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx
index 024629198..f818e47a1 100644
--- a/src/view/com/post-thread/PostThreadItem.tsx
+++ b/src/view/com/post-thread/PostThreadItem.tsx
@@ -375,6 +375,7 @@ let PostThreadItemLoaded = ({
                   value={richText}
                   style={[a.flex_1, a.text_xl]}
                   authorHandle={post.author.handle}
+                  shouldProxyLinks={true}
                 />
               ) : undefined}
               {post.embed && (
@@ -590,6 +591,7 @@ let PostThreadItemLoaded = ({
                     style={[a.flex_1, a.text_md]}
                     numberOfLines={limitLines ? MAX_POST_LINES : undefined}
                     authorHandle={post.author.handle}
+                    shouldProxyLinks={true}
                   />
                 </View>
               ) : undefined}
diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx
index e3fca3e8b..600cee428 100644
--- a/src/view/com/post/Post.tsx
+++ b/src/view/com/post/Post.tsx
@@ -234,6 +234,7 @@ function PostInner({
                   numberOfLines={limitLines ? MAX_POST_LINES : undefined}
                   style={[a.flex_1, a.text_md]}
                   authorHandle={post.author.handle}
+                  shouldProxyLinks={true}
                 />
               </View>
             ) : undefined}
diff --git a/src/view/com/posts/PostFeedItem.tsx b/src/view/com/posts/PostFeedItem.tsx
index 13c243c0a..499b9ccd5 100644
--- a/src/view/com/posts/PostFeedItem.tsx
+++ b/src/view/com/posts/PostFeedItem.tsx
@@ -506,6 +506,7 @@ let PostContent = ({
             numberOfLines={limitLines ? MAX_POST_LINES : undefined}
             style={[a.flex_1, a.text_md]}
             authorHandle={postAuthor.handle}
+            shouldProxyLinks={true}
           />
         </View>
       ) : undefined}
diff --git a/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx b/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx
index 64e869c94..5b05cd963 100644
--- a/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx
+++ b/src/view/com/util/post-embeds/ExternalLinkEmbed.tsx
@@ -70,6 +70,7 @@ export const ExternalLinkEmbed = ({
     <Link
       label={link.title || _(msg`Open link to ${niceUrl}`)}
       to={link.uri}
+      shouldProxy={true}
       onPress={onOpen}
       onLongPress={onShareExternal}>
       {({hovered}) => (