io.stallion.utils.Sanitize.java Source code

Java tutorial

Introduction

Here is the source code for io.stallion.utils.Sanitize.java

Source

/*
 * Stallion Core: A Modern Web Framework
 *
 * Copyright (C) 2015 - 2016 Stallion Software LLC.
 *
 * This program is free software: you can redistribute it and/or modify it under the terms of the
 * GNU General Public License as published by the Free Software Foundation, either version 2 of
 * the License, or (at your option) any later version. This program is distributed in the hope that
 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 * License for more details. You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/gpl-2.0.html>.
 *
 *
 *
 */

package io.stallion.utils;

import com.fasterxml.jackson.core.JsonProcessingException;
import io.stallion.Context;
import io.stallion.dataAccess.Model;
import io.stallion.services.Log;
import io.stallion.users.Role;
import io.stallion.utils.json.JSON;
import io.stallion.utils.json.RestrictedViews;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.owasp.html.HtmlPolicyBuilder;
import org.owasp.html.PolicyFactory;

import java.util.regex.Pattern;

public class Sanitize {

    public static final PolicyFactory COMMENTS_BOX_POLICY = new HtmlPolicyBuilder().allowStandardUrlProtocols()
            // Allow title="..." on any element.
            .allowAttributes("title").globally()
            // Allow href="..." on <a> elements.
            .allowAttributes("href", "data-mentioned-contact").onElements("a")
            // Defeat link spammers.
            .requireRelNofollowOnLinks().allowAttributes("lang").matching(Pattern.compile("[a-zA-Z]{2,20}"))
            .globally()
            // The align attribute on <p> elements can have any value below.
            .allowAttributes("align").matching(true, "center", "left", "right", "justify", "char").onElements("p")
            // These elements are allowed.
            .allowElements("a", "p", "i", "b", "em", "blockquote", "code", "strong", "br", "ul", "ol", "li")
            // Custom slashdot tags.
            // These could be rewritten in the sanitizer using an ElementPolicy.
            .allowElements("quote", "ecode")

            .toFactory();

    public static final PolicyFactory STANDARD_POLICY = new HtmlPolicyBuilder().allowTextIn("div")
            .allowStandardUrlProtocols()
            // Allow title="..." on any element.
            .allowAttributes("title").globally()
            // Allow href="..." on <a> elements.
            .allowAttributes("href", "data-mentioned-contact").onElements("a")
            // Defeat link spammers.
            .requireRelNofollowOnLinks()
            // Allow lang= with an alphabetic value on any element.
            .allowAttributes("lang").matching(Pattern.compile("[a-zA-Z]{2,20}")).globally()
            // The align attribute on <p> elements can have any value below.
            .allowAttributes("align").matching(true, "center", "left", "right", "justify", "char").onElements("p")
            // These elements are allowed.
            .allowElements("a", "p", "div", "i", "b", "em", "blockquote", "tt", "strong", "br", "ul", "ol", "li")
            // Custom slashdot tags.
            // These could be rewritten in the sanitizer using an ElementPolicy.
            .allowElements("quote", "ecode")

            .toFactory();

    public static final PolicyFactory STANDARD_POLICY_WITH_IMAGES = new HtmlPolicyBuilder()

            .allowStandardUrlProtocols()
            // Allow title="..." on any element.
            .allowAttributes("title").globally()
            // Allow href="..." on <a> elements.
            .allowAttributes("href", "data-mentioned-contact").onElements("a")
            // Defeat link spammers.
            .requireRelNofollowOnLinks()
            // Allow lang= with an alphabetic value on any element.
            .allowAttributes("lang").matching(Pattern.compile("[a-zA-Z]{2,20}")).globally()
            // The align attribute on <p> elements can have any value below.
            .allowAttributes("align").matching(true, "center", "left", "right", "justify", "char").onElements("p")
            // These elements are allowed.
            .allowElements("a", "p", "div", "i", "b", "em", "blockquote", "tt", "strong", "br", "ul", "ol", "li",
                    "img")
            // Custom slashdot tags.
            // These could be rewritten in the sanitizer using an ElementPolicy.
            .allowAttributes("src", "alt").onElements("img").allowElements("quote", "ecode").toFactory();

