[feat] new css parsing
This commit is contained in:
@@ -42,34 +42,17 @@ DOMPurify.addHook("uponSanitizeElement", (node: HTMLElement, data) => {
|
|||||||
return node.parentNode.removeChild(node);
|
return node.parentNode.removeChild(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(data.tagName === 'style'){
|
|
||||||
try {
|
|
||||||
const ast = css.parse(node.innerHTML)
|
|
||||||
const rules = ast?.stylesheet?.rules
|
|
||||||
if(rules){
|
|
||||||
for(const rule of rules){
|
|
||||||
if(rule.selectors){
|
|
||||||
for(let i=0;i<rule.selectors.length;i++){
|
|
||||||
rule.selectors[i] = ".chattext " + rule.selectors[i]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
node.innerHTML = css.stringify(ast)
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
const ErrorNode = document.createElement("div")
|
|
||||||
ErrorNode.innerText = `CSS ERROR: ${error}`
|
|
||||||
node.parentNode.appendChild(ErrorNode)
|
|
||||||
return node.parentNode.removeChild(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
DOMPurify.addHook("uponSanitizeAttribute", (node, data) => {
|
DOMPurify.addHook("uponSanitizeAttribute", (node, data) => {
|
||||||
if(data.attrName === 'style'){
|
if(data.attrName === 'style'){
|
||||||
data.attrValue = data.attrValue.replace(/(absolute)|(z-index)|(fixed)/g, '')
|
data.attrValue = data.attrValue.replace(/(absolute)|(z-index)|(fixed)/g, '')
|
||||||
}
|
}
|
||||||
|
if(data.attrName === 'class'){
|
||||||
|
data.attrValue = data.attrValue.split(' ').map((v) => {
|
||||||
|
return "x-risu-" + v
|
||||||
|
}).join(' ')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
async function parseAdditionalAssets(data:string, char:character, mode:'normal'|'back'){
|
async function parseAdditionalAssets(data:string, char:character, mode:'normal'|'back'){
|
||||||
@@ -102,17 +85,57 @@ export async function ParseMarkdown(data:string, char:(character | groupChat) =
|
|||||||
if(firstParsed !== data && char && char.type !== 'group'){
|
if(firstParsed !== data && char && char.type !== 'group'){
|
||||||
data = await parseAdditionalAssets(data, char, mode)
|
data = await parseAdditionalAssets(data, char, mode)
|
||||||
}
|
}
|
||||||
return DOMPurify.sanitize(mconverted.parse(data), {
|
return decodeStyle(DOMPurify.sanitize(mconverted.parse(encodeStyle(data)), {
|
||||||
ADD_TAGS: ["iframe"],
|
ADD_TAGS: ["iframe", "style", "risu-style"],
|
||||||
ADD_ATTR: ["allow", "allowfullscreen", "frameborder", "scrolling"],
|
ADD_ATTR: ["allow", "allowfullscreen", "frameborder", "scrolling"],
|
||||||
FORBID_ATTR: ["href"]
|
FORBID_ATTR: ["href"]
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseMarkdownSafe(data:string) {
|
export function parseMarkdownSafe(data:string) {
|
||||||
return DOMPurify.sanitize(safeConvertor.makeHtml(data), {
|
return DOMPurify.sanitize(safeConvertor.makeHtml(data), {
|
||||||
FORBID_TAGS: ["a", "style"],
|
FORBID_TAGS: ["a", "style"],
|
||||||
FORBID_ATTR: ["style", "href"]
|
FORBID_ATTR: ["style", "href", "class"]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const styleRegex = /\<style\>(.+?)\<\/style\>/gms
|
||||||
|
function encodeStyle(txt:string){
|
||||||
|
return txt.replaceAll(styleRegex, (f, c1) => {
|
||||||
|
return "<risu-style>" + Buffer.from(c1).toString('hex') + "</risu-style>"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const styleDecodeRegex = /\<risu-style\>(.+?)\<\/risu-style\>/gms
|
||||||
|
|
||||||
|
function decodeStyle(text:string){
|
||||||
|
|
||||||
|
return text.replaceAll(styleDecodeRegex, (full, txt:string) => {
|
||||||
|
try {
|
||||||
|
const ast = css.parse(Buffer.from(txt, 'hex').toString('utf-8'))
|
||||||
|
const rules = ast?.stylesheet?.rules
|
||||||
|
if(rules){
|
||||||
|
for(const rule of rules){
|
||||||
|
if(rule.selectors){
|
||||||
|
for(let i=0;i<rule.selectors.length;i++){
|
||||||
|
let slt:string = rule.selectors[i]
|
||||||
|
let selectors = slt.split(' ').map((v) => {
|
||||||
|
if(v.startsWith('.')){
|
||||||
|
return ".x-risu-" + v.substring(1)
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}).join(' ')
|
||||||
|
|
||||||
|
rule.selectors[i] = ".chattext " + selectors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return `<style>${css.stringify(ast)}</style>`
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
return `CSS ERROR: ${error}`;
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -363,6 +363,7 @@ export interface character{
|
|||||||
replaceGlobalNote:string
|
replaceGlobalNote:string
|
||||||
backgroundHTML?:string
|
backgroundHTML?:string
|
||||||
reloadKeys?:number
|
reloadKeys?:number
|
||||||
|
backgroundCSS?:string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -401,6 +402,7 @@ export interface groupChat{
|
|||||||
orderByOrder?:boolean
|
orderByOrder?:boolean
|
||||||
backgroundHTML?:string,
|
backgroundHTML?:string,
|
||||||
reloadKeys?:number
|
reloadKeys?:number
|
||||||
|
backgroundCSS?:string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface botPreset{
|
export interface botPreset{
|
||||||
|
|||||||
Reference in New Issue
Block a user