mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-25 23:35:43 +00:00
fix: hotfix export regressions
This commit is contained in:
@@ -157,6 +157,7 @@ let currentProjectPath: string | null = null
|
||||
let nativeScreenRecordingActive = false
|
||||
let currentVideoPath: string | null = null
|
||||
let currentRecordingSession: RecordingSessionData | null = null
|
||||
const approvedLocalReadPaths = new Set<string>()
|
||||
let nativeCaptureProcess: ChildProcessWithoutNullStreams | null = null
|
||||
let nativeCaptureOutputBuffer = ''
|
||||
let nativeCaptureTargetPath: string | null = null
|
||||
@@ -623,6 +624,44 @@ function normalizeVideoSourcePath(videoPath?: string | null): string | null {
|
||||
return trimmed
|
||||
}
|
||||
|
||||
function isPathInsideDirectory(candidatePath: string, directoryPath: string) {
|
||||
const normalizedDirectoryPath = normalizePath(directoryPath)
|
||||
return candidatePath === normalizedDirectoryPath || candidatePath.startsWith(`${normalizedDirectoryPath}${path.sep}`)
|
||||
}
|
||||
|
||||
function isAllowedLocalReadPath(candidatePath: string) {
|
||||
const allowedPrefixes = [
|
||||
RECORDINGS_DIR,
|
||||
USER_DATA_PATH,
|
||||
getAssetRootPath(),
|
||||
app.getPath('temp'),
|
||||
]
|
||||
|
||||
return allowedPrefixes.some((prefix) => isPathInsideDirectory(candidatePath, prefix))
|
||||
|| approvedLocalReadPaths.has(candidatePath)
|
||||
}
|
||||
|
||||
async function rememberApprovedLocalReadPath(filePath?: string | null) {
|
||||
const normalizedPath = normalizeVideoSourcePath(filePath)
|
||||
if (!normalizedPath) {
|
||||
return
|
||||
}
|
||||
|
||||
const resolvedPath = normalizePath(normalizedPath)
|
||||
approvedLocalReadPaths.add(resolvedPath)
|
||||
|
||||
try {
|
||||
approvedLocalReadPaths.add(await fs.realpath(resolvedPath))
|
||||
} catch {
|
||||
// Ignore missing files; the eventual read will surface the real error.
|
||||
}
|
||||
}
|
||||
|
||||
async function replaceApprovedSessionLocalReadPaths(filePaths: Array<string | null | undefined>) {
|
||||
approvedLocalReadPaths.clear()
|
||||
await Promise.all(filePaths.map((filePath) => rememberApprovedLocalReadPath(filePath)))
|
||||
}
|
||||
|
||||
async function resolveProjectMediaSources(project: unknown): Promise<
|
||||
| {
|
||||
success: true
|
||||
@@ -4887,7 +4926,12 @@ body{background:transparent;overflow:hidden;width:100vw;height:100vh}
|
||||
}
|
||||
|
||||
try {
|
||||
return { success: true, paths: await getCompanionAudioFallbackPaths(videoPath) }
|
||||
const paths = await getCompanionAudioFallbackPaths(videoPath)
|
||||
await Promise.all([
|
||||
rememberApprovedLocalReadPath(videoPath),
|
||||
...paths.map((fallbackPath) => rememberApprovedLocalReadPath(fallbackPath)),
|
||||
])
|
||||
return { success: true, paths }
|
||||
} catch (error) {
|
||||
console.error('Failed to resolve companion audio fallback paths:', error)
|
||||
return { success: false, paths: [], error: String(error) }
|
||||
@@ -5349,14 +5393,9 @@ body{background:transparent;overflow:hidden;width:100vw;height:100vh}
|
||||
try {
|
||||
// Security: only allow reads from known safe directories to prevent
|
||||
// malicious code from reading arbitrary files (SSH keys, credentials, etc.)
|
||||
const resolved = path.resolve(filePath)
|
||||
const allowedPrefixes = [
|
||||
RECORDINGS_DIR,
|
||||
USER_DATA_PATH,
|
||||
getAssetRootPath(),
|
||||
app.getPath('temp'),
|
||||
]
|
||||
if (!allowedPrefixes.some((prefix) => resolved.startsWith(path.resolve(prefix)))) {
|
||||
const resolved = normalizePath(filePath)
|
||||
const realResolved = await fs.realpath(resolved).catch(() => resolved)
|
||||
if (!isAllowedLocalReadPath(resolved) && !isAllowedLocalReadPath(realResolved)) {
|
||||
console.warn(`[read-local-file] Blocked read outside allowed directories: ${resolved}`)
|
||||
return { success: false, error: 'Access denied: path outside allowed directories' }
|
||||
}
|
||||
@@ -6151,6 +6190,10 @@ body{background:transparent;overflow:hidden;width:100vw;height:100vh}
|
||||
}
|
||||
|
||||
currentRecordingSession = resolvedSession
|
||||
await replaceApprovedSessionLocalReadPaths([
|
||||
resolvedSession.videoPath,
|
||||
resolvedSession.webcamPath,
|
||||
])
|
||||
|
||||
if (resolvedSession.webcamPath) {
|
||||
await persistRecordingSessionManifest(resolvedSession)
|
||||
@@ -6168,6 +6211,10 @@ body{background:transparent;overflow:hidden;width:100vw;height:100vh}
|
||||
webcamPath: normalizeVideoSourcePath(session.webcamPath ?? null),
|
||||
timeOffsetMs: normalizeRecordingTimeOffsetMs(session.timeOffsetMs),
|
||||
}
|
||||
await replaceApprovedSessionLocalReadPaths([
|
||||
currentRecordingSession.videoPath,
|
||||
currentRecordingSession.webcamPath,
|
||||
])
|
||||
currentProjectPath = null
|
||||
await persistRecordingSessionManifest(currentRecordingSession)
|
||||
return { success: true }
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "recordly",
|
||||
"version": "1.1.22",
|
||||
"version": "1.1.23",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "recordly",
|
||||
"version": "1.1.22",
|
||||
"version": "1.1.23",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"capturekit": "^1.0.13",
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
"url": "https://github.com/webadderall/Recordly/issues"
|
||||
},
|
||||
"private": true,
|
||||
"version": "1.1.22",
|
||||
"version": "1.1.23",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -12,7 +12,7 @@ import type {
|
||||
ZoomRegion,
|
||||
ZoomTransitionEasing,
|
||||
} from "@/components/video-editor/types";
|
||||
import { AudioProcessor } from "./audioEncoder";
|
||||
import { AudioProcessor, isAacAudioEncodingSupported } from "./audioEncoder";
|
||||
import {
|
||||
normalizeLightningRuntimePlatform,
|
||||
shouldPreferNativeAutoBackend,
|
||||
@@ -293,7 +293,9 @@ export class ModernVideoExporter {
|
||||
this.metadataLoadTimeMs = this.getNowMs() - stageStartedAt;
|
||||
const nativeAudioPlan = this.buildNativeAudioPlan(videoInfo);
|
||||
const shouldUseFfmpegAudioFallback =
|
||||
!useNativeEncoder && nativeAudioPlan.audioMode !== "none";
|
||||
!useNativeEncoder
|
||||
&& nativeAudioPlan.audioMode !== "none"
|
||||
&& !(await isAacAudioEncodingSupported());
|
||||
const effectiveDuration = this.streamingDecoder.getEffectiveDuration(
|
||||
this.config.trimRegions,
|
||||
this.config.speedRegions,
|
||||
|
||||
@@ -12,7 +12,7 @@ import type {
|
||||
ZoomTransitionEasing,
|
||||
ZoomRegion,
|
||||
} from "@/components/video-editor/types";
|
||||
import { AudioProcessor } from "./audioEncoder";
|
||||
import { AudioProcessor, isAacAudioEncodingSupported } from "./audioEncoder";
|
||||
import { FrameRenderer } from "./frameRenderer";
|
||||
import type { SupportedMp4EncoderPath } from "./mp4Support";
|
||||
import { captureCanvasFrameForNativeExport } from "./nativeFrameCapture";
|
||||
@@ -129,7 +129,10 @@ export class VideoExporter {
|
||||
let useNativeEncoder = shouldUseExperimentalNativeExport
|
||||
? await this.tryStartNativeVideoExport()
|
||||
: false;
|
||||
const shouldUseFfmpegAudioFallback = !useNativeEncoder && audioPlan.audioMode !== "none";
|
||||
const shouldUseFfmpegAudioFallback =
|
||||
!useNativeEncoder
|
||||
&& audioPlan.audioMode !== "none"
|
||||
&& !(await isAacAudioEncodingSupported());
|
||||
|
||||
if (!useNativeEncoder) {
|
||||
await this.initializeEncoder();
|
||||
|
||||
Reference in New Issue
Block a user