MCPcopy Create free account
hub / github.com/ZenNotes/zennotes / resolveThemeAssetPath

Function resolveThemeAssetPath

apps/desktop/src/main/custom-themes.ts:349–378  ·  view source on GitHub ↗
(slug: string, relPath: string)

Source from the content-addressed store, hash-verified

347 * the folder (traversal, symlink, absolute path) or isn't a file.
348 */
349export function resolveThemeAssetPath(slug: string, relPath: string): string | null {
350 if (!isSafeSlug(slug) || typeof relPath !== 'string' || !relPath) return null
351 let decoded: string
352 try {
353 decoded = decodeURIComponent(relPath)
354 } catch {
355 return null
356 }
357 decoded = decoded.replace(/\\/g, '/').replace(/^\/+/, '')
358 if (!decoded || decoded.includes('\0') || path.isAbsolute(decoded)) return null
359 const themeDir = path.join(getCustomThemesDir(), slug)
360 const abs = path.resolve(themeDir, decoded)
361 const root = path.resolve(themeDir)
362 if (abs !== root && !abs.startsWith(root + path.sep)) return null
363 let real: string
364 let realRoot: string
365 try {
366 real = fsSync.realpathSync(abs)
367 realRoot = fsSync.realpathSync(themeDir)
368 } catch {
369 return null
370 }
371 if (real !== realRoot && !real.startsWith(realRoot + path.sep)) return null
372 try {
373 if (!fsSync.statSync(real).isFile()) return null
374 } catch {
375 return null
376 }
377 return real
378}
379
380let watcher: ReturnType<typeof chokidar.watch> | null = null
381

Callers 2

index.tsFile · 0.90

Calls 2

isSafeSlugFunction · 0.85
getCustomThemesDirFunction · 0.85

Tested by

no test coverage detected