diff --git a/WebContent/WEB-INF/jsp/include/highlight.jsp b/WebContent/WEB-INF/jsp/include/highlight.jsp index 1f2d229dc4..41ad467f82 100644 --- a/WebContent/WEB-INF/jsp/include/highlight.jsp +++ b/WebContent/WEB-INF/jsp/include/highlight.jsp @@ -15,9 +15,6 @@ function updateCodeText(text, destination) { function updateCodeTextEscaped(text, destination) { let result_element = document.querySelector(destination); - if(text[text.length-1] == "\n") { - text += " "; - } result_element.innerHTML = text; hljs.highlightElement(result_element); } diff --git a/WebContent/WEB-INF/jsp/systemSettings.jsp b/WebContent/WEB-INF/jsp/systemSettings.jsp index 35899f2afa..c8e12ff945 100644 --- a/WebContent/WEB-INF/jsp/systemSettings.jsp +++ b/WebContent/WEB-INF/jsp/systemSettings.jsp @@ -33,7 +33,7 @@
@@ -1142,13 +1163,18 @@
- + - +
+ + + + +
diff --git a/WebContent/WEB-INF/lib/classmate-1.3.4.jar b/WebContent/WEB-INF/lib/classmate-1.3.4.jar new file mode 100644 index 0000000000..5be6d9961f Binary files /dev/null and b/WebContent/WEB-INF/lib/classmate-1.3.4.jar differ diff --git a/WebContent/WEB-INF/lib/cssparser-0.9.30.jar b/WebContent/WEB-INF/lib/cssparser-0.9.30.jar new file mode 100644 index 0000000000..1ee9271c84 Binary files /dev/null and b/WebContent/WEB-INF/lib/cssparser-0.9.30.jar differ diff --git a/WebContent/WEB-INF/lib/hibernate-validator-6.0.23.Final.jar b/WebContent/WEB-INF/lib/hibernate-validator-6.0.23.Final.jar new file mode 100644 index 0000000000..a6bed2af81 Binary files /dev/null and b/WebContent/WEB-INF/lib/hibernate-validator-6.0.23.Final.jar differ diff --git a/WebContent/WEB-INF/lib/jboss-logging-3.3.2.Final.jar b/WebContent/WEB-INF/lib/jboss-logging-3.3.2.Final.jar new file mode 100644 index 0000000000..67cde710fc Binary files /dev/null and b/WebContent/WEB-INF/lib/jboss-logging-3.3.2.Final.jar differ diff --git a/WebContent/WEB-INF/lib/sac-1.3.jar b/WebContent/WEB-INF/lib/sac-1.3.jar new file mode 100644 index 0000000000..39b92b1d89 Binary files /dev/null and b/WebContent/WEB-INF/lib/sac-1.3.jar differ diff --git a/WebContent/WEB-INF/lib/validation-api-2.0.1.Final.jar b/WebContent/WEB-INF/lib/validation-api-2.0.1.Final.jar new file mode 100644 index 0000000000..2368e10a53 Binary files /dev/null and b/WebContent/WEB-INF/lib/validation-api-2.0.1.Final.jar differ diff --git a/build.gradle b/build.gradle index d4ef81117f..2962dd4b1e 100644 --- a/build.gradle +++ b/build.gradle @@ -242,6 +242,7 @@ test { includeTestsMatching "org.scada_lts.utils.BlockingQueuesUtilsTest" includeTestsMatching "org.scada_lts.web.security.XssProtectHtmlEscapeUtilsTest" includeTestsMatching "org.scada_lts.web.security.XssUtilsTest" + includeTestsMatching "org.scada_lts.web.mvc.api.css.validation.utils.CssValidatorTestsSuite" } failFast = true diff --git a/src/org/scada_lts/config/ScadaConfig.java b/src/org/scada_lts/config/ScadaConfig.java index a509ff4726..379154faa7 100644 --- a/src/org/scada_lts/config/ScadaConfig.java +++ b/src/org/scada_lts/config/ScadaConfig.java @@ -148,6 +148,7 @@ public class ScadaConfig { private static final String FILE_NAME_PROPERTIES="env.properties"; private static final String FILE_NAME_CUSTOM_CSS="common.css"; private static final String DIR_NAME_CUSTOM_CONFIG="assets"; + private static final String FILE_NAME_USER_STYLESHEET="user_styles.css"; private static ScadaConfig instance = null; @@ -424,6 +425,5 @@ private static String getPathCustomConfig() { return path; } - } diff --git a/src/org/scada_lts/dao/SystemSettingsDAO.java b/src/org/scada_lts/dao/SystemSettingsDAO.java index 12aa9edcce..f469be10e4 100644 --- a/src/org/scada_lts/dao/SystemSettingsDAO.java +++ b/src/org/scada_lts/dao/SystemSettingsDAO.java @@ -166,6 +166,7 @@ public class SystemSettingsDAO { public static final String EVENT_ASSIGN_ENABLED = "eventAssignEnabled"; public static final String TOP_DESCRIPTION_PREFIX = "topDescriptionPrefix"; public static final String TOP_DESCRIPTION = "topDescription"; + public static final String CUSTOM_CSS_CONTENT = "customCssContent"; // @formatter:off private static final String SELECT_SETTING_VALUE_WHERE = "" @@ -418,7 +419,8 @@ public String getDatabaseSchemaVersion(String key, String defaultValue) { DEFAULT_VALUES.put(EVENT_ASSIGN_ENABLED, SystemSettingsUtils.isEventAssignEnabled()); DEFAULT_VALUES.put(TOP_DESCRIPTION, ""); DEFAULT_VALUES.put(TOP_DESCRIPTION_PREFIX, ""); - } + DEFAULT_VALUES.put(CUSTOM_CSS_CONTENT, SystemSettingsUtils.getCustomCssContent()); + } @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED, rollbackFor = SQLException.class) public void resetDataBase() { diff --git a/src/org/scada_lts/mango/adapter/MangoScadaConfig.java b/src/org/scada_lts/mango/adapter/MangoScadaConfig.java index 4781584670..27f05773fd 100644 --- a/src/org/scada_lts/mango/adapter/MangoScadaConfig.java +++ b/src/org/scada_lts/mango/adapter/MangoScadaConfig.java @@ -21,6 +21,9 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.scada_lts.config.ScadaConfig; +import org.scada_lts.mango.service.SystemSettingsService; +import org.scada_lts.web.mvc.api.css.CssStyle; +import org.scada_lts.web.mvc.api.css.CustomCssUtils; /** @@ -55,6 +58,11 @@ public void init() { LOG.info("copy env.properties"); ScadaConfig.copyConfig(); } + + LOG.info("loading user_styles.css form database"); + SystemSettingsService service = new SystemSettingsService(); + CssStyle cssStyle = service.getCustomCss(); + CustomCssUtils.saveToFile(cssStyle); } diff --git a/src/org/scada_lts/mango/service/SystemSettingsService.java b/src/org/scada_lts/mango/service/SystemSettingsService.java index a1c1e889d9..049c75a970 100644 --- a/src/org/scada_lts/mango/service/SystemSettingsService.java +++ b/src/org/scada_lts/mango/service/SystemSettingsService.java @@ -24,6 +24,7 @@ import org.scada_lts.utils.SystemSettingsUtils; import org.scada_lts.web.beans.ApplicationBeans; import org.scada_lts.web.mvc.api.AggregateSettings; +import org.scada_lts.web.mvc.api.css.CssStyle; import org.scada_lts.web.mvc.api.json.*; import org.springframework.stereotype.Service; @@ -519,4 +520,13 @@ private static Map deserializeMap(String json) { return Collections.emptyMap(); } } + + public CssStyle getCustomCss() { + String content = SystemSettingsDAO.getValue(SystemSettingsDAO.CUSTOM_CSS_CONTENT); + return new CssStyle(content); + } + + public void saveCustomCss(CssStyle cssStyle) { + systemSettingsDAO.setValue(SystemSettingsDAO.CUSTOM_CSS_CONTENT, cssStyle.getContent()); + } } diff --git a/src/org/scada_lts/utils/SystemSettingsUtils.java b/src/org/scada_lts/utils/SystemSettingsUtils.java index c0dab97fff..39c630d476 100644 --- a/src/org/scada_lts/utils/SystemSettingsUtils.java +++ b/src/org/scada_lts/utils/SystemSettingsUtils.java @@ -73,6 +73,8 @@ private SystemSettingsUtils() {} private static final String SECURITY_HTTP_QUERY_LIMIT_KEY = "scadalts.security.http.query.limit"; private static final String SECURITY_HTTP_QUERY_PROTECT_ENABLED_KEY = "scadalts.security.http.query.protect.enabled"; + private static final String CUSTOM_CSS_CONTENT_KEY = "systemsettings.custom.css.content"; + private static final org.apache.commons.logging.Log LOG = LogFactory.getLog(SystemSettingsUtils.class); public static DataPointSyncMode getDataPointSynchronizedMode() { @@ -594,4 +596,13 @@ public static boolean isSecurityHttpQueryProtectEnabled() { return false; } } + + public static String getCustomCssContent() { + try { + return ScadaConfig.getInstance().getConf().getProperty(CUSTOM_CSS_CONTENT_KEY, ""); + } catch (Exception e) { + LOG.error(e.getMessage()); + return ""; + } + } } diff --git a/src/org/scada_lts/web/mvc/api/CustomCssAPI.java b/src/org/scada_lts/web/mvc/api/CustomCssAPI.java index 0fa9823069..2c063da8e1 100644 --- a/src/org/scada_lts/web/mvc/api/CustomCssAPI.java +++ b/src/org/scada_lts/web/mvc/api/CustomCssAPI.java @@ -1,80 +1,71 @@ package org.scada_lts.web.mvc.api; -import com.serotonin.mango.Common; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.scada_lts.mango.service.SystemSettingsService; +import org.scada_lts.serorepl.utils.StringUtils; import org.scada_lts.web.mvc.api.css.CssStyle; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; -import java.io.*; -import java.nio.file.Files; +import javax.validation.Valid; -@Controller +import java.util.List; +import java.util.stream.Collectors; + +import static org.scada_lts.web.mvc.api.css.CustomCssUtils.saveToFile; + +@RestController @RequestMapping("/api/customcss") public class CustomCssAPI { private static final Log LOG = LogFactory.getLog(CustomCssAPI.class); - private static final String CSS_FILENAME = "/assets/user_styles.css"; - private static final String REQ_RESP_ERROR = "Couldn't create a *.css file."; + private final SystemSettingsService systemSettingsService; + + public CustomCssAPI(SystemSettingsService systemSettingsService) { + this.systemSettingsService = systemSettingsService; + } - @GetMapping("/") - public ResponseEntity getCustomCssFile(HttpServletRequest request) { + @GetMapping(value = "", produces = {"application/json;charset=UTF-8"}) + public ResponseEntity getCustomCss(HttpServletRequest request) { LOG.info("GET: /api/customcss"); try { - File cssFile = getCustomCssFileFromPath(); - if(cssFile != null) { - String content = Files.readString(cssFile.toPath()); - return new ResponseEntity<>(new CssStyle(content), HttpStatus.OK); - } else { - return new ResponseEntity<>(REQ_RESP_ERROR,HttpStatus.INTERNAL_SERVER_ERROR); + CssStyle customCss = systemSettingsService.getCustomCss(); + if (!StringUtils.isEmpty(customCss.getContent())) { + return new ResponseEntity<>(customCss.clearedOfTabs(), HttpStatus.OK); } + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } catch (Exception e) { LOG.error(e); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } } - @PostMapping("/") - public ResponseEntity saveCustomCssFile(HttpServletRequest request, @RequestBody String fileContent) { + @PostMapping(value = "", consumes = {"application/json;charset=UTF-8"}) + public ResponseEntity saveCustomCss(HttpServletRequest request, @Valid @RequestBody(required = true) CssStyle cssStyle, BindingResult bindingResult) { LOG.info("POST: /api/customcss"); + if (bindingResult.hasErrors()) { + List errors = bindingResult.getFieldErrors().stream() + .map(error -> error.getDefaultMessage()) + .collect(Collectors.toList()); + + return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST); + } + try { - File cssFile = getCustomCssFileFromPath(); - if(cssFile != null) { - try (BufferedWriter writer = new BufferedWriter(new FileWriter(cssFile.getAbsolutePath()))) { - writer.write(fileContent); - } + if (!StringUtils.isEmpty(cssStyle.getContent())) { + systemSettingsService.saveCustomCss(cssStyle); + saveToFile(cssStyle); return new ResponseEntity<>(HttpStatus.OK); - } else { - return new ResponseEntity<>(REQ_RESP_ERROR, HttpStatus.INTERNAL_SERVER_ERROR); } + return new ResponseEntity<>(HttpStatus.BAD_REQUEST); } catch (Exception e) { LOG.error(e); return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR); } - - } - - private File getCustomCssFileFromPath() { - try { - File cssFile = new File(Common.ctx.getCtx().getRealPath(CSS_FILENAME)); - if(!cssFile.exists()) { - boolean created = cssFile.createNewFile(); - if(created) { - LOG.info("Created custom CSS stylesheet file: " + CSS_FILENAME); - } - } - return cssFile; - } catch (IOException e) { - LOG.error("Could not create a custom CSS file: " + CSS_FILENAME); - } - return null; } } diff --git a/src/org/scada_lts/web/mvc/api/css/CssStyle.java b/src/org/scada_lts/web/mvc/api/css/CssStyle.java index a969130d35..a152ea0a39 100644 --- a/src/org/scada_lts/web/mvc/api/css/CssStyle.java +++ b/src/org/scada_lts/web/mvc/api/css/CssStyle.java @@ -1,13 +1,25 @@ package org.scada_lts.web.mvc.api.css; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.scada_lts.web.mvc.api.css.validation.CssValid; + public class CssStyle { + + @CssValid private final String content; - public CssStyle(String content) { - this.content = content; + @JsonCreator(mode = JsonCreator.Mode.PROPERTIES) + public CssStyle(@JsonProperty("content") String content) { + this.content = CustomCssUtils.replaceToTab(content); } public String getContent() { return content; } + + public CssStyle clearedOfTabs() { + return new CssStyle(getContent().replace("\t", " ")); + } } diff --git a/src/org/scada_lts/web/mvc/api/css/CustomCssUtils.java b/src/org/scada_lts/web/mvc/api/css/CustomCssUtils.java new file mode 100644 index 0000000000..feb7c0d9c4 --- /dev/null +++ b/src/org/scada_lts/web/mvc/api/css/CustomCssUtils.java @@ -0,0 +1,61 @@ +package org.scada_lts.web.mvc.api.css; + +import com.serotonin.mango.util.LoggingUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.scada_lts.utils.PathSecureUtils; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +public class CustomCssUtils { + + private static final Log LOG = LogFactory.getLog(CustomCssUtils.class); + private static final String CSS_FILENAME = "/assets/user_styles.css"; + private static final String TAB = new String(new byte[]{-30, -128, -125}, StandardCharsets.UTF_8); + + public static boolean saveToFile(CssStyle cssStyle) { + try { + File customCssFile = getCustomCssFileFromPath(); + if (customCssFile != null) { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(customCssFile, StandardCharsets.UTF_8))) { + writer.write(cssStyle.getContent()); + } + } + return true; + } catch (Exception ex) { + LOG.warn(LoggingUtils.exceptionInfo(ex)); + return false; + } + } + + private static File getCustomCssFileFromPath() { + try { + Path path = PathSecureUtils.getAppContextSystemFilePath(CSS_FILENAME); + File cssFile = path.toFile(); + if(Files.exists(path) == Files.notExists(path)) { + LOG.warn("Missing file permissions!: " + CSS_FILENAME); + return null; + } + if(Files.notExists(path)) { + boolean created = cssFile.createNewFile(); + if(created) { + LOG.info("Created custom CSS stylesheet file: " + CSS_FILENAME); + } + } + return cssFile; + } catch (IOException e) { + LOG.warn("Could not create a custom CSS file: " + CSS_FILENAME); + } + return null; + } + + public static String replaceToTab(String content) { + return content.replace(TAB, "\t"); + } +} diff --git a/src/org/scada_lts/web/mvc/api/css/validation/CssConstraintValidator.java b/src/org/scada_lts/web/mvc/api/css/validation/CssConstraintValidator.java new file mode 100644 index 0000000000..a57b3af538 --- /dev/null +++ b/src/org/scada_lts/web/mvc/api/css/validation/CssConstraintValidator.java @@ -0,0 +1,39 @@ +package org.scada_lts.web.mvc.api.css.validation; + + +import com.serotonin.mango.util.LoggingUtils; +import org.scada_lts.serorepl.utils.StringUtils; +import org.scada_lts.web.mvc.api.css.validation.utils.CssValidator; +import org.scada_lts.web.mvc.api.css.validation.utils.SacCssValidator; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + + +public class CssConstraintValidator implements ConstraintValidator { + + @Override + public void initialize(CssValid constraintAnnotation) { + } + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + if (StringUtils.isEmpty(value)) { + addErrors(context, "Empty"); + return false; + } + try { + CssValidator validator = new SacCssValidator(); + validator.validate(value); + return true; + }catch (Exception e) { + addErrors(context, LoggingUtils.causeInfo(e)); + return false; + } + } + + private static void addErrors(ConstraintValidatorContext context, String msg) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate("Unexpected error: " + msg).addConstraintViolation(); + } +} diff --git a/src/org/scada_lts/web/mvc/api/css/validation/CssValid.java b/src/org/scada_lts/web/mvc/api/css/validation/CssValid.java new file mode 100644 index 0000000000..f48f46fc1f --- /dev/null +++ b/src/org/scada_lts/web/mvc/api/css/validation/CssValid.java @@ -0,0 +1,16 @@ +package org.scada_lts.web.mvc.api.css.validation; + + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.*; + +@Documented +@Constraint(validatedBy = CssConstraintValidator.class) +@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +public @interface CssValid { + String message() default "Wrong Css format detected"; + Class[] groups() default {}; + Class[] payload() default {}; +} diff --git a/src/org/scada_lts/web/mvc/api/css/validation/utils/CssValidator.java b/src/org/scada_lts/web/mvc/api/css/validation/utils/CssValidator.java new file mode 100644 index 0000000000..8ed98f7ab3 --- /dev/null +++ b/src/org/scada_lts/web/mvc/api/css/validation/utils/CssValidator.java @@ -0,0 +1,6 @@ +package org.scada_lts.web.mvc.api.css.validation.utils; + +public interface CssValidator { + + void validate(String style) throws CustomCssException; +} diff --git a/src/org/scada_lts/web/mvc/api/css/validation/utils/CustomCssException.java b/src/org/scada_lts/web/mvc/api/css/validation/utils/CustomCssException.java new file mode 100644 index 0000000000..c9561bc583 --- /dev/null +++ b/src/org/scada_lts/web/mvc/api/css/validation/utils/CustomCssException.java @@ -0,0 +1,23 @@ +package org.scada_lts.web.mvc.api.css.validation.utils; + +public class CustomCssException extends Exception { + + public CustomCssException() { + } + + public CustomCssException(String message) { + super(message); + } + + public CustomCssException(String message, Throwable cause) { + super(message, cause); + } + + public CustomCssException(Throwable cause) { + super(cause); + } + + public CustomCssException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/src/org/scada_lts/web/mvc/api/css/validation/utils/SacCssValidator.java b/src/org/scada_lts/web/mvc/api/css/validation/utils/SacCssValidator.java new file mode 100644 index 0000000000..ebefad4d16 --- /dev/null +++ b/src/org/scada_lts/web/mvc/api/css/validation/utils/SacCssValidator.java @@ -0,0 +1,53 @@ +package org.scada_lts.web.mvc.api.css.validation.utils; + +import com.steadystate.css.parser.SACParserCSS3; +import org.w3c.css.sac.*; + +import java.io.IOException; +import java.io.StringReader; + +public final class SacCssValidator implements CssValidator { + + private final Parser parser; + + public SacCssValidator() { + this.parser = createParser(); + } + + @Override + public void validate(String style) throws CustomCssException { + try { + validateStyle(parser, style); + } catch (Exception e) { + throw new CustomCssException(e.getMessage(), e); + } + } + + private static void validateStyle(Parser parser, String value) throws CSSParseException, IOException { + try (StringReader stringReader = new StringReader(value)) { + InputSource inputSource = new InputSource(stringReader); + parser.parseStyleSheet(inputSource); + } + } + + private static Parser createParser() { + Parser parser = new SACParserCSS3(); + parser.setErrorHandler(new ErrorHandler() { + @Override + public void warning(CSSParseException e) throws CSSException { + throw e; + } + + @Override + public void error(CSSParseException e) throws CSSException { + throw e; + } + + @Override + public void fatalError(CSSParseException e) throws CSSException { + throw e; + } + }); + return parser; + } +} diff --git a/test/org/scada_lts/web/mvc/api/css/validation/utils/CssValidatorExceptionTest.java b/test/org/scada_lts/web/mvc/api/css/validation/utils/CssValidatorExceptionTest.java new file mode 100644 index 0000000000..c15f26dab8 --- /dev/null +++ b/test/org/scada_lts/web/mvc/api/css/validation/utils/CssValidatorExceptionTest.java @@ -0,0 +1,37 @@ +package org.scada_lts.web.mvc.api.css.validation.utils; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; +import java.util.Collection; + +@RunWith(Parameterized.class) +public class CssValidatorExceptionTest { + + @Parameterized.Parameters(name = "{index}: CSS: {0}") + public static Collection data() { + return Arrays.asList(new Object[][]{ + {"body { color: ; }"}, + {"#id { background-color: #ggg; }"}, + {"div { margin; }"}, + {"@media screen and (max-width: 600px) { h1 { font-size: 30px }"}, + {"body { color red; }"}, + {"\">"}, + }); + } + + private final String css; + public final CssValidator validator; + + public CssValidatorExceptionTest(String css) { + this.css = css; + this.validator = new SacCssValidator(); + } + + @Test(expected = CustomCssException.class) + public void when_isInvalidCss() throws CustomCssException { + validator.validate(css); + } +} diff --git a/test/org/scada_lts/web/mvc/api/css/validation/utils/CssValidatorTest.java b/test/org/scada_lts/web/mvc/api/css/validation/utils/CssValidatorTest.java new file mode 100644 index 0000000000..d3658ed1ec --- /dev/null +++ b/test/org/scada_lts/web/mvc/api/css/validation/utils/CssValidatorTest.java @@ -0,0 +1,37 @@ +package org.scada_lts.web.mvc.api.css.validation.utils; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; +import java.util.Collection; + +@RunWith(Parameterized.class) +public class CssValidatorTest { + + @Parameterized.Parameters(name = "{index}: CSS: {0}") + public static Collection data() { + return Arrays.asList(new Object[][]{ + {"body { color: red; }"}, + {"h1 { font-size: 20px; }"}, + {"#id { background-color: #fff; }"}, + {"div { margin: 0 auto; padding: 10px; }"}, + {".class { border: 1px solid black; }"}, + {"p { line-height: 1.5; }"}, + }); + } + + private final String css; + public final CssValidator validator; + + public CssValidatorTest(String css) { + this.css = css; + this.validator = new SacCssValidator(); + } + + @Test + public void when_isValidCss() throws CustomCssException { + validator.validate(css); + } +} diff --git a/test/org/scada_lts/web/mvc/api/css/validation/utils/CssValidatorTestsSuite.java b/test/org/scada_lts/web/mvc/api/css/validation/utils/CssValidatorTestsSuite.java new file mode 100644 index 0000000000..affe36a966 --- /dev/null +++ b/test/org/scada_lts/web/mvc/api/css/validation/utils/CssValidatorTestsSuite.java @@ -0,0 +1,12 @@ +package org.scada_lts.web.mvc.api.css.validation.utils; + +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +@RunWith(Suite.class) +@Suite.SuiteClasses({ + CssValidatorTest.class, + CssValidatorExceptionTest.class +}) +public class CssValidatorTestsSuite { +} diff --git a/webapp-resources/env.properties b/webapp-resources/env.properties index 84ca3ac51b..00c3f7ed82 100644 --- a/webapp-resources/env.properties +++ b/webapp-resources/env.properties @@ -191,3 +191,5 @@ scadalts.security.http.query.protect.enabled=true scadalts.security.http.query.limit=3900 scadalts.security.http.query.access.denied.regex=^(.*?(script>||