Files
cinny/src/app/hooks/useStrippedFilePicker.ts
T
Lotus CIandClaude Opus 5.5 4486f02bc6
CI / Build & Quality Checks (pull_request) Successful in 3m25s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 8s
CI / Playwright smoke (e2e) (pull_request) Successful in 15m42s
fix(privacy): "Remove Photo Metadata" also covers emoji/sticker packs and badges (#332)
Custom emoji and sticker images, pack avatars and power-level badge
images were uploaded with their EXIF intact (GPS location, timestamp),
although they are published to every member of the room or space. Route
those three pickers through a new useStrippedFilePicker, which applies
the same stripImageMetadata as attachments and avatars.

Fixes #332

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-18 00:09:14 -04:00

37 lines
1.4 KiB
TypeScript

import { useCallback } from 'react';
import { useFilePicker } from './useFilePicker';
import { useSetting } from '../state/hooks/settings';
import { settingsAtom } from '../state/settings';
import { stripImageMetadata } from '../utils/stripImageMetadata';
/**
* [Gitea #332] `useFilePicker` for images that get published (emoji / sticker
* packs, pack avatars, power-level badges): applies "Remove Photo Metadata"
* like message attachments and avatars, so a phone photo's GPS location and
* timestamp don't go to every member of the room or space.
*/
export const useStrippedFilePicker = <M extends boolean | undefined = undefined>(
onSelect: (file: M extends true ? File[] : File) => void,
multiple?: M,
) => {
const [strip] = useSetting(settingsAtom, 'stripImageMetadata');
const handle = useCallback(
(picked: File | File[]) => {
if (!strip) {
onSelect(picked as M extends true ? File[] : File);
return;
}
const clean = (f: File) => stripImageMetadata(f).then((r) => r.file);
if (Array.isArray(picked)) {
Promise.all(picked.map(clean)).then((files) =>
onSelect(files as M extends true ? File[] : File),
);
} else {
clean(picked).then((file) => onSelect(file as M extends true ? File[] : File));
}
},
[strip, onSelect],
);
return useFilePicker(handle as (file: M extends true ? File[] : File) => void, multiple);
};