aboutsummaryrefslogtreecommitdiff
path: root/js/mathjax/extensions/Safe.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/mathjax/extensions/Safe.js')
-rw-r--r--js/mathjax/extensions/Safe.js430
1 files changed, 430 insertions, 0 deletions
diff --git a/js/mathjax/extensions/Safe.js b/js/mathjax/extensions/Safe.js
new file mode 100644
index 0000000..8b77af4
--- /dev/null
+++ b/js/mathjax/extensions/Safe.js
@@ -0,0 +1,430 @@
+// @license magnet:?xt=urn:btih:8e4f440f4c65981c5bf93c76d35135ba5064d8b7dn=apache-2.0.txt Apache-2.0
+/* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+
+/*************************************************************
+ *
+ * MathJax/extensions/Safe.js
+ *
+ * Implements a "Safe" mode that disables features that could be
+ * misused in a shared environment (such as href's to javascript URL's).
+ * See the CONFIG variable below for configuration options.
+ *
+ * ---------------------------------------------------------------------
+ *
+ * Copyright (c) 2013-2020 The MathJax Consortium
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+(function (HUB,AJAX) {
+ var VERSION = "2.7.9";
+
+ var CONFIG = MathJax.Hub.CombineConfig("Safe",{
+ allow: {
+ //
+ // Values can be "all", "safe", or "none"
+ //
+ URLs: "safe", // safe are in safeProtocols below
+ classes: "safe", // safe start with MJX-
+ cssIDs: "safe", // safe start with MJX-
+ styles: "safe", // safe are in safeStyles below
+ fontsize: "all", // safe are between sizeMin and sizeMax em's
+ require: "safe" // safe are in safeRequire below
+ },
+ sizeMin: .7, // \scriptsize
+ sizeMax: 1.44, // \large
+ lengthMax: 3, // largest padding/border/margin, etc. in em's
+ safeProtocols: {
+ http: true,
+ https: true,
+ file: true,
+ javascript: false
+ },
+ safeStyles: {
+ color: true,
+ backgroundColor: true,
+ border: true,
+ cursor: true,
+ margin: true,
+ padding: true,
+ textShadow: true,
+ fontFamily: true,
+ fontSize: true,
+ fontStyle: true,
+ fontWeight: true,
+ opacity: true,
+ outline: true
+ },
+ safeRequire: {
+ action: true,
+ amscd: true,
+ amsmath: true,
+ amssymbols: true,
+ autobold: false,
+ "autoload-all": false,
+ bbox: true,
+ begingroup: true,
+ boldsymbol: true,
+ cancel: true,
+ color: true,
+ enclose: true,
+ extpfeil: true,
+ HTML: true,
+ mathchoice: true,
+ mhchem: true,
+ newcommand: true,
+ noErrors: false,
+ noUndefined: false,
+ unicode: true,
+ verb: true
+ },
+ //
+ // CSS styles that have Top/Right/Bottom/Left versions
+ //
+ styleParts: {
+ border: true,
+ padding: true,
+ margin: true,
+ outline: true
+ },
+ //
+ // CSS styles that are lengths needing max/min testing
+ // A string value means test that style value;
+ // An array gives [min,max] in em's
+ // Otherwise use [-lengthMax,lengthMax] from above
+ //
+ styleLengths: {
+ borderTop: "borderTopWidth",
+ borderRight: "borderRightWidth",
+ borderBottom: "borderBottomWidth",
+ borderLeft: "borderLeftWidth",
+ paddingTop: true,
+ paddingRight: true,
+ paddingBottom: true,
+ paddingLeft: true,
+ marginTop: true,
+ marginRight: true,
+ marginBottom: true,
+ marginLeft: true,
+ outlineTop: true,
+ outlineRight: true,
+ outlineBottom: true,
+ outlineLeft: true,
+ fontSize: [.7,1.44]
+ }
+ });
+
+ var ALLOW = CONFIG.allow;
+ if (ALLOW.fontsize !== "all") {CONFIG.safeStyles.fontSize = false}
+
+ var SAFE = MathJax.Extension.Safe = {
+ version: VERSION,
+ config: CONFIG,
+ div1: document.createElement("div"), // for CSS processing
+ div2: document.createElement("div"),
+
+ //
+ // Methods called for MathML attribute processing
+ //
+ filter: {
+ href: "filterURL",
+ src: "filterURL",
+ altimg: "filterURL",
+ "class": "filterClass",
+ style: "filterStyles",
+ id: "filterID",
+ fontsize: "filterFontSize",
+ mathsize: "filterFontSize",
+ scriptminsize: "filterFontSize",
+ scriptsizemultiplier: "filterSizeMultiplier",
+ scriptlevel: "filterScriptLevel"
+ },
+
+ //
+ // Filter HREF URL's
+ //
+ filterURL: function (url) {
+ var protocol = (url.match(/^\s*([a-z]+):/i)||[null,""])[1].toLowerCase();
+ if (ALLOW.URLs === "none" ||
+ (ALLOW.URLs !== "all" && !CONFIG.safeProtocols[protocol])) {url = null}
+ return url;
+ },
+
+ //
+ // Filter class names and css ID's
+ //
+ filterClass: function (CLASS) {
+ if (ALLOW.classes === "none" ||
+ (ALLOW.classes !== "all" && !CLASS.match(/^MJX-[-a-zA-Z0-9_.]+$/))) {CLASS = null}
+ return CLASS;
+ },
+ filterID: function (id) {
+ if (ALLOW.cssIDs === "none" ||
+ (ALLOW.cssIDs !== "all" && !id.match(/^MJX-[-a-zA-Z0-9_.]+$/))) {id = null}
+ return id;
+ },
+
+ //
+ // Filter style strings
+ //
+ filterStyles: function (styles) {
+ if (ALLOW.styles === "all") {return styles}
+ if (ALLOW.styles === "none") {return null}
+ try {
+ //
+ // Set the div1 styles to the given styles, and clear div2
+ //
+ var STYLE1 = this.div1.style, STYLE2 = this.div2.style, value;
+ STYLE1.cssText = styles; STYLE2.cssText = "";
+ //
+ // Check each allowed style and transfer OK ones to div2
+ // If the style has Top/Right/Bottom/Left, look at all four separately
+ //
+ for (var name in CONFIG.safeStyles) {if (CONFIG.safeStyles.hasOwnProperty(name)) {
+ if (CONFIG.styleParts[name]) {
+ for (var i = 0; i < 4; i++) {
+ var NAME = name+["Top","Right","Bottom","Left"][i]
+ value = this.filterStyle(NAME,STYLE1);
+ if (value) {STYLE2[NAME] = value}
+ }
+ } else {
+ value = this.filterStyle(name,STYLE1);
+ if (value) {STYLE2[name] = value}
+ }
+ }}
+ //
+ // Return the div2 style string
+ //
+ styles = STYLE2.cssText;
+ } catch (e) {styles = null}
+ return styles;
+ },
+ //
+ // Filter an individual name:value style pair
+ //
+ filterStyle: function (name,styles) {
+ var value = styles[name];
+ if (typeof value !== "string" || value === "") {return null}
+ if (value.match(/^\s*expression/)) {return null}
+ if (value.match(/javascript:/)) {return null}
+ var NAME = name.replace(/Top|Right|Left|Bottom/,"");
+ if (!CONFIG.safeStyles[name] && !CONFIG.safeStyles[NAME]) {return null}
+ if (!CONFIG.styleLengths[name]) {return value}
+ return (this.filterStyleLength(name,value,styles) ? value : null);
+ },
+ filterStyleLength: function (name,value,styles) {
+ if (typeof CONFIG.styleLengths[name] === "string") value = styles[CONFIG.styleLengths[name]];
+ value = this.length2em(value);
+ if (value == null) return false;
+ var mM = [-CONFIG.lengthMax,CONFIG.lengthMax];
+ if (MathJax.Object.isArray(CONFIG.styleLengths[name])) mM = CONFIG.styleLengths[name];
+ return (value >= mM[0] && value <= mM[1]);
+ },
+ //
+ // Conversion of units to em's
+ //
+ unit2em: {
+ em: 1,
+ ex: .5, // assume 1ex = .5em
+ ch: .5, // assume 1ch = .5em
+ rem: 1, // assume 1rem = 1em
+ px: 1/16, // assume 1em = 16px
+ mm: 96/25.4/16, // 25.4mm = 96px
+ cm: 96/2.54/16, // 2.54cm = 96px
+ 'in': 96/16, // 1in = 96px
+ pt: 96/72/16, // 72pt = 1in
+ pc: 96/6/16 // 1pc = 12pt
+ },
+ length2em: function (value) {
+ var match = value.match(/(.+)(em|ex|ch|rem|px|mm|cm|in|pt|pc)/);
+ if (!match) return null;
+ return parseFloat(match[1])*this.unit2em[match[2]];
+ },
+
+ //
+ // Filter TeX font size values (in em's)
+ //
+ filterSize: function (size) {
+ if (ALLOW.fontsize === "none") {return null}
+ if (ALLOW.fontsize !== "all")
+ {size = Math.min(Math.max(size,CONFIG.sizeMin),CONFIG.sizeMax)}
+ return size;
+ },
+ filterFontSize: function (size) {
+ return (ALLOW.fontsize === "all" ? size: null);
+ },
+
+ //
+ // Filter scriptsizemultiplier
+ //
+ filterSizeMultiplier: function (size) {
+ if (ALLOW.fontsize === "none") {size = null}
+ else if (ALLOW.fontsize !== "all") {size = Math.min(1,Math.max(.6,size)).toString()}
+ return size;
+ },
+ //
+ // Filter scriptLevel
+ //
+ filterScriptLevel: function (level) {
+ if (ALLOW.fontsize === "none") {level = null}
+ else if (ALLOW.fontsize !== "all") {level = Math.max(0,level).toString()}
+ return level;
+ },
+
+ //
+ // Filter TeX extension names
+ //
+ filterRequire: function (name) {
+ if (ALLOW.require === "none" ||
+ (ALLOW.require !== "all" && !CONFIG.safeRequire[name.toLowerCase()]))
+ {name = null}
+ return name;
+ }
+
+ };
+
+ HUB.Register.StartupHook("TeX HTML Ready",function () {
+ var TEX = MathJax.InputJax.TeX;
+
+ TEX.Parse.Augment({
+
+ //
+ // Implements \href{url}{math} with URL filter
+ //
+ HREF_attribute: function (name) {
+ var url = SAFE.filterURL(this.GetArgument(name)),
+ arg = this.GetArgumentMML(name);
+ if (url) {arg.With({href:url})}
+ this.Push(arg);
+ },
+
+ //
+ // Implements \class{name}{math} with class-name filter
+ //
+ CLASS_attribute: function (name) {
+ var CLASS = SAFE.filterClass(this.GetArgument(name)),
+ arg = this.GetArgumentMML(name);
+ if (CLASS) {
+ if (arg["class"] != null) {CLASS = arg["class"] + " " + CLASS}
+ arg.With({"class":CLASS});
+ }
+ this.Push(arg);
+ },
+
+ //
+ // Implements \style{style-string}{math} with style filter
+ //
+ STYLE_attribute: function (name) {
+ var style = SAFE.filterStyles(this.GetArgument(name)),
+ arg = this.GetArgumentMML(name);
+ if (style) {
+ if (arg.style != null) {
+ if (style.charAt(style.length-1) !== ";") {style += ";"}
+ style = arg.style + " " + style;
+ }
+ arg.With({style: style});
+ }
+ this.Push(arg);
+ },
+
+ //
+ // Implements \cssId{id}{math} with ID filter
+ //
+ ID_attribute: function (name) {
+ var ID = SAFE.filterID(this.GetArgument(name)),
+ arg = this.GetArgumentMML(name);
+ if (ID) {arg.With({id:ID})}
+ this.Push(arg);
+ }
+
+ });
+
+ });
+
+ HUB.Register.StartupHook("TeX Jax Ready",function () {
+ var TEX = MathJax.InputJax.TeX,
+ PARSE = TEX.Parse, METHOD = SAFE.filter;
+
+ PARSE.Augment({
+
+ //
+ // Implements \require{name} with filtering
+ //
+ Require: function (name) {
+ var file = this.GetArgument(name).replace(/.*\//,"").replace(/[^a-z0-9_.-]/ig,"");
+ file = SAFE.filterRequire(file);
+ if (file) {this.Extension(null,file)}
+ },
+
+ //
+ // Controls \mmlToken attributes
+ //
+ MmlFilterAttribute: function (name,value) {
+ if (METHOD[name]) {value = SAFE[METHOD[name]](value)}
+ return value;
+ },
+
+ //
+ // Handles font size macros with filtering
+ //
+ SetSize: function (name,size) {
+ size = SAFE.filterSize(size);
+ if (size) {
+ this.stack.env.size = size;
+ this.Push(TEX.Stack.Item.style().With({styles: {mathsize: size+"em"}}));
+ }
+ }
+
+ });
+ });
+
+ HUB.Register.StartupHook("TeX bbox Ready",function () {
+ var TEX = MathJax.InputJax.TeX;
+
+ //
+ // Filter the styles for \bbox
+ //
+ TEX.Parse.Augment({
+ BBoxStyle: function (styles) {return SAFE.filterStyles(styles)},
+ BBoxPadding: function (pad) {
+ var styles = SAFE.filterStyles("padding: "+pad);
+ return (styles ? pad : 0);
+ }
+ });
+
+ });
+
+ HUB.Register.StartupHook("MathML Jax Ready",function () {
+ var PARSE = MathJax.InputJax.MathML.Parse,
+ METHOD = SAFE.filter;
+
+ //
+ // Filter MathML attributes
+ //
+ PARSE.Augment({
+ filterAttribute: function (name,value) {
+ if (METHOD[name]) {value = SAFE[METHOD[name]](value)}
+ return value;
+ }
+ });
+
+ });
+
+ // MathML input (href, style, fontsize, class, id)
+
+ HUB.Startup.signal.Post("Safe Extension Ready");
+ AJAX.loadComplete("[MathJax]/extensions/Safe.js");
+
+})(MathJax.Hub,MathJax.Ajax);
+// @license-end