fix: avoid shell interpolation in image conversion commands
This commit is contained in:
parent
814380b85c
commit
479bbb240f
60
src/tools/look-at/image-converter.test.ts
Normal file
60
src/tools/look-at/image-converter.test.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { describe, expect, test, mock, beforeEach } from "bun:test"
|
||||||
|
import { existsSync, mkdtempSync, writeFileSync, unlinkSync, rmSync } from "node:fs"
|
||||||
|
import { tmpdir } from "node:os"
|
||||||
|
import { join } from "node:path"
|
||||||
|
|
||||||
|
const originalChildProcess = await import("node:child_process")
|
||||||
|
|
||||||
|
const execFileSyncMock = mock((_command: string, _args: string[]) => "")
|
||||||
|
const execSyncMock = mock(() => {
|
||||||
|
throw new Error("execSync should not be called")
|
||||||
|
})
|
||||||
|
|
||||||
|
mock.module("node:child_process", () => ({
|
||||||
|
...originalChildProcess,
|
||||||
|
execFileSync: execFileSyncMock,
|
||||||
|
execSync: execSyncMock,
|
||||||
|
}))
|
||||||
|
|
||||||
|
const { convertImageToJpeg } = await import("./image-converter")
|
||||||
|
|
||||||
|
describe("image-converter command execution safety", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
execFileSyncMock.mockReset()
|
||||||
|
execSyncMock.mockReset()
|
||||||
|
})
|
||||||
|
|
||||||
|
test("uses execFileSync with argument arrays for conversion commands", () => {
|
||||||
|
const testDir = mkdtempSync(join(tmpdir(), "img-converter-test-"))
|
||||||
|
const inputPath = join(testDir, "evil$(touch_pwn).heic")
|
||||||
|
writeFileSync(inputPath, "fake-heic-data")
|
||||||
|
|
||||||
|
execFileSyncMock.mockImplementation((command: string, args: string[]) => {
|
||||||
|
if (command === "sips") {
|
||||||
|
const outIndex = args.indexOf("--out")
|
||||||
|
const outputPath = outIndex >= 0 ? args[outIndex + 1] : undefined
|
||||||
|
if (outputPath) writeFileSync(outputPath, "jpeg")
|
||||||
|
} else if (command === "convert") {
|
||||||
|
writeFileSync(args[1], "jpeg")
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
})
|
||||||
|
|
||||||
|
const outputPath = convertImageToJpeg(inputPath, "image/heic")
|
||||||
|
|
||||||
|
expect(execSyncMock).not.toHaveBeenCalled()
|
||||||
|
expect(execFileSyncMock).toHaveBeenCalled()
|
||||||
|
|
||||||
|
const [firstCommand, firstArgs] = execFileSyncMock.mock.calls[0] as [string, string[]]
|
||||||
|
expect(typeof firstCommand).toBe("string")
|
||||||
|
expect(Array.isArray(firstArgs)).toBe(true)
|
||||||
|
expect(firstArgs).toContain(inputPath)
|
||||||
|
expect(firstArgs.join(" ")).not.toContain(`\"${inputPath}\"`)
|
||||||
|
|
||||||
|
expect(existsSync(outputPath)).toBe(true)
|
||||||
|
|
||||||
|
if (existsSync(outputPath)) unlinkSync(outputPath)
|
||||||
|
if (existsSync(inputPath)) unlinkSync(inputPath)
|
||||||
|
rmSync(testDir, { recursive: true, force: true })
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { execSync } from "node:child_process"
|
import { execFileSync } from "node:child_process"
|
||||||
import { existsSync, mkdtempSync, unlinkSync, writeFileSync, readFileSync } from "node:fs"
|
import { existsSync, mkdtempSync, unlinkSync, writeFileSync, readFileSync } from "node:fs"
|
||||||
import { tmpdir } from "node:os"
|
import { tmpdir } from "node:os"
|
||||||
import { join } from "node:path"
|
import { join } from "node:path"
|
||||||
@ -57,7 +57,7 @@ export function convertImageToJpeg(inputPath: string, mimeType: string): string
|
|||||||
try {
|
try {
|
||||||
if (process.platform === "darwin") {
|
if (process.platform === "darwin") {
|
||||||
try {
|
try {
|
||||||
execSync(`sips -s format jpeg "${inputPath}" --out "${outputPath}"`, {
|
execFileSync("sips", ["-s", "format", "jpeg", inputPath, "--out", outputPath], {
|
||||||
stdio: "pipe",
|
stdio: "pipe",
|
||||||
encoding: "utf-8",
|
encoding: "utf-8",
|
||||||
})
|
})
|
||||||
@ -72,7 +72,7 @@ export function convertImageToJpeg(inputPath: string, mimeType: string): string
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
execSync(`convert "${inputPath}" "${outputPath}"`, {
|
execFileSync("convert", [inputPath, outputPath], {
|
||||||
stdio: "pipe",
|
stdio: "pipe",
|
||||||
encoding: "utf-8",
|
encoding: "utf-8",
|
||||||
})
|
})
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user