Skip to content

Commit

Permalink
[JENKINS-71728] Add CSP compatible version of `FormApply#applyRespons…
Browse files Browse the repository at this point in the history
…e` (#8351)

Co-authored-by: Daniel Beck <[email protected]>
Co-authored-by: Yaroslav Afenkin <[email protected]>
Co-authored-by: Alexander Brandes <[email protected]>
Co-authored-by: Basil Crow <[email protected]>
  • Loading branch information
5 people authored Oct 21, 2024
1 parent d7eda6a commit 5f7026d
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 3 deletions.
3 changes: 1 addition & 2 deletions core/src/main/java/hudson/model/Descriptor.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

package hudson.model;

import static hudson.util.QuotedStringTokenizer.quote;
import static jakarta.servlet.http.HttpServletResponse.SC_NOT_FOUND;

import edu.umd.cs.findbugs.annotations.CheckForNull;
Expand Down Expand Up @@ -1306,7 +1305,7 @@ public String getFormField() {
@Override
public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
if (FormApply.isApply(req)) {
FormApply.applyResponse("notificationBar.show(" + quote(getMessage()) + ",notificationBar.ERROR)")
FormApply.showNotification(getMessage(), FormApply.NotificationType.ERROR)
.generateResponse(req, rsp, node);
} else {
// for now, we can't really use the field name that caused the problem.
Expand Down
40 changes: 39 additions & 1 deletion core/src/main/java/hudson/util/FormApply.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@

package hudson.util;

import hudson.Functions;
import jakarta.servlet.ServletException;
import java.io.IOException;
import jenkins.model.Jenkins;
import org.kohsuke.stapler.HttpResponses.HttpResponseException;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerRequest2;
Expand All @@ -51,7 +53,7 @@ public static HttpResponseException success(final String destination) {
public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
if (isApply(req)) {
// if the submission is via 'apply', show a response in the notification bar
applyResponse("notificationBar.show('" + Messages.HttpResponses_Saved() + "',notificationBar.SUCCESS)")
showNotification(Messages.HttpResponses_Saved(), NotificationType.SUCCESS)
.generateResponse(req, rsp, node);
} else {
rsp.sendRedirect(destination);
Expand All @@ -69,6 +71,7 @@ public static boolean isApply(StaplerRequest2 req) {
return Boolean.parseBoolean(req.getParameter("core:apply"));
}


/**
* @deprecated use {@link #isApply(StaplerRequest2)}
*/
Expand All @@ -82,7 +85,10 @@ public static boolean isApply(StaplerRequest req) {
* <p>
* When the response HTML includes a JavaScript function in a pre-determined name, that function gets executed.
* This method generates such a response from JavaScript text.
*
* @deprecated use {@link #showNotification(String, NotificationType)} instead, which is CSP compatible version
*/
@Deprecated
public static HttpResponseException applyResponse(final String script) {
return new HttpResponseException() {
@Override
Expand All @@ -98,4 +104,36 @@ public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object n
}
};
}

/**
* Generates the response for the asynchronous background form submission (AKA the Apply button),
* that will show a notification of certain type and with provided message.
*
* @param message a message to display in the popup. Only plain text is supported.
* @param notificationType type of notification. See {@link NotificationType} for supported types. Defines the notification
* color and the icon that will be shown.
*
* @since TODO
*/
public static HttpResponseException showNotification(final String message, final NotificationType notificationType) {
return new HttpResponseException() {
@Override
public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException {
rsp.setContentType("text/html;charset=UTF-8");
rsp.getWriter().println("<script id='form-apply-data-holder' data-message='" + Functions.htmlAttributeEscape(message) + "' " +
"data-notification-type='" + notificationType + "' " +
"src='" + req.getContextPath() + Jenkins.RESOURCE_PATH + "/scripts/apply.js" + "'></script>");
}
};
}


/**
* Corresponds to types declared in <a href="https://github.com/jenkinsci/jenkins/blob/74610e024a6b8fd8feccdc51b8f7741aa6c30e3b/war/src/main/js/components/notifications/index.js#L13-L25">index.js</a>
*/
public enum NotificationType {
SUCCESS,
WARNING,
ERROR
}
}
8 changes: 8 additions & 0 deletions war/src/main/webapp/scripts/apply.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
window.applyCompletionHandler = function (w) {
let scriptTagData = document.getElementById("form-apply-data-holder").dataset;

w.notificationBar.show(
scriptTagData.message,
w.notificationBar[scriptTagData.notificationType],
);
};

0 comments on commit 5f7026d

Please sign in to comment.