[Embeds] stop adding tracking params to non-bsky.app links (#4167)

* don't add tracking params on non-bsky.app links

* validate facets
zio/stable
Samuel Newman 2024-05-23 03:52:46 +01:00 committed by GitHub
parent 69f4684859
commit 334483ad9a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 37 additions and 19 deletions

View File

@ -15,6 +15,6 @@
"parserOptions": { "parserOptions": {
"sourceType": "module", "sourceType": "module",
"ecmaVersion": "latest", "ecmaVersion": "latest",
"project": "./tsconfig.json" "project": "./bskyembed/tsconfig.json"
} }
} }

View File

@ -193,7 +193,7 @@ export function Embed({
function Info({children}: {children: ComponentChildren}) { function Info({children}: {children: ComponentChildren}) {
return ( return (
<div className="w-full rounded-lg border py-2 px-2.5 flex-row flex gap-2 bg-neutral-50"> <div className="w-full rounded-lg border py-2 px-2.5 flex-row flex gap-2 bg-neutral-50">
<img src={infoIcon as string} className="w-4 h-4 shrink-0 mt-0.5" /> <img src={infoIcon} className="w-4 h-4 shrink-0 mt-0.5" />
<p className="text-sm text-textLight">{children}</p> <p className="text-sm text-textLight">{children}</p>
</div> </div>
) )
@ -293,7 +293,8 @@ function ExternalEmbed({
return ( return (
<Link <Link
href={content.external.uri} href={content.external.uri}
className="w-full rounded-lg overflow-hidden border flex flex-col items-stretch"> className="w-full rounded-lg overflow-hidden border flex flex-col items-stretch"
disableTracking>
{content.external.thumb && ( {content.external.thumb && (
<img <img
src={content.external.thumb} src={content.external.thumb}

View File

@ -3,10 +3,12 @@ import {h} from 'preact'
export function Link({ export function Link({
href, href,
className, className,
disableTracking,
...props ...props
}: { }: {
href: string href: string
className?: string className?: string
disableTracking?: boolean
} & h.JSX.HTMLAttributes<HTMLAnchorElement>) { } & h.JSX.HTMLAttributes<HTMLAnchorElement>) {
const searchParam = new URLSearchParams(window.location.search) const searchParam = new URLSearchParams(window.location.search)
const ref_url = searchParam.get('ref_url') const ref_url = searchParam.get('ref_url')
@ -19,9 +21,9 @@ export function Link({
return ( return (
<a <a
href={`${ href={`${href.startsWith('http') ? href : `https://bsky.app${href}`}${
href.startsWith('http') ? href : `https://bsky.app${href}` disableTracking ? '' : `?${newSearchParam.toString()}`
}?${newSearchParam.toString()}`} }`}
target="_blank" target="_blank"
rel="noopener noreferrer nofollow" rel="noopener noreferrer nofollow"
onClick={evt => evt.stopPropagation()} onClick={evt => evt.stopPropagation()}

View File

@ -1,4 +1,9 @@
import {AppBskyFeedDefs, AppBskyFeedPost, RichText} from '@atproto/api' import {
AppBskyFeedDefs,
AppBskyFeedPost,
AppBskyRichtextFacet,
RichText,
} from '@atproto/api'
import {h} from 'preact' import {h} from 'preact'
import replyIcon from '../../assets/bubble_filled_stroke2_corner2_rounded.svg' import replyIcon from '../../assets/bubble_filled_stroke2_corner2_rounded.svg'
@ -56,7 +61,7 @@ export function Post({thread}: Props) {
<Link <Link
href={href} href={href}
className="transition-transform hover:scale-110 shrink-0 self-start"> className="transition-transform hover:scale-110 shrink-0 self-start">
<img src={logo as string} className="h-8" /> <img src={logo} className="h-8" />
</Link> </Link>
</div> </div>
<PostContent record={record} /> <PostContent record={record} />
@ -71,7 +76,7 @@ export function Post({thread}: Props) {
<div className="border-t w-full pt-2.5 flex items-center gap-5 text-sm cursor-pointer"> <div className="border-t w-full pt-2.5 flex items-center gap-5 text-sm cursor-pointer">
{!!post.likeCount && ( {!!post.likeCount && (
<div className="flex items-center gap-2 cursor-pointer"> <div className="flex items-center gap-2 cursor-pointer">
<img src={likeIcon as string} className="w-5 h-5" /> <img src={likeIcon} className="w-5 h-5" />
<p className="font-bold text-neutral-500 mb-px"> <p className="font-bold text-neutral-500 mb-px">
{post.likeCount} {post.likeCount}
</p> </p>
@ -79,14 +84,14 @@ export function Post({thread}: Props) {
)} )}
{!!post.repostCount && ( {!!post.repostCount && (
<div className="flex items-center gap-2 cursor-pointer"> <div className="flex items-center gap-2 cursor-pointer">
<img src={repostIcon as string} className="w-5 h-5" /> <img src={repostIcon} className="w-5 h-5" />
<p className="font-bold text-neutral-500 mb-px"> <p className="font-bold text-neutral-500 mb-px">
{post.repostCount} {post.repostCount}
</p> </p>
</div> </div>
)} )}
<div className="flex items-center gap-2 cursor-pointer"> <div className="flex items-center gap-2 cursor-pointer">
<img src={replyIcon as string} className="w-5 h-5" /> <img src={replyIcon} className="w-5 h-5" />
<p className="font-bold text-neutral-500 mb-px">Reply</p> <p className="font-bold text-neutral-500 mb-px">Reply</p>
</div> </div>
<div className="flex-1" /> <div className="flex-1" />
@ -118,16 +123,23 @@ function PostContent({record}: {record: AppBskyFeedPost.Record | null}) {
let counter = 0 let counter = 0
for (const segment of rt.segments()) { for (const segment of rt.segments()) {
if (segment.isLink() && segment.link) { if (
segment.link &&
AppBskyRichtextFacet.validateLink(segment.link).success
) {
richText.push( richText.push(
<Link <Link
key={counter} key={counter}
href={segment.link.uri} href={segment.link.uri}
className="text-blue-400 hover:underline"> className="text-blue-400 hover:underline"
disableTracking={!segment.link.uri.startsWith('https://bsky.app')}>
{segment.text} {segment.text}
</Link>, </Link>,
) )
} else if (segment.isMention() && segment.mention) { } else if (
segment.mention &&
AppBskyRichtextFacet.validateMention(segment.mention).success
) {
richText.push( richText.push(
<Link <Link
key={counter} key={counter}
@ -136,7 +148,10 @@ function PostContent({record}: {record: AppBskyFeedPost.Record | null}) {
{segment.text} {segment.text}
</Link>, </Link>,
) )
} else if (segment.isTag() && segment.tag) { } else if (
segment.tag &&
AppBskyRichtextFacet.validateTag(segment.tag).success
) {
richText.push( richText.push(
<Link <Link
key={counter} key={counter}

View File

@ -112,7 +112,7 @@ function LandingPage() {
<Link <Link
href="https://bsky.social/about" href="https://bsky.social/about"
className="transition-transform hover:scale-110"> className="transition-transform hover:scale-110">
<img src={logo as string} className="h-10" /> <img src={logo} className="h-10" />
</Link> </Link>
<h1 className="text-4xl font-bold text-center">Embed a Bluesky Post</h1> <h1 className="text-4xl font-bold text-center">Embed a Bluesky Post</h1>
@ -125,7 +125,7 @@ function LandingPage() {
placeholder={DEFAULT_POST} placeholder={DEFAULT_POST}
/> />
<img src={arrowBottom as string} className="w-6" /> <img src={arrowBottom} className="w-6" />
{loading ? ( {loading ? (
<Skeleton /> <Skeleton />

View File

@ -52,7 +52,7 @@ function PwiOptOut({thread}: {thread: AppBskyFeedDefs.ThreadViewPost}) {
<Link <Link
href={href} href={href}
className="transition-transform hover:scale-110 absolute top-4 right-4"> className="transition-transform hover:scale-110 absolute top-4 right-4">
<img src={logo as string} className="h-6" /> <img src={logo} className="h-6" />
</Link> </Link>
<div className="w-full py-12 gap-4 flex flex-col items-center"> <div className="w-full py-12 gap-4 flex flex-col items-center">
<p className="max-w-80 text-center w-full text-textLight"> <p className="max-w-80 text-center w-full text-textLight">
@ -75,7 +75,7 @@ function ErrorMessage() {
<Link <Link
href="https://bsky.app/" href="https://bsky.app/"
className="transition-transform hover:scale-110 absolute top-4 right-4"> className="transition-transform hover:scale-110 absolute top-4 right-4">
<img src={logo as string} className="h-6" /> <img src={logo} className="h-6" />
</Link> </Link>
<p className="my-16 text-center w-full text-textLight"> <p className="my-16 text-center w-full text-textLight">
Post not found, it may have been deleted. Post not found, it may have been deleted.