diff --git a/app/src/main/java/org/jboss/hal/client/deployment/BrowseContentElement.java b/app/src/main/java/org/jboss/hal/client/deployment/BrowseContentElement.java index dd2c67dd7b..c6363b31ba 100644 --- a/app/src/main/java/org/jboss/hal/client/deployment/BrowseContentElement.java +++ b/app/src/main/java/org/jboss/hal/client/deployment/BrowseContentElement.java @@ -469,6 +469,7 @@ private void uploadContent() { }); form.setSaveCallback((f, model) -> { String path = targetPathItem.getValue(); + String safePath = SafeHtmlUtils.htmlEscape(path); ResourceAddress address = new ResourceAddress().add(DEPLOYMENT, content.getName()); ModelNode contentNode = new ModelNode(); @@ -477,7 +478,7 @@ private void uploadContent() { } else { contentNode.get(INPUT_STREAM_INDEX).set(0); } - contentNode.get(TARGET_PATH).set(path); + contentNode.get(TARGET_PATH).set(safePath); Operation operation = new Operation.Builder(address, ADD_CONTENT) .param(CONTENT, new ModelNode().add(contentNode)) .build(); @@ -490,7 +491,7 @@ private void uploadContent() { .subscribe(() -> { MessageEvent.fire(eventBus, Message.success(resources.messages().newContentSuccess(content.getName(), path))); - tree.selectNode(NODE_ID.apply(path)); + tree.selectNode(NODE_ID.apply(safePath)); }); }); @@ -583,7 +584,8 @@ private void removeContent() { if (selection != null) { String path = selection.data.path; DialogFactory.buildConfirmation(resources.constants().removeContent(), - resources.messages().removeContentQuestion(content.getName(), path), null, Dialog.Size.MEDIUM, + resources.messages().removeContentQuestion(content.getName(), SafeHtmlUtils.fromTrustedString(path)), null, + Dialog.Size.MEDIUM, () -> { ResourceAddress address = new ResourceAddress().add(DEPLOYMENT, content.getName()); Operation operation = new Operation.Builder(address, REMOVE_CONTENT) @@ -595,7 +597,9 @@ private void removeContent() { .andThen(awaitTreeReady()) .subscribe(() -> { MessageEvent.fire(eventBus, Message.success( - resources.messages().removeContentSuccess(content.getName(), path))); + resources.messages() + .removeContentSuccess(content.getName(), + SafeHtmlUtils.fromTrustedString(path)))); noSelection(); }); }).show(); @@ -707,7 +711,7 @@ private void viewInEditor(ContentEntry contentEntry) { setVisible(previewContainer, false); adjustEditorHeight(); - editorStatus.textContent = contentEntry.name + " - " + Format.humanReadableFileSize(contentEntry.fileSize); + editorStatus.innerHTML = contentEntry.name + " - " + Format.humanReadableFileSize(contentEntry.fileSize); loadContent(contentEntry, result -> { editor.setModeFromPath(contentEntry.name); editor.getEditor().getSession().setValue(result); @@ -802,6 +806,6 @@ private File file(String name, String content) { } private Completable awaitTreeReady() { - return Completable.fromEmitter(emitter -> tree.onReady((event, any) -> emitter.onCompleted())); + return Completable.fromEmitter(emitter -> tree.onReady((event) -> emitter.onCompleted())); } } diff --git a/app/src/main/java/org/jboss/hal/client/deployment/ContentParser.java b/app/src/main/java/org/jboss/hal/client/deployment/ContentParser.java index a2e3437f42..c788d19a04 100644 --- a/app/src/main/java/org/jboss/hal/client/deployment/ContentParser.java +++ b/app/src/main/java/org/jboss/hal/client/deployment/ContentParser.java @@ -23,6 +23,7 @@ import com.google.common.base.Splitter; import com.google.common.collect.Iterables; +import com.google.gwt.safehtml.shared.SafeHtmlUtils; import elemental2.core.JsArray; import org.jboss.hal.ballroom.tree.Node; import org.jboss.hal.dmr.ModelNode; @@ -75,11 +76,12 @@ void parse(Node root, JsArray> nodes, List segments = Splitter.on('/').omitEmptyStrings().split(path); + String safePath = SafeHtmlUtils.htmlEscape(path); + Iterable segments = Splitter.on('/').omitEmptyStrings().split(safePath); ContentEntry contentEntry = new ContentEntry(); contentEntry.name = Iterables.getLast(segments); - contentEntry.path = path; + contentEntry.path = safePath; contentEntry.depth = Iterables.size(segments); contentEntry.directory = node.hasDefined(DIRECTORY) && node.get(DIRECTORY).asBoolean(); contentEntry.fileSize = node.hasDefined(FILE_SIZE) ? node.get(FILE_SIZE).asLong() : 0; diff --git a/app/src/main/java/org/jboss/hal/client/runtime/configurationchanges/ConfigurationChangeDisplay.java b/app/src/main/java/org/jboss/hal/client/runtime/configurationchanges/ConfigurationChangeDisplay.java index c0de73c61d..bd8ae12bff 100644 --- a/app/src/main/java/org/jboss/hal/client/runtime/configurationchanges/ConfigurationChangeDisplay.java +++ b/app/src/main/java/org/jboss/hal/client/runtime/configurationchanges/ConfigurationChangeDisplay.java @@ -94,8 +94,9 @@ public SafeHtml getDescriptionHtml() { boolean allowedProperties = !(prop.getName().equals(OPERATION) || prop.getName() .equals(ADDRESS) || prop.getName().equals(OPERATION_HEADERS)); if (allowedProperties) { + String safeValue = SafeHtmlUtils.htmlEscape(prop.getValue().asString()); html.append(SafeHtmlUtils.fromTrustedString( - "    " + prop.getName() + COLON + prop.getValue() + "
")); + "    " + prop.getName() + COLON + safeValue + "
")); } }); }); diff --git a/app/src/main/java/org/jboss/hal/client/runtime/subsystem/jaxrs/RestResourcePreview.java b/app/src/main/java/org/jboss/hal/client/runtime/subsystem/jaxrs/RestResourcePreview.java index f9c12843fa..c28396cf0f 100644 --- a/app/src/main/java/org/jboss/hal/client/runtime/subsystem/jaxrs/RestResourcePreview.java +++ b/app/src/main/java/org/jboss/hal/client/runtime/subsystem/jaxrs/RestResourcePreview.java @@ -234,7 +234,7 @@ public void onSuccess(ServerUrl url) { Elements.removeChildrenFrom(linkContainer); //noinspection UnstableApiUsage linkContainer.appendChild(a().css(clickable) - .on(click, e -> specifyParameters(url.getUrl(), link, Splitter.on(',') + .on(click, e -> specifyParameters(url.getUrl().asString(), link, Splitter.on(',') .splitToList(linkContainer.dataset.get(LINK)))) .textContent(link).element()); } diff --git a/app/src/main/java/org/jboss/hal/client/runtime/subsystem/undertow/DeploymentPreview.java b/app/src/main/java/org/jboss/hal/client/runtime/subsystem/undertow/DeploymentPreview.java index 3e4b2a2ab6..85a9439e30 100644 --- a/app/src/main/java/org/jboss/hal/client/runtime/subsystem/undertow/DeploymentPreview.java +++ b/app/src/main/java/org/jboss/hal/client/runtime/subsystem/undertow/DeploymentPreview.java @@ -277,7 +277,7 @@ public void onSuccess(ServerUrl url) { for (HTMLElement linkContainer : linkContainers) { String link = linkContainer.textContent; Elements.removeChildrenFrom(linkContainer); - linkContainer.appendChild(a(url.getUrl() + link) + linkContainer.appendChild(a(url.getUrl().asString() + link) .apply(a -> a.target = Ids.hostServer(host, server)) .textContent(link).element()); } diff --git a/ballroom/src/main/java/org/jboss/hal/ballroom/tree/Bridge.java b/ballroom/src/main/java/org/jboss/hal/ballroom/tree/Bridge.java index 36b2f27993..7b71f0f665 100644 --- a/ballroom/src/main/java/org/jboss/hal/ballroom/tree/Bridge.java +++ b/ballroom/src/main/java/org/jboss/hal/ballroom/tree/Bridge.java @@ -26,10 +26,12 @@ class Bridge { @JsMethod(namespace = GLOBAL, name = "$") static native Bridge select(String selector); - native void jstree(Options options); + native void jstree(Options options); @SuppressWarnings("SameParameterValue") native Api jstree(boolean _true); + native void on(String event, SimpleEventHandler handler); + native void on(String event, EventHandler handler); } diff --git a/ballroom/src/main/java/org/jboss/hal/ballroom/tree/SimpleEventHandler.java b/ballroom/src/main/java/org/jboss/hal/ballroom/tree/SimpleEventHandler.java new file mode 100644 index 0000000000..d7bb4f527b --- /dev/null +++ b/ballroom/src/main/java/org/jboss/hal/ballroom/tree/SimpleEventHandler.java @@ -0,0 +1,26 @@ +/* + * Copyright 2022 Red Hat + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jboss.hal.ballroom.tree; + +import elemental2.dom.Event; +import jsinterop.annotations.JsFunction; + +@JsFunction +@FunctionalInterface +public interface SimpleEventHandler { + + void onEvent(Event event); +} diff --git a/ballroom/src/main/java/org/jboss/hal/ballroom/tree/Tree.java b/ballroom/src/main/java/org/jboss/hal/ballroom/tree/Tree.java index 4c2d067a63..309da1ac18 100644 --- a/ballroom/src/main/java/org/jboss/hal/ballroom/tree/Tree.java +++ b/ballroom/src/main/java/org/jboss/hal/ballroom/tree/Tree.java @@ -175,7 +175,7 @@ public void clearSearch() { // ------------------------------------------------------ events - public void onReady(EventHandler handler) { + public void onReady(SimpleEventHandler handler) { bridge().on("ready.jstree", handler); } diff --git a/core/src/main/java/org/jboss/hal/core/runtime/server/ServerActions.java b/core/src/main/java/org/jboss/hal/core/runtime/server/ServerActions.java index 33bcc09eae..104654f63c 100644 --- a/core/src/main/java/org/jboss/hal/core/runtime/server/ServerActions.java +++ b/core/src/main/java/org/jboss/hal/core/runtime/server/ServerActions.java @@ -369,7 +369,7 @@ public void suspend(Server server) { new MetadataProcessor.MetadataCallback() { @Override public void onMetadata(Metadata metadata) { - String id = Ids.build(SUSPEND, server.getName(), Ids.FORM); + String id = Ids.build(SUSPEND, server.getName(), FORM); Form form = new OperationFormBuilder<>(id, metadata, SUSPEND).build(); Dialog dialog = DialogFactory.buildConfirmation( @@ -442,7 +442,7 @@ public void stop(Server server) { new MetadataProcessor.MetadataCallback() { @Override public void onMetadata(Metadata metadata) { - String id = Ids.build(STOP, server.getName(), Ids.FORM); + String id = Ids.build(STOP, server.getName(), FORM); Form form = new OperationFormBuilder<>(id, metadata, STOP) .include(TIMEOUT).build(); @@ -576,9 +576,9 @@ public void onFailure(Throwable caught) { @Override public void onSuccess(ServerUrl url) { Elements.removeChildrenFrom(element); - element.appendChild(a(url.getUrl()) + element.appendChild(a(url.getUrl().asString()) .apply(a -> a.target = server.getId()) - .textContent(url.getUrl()).element()); + .innerHtml(url.getUrl()).element()); String icon; String tooltip; if (url.isCustom()) { @@ -676,7 +676,7 @@ private void show(ServerUrl serverUrl) { dialog.show(); form.edit(new ModelNode()); if (serverUrl != null) { - urlItem.setValue(serverUrl.getUrl()); + urlItem.setValue(serverUrl.getUrl().asString()); } } }); diff --git a/core/src/main/java/org/jboss/hal/core/runtime/server/ServerUrl.java b/core/src/main/java/org/jboss/hal/core/runtime/server/ServerUrl.java index 5f527e623d..6cddcec823 100644 --- a/core/src/main/java/org/jboss/hal/core/runtime/server/ServerUrl.java +++ b/core/src/main/java/org/jboss/hal/core/runtime/server/ServerUrl.java @@ -15,6 +15,9 @@ */ package org.jboss.hal.core.runtime.server; +import com.google.gwt.safehtml.shared.SafeHtml; +import com.google.gwt.safehtml.shared.SafeHtmlUtils; + public class ServerUrl { private final String url; @@ -30,8 +33,8 @@ public String toString() { return "ServerUrl(" + url + '\'' + ", custom=" + custom + ')'; } - public String getUrl() { - return url; + public SafeHtml getUrl() { + return SafeHtmlUtils.fromString(url); } public boolean isCustom() { diff --git a/resources/src/main/java/org/jboss/hal/resources/Messages.java b/resources/src/main/java/org/jboss/hal/resources/Messages.java index 97546003b2..ddd2d8c57f 100644 --- a/resources/src/main/java/org/jboss/hal/resources/Messages.java +++ b/resources/src/main/java/org/jboss/hal/resources/Messages.java @@ -324,8 +324,8 @@ public interface Messages extends com.google.gwt.i18n.client.Messages { SafeHtml removeAliasSuccess(String alias, String resource); SafeHtml removeConfigurationChangesQuestion(String type, String name); SafeHtml removeConfirmationQuestion(String name); - SafeHtml removeContentQuestion(String deployment, String path); - SafeHtml removeContentSuccess(String deployment, String path); + SafeHtml removeContentQuestion(String deployment, SafeHtml path); + SafeHtml removeContentSuccess(String deployment, SafeHtml path); SafeHtml removeCurrentUserError(); SafeHtml removeExtensionQuestion(); SafeHtml removeExtensionSuccess();