From d9ba2b0f3597a211db2124d3e869410863dc4303 Mon Sep 17 00:00:00 2001 From: claude-bot Date: Fri, 5 Jun 2026 15:58:22 +0900 Subject: [PATCH] installer-rp: decode data: URL images instead of crashing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 사진 URL 에 data: URI 가 들어오면 http/https 만 처리하는 다운로더가 'Protocol "data:" not supported' 로 설치 전체를 중단시키던 문제 수정. data: URL 은 이미지 바이트를 직접 품고 있으므로 base64/percent-encoding 을 디코드해 Buffer 로 바로 반환한다. 잘못된 형식은 명확한 메시지로 거절. --- locales/installer-rp/ko-kr.json | 1 + src/installer-rp/images.ts | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/locales/installer-rp/ko-kr.json b/locales/installer-rp/ko-kr.json index bff65a8..ccf8a24 100644 --- a/locales/installer-rp/ko-kr.json +++ b/locales/installer-rp/ko-kr.json @@ -137,6 +137,7 @@ "ytdlpNoStderr": "(stderr 없음)", "ytdlpMissingOutput": "예상 출력파일이 없음: {{path}}", "imageMetaUnknown": "이미지 크기를 읽지 못함", + "imageDataUrlInvalid": "data: URL 형식이 올바르지 않아 이미지를 디코드하지 못했습니다.", "ytdlpVerifyFailed": "yt-dlp.exe 다운로드는 됐지만 실행 검증에 실패했습니다.", "ytdlpInstallFailed": "yt-dlp.exe 자동 설치 실패: {{message}}", "ffmpegNotInZip": "zip 내부에서 ffmpeg.exe 를 찾을 수 없습니다.", diff --git a/src/installer-rp/images.ts b/src/installer-rp/images.ts index a7d23a4..8b59c43 100644 --- a/src/installer-rp/images.ts +++ b/src/installer-rp/images.ts @@ -63,13 +63,36 @@ function fetchBuffer(url: string, redirects = 0): Promise { }) } +/** + * data: URL 이면 그 안에 들어 있는 바이트를 바로 Buffer 로 디코드한다. + * data: URL 은 이미지 데이터 자체를 품고 있어 네트워크 요청이 필요 없으며, + * http/https 만 다루는 fetchBuffer 에 넘기면 `Protocol "data:" not supported` + * 로 터지므로 여기서 가로챈다. data: URL 이 아니면 null. + */ +function decodeDataUrl(url: string): Buffer | null { + if (!/^data:/i.test(url)) return null + const comma = url.indexOf(',') + if (comma < 0) throw new Error(t('errors.imageDataUrlInvalid')) + const meta = url.slice(5, comma) + const data = url.slice(comma + 1) + // `;base64` 가 있으면 base64, 없으면 percent-encoding 된 텍스트. + const buf = /;base64/i.test(meta) + ? Buffer.from(data, 'base64') + : Buffer.from(decodeURIComponent(data), 'utf8') + if (buf.length === 0) throw new Error(t('errors.imageDataUrlInvalid')) + return buf +} + /** * 이미지 URL 을 다운로드해 Buffer 로 돌려준다. + * - data: URL 이면 내장 바이트를 바로 디코드 (네트워크 없음). * - 유튜브 영상 URL 이면 `i.ytimg.com/vi//maxresdefault.jpg` 1차 → * 실패하면 `hqdefault.jpg` 로 폴백. * - 그 외 URL 은 HTTP GET 으로 그대로 받음. */ export async function downloadImage(rawUrl: string): Promise { + const dataBuf = decodeDataUrl(rawUrl) + if (dataBuf) return dataBuf const ytId = ytIdFromUrl(rawUrl) if (ytId) { try {