3030import static jakarta .servlet .http .HttpServletResponse .SC_NOT_MODIFIED ;
3131import static jakarta .servlet .http .MappingMatch .EXTENSION ;
3232import static java .lang .Boolean .FALSE ;
33+ import static java .nio .charset .StandardCharsets .UTF_8 ;
3334import static java .util .logging .Level .FINE ;
3435import static java .util .logging .Level .WARNING ;
3536
4041import java .nio .channels .ReadableByteChannel ;
4142import java .nio .channels .WritableByteChannel ;
4243import java .util .ArrayList ;
44+ import java .util .Base64 ;
4345import java .util .List ;
4446import java .util .Map ;
47+ import java .util .UUID ;
4548import java .util .logging .Level ;
4649import java .util .logging .Logger ;
4750import java .util .regex .Pattern ;
4851import java .util .stream .Stream ;
4952
5053import com .sun .faces .application .ApplicationAssociate ;
5154import com .sun .faces .config .WebConfiguration ;
55+ import com .sun .faces .renderkit .html_basic .ScriptRenderer ;
56+ import com .sun .faces .renderkit .html_basic .StylesheetRenderer ;
5257import com .sun .faces .util .FacesLogger ;
5358import com .sun .faces .util .RequestStateManager ;
5459import com .sun .faces .util .Util ;
@@ -67,10 +72,13 @@ public class ResourceHandlerImpl extends ResourceHandler {
6772 // Log instance for this class
6873 private static final Logger LOGGER = FacesLogger .APPLICATION .getLogger ();
6974
75+ private static final String CURRENT_NONCE = ResourceHandlerImpl .class .getName () + ".currentNonce" ;
76+
7077 ResourceManager manager ;
7178 List <Pattern > excludePatterns ;
7279 private long creationTime ;
7380 private long maxAge ;
81+ private boolean cspEnabled ;
7482 private WebConfiguration webconfig ;
7583
7684 // ------------------------------------------------------------ Constructors
@@ -85,6 +93,7 @@ public ResourceHandlerImpl() {
8593 manager = ApplicationAssociate .getInstance (extContext ).getResourceManager ();
8694 initExclusions (extContext .getApplicationMap ());
8795 initMaxAge ();
96+ cspEnabled = webconfig .isSet (WebConfiguration .WebContextInitParameter .CspNonceEnabled );
8897 }
8998
9099 // ------------------------------------------- Methods from Resource Handler
@@ -231,6 +240,21 @@ public String getRendererTypeForResourceName(String resourceName) {
231240 return rendererType ;
232241 }
233242
243+ private static String getResourceType (String contentType ) {
244+ if (contentType == null ) {
245+ return null ;
246+ }
247+
248+ final String type = contentType .toLowerCase ();
249+ if (type .equals (ScriptRenderer .DEFAULT_CONTENT_TYPE )) {
250+ return "script" ;
251+ } else if (type .equals (StylesheetRenderer .DEFAULT_CONTENT_TYPE )) {
252+ return "style" ;
253+ }
254+
255+ return null ;
256+ }
257+
234258 /**
235259 * @see jakarta.faces.application.ResourceHandler#handleResourceRequest(jakarta.faces.context.FacesContext)
236260 */
@@ -381,6 +405,23 @@ private void send304(FacesContext ctx) {
381405 ctx .getExternalContext ().setResponseStatus (SC_NOT_MODIFIED );
382406 }
383407
408+ @ Override
409+ public String getCurrentNonce (FacesContext context ) {
410+ if (cspEnabled ) {
411+ var viewMap = context .getViewRoot ().getViewMap (true );
412+ var nonce = (String ) viewMap .get (CURRENT_NONCE );
413+
414+ if (nonce == null ) {
415+ nonce = Base64 .getEncoder ().encodeToString (UUID .randomUUID ().toString ().getBytes (UTF_8 ));
416+ viewMap .put (CURRENT_NONCE , nonce );
417+ }
418+
419+ return nonce ;
420+ }
421+
422+ return null ;
423+ }
424+
384425 // ------------------------------------------------- Package Private Methods
385426
386427 /**
@@ -556,6 +597,9 @@ private void handleHeaders(FacesContext ctx, Resource resource) {
556597 for (Map .Entry <String , String > cur : resource .getResponseHeaders ().entrySet ()) {
557598 extContext .setResponseHeader (cur .getKey (), cur .getValue ());
558599 }
600+ if (cspEnabled && "script" .equals (getResourceType (resource .getContentType ()))) {
601+ extContext .addResponseHeader ("Content-Security-Policy" , "default-src 'none'; script-src 'self'" );
602+ }
559603 }
560604
561605 private ByteBuffer allocateByteBuffer () {
0 commit comments