From 349add70df550cd5cf1508d63f219b5d295696a6 Mon Sep 17 00:00:00 2001 From: Matthias Kurz Date: Tue, 12 Dec 2023 14:41:35 +0100 Subject: [PATCH] Support CSP nonce in Comet helpers --- .../src/main/java/play/libs/Comet.java | 52 ++++++++++++++-- .../src/main/scala/play/api/libs/Comet.scala | 62 ++++++++++++++++--- 2 files changed, 101 insertions(+), 13 deletions(-) diff --git a/core/play-java/src/main/java/play/libs/Comet.java b/core/play-java/src/main/java/play/libs/Comet.java index 5b3cede5a7b..a271e5858b4 100644 --- a/core/play-java/src/main/java/play/libs/Comet.java +++ b/core/play-java/src/main/java/play/libs/Comet.java @@ -50,12 +50,24 @@ public abstract class Comet { * @return a flow of ByteString elements. */ public static Flow string(String callbackName) { + return string(callbackName, null); + } + + /** + * Produces a Flow of escaped ByteString from a series of String elements. Calls out to Comet.flow + * internally. + * + * @param callbackName the javascript callback method. + * @param nonce The CSP nonce to use for the script tag. If {@code null} no nonce will be sent. + * @return a flow of ByteString elements. + */ + public static Flow string(String callbackName, String nonce) { return Flow.of(String.class) .map( str -> { return ByteString.fromString("'" + StringEscapeUtils.escapeEcmaScript(str) + "'"); }) - .via(flow(callbackName)); + .via(flow(callbackName, nonce)); } /** @@ -66,12 +78,24 @@ public static Flow string(String callbackName) { * @return a flow of ByteString elements. */ public static Flow json(String callbackName) { + return json(callbackName, null); + } + + /** + * Produces a flow of ByteString using `Json.stringify` from a Flow of JsonNode. Calls out to + * Comet.flow internally. + * + * @param callbackName the javascript callback method. + * @param nonce The CSP nonce to use for the script tag. If {@code null} no nonce will be sent. + * @return a flow of ByteString elements. + */ + public static Flow json(String callbackName, String nonce) { return Flow.of(JsonNode.class) .map( json -> { return ByteString.fromString(Json.stringify(json)); }) - .via(flow(callbackName)); + .via(flow(callbackName, nonce)); } /** @@ -81,18 +105,36 @@ public static Flow json(String callbackName) { * @return a flow of ByteString elements. */ public static Flow flow(String callbackName) { + return flow(callbackName, null); + } + + /** + * Produces a flow of ByteString with a prepended block and a script wrapper. + * + * @param callbackName the javascript callback method. + * @param nonce The CSP nonce to use for the script tag. If {@code null} no nonce will be sent. + * @return a flow of ByteString elements. + */ + public static Flow flow(String callbackName, String nonce) { ByteString cb = ByteString.fromString(callbackName); return Flow.of(ByteString.class) .map( (msg) -> { - return formatted(cb, msg); + return formatted(cb, msg, nonce); }) .prepend(Source.single(initialChunk)); } - private static ByteString formatted(ByteString callbackName, ByteString javascriptMessage) { + private static ByteString formatted( + ByteString callbackName, ByteString javascriptMessage, String nonce) { ByteStringBuilder b = new ByteStringBuilder(); - b.append(ByteString.fromString("