summaryrefslogtreecommitdiff
path: root/packages/backend/src/server/web/UrlPreviewService.ts
diff options
context:
space:
mode:
authorHazelnoot <acomputerdog@gmail.com>2025-06-05 08:00:32 +0000
committerHazelnoot <acomputerdog@gmail.com>2025-06-05 08:00:32 +0000
commitf88253b95f5ed16f23a23796f76ba4e8ea5f99b3 (patch)
treebec1ce21bd1b2de423b110a74f4c0dd4199583d4 /packages/backend/src/server/web/UrlPreviewService.ts
parentmerge: Add option to keep CWs with "RE:" prefix (!1093) (diff)
parentsupport link attributions in SkUrlPreviewGroup (diff)
downloadsharkey-f88253b95f5ed16f23a23796f76ba4e8ea5f99b3.tar.gz
sharkey-f88253b95f5ed16f23a23796f76ba4e8ea5f99b3.tar.bz2
sharkey-f88253b95f5ed16f23a23796f76ba4e8ea5f99b3.zip
merge: Report admin UX improvements (!1060)
View MR for information: https://activitypub.software/TransFem-org/Sharkey/-/merge_requests/1060 Approved-by: Marie <github@yuugi.dev> Approved-by: dakkar <dakkar@thenautilus.net>
Diffstat (limited to 'packages/backend/src/server/web/UrlPreviewService.ts')
-rw-r--r--packages/backend/src/server/web/UrlPreviewService.ts55
1 files changed, 45 insertions, 10 deletions
diff --git a/packages/backend/src/server/web/UrlPreviewService.ts b/packages/backend/src/server/web/UrlPreviewService.ts
index 2a300782c6..78b2204fbb 100644
--- a/packages/backend/src/server/web/UrlPreviewService.ts
+++ b/packages/backend/src/server/web/UrlPreviewService.ts
@@ -123,26 +123,45 @@ export class UrlPreviewService {
request: FastifyRequest<PreviewRoute>,
reply: FastifyReply,
): Promise<void> {
+ if (!this.meta.urlPreviewEnabled) {
+ return reply.code(403).send({
+ error: {
+ message: 'URL preview is disabled',
+ code: 'URL_PREVIEW_DISABLED',
+ id: '58b36e13-d2f5-0323-b0c6-76aa9dabefb8',
+ },
+ });
+ }
+
const url = request.query.url;
if (typeof url !== 'string' || !URL.canParse(url)) {
reply.code(400);
return;
}
+ // Enforce HTTP(S) for input URLs
+ const urlScheme = this.utilityService.getUrlScheme(url);
+ if (urlScheme !== 'http:' && urlScheme !== 'https:') {
+ reply.code(400);
+ return;
+ }
+
const lang = request.query.lang;
if (Array.isArray(lang)) {
reply.code(400);
return;
}
- if (!this.meta.urlPreviewEnabled) {
- return reply.code(403).send({
- error: {
- message: 'URL preview is disabled',
- code: 'URL_PREVIEW_DISABLED',
- id: '58b36e13-d2f5-0323-b0c6-76aa9dabefb8',
- },
- });
+ // Strip out hash (anchor)
+ const urlObj = new URL(url);
+ if (urlObj.hash) {
+ urlObj.hash = '';
+ const params = new URLSearchParams({ url: urlObj.href });
+ if (lang) params.set('lang', lang);
+ const newUrl = `/url?${params.toString()}`;
+
+ reply.redirect(newUrl, 301);
+ return;
}
// Check rate limit
@@ -151,7 +170,7 @@ export class UrlPreviewService {
return;
}
- if (this.utilityService.isBlockedHost(this.meta.blockedHosts, new URL(url).host)) {
+ if (this.utilityService.isBlockedHost(this.meta.blockedHosts, urlObj.host)) {
return reply.code(403).send({
error: {
message: 'URL is blocked',
@@ -166,7 +185,7 @@ export class UrlPreviewService {
return;
}
- const cacheKey = `${url}@${lang}@${cacheFormatVersion}`;
+ const cacheKey = getCacheKey(url, lang);
if (await this.sendCachedPreview(cacheKey, reply, fetch)) {
return;
}
@@ -217,6 +236,18 @@ export class UrlPreviewService {
// Await this to avoid hammering redis when a bunch of URLs are fetched at once
await this.previewCache.set(cacheKey, summary);
+ // Also cache the response URL in case of redirects
+ if (summary.url !== url) {
+ const responseCacheKey = getCacheKey(summary.url, lang);
+ await this.previewCache.set(responseCacheKey, summary);
+ }
+
+ // Also cache the ActivityPub URL, if different from the others
+ if (summary.activityPub && summary.activityPub !== summary.url) {
+ const apCacheKey = getCacheKey(summary.activityPub, lang);
+ await this.previewCache.set(apCacheKey, summary);
+ }
+
// Cache 1 day (matching redis), but only once we finalize the result
if (!summary.activityPub || summary.haveNoteLocally) {
reply.header('Cache-Control', 'public, max-age=86400');
@@ -533,3 +564,7 @@ export class UrlPreviewService {
return true;
}
}
+
+function getCacheKey(url: string, lang = 'none') {
+ return `${url}@${lang}@${cacheFormatVersion}`;
+}