NoXss and length validation for notification entities
This commit is contained in:
parent
5a57657479
commit
e926854911
@ -103,7 +103,6 @@ import org.thingsboard.server.common.data.rpc.Rpc;
|
|||||||
import org.thingsboard.server.common.data.rule.RuleChain;
|
import org.thingsboard.server.common.data.rule.RuleChain;
|
||||||
import org.thingsboard.server.common.data.rule.RuleChainType;
|
import org.thingsboard.server.common.data.rule.RuleChainType;
|
||||||
import org.thingsboard.server.common.data.rule.RuleNode;
|
import org.thingsboard.server.common.data.rule.RuleNode;
|
||||||
import org.thingsboard.server.common.data.settings.UserDashboardAction;
|
|
||||||
import org.thingsboard.server.common.data.util.ThrowingBiFunction;
|
import org.thingsboard.server.common.data.util.ThrowingBiFunction;
|
||||||
import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
|
import org.thingsboard.server.common.data.widget.WidgetTypeDetails;
|
||||||
import org.thingsboard.server.common.data.widget.WidgetsBundle;
|
import org.thingsboard.server.common.data.widget.WidgetsBundle;
|
||||||
@ -130,12 +129,12 @@ import org.thingsboard.server.dao.queue.QueueService;
|
|||||||
import org.thingsboard.server.dao.relation.RelationService;
|
import org.thingsboard.server.dao.relation.RelationService;
|
||||||
import org.thingsboard.server.dao.rpc.RpcService;
|
import org.thingsboard.server.dao.rpc.RpcService;
|
||||||
import org.thingsboard.server.dao.rule.RuleChainService;
|
import org.thingsboard.server.dao.rule.RuleChainService;
|
||||||
|
import org.thingsboard.server.dao.service.ConstraintValidator;
|
||||||
import org.thingsboard.server.dao.service.Validator;
|
import org.thingsboard.server.dao.service.Validator;
|
||||||
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
|
import org.thingsboard.server.dao.tenant.TbTenantProfileCache;
|
||||||
import org.thingsboard.server.dao.tenant.TenantProfileService;
|
import org.thingsboard.server.dao.tenant.TenantProfileService;
|
||||||
import org.thingsboard.server.dao.tenant.TenantService;
|
import org.thingsboard.server.dao.tenant.TenantService;
|
||||||
import org.thingsboard.server.dao.user.UserService;
|
import org.thingsboard.server.dao.user.UserService;
|
||||||
import org.thingsboard.server.dao.user.UserSettingsService;
|
|
||||||
import org.thingsboard.server.dao.widget.WidgetTypeService;
|
import org.thingsboard.server.dao.widget.WidgetTypeService;
|
||||||
import org.thingsboard.server.dao.widget.WidgetsBundleService;
|
import org.thingsboard.server.dao.widget.WidgetsBundleService;
|
||||||
import org.thingsboard.server.exception.ThingsboardErrorResponseHandler;
|
import org.thingsboard.server.exception.ThingsboardErrorResponseHandler;
|
||||||
@ -164,7 +163,9 @@ import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService;
|
|||||||
|
|
||||||
import javax.mail.MessagingException;
|
import javax.mail.MessagingException;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.validation.ConstraintViolation;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@ -395,16 +396,19 @@ public abstract class BaseController {
|
|||||||
* Handles validation error for controller method arguments annotated with @{@link javax.validation.Valid}
|
* Handles validation error for controller method arguments annotated with @{@link javax.validation.Valid}
|
||||||
* */
|
* */
|
||||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||||
public void handleValidationError(MethodArgumentNotValidException e, HttpServletResponse response) {
|
public void handleValidationError(MethodArgumentNotValidException validationError, HttpServletResponse response) {
|
||||||
String errorMessage = "Validation error: " + e.getFieldErrors().stream()
|
List<ConstraintViolation<Object>> constraintsViolations = validationError.getFieldErrors().stream()
|
||||||
.map(fieldError -> {
|
.map(fieldError -> {
|
||||||
String property = fieldError.getField();
|
try {
|
||||||
if (property.equals("valid") || StringUtils.endsWith(property, ".valid")) { // when custom @AssertTrue is used
|
return (ConstraintViolation<Object>) fieldError.unwrap(ConstraintViolation.class);
|
||||||
property = "";
|
} catch (Exception e) {
|
||||||
|
log.warn("FieldError source is not of type ConstraintViolation");
|
||||||
|
return null; // should not happen
|
||||||
}
|
}
|
||||||
return (!property.isEmpty() ? (property + " ") : "") + fieldError.getDefaultMessage();
|
|
||||||
})
|
})
|
||||||
.collect(Collectors.joining(", "));
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
String errorMessage = "Validation error: " + ConstraintValidator.getErrorMessage(constraintsViolations);
|
||||||
ThingsboardException thingsboardException = new ThingsboardException(errorMessage, ThingsboardErrorCode.BAD_REQUEST_PARAMS);
|
ThingsboardException thingsboardException = new ThingsboardException(errorMessage, ThingsboardErrorCode.BAD_REQUEST_PARAMS);
|
||||||
handleControllerException(thingsboardException, response);
|
handleControllerException(thingsboardException, response);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -125,8 +125,10 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
|
|||||||
NotificationRuleId ruleId = request.getRuleId();
|
NotificationRuleId ruleId = request.getRuleId();
|
||||||
notificationTemplate.getConfiguration().getDeliveryMethodsTemplates().forEach((deliveryMethod, template) -> {
|
notificationTemplate.getConfiguration().getDeliveryMethodsTemplates().forEach((deliveryMethod, template) -> {
|
||||||
if (!template.isEnabled()) return;
|
if (!template.isEnabled()) return;
|
||||||
if (!channels.get(deliveryMethod).check(tenantId)) {
|
try {
|
||||||
throw new IllegalArgumentException("Unable to send notification via " + deliveryMethod.getName() + ": not configured or not working");
|
channels.get(deliveryMethod).check(tenantId);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new IllegalArgumentException(e.getMessage());
|
||||||
}
|
}
|
||||||
if (ruleId == null) {
|
if (ruleId == null) {
|
||||||
if (targets.stream().noneMatch(target -> target.getConfiguration().getType().getSupportedDeliveryMethods().contains(deliveryMethod))) {
|
if (targets.stream().noneMatch(target -> target.getConfiguration().getType().getSupportedDeliveryMethods().contains(deliveryMethod))) {
|
||||||
@ -341,14 +343,20 @@ public class DefaultNotificationCenter extends AbstractSubscriptionService imple
|
|||||||
@Override
|
@Override
|
||||||
public Set<NotificationDeliveryMethod> getAvailableDeliveryMethods(TenantId tenantId) {
|
public Set<NotificationDeliveryMethod> getAvailableDeliveryMethods(TenantId tenantId) {
|
||||||
return channels.values().stream()
|
return channels.values().stream()
|
||||||
.filter(channel -> channel.check(tenantId))
|
.filter(channel -> {
|
||||||
|
try {
|
||||||
|
channel.check(tenantId);
|
||||||
|
return true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
})
|
||||||
.map(NotificationChannel::getDeliveryMethod)
|
.map(NotificationChannel::getDeliveryMethod)
|
||||||
.collect(Collectors.toSet());
|
.collect(Collectors.toSet());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean check(TenantId tenantId) {
|
public void check(TenantId tenantId) throws Exception {
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -48,12 +48,11 @@ public class EmailNotificationChannel implements NotificationChannel<User, Email
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean check(TenantId tenantId) {
|
public void check(TenantId tenantId) throws Exception {
|
||||||
try {
|
try {
|
||||||
mailService.testConnection(tenantId);
|
mailService.testConnection(tenantId);
|
||||||
return true;
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return false;
|
throw new RuntimeException("Mail server is not available");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@ public interface NotificationChannel<R extends NotificationRecipient, T extends
|
|||||||
|
|
||||||
ListenableFuture<Void> sendNotification(R recipient, T processedTemplate, NotificationProcessingContext ctx);
|
ListenableFuture<Void> sendNotification(R recipient, T processedTemplate, NotificationProcessingContext ctx);
|
||||||
|
|
||||||
boolean check(TenantId tenantId);
|
void check(TenantId tenantId) throws Exception;
|
||||||
|
|
||||||
NotificationDeliveryMethod getDeliveryMethod();
|
NotificationDeliveryMethod getDeliveryMethod();
|
||||||
|
|
||||||
|
|||||||
@ -22,12 +22,12 @@ import org.thingsboard.rule.engine.api.slack.SlackService;
|
|||||||
import org.thingsboard.server.common.data.id.TenantId;
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||||
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
|
import org.thingsboard.server.common.data.notification.settings.NotificationSettings;
|
||||||
import org.thingsboard.server.dao.notification.NotificationSettingsService;
|
|
||||||
import org.thingsboard.server.service.notification.NotificationProcessingContext;
|
|
||||||
import org.thingsboard.server.common.data.notification.settings.SlackNotificationDeliveryMethodConfig;
|
import org.thingsboard.server.common.data.notification.settings.SlackNotificationDeliveryMethodConfig;
|
||||||
import org.thingsboard.server.common.data.notification.targets.slack.SlackConversation;
|
import org.thingsboard.server.common.data.notification.targets.slack.SlackConversation;
|
||||||
import org.thingsboard.server.common.data.notification.template.SlackDeliveryMethodNotificationTemplate;
|
import org.thingsboard.server.common.data.notification.template.SlackDeliveryMethodNotificationTemplate;
|
||||||
|
import org.thingsboard.server.dao.notification.NotificationSettingsService;
|
||||||
import org.thingsboard.server.service.executors.ExternalCallExecutorService;
|
import org.thingsboard.server.service.executors.ExternalCallExecutorService;
|
||||||
|
import org.thingsboard.server.service.notification.NotificationProcessingContext;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@ -47,9 +47,11 @@ public class SlackNotificationChannel implements NotificationChannel<SlackConver
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean check(TenantId tenantId) {
|
public void check(TenantId tenantId) throws Exception {
|
||||||
NotificationSettings notificationSettings = notificationSettingsService.findNotificationSettings(tenantId);
|
NotificationSettings notificationSettings = notificationSettingsService.findNotificationSettings(tenantId);
|
||||||
return notificationSettings.getDeliveryMethodsConfigs().containsKey(NotificationDeliveryMethod.SLACK);
|
if (!notificationSettings.getDeliveryMethodsConfigs().containsKey(NotificationDeliveryMethod.SLACK)) {
|
||||||
|
throw new RuntimeException("Slack API token is not configured");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -49,8 +49,10 @@ public class SmsNotificationChannel implements NotificationChannel<User, SmsDeli
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean check(TenantId tenantId) {
|
public void check(TenantId tenantId) throws Exception {
|
||||||
return smsService.isConfigured(tenantId);
|
if (!smsService.isConfigured(tenantId)) {
|
||||||
|
throw new RuntimeException("SMS provider is not configured");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.id.NotificationTemplateId;
|
|||||||
import org.thingsboard.server.common.data.id.TenantId;
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig;
|
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerConfig;
|
||||||
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
|
import org.thingsboard.server.common.data.notification.rule.trigger.NotificationRuleTriggerType;
|
||||||
|
import org.thingsboard.server.common.data.validation.Length;
|
||||||
import org.thingsboard.server.common.data.validation.NoXss;
|
import org.thingsboard.server.common.data.validation.NoXss;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
@ -43,6 +44,7 @@ public class NotificationRule extends BaseData<NotificationRuleId> implements Ha
|
|||||||
private TenantId tenantId;
|
private TenantId tenantId;
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@NoXss
|
@NoXss
|
||||||
|
@Length(max = 255, message = "cannot be longer than 255 chars")
|
||||||
private String name;
|
private String name;
|
||||||
@NotNull
|
@NotNull
|
||||||
private NotificationTemplateId templateId;
|
private NotificationTemplateId templateId;
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.HasName;
|
|||||||
import org.thingsboard.server.common.data.HasTenantId;
|
import org.thingsboard.server.common.data.HasTenantId;
|
||||||
import org.thingsboard.server.common.data.id.NotificationTargetId;
|
import org.thingsboard.server.common.data.id.NotificationTargetId;
|
||||||
import org.thingsboard.server.common.data.id.TenantId;
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
|
import org.thingsboard.server.common.data.validation.Length;
|
||||||
import org.thingsboard.server.common.data.validation.NoXss;
|
import org.thingsboard.server.common.data.validation.NoXss;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
@ -35,6 +36,7 @@ public class NotificationTarget extends BaseData<NotificationTargetId> implement
|
|||||||
private TenantId tenantId;
|
private TenantId tenantId;
|
||||||
@NotBlank
|
@NotBlank
|
||||||
@NoXss
|
@NoXss
|
||||||
|
@Length(max = 255, message = "cannot be longer than 255 chars")
|
||||||
private String name;
|
private String name;
|
||||||
@NotNull
|
@NotNull
|
||||||
@Valid
|
@Valid
|
||||||
|
|||||||
@ -23,6 +23,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
|||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig;
|
import org.thingsboard.server.common.data.notification.targets.platform.PlatformUsersNotificationTargetConfig;
|
||||||
import org.thingsboard.server.common.data.notification.targets.slack.SlackNotificationTargetConfig;
|
import org.thingsboard.server.common.data.notification.targets.slack.SlackNotificationTargetConfig;
|
||||||
|
import org.thingsboard.server.common.data.validation.Length;
|
||||||
import org.thingsboard.server.common.data.validation.NoXss;
|
import org.thingsboard.server.common.data.validation.NoXss;
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
@ -35,6 +36,7 @@ import org.thingsboard.server.common.data.validation.NoXss;
|
|||||||
public abstract class NotificationTargetConfig {
|
public abstract class NotificationTargetConfig {
|
||||||
|
|
||||||
@NoXss
|
@NoXss
|
||||||
|
@Length(max = 500, message = "cannot be longer than 500 chars")
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
|
|||||||
@ -21,6 +21,8 @@ import lombok.NoArgsConstructor;
|
|||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||||
|
import org.thingsboard.server.common.data.validation.Length;
|
||||||
|
import org.thingsboard.server.common.data.validation.NoXss;
|
||||||
|
|
||||||
import javax.validation.constraints.NotEmpty;
|
import javax.validation.constraints.NotEmpty;
|
||||||
|
|
||||||
@ -30,6 +32,8 @@ import javax.validation.constraints.NotEmpty;
|
|||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class EmailDeliveryMethodNotificationTemplate extends DeliveryMethodNotificationTemplate implements HasSubject {
|
public class EmailDeliveryMethodNotificationTemplate extends DeliveryMethodNotificationTemplate implements HasSubject {
|
||||||
|
|
||||||
|
@NoXss(fieldName = "email subject")
|
||||||
|
@Length(fieldName = "email subject", max = 250, message = "cannot be longer than 250 chars")
|
||||||
@NotEmpty
|
@NotEmpty
|
||||||
private String subject;
|
private String subject;
|
||||||
|
|
||||||
|
|||||||
@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.HasTenantId;
|
|||||||
import org.thingsboard.server.common.data.id.NotificationTemplateId;
|
import org.thingsboard.server.common.data.id.NotificationTemplateId;
|
||||||
import org.thingsboard.server.common.data.id.TenantId;
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
import org.thingsboard.server.common.data.notification.NotificationType;
|
import org.thingsboard.server.common.data.notification.NotificationType;
|
||||||
|
import org.thingsboard.server.common.data.validation.Length;
|
||||||
import org.thingsboard.server.common.data.validation.NoXss;
|
import org.thingsboard.server.common.data.validation.NoXss;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
@ -36,6 +37,7 @@ public class NotificationTemplate extends BaseData<NotificationTemplateId> imple
|
|||||||
private TenantId tenantId;
|
private TenantId tenantId;
|
||||||
@NoXss
|
@NoXss
|
||||||
@NotEmpty
|
@NotEmpty
|
||||||
|
@Length(max = 255, message = "cannot be longer than 255 chars")
|
||||||
private String name;
|
private String name;
|
||||||
@NoXss
|
@NoXss
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@ -1,30 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright © 2016-2023 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.server.common.data.notification.template;
|
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
public class NotificationText {
|
|
||||||
|
|
||||||
private String body;
|
|
||||||
private String subject;
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -20,6 +20,7 @@ import lombok.EqualsAndHashCode;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||||
|
import org.thingsboard.server.common.data.validation.NoXss;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@ -31,6 +32,12 @@ public class SlackDeliveryMethodNotificationTemplate extends DeliveryMethodNotif
|
|||||||
super(other);
|
super(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NoXss(fieldName = "Slack message")
|
||||||
|
@Override
|
||||||
|
public String getBody() {
|
||||||
|
return super.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NotificationDeliveryMethod getMethod() {
|
public NotificationDeliveryMethod getMethod() {
|
||||||
return NotificationDeliveryMethod.SLACK;
|
return NotificationDeliveryMethod.SLACK;
|
||||||
|
|||||||
@ -20,6 +20,8 @@ import lombok.EqualsAndHashCode;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||||
|
import org.thingsboard.server.common.data.validation.Length;
|
||||||
|
import org.thingsboard.server.common.data.validation.NoXss;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@ -31,6 +33,13 @@ public class SmsDeliveryMethodNotificationTemplate extends DeliveryMethodNotific
|
|||||||
super(other);
|
super(other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NoXss(fieldName = "SMS message")
|
||||||
|
@Length(fieldName = "SMS message", max = 320, message = "cannot be longer than 320 chars")
|
||||||
|
@Override
|
||||||
|
public String getBody() {
|
||||||
|
return super.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NotificationDeliveryMethod getMethod() {
|
public NotificationDeliveryMethod getMethod() {
|
||||||
return NotificationDeliveryMethod.SMS;
|
return NotificationDeliveryMethod.SMS;
|
||||||
|
|||||||
@ -25,6 +25,8 @@ import lombok.NoArgsConstructor;
|
|||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
import org.thingsboard.server.common.data.notification.NotificationDeliveryMethod;
|
||||||
|
import org.thingsboard.server.common.data.validation.Length;
|
||||||
|
import org.thingsboard.server.common.data.validation.NoXss;
|
||||||
|
|
||||||
import javax.validation.constraints.NotEmpty;
|
import javax.validation.constraints.NotEmpty;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -35,6 +37,8 @@ import java.util.Optional;
|
|||||||
@ToString(callSuper = true)
|
@ToString(callSuper = true)
|
||||||
public class WebDeliveryMethodNotificationTemplate extends DeliveryMethodNotificationTemplate implements HasSubject {
|
public class WebDeliveryMethodNotificationTemplate extends DeliveryMethodNotificationTemplate implements HasSubject {
|
||||||
|
|
||||||
|
@NoXss(fieldName = "web notification subject")
|
||||||
|
@Length(fieldName = "web notification subject", max = 150, message = "cannot be longer than 150 chars")
|
||||||
@NotEmpty
|
@NotEmpty
|
||||||
private String subject;
|
private String subject;
|
||||||
private JsonNode additionalConfig;
|
private JsonNode additionalConfig;
|
||||||
@ -45,6 +49,15 @@ public class WebDeliveryMethodNotificationTemplate extends DeliveryMethodNotific
|
|||||||
this.additionalConfig = other.additionalConfig != null ? other.additionalConfig.deepCopy() : null;
|
this.additionalConfig = other.additionalConfig != null ? other.additionalConfig.deepCopy() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NoXss(fieldName = "web notification message")
|
||||||
|
@Length(fieldName = "web notification message", max = 250, message = "cannot be longer than 250 chars")
|
||||||
|
@Override
|
||||||
|
public String getBody() {
|
||||||
|
return super.getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NoXss(fieldName = "web notification button text")
|
||||||
|
@Length(fieldName = "web notification button text", max = 50, message = "cannot be longer than 50 chars")
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public String getButtonText() {
|
public String getButtonText() {
|
||||||
return getButtonConfigProperty("text");
|
return getButtonConfigProperty("text");
|
||||||
@ -57,6 +70,8 @@ public class WebDeliveryMethodNotificationTemplate extends DeliveryMethodNotific
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NoXss(fieldName = "web notification button link")
|
||||||
|
@Length(fieldName = "web notification button link", max = 300, message = "cannot be longer than 300 chars")
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public String getButtonLink() {
|
public String getButtonLink() {
|
||||||
return getButtonConfigProperty("link");
|
return getButtonConfigProperty("link");
|
||||||
|
|||||||
@ -23,12 +23,12 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.FIELD)
|
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||||
@Constraint(validatedBy = {})
|
@Constraint(validatedBy = {})
|
||||||
public @interface Length {
|
public @interface Length {
|
||||||
String message() default "length must be equal or less than {max}";
|
String message() default "length must be equal or less than {max}";
|
||||||
|
|
||||||
String fieldName();
|
String fieldName() default "";
|
||||||
|
|
||||||
int max() default 255;
|
int max() default 255;
|
||||||
|
|
||||||
|
|||||||
@ -23,12 +23,16 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Target(ElementType.FIELD)
|
@Target({ElementType.FIELD, ElementType.METHOD})
|
||||||
@Constraint(validatedBy = {})
|
@Constraint(validatedBy = {})
|
||||||
public @interface NoXss {
|
public @interface NoXss {
|
||||||
|
|
||||||
String message() default "is malformed";
|
String message() default "is malformed";
|
||||||
|
|
||||||
|
String fieldName() default "";
|
||||||
|
|
||||||
Class<?>[] groups() default {};
|
Class<?>[] groups() default {};
|
||||||
|
|
||||||
Class<? extends Payload>[] payload() default {};
|
Class<? extends Payload>[] payload() default {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@ package org.thingsboard.server.dao.service;
|
|||||||
|
|
||||||
import com.google.common.collect.Iterators;
|
import com.google.common.collect.Iterators;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.hibernate.validator.HibernateValidator;
|
import org.hibernate.validator.HibernateValidator;
|
||||||
import org.hibernate.validator.HibernateValidatorConfiguration;
|
import org.hibernate.validator.HibernateValidatorConfiguration;
|
||||||
import org.hibernate.validator.cfg.ConstraintMapping;
|
import org.hibernate.validator.cfg.ConstraintMapping;
|
||||||
@ -29,11 +30,13 @@ import org.thingsboard.server.common.data.validation.Length;
|
|||||||
import org.thingsboard.server.common.data.validation.NoXss;
|
import org.thingsboard.server.common.data.validation.NoXss;
|
||||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||||
|
|
||||||
import javax.validation.Path;
|
import javax.validation.ConstraintViolation;
|
||||||
import javax.validation.Validation;
|
import javax.validation.Validation;
|
||||||
import javax.validation.Validator;
|
import javax.validation.Validator;
|
||||||
import javax.validation.constraints.AssertTrue;
|
import javax.validation.constraints.AssertTrue;
|
||||||
import java.util.List;
|
import javax.validation.metadata.ConstraintDescriptor;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ -51,26 +54,31 @@ public class ConstraintValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void validateFields(Object data, String errorPrefix) {
|
public static void validateFields(Object data, String errorPrefix) {
|
||||||
List<String> constraintsViolations = getConstraintsViolations(data);
|
Set<ConstraintViolation<Object>> constraintsViolations = fieldsValidator.validate(data);
|
||||||
if (!constraintsViolations.isEmpty()) {
|
if (!constraintsViolations.isEmpty()) {
|
||||||
throw new DataValidationException(errorPrefix + String.join(", ", constraintsViolations));
|
throw new DataValidationException(errorPrefix + getErrorMessage(constraintsViolations));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<String> getConstraintsViolations(Object data) {
|
public static String getErrorMessage(Collection<ConstraintViolation<Object>> constraintsViolations) {
|
||||||
return fieldsValidator.validate(data).stream()
|
return constraintsViolations.stream()
|
||||||
.map(constraintViolation -> {
|
.map(ConstraintValidator::getErrorMessage)
|
||||||
String property;
|
.distinct().sorted().collect(Collectors.joining(", "));
|
||||||
if (constraintViolation.getConstraintDescriptor().getAttributes().containsKey("fieldName")) {
|
|
||||||
property = constraintViolation.getConstraintDescriptor().getAttributes().get("fieldName").toString();
|
|
||||||
} else {
|
|
||||||
Path propertyPath = constraintViolation.getPropertyPath();
|
|
||||||
property = Iterators.getLast(propertyPath.iterator()).toString();
|
|
||||||
}
|
}
|
||||||
return property + " " + constraintViolation.getMessage();
|
|
||||||
})
|
public static String getErrorMessage(ConstraintViolation<Object> constraintViolation) {
|
||||||
.distinct()
|
ConstraintDescriptor<?> constraintDescriptor = constraintViolation.getConstraintDescriptor();
|
||||||
.collect(Collectors.toList());
|
String property = (String) constraintDescriptor.getAttributes().get("fieldName");
|
||||||
|
if (StringUtils.isEmpty(property) && !(constraintDescriptor.getAnnotation() instanceof AssertTrue)) {
|
||||||
|
property = Iterators.getLast(constraintViolation.getPropertyPath().iterator()).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
String error = "";
|
||||||
|
if (StringUtils.isNotEmpty(property)) {
|
||||||
|
error += property + " ";
|
||||||
|
}
|
||||||
|
error += constraintViolation.getMessage();
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void initializeValidators() {
|
private static void initializeValidators() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user