    public static final PolicyFactory BLOCK_ALL_POLICY = new HtmlPolicyBuilder().allowElements().toFactory();

    public static Pattern stripTagsPattern = Pattern.compile("<[^>]*>");

    /** Strips all HTML */
    public static String stripAll(String s) {
        if (s == null) {
            return "";
        }
        return stripTagsPattern.matcher(s).replaceAll("");
    }

    /** Standard policy for a blog comment box. Mostly the same as the standard policy, except stripts out divs too.
     *
     *
     * @param s
     * @return
     */
    public static String commentSanitize(String s) {
        if (s == null) {
            return "";
        }
        return COMMENTS_BOX_POLICY.sanitize(s);
    }

    /** Strips all dangerous javascript, all block HTML that could ruin the page
     *  Allows only a limited white list of tags
     * @param s
     * @return
     */
    public static String basicSanitize(String s) {
        if (s == null) {
            return "";
        }
        return STANDARD_POLICY.sanitize(s);
    }

    public static String basicSanitizeWithImages(String s) {
        if (s == null) {
            return "";
        }
        return STANDARD_POLICY_WITH_IMAGES.sanitize(s);
    }

    public static String escapeHtmlAttribute(String s) {
        return s.replace("\"", "&quot;").replace("'", "&#39;").replace("<", "&lt;").replace(">", "&gt;");
    }

    public static String escapeXml(String s) {
        return StringEscapeUtils.escapeXml11(s);
    }

    public static Object htmlSafeJson(Object obj) {

        String out = JSON.stringify(obj);
        out = out.replace("<", "\\u003c");
        return out;
    }

    /**
     * Gets the object in a JSON form that is safe for being outputted on a web page:
     * &lt;script&gt;
     *     var myObj = {{ utils.htmlSafeJson(obj, "member") }}
     * &lt;/script&gt;
     * @param obj
     * @param restrictionLevel - Uses the JsonView annotation to determine which properties of the object
     *                         should be outputed. Possible values are: unrestricted/public/member/owner/internal
     * @return
     */
    public static Object htmlSafeJson(Object obj, String restrictionLevel) {
        String out = "";
        try {
            restrictionLevel = restrictionLevel == null ? "public" : restrictionLevel.toLowerCase();
            if ("public".equals(restrictionLevel)) {
                out = JSON.stringify(obj, RestrictedViews.Public.class, true);
            } else if ("unrestricted".equals(restrictionLevel)) {
                out = JSON.stringify(obj, RestrictedViews.Unrestricted.class, false);
            } else if ("member".equals(restrictionLevel)) {
                out = JSON.stringify(obj, RestrictedViews.Member.class, true);
            } else if ("owner".equals(restrictionLevel)) {
                out = JSON.stringify(obj, RestrictedViews.Owner.class, true);
            } else if ("internal".equals(restrictionLevel)) {
                out = JSON.stringify(obj, RestrictedViews.Internal.class, true);
            } else {
                out = "Unknown restriction level: " + restrictionLevel;
            }
        } catch (JsonProcessingException ex) {
            String objId = obj.toString();
            if (obj instanceof Model) {
                objId = ((Model) obj).getId().toString();
            }
            String msg = "Error JSON.stringifying object {0}" + obj.getClass().getSimpleName() + ":" + objId;
            if (Context.getSettings().getDebug() || Context.getUser().isInRole(Role.ADMIN)) {
                out = msg + "\n\nStacktrace-----\n\n" + ExceptionUtils.getStackTrace(ex);
            }
            Log.exception(ex, msg);
        }
        out = out.replace("<", "\\u003c");
        return out;
    }
}