| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439 | /*! * @esri/arcgis-html-sanitizer - v3.0.1 - Tue Nov 15 2022 09:46:54 GMT-0800 (Pacific Standard Time) * Copyright (c) 2022 - Environmental Systems Research Institute, Inc. * Apache-2.0 *  * js-xss * Copyright (c) 2012-2018 Zongmin Lei(雷宗民) <leizongmin@gmail.com> * http://ucdok.com * MIT License, see https://github.com/leizongmin/js-xss/blob/master/LICENSE for details */'use strict';Object.defineProperty(exports, '__esModule', { value: true });var xss = require('xss');function _interopNamespace(e) {    if (e && e.__esModule) return e;    var n = Object.create(null);    if (e) {        Object.keys(e).forEach(function (k) {            if (k !== 'default') {                var d = Object.getOwnPropertyDescriptor(e, k);                Object.defineProperty(n, k, d.get ? d : {                    enumerable: true,                    get: function () { return e[k]; }                });            }        });    }    n["default"] = e;    return Object.freeze(n);}var xss__namespace = /*#__PURE__*/_interopNamespace(xss);/** * Determine if the value is a plain object. * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. */var isPlainObject = function (value) {    if (typeof value !== "object" || value === null) {        return false;    }    if (Object.prototype.toString.call(value) !== "[object Object]") {        return false;    }    var proto = Object.getPrototypeOf(value);    if (proto === null) {        return true;    }    while (Object.getPrototypeOf(proto) !== null) {        proto = Object.getPrototypeOf(proto);    }    return Object.getPrototypeOf(value) === proto;};/* Copyright (c) 2020 Environmental Systems Research Institute, Inc. * Apache-2.0 * * js-xss * Copyright (c) 2012-2018 Zongmin Lei(雷宗民) <leizongmin@gmail.com> * http://ucdok.com * The MIT License, see * https://github.com/leizongmin/js-xss/blob/master/LICENSE for details * *//** * The Sanitizer Class * * @export * @class Sanitizer */var Sanitizer = /** @class */ (function () {    function Sanitizer(filterOptions, extendDefaults) {        var _this = this;        // Supported HTML Spec: https://doc.arcgis.com/en/arcgis-online/reference/supported-html.htm        this.arcgisWhiteList = {            a: ["href", "style", "target"],            abbr: ["title"],            audio: ["autoplay", "controls", "loop", "muted", "preload"],            b: [],            br: [],            dd: ["style"],            div: ["align", "style"],            dl: ["style"],            dt: ["style"],            em: [],            figcaption: ["style"],            figure: ["style"],            font: ["color", "face", "size", "style"],            h1: ["style"],            h2: ["style"],            h3: ["style"],            h4: ["style"],            h5: ["style"],            h6: ["style"],            hr: [],            i: [],            img: ["alt", "border", "height", "src", "style", "width"],            li: [],            ol: [],            p: ["style"],            source: ["media", "src", "type"],            span: ["style"],            strong: [],            sub: ["style"],            sup: ["style"],            table: ["border", "cellpadding", "cellspacing", "height", "style", "width"],            tbody: [],            tr: ["align", "height", "style", "valign"],            td: [                "align",                "colspan",                "height",                "nowrap",                "rowspan",                "style",                "valign",                "width",            ],            th: [                "align",                "colspan",                "height",                "nowrap",                "rowspan",                "style",                "valign",                "width",            ],            u: [],            ul: [],            video: [                "autoplay",                "controls",                "height",                "loop",                "muted",                "poster",                "preload",                "width",            ],        };        this.allowedProtocols = [            "http",            "https",            "mailto",            "iform",            "tel",            "flow",            "lfmobile",            "arcgis-navigator",            "arcgis-appstudio-player",            "arcgis-survey123",            "arcgis-collector",            "arcgis-workforce",            "arcgis-explorer",            "arcgis-trek2there",            "arcgis-quickcapture",            "mspbi",            "comgooglemaps",            "pdfefile",            "pdfehttp",            "pdfehttps",            "boxapp",            "boxemm",            "awb",            "awbs",            "gropen",            "radarscope",        ];        this.arcgisFilterOptions = {            allowCommentTag: true,            safeAttrValue: function (tag, name, value, cssFilter) {                // Take over safe attribute filtering for `a` `href`, `img` `src`,                // and `source` `src` attributes, otherwise pass onto the                // default `XSS.safeAttrValue` method.                if ((tag === "a" && name === "href") ||                    ((tag === "img" || tag === "source") && name === "src")) {                    return _this.sanitizeUrl(value);                }                return xss__namespace.safeAttrValue(tag, name, value, cssFilter);            },        };        this._entityMap = {            "&": "8",            "<": "<",            ">": ">",            '"': """,            "'": "'",            "/": "/",        };        var xssFilterOptions;        if (filterOptions && !extendDefaults) {            // Override the defaults            xssFilterOptions = filterOptions;        }        else if (filterOptions && extendDefaults) {            // Extend the defaults            xssFilterOptions = Object.create(this.arcgisFilterOptions);            Object.keys(filterOptions).forEach(function (key) {                if (key === "whiteList") {                    // Extend the whitelist by concatenating arrays                    xssFilterOptions.whiteList = _this._extendObjectOfArrays([                        _this.arcgisWhiteList,                        filterOptions.whiteList || {},                    ]);                }                else {                    xssFilterOptions[key] = filterOptions[key];                }            });        }        else {            // Only use the defaults            xssFilterOptions = Object.create(this.arcgisFilterOptions);            xssFilterOptions.whiteList = this.arcgisWhiteList;        }        this.xssFilterOptions = xssFilterOptions;        // Make this readable to tests        this._xssFilter = new xss__namespace.FilterXSS(xssFilterOptions);    }    /**     * Sanitizes value to remove invalid HTML tags.     *     * Note: If the value passed does not contain a valid JSON data type (String,     * Number, JSON Object, Array, Boolean, or null), the value will be nullified.     *     * @param {any} value The value to sanitize.     * @returns {any} The sanitized value.     * @memberof Sanitizer     */    Sanitizer.prototype.sanitize = function (value, options) {        if (options === void 0) { options = {}; }        switch (typeof value) {            case "number":                if (isNaN(value) || !isFinite(value)) {                    return null;                }                return value;            case "boolean":                return value;            case "string":                return this._xssFilter.process(value);            case "object":                return this._iterateOverObject(value, options);            default:                if (options.allowUndefined && typeof value === "undefined") {                    return;                }                return null;        }    };    /**     * Sanitizes a URL string following the allowed protocols and sanitization rules.     *     * @param {string} value The URL to sanitize.     * @param {{ isProtocolRequired: boolean }} options Configuration options for URL checking.     * @returns {string} The sanitized URL if it's valid, or an empty string if the URL is invalid.     */    Sanitizer.prototype.sanitizeUrl = function (value, options) {        var _a = (options !== null && options !== void 0 ? options : {}).isProtocolRequired, isProtocolRequired = _a === void 0 ? true : _a;        var protocol = this._trim(value.substring(0, value.indexOf(":")));        var isRootUrl = value === '/';        var isUrlFragment = /^#/.test(value);        var isValidProtocol = protocol && this.allowedProtocols.indexOf(protocol.toLowerCase()) > -1;        if (isRootUrl || isUrlFragment || isValidProtocol) {            return xss__namespace.escapeAttrValue(value);        }        if (!protocol && !isProtocolRequired) {            return xss__namespace.escapeAttrValue("https://".concat(value));        }        return "";    };    /**     * Sanitizes an HTML attribute value.     *     * @param {string} tag The tagname of the HTML element.     * @param {string} attribute The attribute name of the HTML element.     * @param {string} value The raw value to be used for the HTML attribute value.     * @param {XSS.ICSSFilter} [cssFilter] The CSS filter to be used.     * @returns {string} The sanitized attribute value.     * @memberof Sanitizer     */    Sanitizer.prototype.sanitizeHTMLAttribute = function (tag, attribute, value, cssFilter) {        // use the custom safeAttrValue function if provided        if (typeof this.xssFilterOptions.safeAttrValue === "function") {            return this.xssFilterOptions.safeAttrValue(tag, attribute, value,             // @ts-expect-error safeAttrValue does handle undefined cssFilter            cssFilter);        }        // otherwise use the default        // @ts-ignore safeAttrValue does handle undefined cssFilter        return xss__namespace.safeAttrValue(tag, attribute, value, cssFilter);    };    /**     * Checks if a value only contains valid HTML.     *     * @param {any} value The value to validate.     * @returns {boolean}     * @memberof Sanitizer     */    Sanitizer.prototype.validate = function (value, options) {        if (options === void 0) { options = {}; }        var sanitized = this.sanitize(value, options);        return {            isValid: value === sanitized,            sanitized: sanitized,        };    };    /**     * Encodes the following characters, `& < > \" ' /` to their hexadecimal HTML entity code.     * Example: "·" => "8middot;"     *     * @param {string} value The value to encode.     * @returns {string} The encoded string value.     * @memberof Sanitizer     */    Sanitizer.prototype.encodeHTML = function (value) {        var _this = this;        return String(value).replace(/[&<>"'\/]/g, function (s) {            return _this._entityMap[s];        });    };    /**     * Encodes all non-alphanumeric ASCII characters to their hexadecimal HTML entity codes.     * Example: "alert(document.cookie)" => "alert(document.cookie)"     *     * @param {string} value The value to encode.     * @returns {string} The encoded string value.     * @memberof Sanitizer     */    Sanitizer.prototype.encodeAttrValue = function (value) {        var alphanumericRE = /^[a-zA-Z0-9]$/;        return String(value).replace(/[\x00-\xFF]/g, function (c, idx) {            return !alphanumericRE.test(c)                ? "&#x".concat(Number(value.charCodeAt(idx)).toString(16), ";")                : c;        });    };    /**     * Extends an object of arrays by by concatenating arrays of the same object     * keys. If the if the previous key's value is not an array, the next key's     * value will replace the previous key. This method is used for extending the     * whiteList in the XSS filter options.     *     * @private     * @param {Array<{}>} objects An array of objects.     * @returns {{}} The extended object.     * @memberof Sanitizer     */    Sanitizer.prototype._extendObjectOfArrays = function (objects) {        var finalObj = {};        objects.forEach(function (obj) {            Object.keys(obj).forEach(function (key) {                if (Array.isArray(obj[key]) && Array.isArray(finalObj[key])) {                    finalObj[key] = finalObj[key].concat(obj[key]);                }                else {                    finalObj[key] = obj[key];                }            });        });        return finalObj;    };    /**     * Iterate over a plain object or array to deeply sanitize each value.     *     * @private     * @param {object} obj The object to iterate over.     * @returns {(object | null)} The sanitized object.     * @memberof Sanitizer     */    Sanitizer.prototype._iterateOverObject = function (obj, options) {        var _this = this;        if (options === void 0) { options = {}; }        try {            var hasChanged_1 = false;            var changedObj = void 0;            if (Array.isArray(obj)) {                changedObj = obj.reduce(function (prev, value) {                    var validation = _this.validate(value, options);                    if (validation.isValid) {                        return prev.concat([value]);                    }                    else {                        hasChanged_1 = true;                        return prev.concat([validation.sanitized]);                    }                }, []);            }            else if (!isPlainObject(obj)) {                if (options.allowUndefined && typeof obj === "undefined") {                    return;                }                return null;            }            else {                var keys = Object.keys(obj);                changedObj = keys.reduce(function (prev, key) {                    var value = obj[key];                    var validation = _this.validate(value, options);                    if (validation.isValid) {                        prev[key] = value;                    }                    else {                        hasChanged_1 = true;                        prev[key] = validation.sanitized;                    }                    return prev;                }, {});            }            if (hasChanged_1) {                return changedObj;            }            return obj;        }        catch (err) {            return null;        }    };    /**     * Trim whitespace from the start and ends of a string.     * @param {string} val The string to trim.     * @returns {string} The trimmed string.     */    Sanitizer.prototype._trim = function (val) {        // @ts-ignore This is used by Jest,        // but TypeScript errors since it assumes `trim` is always available.        return String.prototype.trim            ? val.trim()            : val.replace(/(^\s*)|(\s*$)/g, "");    };    return Sanitizer;}());exports.Sanitizer = Sanitizer;exports["default"] = Sanitizer;
 |