Skip to content

Commit 97f85ad

Browse files
authored
Merge pull request #920 from concrnt/develop
update
2 parents 2035d94 + 82f76e6 commit 97f85ad

2 files changed

Lines changed: 54 additions & 2 deletions

File tree

app/src/themes.ts

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,11 +384,63 @@ export const createConcurrentThemeFromObject = (base: any, options?: any): Concu
384384
return createTheme(theme) as ConcurrentTheme
385385
}
386386

387+
export function sanitizeTheme<T>(input: T): T {
388+
const forbiddenKeys = new Set(['href', 'xlinkHref', 'dangerouslySetInnerHTML'])
389+
const normalizeForSchemeCheck = (s: string) =>
390+
s.trim().replace(/[\u0000-\u001F\u007F-\u009F\u200B-\u200D\uFEFF]/g, '')
391+
392+
const isDangerousStringValue = (v: string): boolean => {
393+
const s = normalizeForSchemeCheck(v)
394+
if (/^(?:javascript|vbscript|file)\s*:/i.test(s)) return true
395+
if (/^data\s*:/i.test(s)) return true
396+
if (/[<>]/.test(s)) return true
397+
if (/linear-gradient\s*\(/i.test(s)) return true
398+
return false
399+
}
400+
401+
const seen = new WeakMap<object, any>()
402+
403+
const cloneAndStrip = (value: any): any => {
404+
if (value === null || typeof value === undefined) return value
405+
406+
if (typeof value === 'string') {
407+
if (isDangerousStringValue(value)) return undefined
408+
return value
409+
}
410+
411+
if (seen.has(value)) return seen.get(value)
412+
413+
if (typeof value !== 'object') return value
414+
415+
if (Array.isArray(value)) {
416+
const arr: any[] = []
417+
seen.set(value, arr)
418+
for (const item of value) arr.push(cloneAndStrip(item))
419+
return arr
420+
}
421+
422+
const out: Record<string, any> = {}
423+
seen.set(value, out)
424+
425+
for (const [k, v] of Object.entries(value)) {
426+
if (forbiddenKeys.has(k)) continue
427+
const sanitized = cloneAndStrip(v)
428+
if (sanitized === undefined) continue
429+
out[k] = sanitized
430+
}
431+
432+
return out
433+
}
434+
435+
return cloneAndStrip(input) as T
436+
}
437+
387438
export const loadConcurrentTheme = (
388439
name: string,
389440
customs: Record<string, DeepPartial<ConcurrentTheme>> = {},
390441
options?: { fontSize?: number }
391442
): ConcurrentTheme => {
392443
const base = customs[name] ?? Themes[name] ?? Themes.blue
393-
return createConcurrentThemeFromObject(base, options)
444+
const generated = createConcurrentThemeFromObject(base, options)
445+
return sanitizeTheme<ConcurrentTheme>(generated)
394446
}

client/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@concrnt/worldlib",
3-
"version": "0.1.4",
3+
"version": "0.2.0",
44
"main": "dist/cjs/index.js",
55
"module": "dist/esm/index.js",
66
"types": "dist/types/index.d.ts",

0 commit comments

Comments
 (0)