fix(web): keep share token on shared-memo attachment thumbnails (#6155)

This commit is contained in:
Wally 2026-08-06 19:21:53 +03:00 committed by GitHub
parent ec689c3a03
commit 3f567fda45
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 81 additions and 0 deletions

View file

@ -8,11 +8,34 @@ export const getAttachmentUrl = (attachment: Attachment) => {
return `${window.location.origin}/file/${attachment.name}/${attachment.filename}`;
};
// Appends a flag param to share-mode links so anonymous viewers stay authorized; S3 presigned URLs are left untouched.
const withShareTokenParam = (externalLink: string | undefined, key: string): string | undefined => {
if (!externalLink) {
return undefined;
}
const url = new URL(externalLink, window.location.origin);
if (!url.searchParams.has("share_token")) {
return undefined;
}
url.searchParams.set(key, "true");
return url.toString();
};
export const getAttachmentThumbnailUrl = (attachment: Attachment) => {
const shareUrl = withShareTokenParam(attachment.externalLink, "thumbnail");
if (shareUrl) {
return shareUrl;
}
return `${window.location.origin}/file/${attachment.name}/${attachment.filename}?thumbnail=true`;
};
export const getAttachmentMotionClipUrl = (attachment: Attachment) => {
const shareUrl = withShareTokenParam(attachment.externalLink, "motion");
if (shareUrl) {
return shareUrl;
}
return `${window.location.origin}/file/${attachment.name}/${attachment.filename}?motion=true`;
};

View file

@ -0,0 +1,58 @@
import { describe, expect, it } from "vitest";
import type { Attachment } from "@/types/proto/api/v1/attachment_service_pb";
import { getAttachmentMotionClipUrl, getAttachmentThumbnailUrl, getAttachmentUrl } from "@/utils/attachment";
const origin = window.location.origin;
const baseAttachment = {
name: "attachments/test-uid",
filename: "photo.png",
type: "image/png",
} as Attachment;
// Regression tests for #6128: share-mode thumbnails/motion clips must keep the share token on externalLink.
describe("attachment URL builders in share mode", () => {
it("appends thumbnail=true to an externalLink that carries a share token", () => {
const attachment = {
...baseAttachment,
externalLink: `${origin}/file/attachments/test-uid/photo.png?share_token=abc123`,
} as Attachment;
const url = new URL(getAttachmentThumbnailUrl(attachment));
expect(url.searchParams.get("thumbnail")).toBe("true");
expect(url.searchParams.get("share_token")).toBe("abc123");
});
it("appends motion=true to an externalLink that carries a share token", () => {
const attachment = {
...baseAttachment,
externalLink: `${origin}/file/attachments/test-uid/photo.png?share_token=abc123`,
} as Attachment;
const url = new URL(getAttachmentMotionClipUrl(attachment));
expect(url.searchParams.get("motion")).toBe("true");
expect(url.searchParams.get("share_token")).toBe("abc123");
});
it("keeps the server thumbnail URL when externalLink has no share token (e.g. S3 presigned)", () => {
const attachment = {
...baseAttachment,
externalLink: "https://s3.example.com/bucket/photo.png?X-Amz-Signature=xyz",
} as Attachment;
expect(getAttachmentThumbnailUrl(attachment)).toBe(`${origin}/file/attachments/test-uid/photo.png?thumbnail=true`);
});
it("keeps the server thumbnail URL when no externalLink is set", () => {
expect(getAttachmentThumbnailUrl(baseAttachment)).toBe(`${origin}/file/attachments/test-uid/photo.png?thumbnail=true`);
});
it("leaves getAttachmentUrl returning the externalLink verbatim", () => {
const attachment = {
...baseAttachment,
externalLink: `${origin}/file/attachments/test-uid/photo.png?share_token=abc123`,
} as Attachment;
expect(getAttachmentUrl(attachment)).toBe(attachment.externalLink);
});
});