History

fix(web): reject unsupported composer image types at attach time (#6574)

mohammed shazeb committed 3 months ago

Commit 34a12bc1 parent 7afa1845 files · +39 −0Browse files

Unified · Split

5 files
  1. apps/mobile/src/features/sharing/incoming-share-model.ts +8 −0
  2. apps/mobile/src/lib/composerImages.ts +5 −0
  3. apps/web/src/components/chat/ChatComposer.tsx +5 −0
  4. packages/contracts/src/orchestration.test.ts +7 −0
  5. packages/contracts/src/orchestration.ts +14 −0
apps/mobile/src/features/sharing/incoming-share-model.ts+8−0
@@ -1,4 +1,5 @@
1import {1import {
2 isProviderSendTurnSupportedImageMimeType,
2 PROVIDER_SEND_TURN_MAX_ATTACHMENTS,3 PROVIDER_SEND_TURN_MAX_ATTACHMENTS,
3 PROVIDER_SEND_TURN_MAX_IMAGE_BYTES,4 PROVIDER_SEND_TURN_MAX_IMAGE_BYTES,
4} from "@t3tools/contracts";5} from "@t3tools/contracts";
@@ -162,6 +163,13 @@ export async function buildIncomingShareDraft(input: { · 157 unmodified lines
162 await releaseOwnedFiles(input.fileReader, [uri, payload.value]);163 await releaseOwnedFiles(input.fileReader, [uri, payload.value]);
163 continue;164 continue;
164 }165 }
166 if (!isProviderSendTurnSupportedImageMimeType(mimeType)) {
167 warnings.push(
168 `'${resolved?.originalName ?? fallbackName(uri, index, mimeType)}' is not a supported image type.`,
169 );
170 await releaseOwnedFiles(input.fileReader, [uri, payload.value]);
171 continue;
172 }
165 if (173 if (
166 resolved?.contentSize !== null &&174 resolved?.contentSize !== null &&
167 resolved?.contentSize !== undefined &&175 resolved?.contentSize !== undefined &&
apps/mobile/src/lib/composerImages.ts+5−0
@@ -1,4 +1,5 @@
1import {1import {
2 isProviderSendTurnSupportedImageMimeType,
2 PROVIDER_SEND_TURN_MAX_ATTACHMENTS,3 PROVIDER_SEND_TURN_MAX_ATTACHMENTS,
3 PROVIDER_SEND_TURN_MAX_IMAGE_BYTES,4 PROVIDER_SEND_TURN_MAX_IMAGE_BYTES,
4 type UploadChatImageAttachment,5 type UploadChatImageAttachment,
@@ -98,6 +99,10 @@ export async function pickComposerImages(input: { readonly existingCount: number · 93 unmodified lines
98 error = `Unsupported file type for '${asset.fileName ?? "image"}'.`;99 error = `Unsupported file type for '${asset.fileName ?? "image"}'.`;
99 continue;100 continue;
100 }101 }
102 if (!isProviderSendTurnSupportedImageMimeType(mimeType)) {
103 error = `'${asset.fileName ?? "image"}' is not a supported image type. Attach GIF, JPEG, PNG, or WebP images.`;
104 continue;
105 }
101 106
102 const base64 = asset.base64;107 const base64 = asset.base64;
103 if (!base64) {108 if (!base64) {
apps/web/src/components/chat/ChatComposer.tsx+5−0
@@ -12,6 +12,7 @@ import type { · 11 unmodified lines
12 ThreadId,12 ThreadId,
13} from "@t3tools/contracts";13} from "@t3tools/contracts";
14import {14import {
15 isProviderSendTurnSupportedImageMimeType,
15 ProviderDriverKind,16 ProviderDriverKind,
16 ProviderInstanceId,17 ProviderInstanceId,
17 PROVIDER_SEND_TURN_MAX_ATTACHMENTS,18 PROVIDER_SEND_TURN_MAX_ATTACHMENTS,
@@ -2305,6 +2306,10 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) · 2287 unmodified lines
2305 error = `Unsupported file type for '${file.name}'. Please attach image files only.`;2306 error = `Unsupported file type for '${file.name}'. Please attach image files only.`;
2306 continue;2307 continue;
2307 }2308 }
2309 if (!isProviderSendTurnSupportedImageMimeType(file.type)) {
2310 error = `'${file.name}' is not a supported image type. Attach GIF, JPEG, PNG, or WebP images.`;
2311 continue;
2312 }
2308 if (reservedCount >= PROVIDER_SEND_TURN_MAX_ATTACHMENTS) {2313 if (reservedCount >= PROVIDER_SEND_TURN_MAX_ATTACHMENTS) {
2309 error = `You can attach up to ${PROVIDER_SEND_TURN_MAX_ATTACHMENTS} images per message.`;2314 error = `You can attach up to ${PROVIDER_SEND_TURN_MAX_ATTACHMENTS} images per message.`;
2310 break;2315 break;
packages/contracts/src/orchestration.test.ts+7−0
@@ -23,6 +23,7 @@ import { · 22 unmodified lines
23 ThreadCreatedPayload,23 ThreadCreatedPayload,
24 ThreadTurnDiff,24 ThreadTurnDiff,
25 ThreadTurnStartRequestedPayload,25 ThreadTurnStartRequestedPayload,
26 isProviderSendTurnSupportedImageMimeType,
26} from "./orchestration.ts";27} from "./orchestration.ts";
27import { ProviderInstanceId } from "./providerInstance.ts";28import { ProviderInstanceId } from "./providerInstance.ts";
28 29
@@ -935,3 +936,9 @@ it.effect("project favicon overrides accept only supported image files", () => · 906 unmodified lines
935 assert.strictEqual(invalid._tag, "Failure");936 assert.strictEqual(invalid._tag, "Failure");
936 }),937 }),
937);938);
939
940it("isProviderSendTurnSupportedImageMimeType accepts raster formats and rejects svg", () => {
941 assert.strictEqual(isProviderSendTurnSupportedImageMimeType("image/png"), true);
942 assert.strictEqual(isProviderSendTurnSupportedImageMimeType("IMAGE/JPEG"), true);
943 assert.strictEqual(isProviderSendTurnSupportedImageMimeType("image/svg+xml"), false);
944});
packages/contracts/src/orchestration.ts+14−0
@@ -144,6 +144,20 @@ export type ProviderUserInputAnswers = typeof ProviderUserInputAnswers.Type; · 143 unmodified lines
144export const PROVIDER_SEND_TURN_MAX_INPUT_CHARS = 120_000;144export const PROVIDER_SEND_TURN_MAX_INPUT_CHARS = 120_000;
145export const PROVIDER_SEND_TURN_MAX_ATTACHMENTS = 8;145export const PROVIDER_SEND_TURN_MAX_ATTACHMENTS = 8;
146export const PROVIDER_SEND_TURN_MAX_IMAGE_BYTES = 10 * 1024 * 1024;146export const PROVIDER_SEND_TURN_MAX_IMAGE_BYTES = 10 * 1024 * 1024;
147export const PROVIDER_SEND_TURN_SUPPORTED_IMAGE_MIME_TYPES = [
148 "image/gif",
149 "image/jpeg",
150 "image/png",
151 "image/webp",
152] as const;
153const PROVIDER_SEND_TURN_SUPPORTED_IMAGE_MIME_TYPE_SET = new Set<string>(
154 PROVIDER_SEND_TURN_SUPPORTED_IMAGE_MIME_TYPES,
155);
156
157/** Whether a pasted or picked image mime type can be sent on a provider turn. */
158export function isProviderSendTurnSupportedImageMimeType(mimeType: string): boolean {
159 return PROVIDER_SEND_TURN_SUPPORTED_IMAGE_MIME_TYPE_SET.has(mimeType.toLowerCase());
160}
147const PROVIDER_SEND_TURN_MAX_IMAGE_DATA_URL_CHARS = 14_000_000;161const PROVIDER_SEND_TURN_MAX_IMAGE_DATA_URL_CHARS = 14_000_000;
148const CHAT_ATTACHMENT_ID_MAX_CHARS = 128;162const CHAT_ATTACHMENT_ID_MAX_CHARS = 128;
149// Correlation id is command id by design in this model.163// Correlation id is command id by design in this model.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t