From 1898ea4a15c0ef035c2cd4cb9a4fa0b01baeebed Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 27 Oct 2022 17:30:08 +0300 Subject: [PATCH] Minor fixes --- .../api/AbstractScriptInvokeService.java | 2 +- .../api/mvel/DefaultMvelInvokeService.java | 14 +-- .../thingsboard/script/api/mvel/TbUtils.java | 87 +++++++++++++++++++ pom.xml | 2 +- .../node-script-test-dialog.component.html | 1 + 5 files changed, 98 insertions(+), 8 deletions(-) create mode 100644 common/script/script-api/src/main/java/org/thingsboard/script/api/mvel/TbUtils.java diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java index 5f2b6d0b67..bfaadfb4cc 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java @@ -274,7 +274,7 @@ public abstract class AbstractScriptInvokeService implements ScriptInvokeService private boolean resultSizeExceeded(String result) { if (getMaxResultSize() <= 0) return false; - return result.length() > getMaxResultSize(); + return result != null && result.length() > getMaxResultSize(); } private ListenableFuture error(String message) { diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/mvel/DefaultMvelInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/mvel/DefaultMvelInvokeService.java index 54917b7eb5..844f39a6f2 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/mvel/DefaultMvelInvokeService.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/mvel/DefaultMvelInvokeService.java @@ -25,6 +25,7 @@ import lombok.extern.slf4j.Slf4j; import org.mvel2.ExecutionContext; import org.mvel2.MVEL; import org.mvel2.ParserContext; +import org.mvel2.SandboxedParserConfiguration; import org.mvel2.SandboxedParserContext; import org.mvel2.ScriptMemoryOverflowException; import org.mvel2.optimizers.OptimizerFactory; @@ -56,7 +57,7 @@ import java.util.regex.Pattern; public class DefaultMvelInvokeService extends AbstractScriptInvokeService implements MvelInvokeService { protected Map scriptMap = new ConcurrentHashMap<>(); - private ParserContext parserContext; + private SandboxedParserConfiguration parserConfig; private static final Pattern NEW_KEYWORD_PATTERN = Pattern.compile("new\\s"); @@ -108,8 +109,9 @@ public class DefaultMvelInvokeService extends AbstractScriptInvokeService implem public void init() { super.init(); OptimizerFactory.setDefaultOptimizer(OptimizerFactory.SAFE_REFLECTIVE); - parserContext = new SandboxedParserContext(); - parserContext.addImport("JSON", TbJson.class); + parserConfig = new SandboxedParserConfiguration(); + parserConfig.addImport("JSON", TbJson.class); + TbUtils.register(parserConfig); executor = MoreExecutors.listeningDecorator(ThingsBoardExecutors.newWorkStealingPool(threadPoolSize, "mvel-executor")); } @@ -144,7 +146,7 @@ public class DefaultMvelInvokeService extends AbstractScriptInvokeService implem } return executor.submit(() -> { try { - Serializable compiledScript = MVEL.compileExpression(scriptBody, parserContext); + Serializable compiledScript = MVEL.compileExpression(scriptBody, new SandboxedParserContext(parserConfig)); MvelScript script = new MvelScript(compiledScript, scriptBody, argNames); scriptMap.put(scriptId, script); return scriptId; @@ -163,9 +165,9 @@ public class DefaultMvelInvokeService extends AbstractScriptInvokeService implem throw new TbScriptException(scriptId, TbScriptException.ErrorCode.OTHER, null, new RuntimeException("Script not found!")); } try { - return MVEL.executeExpression(script.getCompiledScript(), executionContext, script.createVars(args)); + return MVEL.executeTbExpression(script.getCompiledScript(), executionContext, script.createVars(args)); } catch (ScriptMemoryOverflowException e) { - throw new TbScriptException(scriptId, TbScriptException.ErrorCode.OTHER, script.getScriptBody(), new RuntimeException("Memory error!")); + throw new TbScriptException(scriptId, TbScriptException.ErrorCode.OTHER, script.getScriptBody(), new RuntimeException("Script memory overflow!")); } catch (Exception e) { throw new TbScriptException(scriptId, TbScriptException.ErrorCode.RUNTIME, script.getScriptBody(), e); } diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/mvel/TbUtils.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/mvel/TbUtils.java new file mode 100644 index 0000000000..03d9f77b85 --- /dev/null +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/mvel/TbUtils.java @@ -0,0 +1,87 @@ +/** + * Copyright © 2016-2022 The Thingsboard Authors + * + * 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 + * + * http://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.thingsboard.script.api.mvel; + +import org.mvel2.ExecutionContext; +import org.mvel2.ParserConfiguration; +import org.mvel2.execution.ExecutionArrayList; +import org.mvel2.util.MethodStub; + +import java.io.UnsupportedEncodingException; +import java.util.Base64; +import java.util.List; + +public class TbUtils { + + public static void register(ParserConfiguration parserConfig) throws Exception { + parserConfig.addImport("btoa", new MethodStub(TbUtils.class.getMethod("btoa", + String.class))); + parserConfig.addImport("atob", new MethodStub(TbUtils.class.getMethod("atob", + String.class))); + parserConfig.addImport("bytesToString", new MethodStub(TbUtils.class.getMethod("bytesToString", + List.class))); + parserConfig.addImport("bytesToString", new MethodStub(TbUtils.class.getMethod("bytesToString", + List.class, String.class))); + parserConfig.addImport("stringToBytes", new MethodStub(TbUtils.class.getMethod("stringToBytes", + ExecutionContext.class, String.class))); + parserConfig.addImport("stringToBytes", new MethodStub(TbUtils.class.getMethod("stringToBytes", + ExecutionContext.class, String.class, String.class))); + } + + public static String btoa(String input) { + return new String(Base64.getEncoder().encode(input.getBytes())); + } + + public static String atob(String encoded) { + return new String(Base64.getDecoder().decode(encoded)); + } + + public static String bytesToString(List bytesList) { + byte[] bytes = bytesFromList(bytesList); + return new String(bytes); + } + + public static String bytesToString(List bytesList, String charsetName) throws UnsupportedEncodingException { + byte[] bytes = bytesFromList(bytesList); + return new String(bytes, charsetName); + } + + public static List stringToBytes(ExecutionContext ctx, String str) { + byte[] bytes = str.getBytes(); + return bytesToList(ctx, bytes); + } + + public static List stringToBytes(ExecutionContext ctx, String str, String charsetName) throws UnsupportedEncodingException { + byte[] bytes = str.getBytes(charsetName); + return bytesToList(ctx, bytes); + } + + private static byte[] bytesFromList(List bytesList) { + byte[] bytes = new byte[bytesList.size()]; + for (int i = 0; i < bytesList.size(); i++) { + bytes[i] = bytesList.get(i); + } + return bytes; + } + + private static List bytesToList(ExecutionContext ctx, byte[] bytes) { + List list = new ExecutionArrayList<>(ctx); + for (int i = 0; i < bytes.length; i++) { + list.add(bytes[i]); + } + return list; + } +} diff --git a/pom.xml b/pom.xml index 9589570026..46cc74f2dc 100755 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ 3.5.5 3.17.2 1.42.1 - 2.4.16TB + 2.4.19TB 1.18.18 1.2.4 4.1.75.Final diff --git a/ui-ngx/src/app/shared/components/dialog/node-script-test-dialog.component.html b/ui-ngx/src/app/shared/components/dialog/node-script-test-dialog.component.html index 8d7179d2cf..c0f0ff4b42 100644 --- a/ui-ngx/src/app/shared/components/dialog/node-script-test-dialog.component.html +++ b/ui-ngx/src/app/shared/components/dialog/node-script-test-dialog.component.html @@ -77,6 +77,7 @@ functionName="{{ data.functionName }}" [functionArgs]="data.argNames" [validationArgs]="[data.msg, data.metadata, data.msgType]" + [disableUndefinedCheck]="scriptLang === scriptLanguage.MVEL" resultType="object" [helpId]="data.helpId" [fillHeight]="true">