001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with this work for additional 004 * information regarding copyright ownership. The ASF licenses this file to You under the Apache 005 * License, Version 2.0 (the "License"); you may not use this file except in compliance with 006 * the License. You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software distributed under the 011 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 012 * express or implied. See the License for the specific language governing permissions and 013 * limitations under the License. 014 */ 015package org.apache.juneau.console.views; 016 017/** 018 * How a field-grid catalog entry (or a remaining declarative field) is painted. 019 * 020 * <p> 021 * Each constant carries the lowercase token emitted on {@code format} / {@code data-juneau-field-format}. 022 * {@link #TEXT} is omitted from the wire (the default). 023 * 024 * @since 10.0.0 025 */ 026public enum FieldFormat { 027 028 /** Paint with {@code textContent}. The default. */ 029 TEXT("text"), 030 031 /** 032 * Treat the value as sanitizing-markdown HTML and copy allowlisted nodes into the slot. 033 * Never {@code innerHTML}. 034 */ 035 MARKDOWN("markdown"), 036 037 /** 038 * Treat the value as rich HTML the <b>caller has already sanitized server-side</b>, and paint it 039 * through this runtime's own second allowlist — a wider one than {@link #MARKDOWN}'s, admitting 040 * {@code <img>} and the remaining table/typographic tags a full-fidelity rich-text body needs. 041 * 042 * <p> 043 * <b>This is not a raw-HTML sink.</b> Like {@link #MARKDOWN}, the client parses the value with 044 * {@code DOMParser} into an inert document and copies allowlisted nodes via {@code createElement}/ 045 * {@code createTextNode}; it never assigns {@code innerHTML}, and it never serializes back to a string (so 046 * the mutation-XSS class that a parse→serialize→reparse sanitizer is prone to cannot arise). 047 * Attributes are copied by an explicit per-tag allowlist, so {@code on*} handlers, {@code srcdoc}, 048 * {@code style} and every other unnamed attribute cannot survive <i>by construction</i> rather than by a 049 * deny-list that has to anticipate them. {@code href} and {@code src} are scheme-checked in two layers, 050 * not one: an explicit prefix reject for {@code javascript:}, {@code data:} and {@code vbscript:}, plus a 051 * <b>colon-fallback</b> rule underneath it that rejects any value containing a colon outside the 052 * explicitly allowlisted absolute prefixes ({@code http:}/{@code https:}/{@code mailto:} for 053 * {@code href}; {@code http:}/{@code https:} for {@code src}). <b>The colon-fallback, not the named- 054 * scheme prefix check, is the load-bearing defense</b>: it is what still rejects an obfuscated spelling 055 * of one of those three schemes (e.g. one split by a stray whitespace/control character that a browser's 056 * URL parser strips before resolving, such as {@code java\tscript:}) — the prefix check alone would 057 * miss it, but the obfuscated string still contains a colon and matches none of the allowed prefixes, so 058 * it still fails closed. A future "simplification" to a longer bare {@code javascript:}/{@code data:}/ 059 * {@code vbscript:} deny-list that drops the colon-fallback as apparently redundant would silently 060 * reopen that hole. 061 * 062 * <p> 063 * <b>The contract is nonetheless caller-sanitizes-first.</b> This runtime's allowlist is a second, 064 * independent gate — defense in depth — not a substitute for a real server-side sanitizer. Juneau 065 * takes on no HTML-sanitizer dependency and makes no claim to sanitize hostile input on the caller's behalf: 066 * an application pointing this format at externally-authored HTML is expected to have run that HTML through 067 * a dedicated allowlist sanitizer at its own trust boundary first. What this format guarantees is narrower 068 * and worth stating exactly: <i>if that upstream pass is wrong, a script still does not execute here.</i> 069 * 070 * <p> 071 * Fidelity is bounded by the allowlist. Tags outside it are unwrapped (their children are kept), so an 072 * unexpected element degrades to its text rather than rendering — a body that needs an element this 073 * allowlist does not name will silently lose that element's markup, not its content. 074 * 075 * <p> 076 * Like {@link #MARKDOWN}, a field with this format spans full width. 077 */ 078 SANITIZED_HTML("sanitizedHtml"); 079 080 private final String wire; 081 082 FieldFormat(String wire) { 083 this.wire = wire; 084 } 085 086 /** 087 * Returns the lowercase wire token for this format. 088 * 089 * @return The wire token (e.g. <c>"markdown"</c>). 090 */ 091 public String wire() { 092 return wire; 093 } 094}