Reorganize kcSanitarize
This commit is contained in:
288
src/lib/kcSanitize/KcSanitizerPolicy.ts
Normal file
288
src/lib/kcSanitize/KcSanitizerPolicy.ts
Normal file
@ -0,0 +1,288 @@
|
||||
import { HtmlPolicyBuilder } from "keycloakify/tools/kcSanitize/HtmlPolicyBuilder";
|
||||
|
||||
//implementation of java Sanitizer policy ( KeycloakSanitizerPolicy )
|
||||
// All regex directly copied from the keycloak source but some of them changed slightly to work with typescript(ONSITE_URL and OFFSITE_URL)
|
||||
// Also replaced ?i with "i" tag as second parameter of RegExp
|
||||
//https://github.com/keycloak/keycloak/blob/8ce8a4ba089eef25a0e01f58e09890399477b9ef/services/src/main/java/org/keycloak/theme/KeycloakSanitizerPolicy.java#L29
|
||||
export class KcSanitizerPolicy {
|
||||
public static readonly COLOR_NAME = new RegExp(
|
||||
"(?:aqua|black|blue|fuchsia|gray|grey|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow)"
|
||||
);
|
||||
|
||||
public static readonly COLOR_CODE = new RegExp(
|
||||
"(?:#(?:[0-9a-fA-F]{3}(?:[0-9a-fA-F]{3})?))"
|
||||
);
|
||||
|
||||
public static readonly NUMBER_OR_PERCENT = new RegExp("[0-9]+%?");
|
||||
|
||||
public static readonly PARAGRAPH = new RegExp(
|
||||
"(?:[\\p{L}\\p{N},'\\.\\s\\-_\\(\\)]|&[0-9]{2};)*",
|
||||
"u" // Unicode flag for \p{L} and \p{N} in the pattern
|
||||
);
|
||||
|
||||
public static readonly HTML_ID = new RegExp("[a-zA-Z0-9\\:\\-_\\.]+");
|
||||
|
||||
public static readonly HTML_TITLE = new RegExp(
|
||||
"[\\p{L}\\p{N}\\s\\-_',:\\[\\]!\\./\\\\\\(\\)&]*",
|
||||
"u" // Unicode flag for \p{L} and \p{N} in the pattern
|
||||
);
|
||||
|
||||
public static readonly HTML_CLASS = new RegExp("[a-zA-Z0-9\\s,\\-_]+");
|
||||
|
||||
public static readonly ONSITE_URL = new RegExp(
|
||||
"(?:[\\p{L}\\p{N}.#@\\$%+&;\\-_~,?=/!]+|#(\\w)+)",
|
||||
"u" // Unicode flag for \p{L} and \p{N} in the pattern
|
||||
);
|
||||
|
||||
public static readonly OFFSITE_URL = new RegExp(
|
||||
"\\s*(?:(?:ht|f)tps?://|mailto:)[\\p{L}\\p{N}]+" +
|
||||
"[\\p{L}\\p{N}\\p{Zs}.#@\\$%+&;:\\-_~,?=/!()]*\\s*",
|
||||
"u" // Unicode flag for \p{L} and \p{N} in the pattern
|
||||
);
|
||||
|
||||
public static readonly NUMBER = new RegExp(
|
||||
"[+-]?(?:(?:[0-9]+(?:\\.[0-9]*)?)|\\.[0-9]+)"
|
||||
);
|
||||
public static readonly NAME = new RegExp("[a-zA-Z0-9\\-_\\$]+");
|
||||
|
||||
public static readonly ALIGN = new RegExp(
|
||||
"\\b(center|left|right|justify|char)\\b",
|
||||
"i" // Case-insensitive flag
|
||||
);
|
||||
|
||||
public static readonly VALIGN = new RegExp(
|
||||
"\\b(baseline|bottom|middle|top)\\b",
|
||||
"i" // Case-insensitive flag
|
||||
);
|
||||
|
||||
public static readonly HISTORY_BACK = new RegExp(
|
||||
"(?:javascript:)?\\Qhistory.go(-1)\\E"
|
||||
);
|
||||
|
||||
public static readonly ONE_CHAR = new RegExp(
|
||||
".?",
|
||||
"s" // Dotall flag for . to match newlines
|
||||
);
|
||||
|
||||
private static COLOR_NAME_OR_COLOR_CODE(s: string): boolean {
|
||||
return (
|
||||
KcSanitizerPolicy.COLOR_NAME.test(s) || KcSanitizerPolicy.COLOR_CODE.test(s)
|
||||
);
|
||||
}
|
||||
|
||||
private static ONSITE_OR_OFFSITE_URL(s: string): boolean {
|
||||
return (
|
||||
KcSanitizerPolicy.ONSITE_URL.test(s) || KcSanitizerPolicy.OFFSITE_URL.test(s)
|
||||
);
|
||||
}
|
||||
|
||||
public static sanitize(html: string) {
|
||||
return new HtmlPolicyBuilder()
|
||||
.allowWithoutAttributes("span")
|
||||
|
||||
.allowAttributes("id")
|
||||
.matching(this.HTML_ID)
|
||||
.globally()
|
||||
|
||||
.allowAttributes("class")
|
||||
.matching(this.HTML_CLASS)
|
||||
.globally()
|
||||
|
||||
.allowAttributes("lang")
|
||||
.matching(/[a-zA-Z]{2,20}/)
|
||||
.globally()
|
||||
|
||||
.allowAttributes("title")
|
||||
.matching(this.HTML_TITLE)
|
||||
.globally()
|
||||
|
||||
.allowStyling()
|
||||
|
||||
.allowAttributes("align")
|
||||
.matching(this.ALIGN)
|
||||
.onElements("p")
|
||||
|
||||
.allowAttributes("for")
|
||||
.matching(this.HTML_ID)
|
||||
.onElements("label")
|
||||
|
||||
.allowAttributes("color")
|
||||
.matching(this.COLOR_NAME_OR_COLOR_CODE)
|
||||
.onElements("font")
|
||||
|
||||
.allowAttributes("face")
|
||||
.matching(/[\w;, \-]+/)
|
||||
.onElements("font")
|
||||
|
||||
.allowAttributes("size")
|
||||
.matching(this.NUMBER)
|
||||
.onElements("font")
|
||||
|
||||
.allowAttributes("href")
|
||||
.matching(this.ONSITE_OR_OFFSITE_URL)
|
||||
.onElements("a")
|
||||
|
||||
.allowStandardUrlProtocols()
|
||||
.allowAttributes("nohref")
|
||||
.onElements("a")
|
||||
|
||||
.allowAttributes("name")
|
||||
.matching(this.NAME)
|
||||
.onElements("a")
|
||||
|
||||
.allowAttributes("onfocus", "onblur", "onclick", "onmousedown", "onmouseup")
|
||||
.matching(this.HISTORY_BACK)
|
||||
.onElements("a")
|
||||
|
||||
.requireRelNofollowOnLinks()
|
||||
.allowAttributes("src")
|
||||
.matching(this.ONSITE_OR_OFFSITE_URL)
|
||||
.onElements("img")
|
||||
|
||||
.allowAttributes("name")
|
||||
.matching(this.NAME)
|
||||
.onElements("img")
|
||||
|
||||
.allowAttributes("alt")
|
||||
.matching(this.PARAGRAPH)
|
||||
.onElements("img")
|
||||
|
||||
.allowAttributes("border", "hspace", "vspace")
|
||||
.matching(this.NUMBER)
|
||||
.onElements("img")
|
||||
|
||||
.allowAttributes("border", "cellpadding", "cellspacing")
|
||||
.matching(this.NUMBER)
|
||||
.onElements("table")
|
||||
|
||||
.allowAttributes("bgcolor")
|
||||
.matching(this.COLOR_NAME_OR_COLOR_CODE)
|
||||
.onElements("table")
|
||||
|
||||
.allowAttributes("background")
|
||||
.matching(this.ONSITE_URL)
|
||||
.onElements("table")
|
||||
|
||||
.allowAttributes("align")
|
||||
.matching(this.ALIGN)
|
||||
.onElements("table")
|
||||
|
||||
.allowAttributes("noresize")
|
||||
.matching(new RegExp("noresize", "i"))
|
||||
.onElements("table")
|
||||
|
||||
.allowAttributes("background")
|
||||
.matching(this.ONSITE_URL)
|
||||
.onElements("td", "th", "tr")
|
||||
|
||||
.allowAttributes("bgcolor")
|
||||
.matching(this.COLOR_NAME_OR_COLOR_CODE)
|
||||
.onElements("td", "th")
|
||||
|
||||
.allowAttributes("abbr")
|
||||
.matching(this.PARAGRAPH)
|
||||
.onElements("td", "th")
|
||||
|
||||
.allowAttributes("axis", "headers")
|
||||
.matching(this.NAME)
|
||||
.onElements("td", "th")
|
||||
|
||||
.allowAttributes("scope")
|
||||
.matching(new RegExp("(?:row|col)(?:group)?", "i"))
|
||||
.onElements("td", "th")
|
||||
|
||||
.allowAttributes("nowrap")
|
||||
.onElements("td", "th")
|
||||
|
||||
.allowAttributes("height", "width")
|
||||
.matching(this.NUMBER_OR_PERCENT)
|
||||
.onElements("table", "td", "th", "tr", "img")
|
||||
|
||||
.allowAttributes("align")
|
||||
.matching(this.ALIGN)
|
||||
.onElements(
|
||||
"thead",
|
||||
"tbody",
|
||||
"tfoot",
|
||||
"img",
|
||||
"td",
|
||||
"th",
|
||||
"tr",
|
||||
"colgroup",
|
||||
"col"
|
||||
)
|
||||
|
||||
.allowAttributes("valign")
|
||||
.matching(this.VALIGN)
|
||||
.onElements("thead", "tbody", "tfoot", "td", "th", "tr", "colgroup", "col")
|
||||
|
||||
.allowAttributes("charoff")
|
||||
.matching(this.NUMBER_OR_PERCENT)
|
||||
.onElements("td", "th", "tr", "colgroup", "col", "thead", "tbody", "tfoot")
|
||||
|
||||
.allowAttributes("char")
|
||||
.matching(this.ONE_CHAR)
|
||||
.onElements("td", "th", "tr", "colgroup", "col", "thead", "tbody", "tfoot")
|
||||
|
||||
.allowAttributes("colspan", "rowspan")
|
||||
.matching(this.NUMBER)
|
||||
.onElements("td", "th")
|
||||
|
||||
.allowAttributes("span", "width")
|
||||
.matching(this.NUMBER_OR_PERCENT)
|
||||
.onElements("colgroup", "col")
|
||||
.allowElements(
|
||||
"a",
|
||||
"label",
|
||||
"noscript",
|
||||
"h1",
|
||||
"h2",
|
||||
"h3",
|
||||
"h4",
|
||||
"h5",
|
||||
"h6",
|
||||
"p",
|
||||
"i",
|
||||
"b",
|
||||
"u",
|
||||
"strong",
|
||||
"em",
|
||||
"small",
|
||||
"big",
|
||||
"pre",
|
||||
"code",
|
||||
"cite",
|
||||
"samp",
|
||||
"sub",
|
||||
"sup",
|
||||
"strike",
|
||||
"center",
|
||||
"blockquote",
|
||||
"hr",
|
||||
"br",
|
||||
"col",
|
||||
"font",
|
||||
"map",
|
||||
"span",
|
||||
"div",
|
||||
"img",
|
||||
"ul",
|
||||
"ol",
|
||||
"li",
|
||||
"dd",
|
||||
"dt",
|
||||
"dl",
|
||||
"tbody",
|
||||
"thead",
|
||||
"tfoot",
|
||||
"table",
|
||||
"td",
|
||||
"th",
|
||||
"tr",
|
||||
"colgroup",
|
||||
"fieldset",
|
||||
"legend"
|
||||
)
|
||||
.apply(html);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user