mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
fix(workflow-renderer): validate dropbox host in note embed renderer (#5288)
* fix(workflow-renderer): validate dropbox host in note embed renderer
Replace the bare url.includes('dropbox.com') check with a parsed-hostname
match so attacker-controlled hosts (dropbox.com.evil.com, evil.com/?dropbox.com)
no longer get treated as direct dropbox videos. Resolves CodeQL
js/incomplete-url-substring-sanitization (#430).
* fix(workflow-renderer): rewrite dropbox embed via parsed URL, tolerate scheme-less links
Derive the direct video URL from the parsed URL object (rewrite hostname to
dl.dropboxusercontent.com for any dropbox.com/*.dropbox.com host) instead of a
www-only string replace, and accept scheme-less links. Fixes broken embeds for
m.dropbox.com / bare-host links flagged in review.
This commit is contained in:
@@ -17,6 +17,34 @@ function getTwitchParent(): string {
|
||||
return typeof window !== 'undefined' ? window.location.hostname : 'localhost'
|
||||
}
|
||||
|
||||
/** Parse a URL, tolerating scheme-less inputs (https is assumed). Returns null if unparseable. */
|
||||
function parseUrl(url: string): URL | null {
|
||||
for (const candidate of [url, `https://${url}`]) {
|
||||
try {
|
||||
return new URL(candidate)
|
||||
} catch {}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a Dropbox share link to a direct, embeddable video URL. Accepts only URLs
|
||||
* whose host is `dropbox.com` or a `*.dropbox.com` subdomain (so attacker-controlled
|
||||
* hosts like `dropbox.com.evil.com` are rejected), then rewrites the host to
|
||||
* `dl.dropboxusercontent.com` so the file streams as media. Returns null for any
|
||||
* non-Dropbox host or non-video path.
|
||||
*/
|
||||
function getDropboxDirectVideoUrl(url: string): string | null {
|
||||
const parsed = parseUrl(url)
|
||||
if (!parsed) return null
|
||||
const host = parsed.hostname.toLowerCase()
|
||||
if (host !== 'dropbox.com' && !host.endsWith('.dropbox.com')) return null
|
||||
if (!/\.(mp4|mov|webm)$/i.test(parsed.pathname)) return null
|
||||
parsed.hostname = 'dl.dropboxusercontent.com'
|
||||
parsed.searchParams.delete('dl')
|
||||
return parsed.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get embed info for supported media platforms
|
||||
*/
|
||||
@@ -250,11 +278,9 @@ function getEmbedInfo(url: string): EmbedInfo | null {
|
||||
return { url: `https://drive.google.com/file/d/${googleDriveMatch[1]}/preview`, type: 'iframe' }
|
||||
}
|
||||
|
||||
if (url.includes('dropbox.com') && /\.(mp4|mov|webm)/.test(url)) {
|
||||
const directUrl = url
|
||||
.replace('www.dropbox.com', 'dl.dropboxusercontent.com')
|
||||
.replace('?dl=0', '')
|
||||
return { url: directUrl, type: 'video' }
|
||||
const dropboxDirectVideoUrl = getDropboxDirectVideoUrl(url)
|
||||
if (dropboxDirectVideoUrl) {
|
||||
return { url: dropboxDirectVideoUrl, type: 'video' }
|
||||
}
|
||||
|
||||
const tenorMatch = url.match(/tenor\.com\/view\/[^/]+-(\d+)/)
|
||||
|
||||
Reference in New Issue
Block a user