diff --git a/xjs-business/xjs-business-common/src/main/java/com/xjs/consts/ProductConstant.java b/xjs-business/xjs-business-common/src/main/java/com/xjs/consts/ProductConstant.java new file mode 100644 index 00000000..49c0af31 --- /dev/null +++ b/xjs-business/xjs-business-common/src/main/java/com/xjs/consts/ProductConstant.java @@ -0,0 +1,29 @@ +package com.xjs.consts; + +/** + * 商品常量 + * @since 2022-03-15 09:02:22 + * @author xjejs + */ +public class ProductConstant { + + + public enum AttrEnum{ + ATTR_TYPE_BASE(1,"基本属性"),ATTR_TYPE_SALE(0,"销售属性"); + private int code; + private String msg; + + AttrEnum(int code,String msg){ + this.code = code; + this.msg = msg; + } + + public int getCode() { + return code; + } + + public String getMsg() { + return msg; + } + } +} diff --git a/xjs-business/xjs-business-common/src/main/java/com/xjs/consts/RenRenConstant.java b/xjs-business/xjs-business-common/src/main/java/com/xjs/consts/RenRenConstant.java new file mode 100644 index 00000000..1a3599de --- /dev/null +++ b/xjs-business/xjs-business-common/src/main/java/com/xjs/consts/RenRenConstant.java @@ -0,0 +1,127 @@ +/** + * Copyright (c) 2016-2019 人人开源 All rights reserved. + * + * https://www.renren.io + * + * 版权所有,侵权必究! + */ + +package com.xjs.consts; + +/** + * 常量 + * + * @author Mark sunlightcs@gmail.com + */ +public class RenRenConstant { + /** 超级管理员ID */ + public static final int SUPER_ADMIN = 1; + /** + * 当前页码 + */ + public static final String PAGE = "page"; + /** + * 每页显示记录数 + */ + public static final String LIMIT = "limit"; + /** + * 排序字段 + */ + public static final String ORDER_FIELD = "sidx"; + /** + * 排序方式 + */ + public static final String ORDER = "order"; + /** + * 升序 + */ + public static final String ASC = "asc"; + /** + * 菜单类型 + * + * @author chenshun + * @email sunlightcs@gmail.com + * @date 2016年11月15日 下午1:24:29 + */ + public enum MenuType { + /** + * 目录 + */ + CATALOG(0), + /** + * 菜单 + */ + MENU(1), + /** + * 按钮 + */ + BUTTON(2); + + private int value; + + MenuType(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + + /** + * 定时任务状态 + * + * @author chenshun + * @email sunlightcs@gmail.com + * @date 2016年12月3日 上午12:07:22 + */ + public enum ScheduleStatus { + /** + * 正常 + */ + NORMAL(0), + /** + * 暂停 + */ + PAUSE(1); + + private int value; + + ScheduleStatus(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + + /** + * 云服务商 + */ + public enum CloudService { + /** + * 七牛云 + */ + QINIU(1), + /** + * 阿里云 + */ + ALIYUN(2), + /** + * 腾讯云 + */ + QCLOUD(3); + + private int value; + + CloudService(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + +} diff --git a/xjs-business/xjs-business-common/src/main/java/com/xjs/consts/WareConstant.java b/xjs-business/xjs-business-common/src/main/java/com/xjs/consts/WareConstant.java new file mode 100644 index 00000000..71cc583b --- /dev/null +++ b/xjs-business/xjs-business-common/src/main/java/com/xjs/consts/WareConstant.java @@ -0,0 +1,52 @@ +package com.xjs.consts; + +/** + * 采购常量 + * @since 2022-03-15 09:02:22 + * @author xjejs + */ +public class WareConstant { + + public enum PurchaseStatusEnum{ + CREATED(0,"新建"),ASSIGNED(1,"已分配"), + RECEIVE(2,"已领取"),FINISH(3,"已完成"), + HASERROR(4,"有异常"); + private int code; + private String msg; + + PurchaseStatusEnum(int code,String msg){ + this.code = code; + this.msg = msg; + } + + public int getCode() { + return code; + } + + public String getMsg() { + return msg; + } + } + + + public enum PurchaseDetailStatusEnum{ + CREATED(0,"新建"),ASSIGNED(1,"已分配"), + BUYING(2,"正在采购"),FINISH(3,"已完成"), + HASERROR(4,"采购失败"); + private int code; + private String msg; + + PurchaseDetailStatusEnum(int code,String msg){ + this.code = code; + this.msg = msg; + } + + public int getCode() { + return code; + } + + public String getMsg() { + return msg; + } + } +} diff --git a/xjs-business/xjs-business-common/src/main/java/com/xjs/exception/BizCodeEnume.java b/xjs-business/xjs-business-common/src/main/java/com/xjs/exception/BizCodeEnume.java new file mode 100644 index 00000000..d7059520 --- /dev/null +++ b/xjs-business/xjs-business-common/src/main/java/com/xjs/exception/BizCodeEnume.java @@ -0,0 +1,34 @@ +package com.xjs.exception; + +/*** + * 错误码和错误信息定义类 + * 1. 错误码定义规则为5为数字 + * 2. 前两位表示业务场景,最后三位表示错误码。例如:100001。10:通用 001:系统未知异常 + * 3. 维护错误码后需要维护错误描述,将他们定义为枚举形式 + * 错误码列表: + * 10: 通用 + * 001:参数格式校验 + * 11: 商品 + * 12: 订单 + * 13: 购物车 + * 14: 物流 + */ +public enum BizCodeEnume { + UNKNOW_EXCEPTION(10000,"系统未知异常"), + VAILD_EXCEPTION(10001,"参数格式校验失败"); + + private int code; + private String msg; + BizCodeEnume(int code,String msg){ + this.code = code; + this.msg = msg; + } + + public int getCode() { + return code; + } + + public String getMsg() { + return msg; + } +} diff --git a/xjs-business/xjs-business-common/src/main/java/com/xjs/exception/RRException.java b/xjs-business/xjs-business-common/src/main/java/com/xjs/exception/RRException.java new file mode 100644 index 00000000..932fd73b --- /dev/null +++ b/xjs-business/xjs-business-common/src/main/java/com/xjs/exception/RRException.java @@ -0,0 +1,61 @@ +/** + * Copyright (c) 2016-2019 人人开源 All rights reserved. + * + * https://www.renren.io + * + * 版权所有,侵权必究! + */ + +package com.xjs.exception; + +/** + * 自定义异常 + * + * @author Mark sunlightcs@gmail.com + */ +public class RRException extends RuntimeException { + private static final long serialVersionUID = 1L; + + private String msg; + private int code = 500; + + public RRException(String msg) { + super(msg); + this.msg = msg; + } + + public RRException(String msg, Throwable e) { + super(msg, e); + this.msg = msg; + } + + public RRException(String msg, int code) { + super(msg); + this.msg = msg; + this.code = code; + } + + public RRException(String msg, int code, Throwable e) { + super(msg, e); + this.msg = msg; + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + +} diff --git a/xjs-business/xjs-business-common/src/main/java/com/xjs/to/MemberPrice.java b/xjs-business/xjs-business-common/src/main/java/com/xjs/to/MemberPrice.java new file mode 100644 index 00000000..5bbfd1d1 --- /dev/null +++ b/xjs-business/xjs-business-common/src/main/java/com/xjs/to/MemberPrice.java @@ -0,0 +1,21 @@ + +package com.xjs.to; + +import lombok.Data; + +import java.math.BigDecimal; + +/** + * Auto-generated: 2019-11-26 10:50:34 + * + * @author bejson.com (i@bejson.com) + * @website http://www.bejson.com/java2pojo/ + */ +@Data +public class MemberPrice { + + private Long id; + private String name; + private BigDecimal price; + +} \ No newline at end of file diff --git a/xjs-business/xjs-business-common/src/main/java/com/xjs/to/SkuReductionTo.java b/xjs-business/xjs-business-common/src/main/java/com/xjs/to/SkuReductionTo.java new file mode 100644 index 00000000..46f06b95 --- /dev/null +++ b/xjs-business/xjs-business-common/src/main/java/com/xjs/to/SkuReductionTo.java @@ -0,0 +1,19 @@ +package com.xjs.to; + +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +@Data +public class SkuReductionTo { + + private Long skuId; + private int fullCount; + private BigDecimal discount; + private int countStatus; + private BigDecimal fullPrice; + private BigDecimal reducePrice; + private int priceStatus; + private List memberPrice; +} diff --git a/xjs-business/xjs-business-common/src/main/java/com/xjs/to/SpuBoundTo.java b/xjs-business/xjs-business-common/src/main/java/com/xjs/to/SpuBoundTo.java new file mode 100644 index 00000000..8e1397f1 --- /dev/null +++ b/xjs-business/xjs-business-common/src/main/java/com/xjs/to/SpuBoundTo.java @@ -0,0 +1,13 @@ +package com.xjs.to; + +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class SpuBoundTo { + + private Long spuId; + private BigDecimal buyBounds; + private BigDecimal growBounds; +} diff --git a/xjs-business/xjs-business-common/src/main/java/com/xjs/utils/PageUtils.java b/xjs-business/xjs-business-common/src/main/java/com/xjs/utils/PageUtils.java new file mode 100644 index 00000000..f917d678 --- /dev/null +++ b/xjs-business/xjs-business-common/src/main/java/com/xjs/utils/PageUtils.java @@ -0,0 +1,110 @@ +/** + * Copyright (c) 2016-2019 人人开源 All rights reserved. + * + * https://www.renren.io + * + * 版权所有,侵权必究! + */ + +package com.xjs.utils; + +import com.baomidou.mybatisplus.core.metadata.IPage; + +import java.io.Serializable; +import java.util.List; + +/** + * 分页工具类 + * + * @author Mark sunlightcs@gmail.com + */ +public class PageUtils implements Serializable { + private static final long serialVersionUID = 1L; + /** + * 总记录数 + */ + private int totalCount; + /** + * 每页记录数 + */ + private int pageSize; + /** + * 总页数 + */ + private int totalPage; + /** + * 当前页数 + */ + private int currPage; + /** + * 列表数据 + */ + private List list; + + /** + * 分页 + * @param list 列表数据 + * @param totalCount 总记录数 + * @param pageSize 每页记录数 + * @param currPage 当前页数 + */ + public PageUtils(List list, int totalCount, int pageSize, int currPage) { + this.list = list; + this.totalCount = totalCount; + this.pageSize = pageSize; + this.currPage = currPage; + this.totalPage = (int)Math.ceil((double)totalCount/pageSize); + } + + /** + * 分页 + */ + public PageUtils(IPage page) { + this.list = page.getRecords(); + this.totalCount = (int)page.getTotal(); + this.pageSize = (int)page.getSize(); + this.currPage = (int)page.getCurrent(); + this.totalPage = (int)page.getPages(); + } + + public int getTotalCount() { + return totalCount; + } + + public void setTotalCount(int totalCount) { + this.totalCount = totalCount; + } + + public int getPageSize() { + return pageSize; + } + + public void setPageSize(int pageSize) { + this.pageSize = pageSize; + } + + public int getTotalPage() { + return totalPage; + } + + public void setTotalPage(int totalPage) { + this.totalPage = totalPage; + } + + public int getCurrPage() { + return currPage; + } + + public void setCurrPage(int currPage) { + this.currPage = currPage; + } + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + +} diff --git a/xjs-business/xjs-business-common/src/main/java/com/xjs/utils/Query.java b/xjs-business/xjs-business-common/src/main/java/com/xjs/utils/Query.java new file mode 100644 index 00000000..4a0cb0b2 --- /dev/null +++ b/xjs-business/xjs-business-common/src/main/java/com/xjs/utils/Query.java @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2016-2019 人人开源 All rights reserved. + * + * https://www.renren.io + * + * 版权所有,侵权必究! + */ + +package com.xjs.utils; + +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.metadata.OrderItem; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.xjs.consts.RenRenConstant; +import com.xjs.xss.SQLFilter; +import org.apache.commons.lang.StringUtils; + +import java.util.Map; + +/** + * 查询参数 + * + * @author Mark sunlightcs@gmail.com + */ +public class Query { + + public IPage getPage(Map params) { + return this.getPage(params, null, false); + } + + public IPage getPage(Map params, String defaultOrderField, boolean isAsc) { + //分页参数 + long curPage = 1; + long limit = 10; + + if(params.get(RenRenConstant.PAGE) != null){ + curPage = Long.parseLong((String)params.get(RenRenConstant.PAGE)); + } + if(params.get(RenRenConstant.LIMIT) != null){ + limit = Long.parseLong((String)params.get(RenRenConstant.LIMIT)); + } + + //分页对象 + Page page = new Page<>(curPage, limit); + + //分页参数 + params.put(RenRenConstant.PAGE, page); + + //排序字段 + //防止SQL注入(因为sidx、order是通过拼接SQL实现排序的,会有SQL注入风险) + String orderField = SQLFilter.sqlInject((String)params.get(RenRenConstant.ORDER_FIELD)); + String order = (String)params.get(RenRenConstant.ORDER); + + + //前端字段排序 + if(StringUtils.isNotEmpty(orderField) && StringUtils.isNotEmpty(order)){ + if(RenRenConstant.ASC.equalsIgnoreCase(order)) { + return page.addOrder(OrderItem.asc(orderField)); + }else { + return page.addOrder(OrderItem.desc(orderField)); + } + } + + //没有排序字段,则不排序 + if(StringUtils.isBlank(defaultOrderField)){ + return page; + } + + //默认排序 + if(isAsc) { + page.addOrder(OrderItem.asc(defaultOrderField)); + }else { + page.addOrder(OrderItem.desc(defaultOrderField)); + } + + return page; + } +} diff --git a/xjs-business/xjs-business-common/src/main/java/com/xjs/validation/annotation/CheckNumber.java b/xjs-business/xjs-business-common/src/main/java/com/xjs/validation/annotation/CheckNumber.java index 793474db..a3989bc9 100644 --- a/xjs-business/xjs-business-common/src/main/java/com/xjs/validation/annotation/CheckNumber.java +++ b/xjs-business/xjs-business-common/src/main/java/com/xjs/validation/annotation/CheckNumber.java @@ -1,10 +1,6 @@ package com.xjs.validation.annotation; -/** - * 自定义校验注解 :检查数字类型长度 - * @author xiejs - * @since 2022-02-18 - */ + import com.xjs.validation.constraintValidator.CheckNumberConstraintValidator; @@ -12,6 +8,11 @@ import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*; +/** + * 自定义校验注解 :检查数字类型长度 + * @author xiejs + * @since 2022-02-18 + */ @Documented @Inherited @Target(ElementType.FIELD) diff --git a/xjs-business/xjs-business-common/src/main/java/com/xjs/validation/annotation/ListValue.java b/xjs-business/xjs-business-common/src/main/java/com/xjs/validation/annotation/ListValue.java new file mode 100644 index 00000000..b8f42fc9 --- /dev/null +++ b/xjs-business/xjs-business-common/src/main/java/com/xjs/validation/annotation/ListValue.java @@ -0,0 +1,30 @@ +package com.xjs.validation.annotation; + +import com.xjs.validation.constraintValidator.ListValueConstraintValidator; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +/** + * 自定义校验注解 :检查列表值 + * @author xiejs + * @since 2022-03-15 09:10:22 + */ +@Documented +@Constraint(validatedBy = { ListValueConstraintValidator.class }) +@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) +@Retention(RUNTIME) +public @interface ListValue { + String message() default "{com.atguigu.common.valid.ListValue.message}"; + + Class[] groups() default { }; + + Class[] payload() default { }; + + int[] vals() default { }; +} diff --git a/xjs-business/xjs-business-common/src/main/java/com/xjs/validation/constraintValidator/ListValueConstraintValidator.java b/xjs-business/xjs-business-common/src/main/java/com/xjs/validation/constraintValidator/ListValueConstraintValidator.java new file mode 100644 index 00000000..e4884913 --- /dev/null +++ b/xjs-business/xjs-business-common/src/main/java/com/xjs/validation/constraintValidator/ListValueConstraintValidator.java @@ -0,0 +1,42 @@ +package com.xjs.validation.constraintValidator; + +import com.xjs.validation.annotation.ListValue; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.util.HashSet; +import java.util.Set; + +/** + * 列表值约束验证器 + * @author xiejs + * @since 2022-03-15 09:09:47 + */ +public class ListValueConstraintValidator implements ConstraintValidator { + + private Set set = new HashSet<>(); + //初始化方法 + @Override + public void initialize(ListValue constraintAnnotation) { + + int[] vals = constraintAnnotation.vals(); + for (int val : vals) { + set.add(val); + } + + } + + //判断是否校验成功 + + /** + * + * @param value 需要校验的值 + * @param context + * @return + */ + @Override + public boolean isValid(Integer value, ConstraintValidatorContext context) { + + return set.contains(value); + } +} diff --git a/xjs-business/xjs-business-common/src/main/java/com/xjs/validation/group/UpdateStatusGroup.java b/xjs-business/xjs-business-common/src/main/java/com/xjs/validation/group/UpdateStatusGroup.java new file mode 100644 index 00000000..569ee8bc --- /dev/null +++ b/xjs-business/xjs-business-common/src/main/java/com/xjs/validation/group/UpdateStatusGroup.java @@ -0,0 +1,10 @@ +package com.xjs.validation.group; + +/** + * 修改状态校验分组 + * + * @author xiejs + * @since 2022-03-15 09:09:27 + */ +public interface UpdateStatusGroup { +} diff --git a/xjs-business/xjs-business-common/src/main/java/com/xjs/xss/HTMLFilter.java b/xjs-business/xjs-business-common/src/main/java/com/xjs/xss/HTMLFilter.java new file mode 100644 index 00000000..83c0ff5b --- /dev/null +++ b/xjs-business/xjs-business-common/src/main/java/com/xjs/xss/HTMLFilter.java @@ -0,0 +1,530 @@ +package com.xjs.xss; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * + * HTML filtering utility for protecting against XSS (Cross Site Scripting). + * + * This code is licensed LGPLv3 + * + * This code is a Java port of the original work in PHP by Cal Hendersen. + * http://code.iamcal.com/php/lib_filter/ + * + * The trickiest part of the translation was handling the differences in regex handling + * between PHP and Java. These resources were helpful in the process: + * + * http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html + * http://us2.php.net/manual/en/reference.pcre.pattern.modifiers.php + * http://www.regular-expressions.info/modifiers.html + * + * A note on naming conventions: instance variables are prefixed with a "v"; global + * constants are in all caps. + * + * Sample use: + * String input = ... + * String clean = new HTMLFilter().filter( input ); + * + * The class is not thread safe. Create a new instance if in doubt. + * + * If you find bugs or have suggestions on improvement (especially regarding + * performance), please contact us. The latest version of this + * source, and our contact details, can be found at http://xss-html-filter.sf.net + * + * @author Joseph O'Connell + * @author Cal Hendersen + * @author Michael Semb Wever + */ +public final class HTMLFilter { + + /** regex flag union representing /si modifiers in php **/ + private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL; + private static final Pattern P_COMMENTS = Pattern.compile("", Pattern.DOTALL); + private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI); + private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL); + private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI); + private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI); + private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI); + private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI); + private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI); + private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?"); + private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?"); + private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?"); + private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))"); + private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL); + private static final Pattern P_END_ARROW = Pattern.compile("^>"); + private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)"); + private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)"); + private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)"); + private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)"); + private static final Pattern P_AMP = Pattern.compile("&"); + private static final Pattern P_QUOTE = Pattern.compile("<"); + private static final Pattern P_LEFT_ARROW = Pattern.compile("<"); + private static final Pattern P_RIGHT_ARROW = Pattern.compile(">"); + private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>"); + + // @xxx could grow large... maybe use sesat's ReferenceMap + private static final ConcurrentMap P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap(); + private static final ConcurrentMap P_REMOVE_SELF_BLANKS = new ConcurrentHashMap(); + + /** set of allowed html elements, along with allowed attributes for each element **/ + private final Map> vAllowed; + /** counts of open tags for each (allowable) html element **/ + private final Map vTagCounts = new HashMap(); + + /** html elements which must always be self-closing (e.g. "") **/ + private final String[] vSelfClosingTags; + /** html elements which must always have separate opening and closing tags (e.g. "") **/ + private final String[] vNeedClosingTags; + /** set of disallowed html elements **/ + private final String[] vDisallowed; + /** attributes which should be checked for valid protocols **/ + private final String[] vProtocolAtts; + /** allowed protocols **/ + private final String[] vAllowedProtocols; + /** tags which should be removed if they contain no content (e.g. "" or "") **/ + private final String[] vRemoveBlanks; + /** entities allowed within html markup **/ + private final String[] vAllowedEntities; + /** flag determining whether comments are allowed in input String. */ + private final boolean stripComment; + private final boolean encodeQuotes; + private boolean vDebug = false; + /** + * flag determining whether to try to make tags when presented with "unbalanced" + * angle brackets (e.g. "" becomes " text "). If set to false, + * unbalanced angle brackets will be html escaped. + */ + private final boolean alwaysMakeTags; + + /** Default constructor. + * + */ + public HTMLFilter() { + vAllowed = new HashMap<>(); + + final ArrayList a_atts = new ArrayList(); + a_atts.add("href"); + a_atts.add("target"); + vAllowed.put("a", a_atts); + + final ArrayList img_atts = new ArrayList(); + img_atts.add("src"); + img_atts.add("width"); + img_atts.add("height"); + img_atts.add("alt"); + vAllowed.put("img", img_atts); + + final ArrayList no_atts = new ArrayList(); + vAllowed.put("b", no_atts); + vAllowed.put("strong", no_atts); + vAllowed.put("i", no_atts); + vAllowed.put("em", no_atts); + + vSelfClosingTags = new String[]{"img"}; + vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"}; + vDisallowed = new String[]{}; + vAllowedProtocols = new String[]{"http", "mailto", "https"}; // no ftp. + vProtocolAtts = new String[]{"src", "href"}; + vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"}; + vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"}; + stripComment = true; + encodeQuotes = true; + alwaysMakeTags = true; + } + + /** Set debug flag to true. Otherwise use default settings. See the default constructor. + * + * @param debug turn debug on with a true argument + */ + public HTMLFilter(final boolean debug) { + this(); + vDebug = debug; + + } + + /** Map-parameter configurable constructor. + * + * @param conf map containing configuration. keys match field names. + */ + public HTMLFilter(final Map conf) { + + assert conf.containsKey("vAllowed") : "configuration requires vAllowed"; + assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags"; + assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags"; + assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed"; + assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols"; + assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts"; + assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks"; + assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities"; + + vAllowed = Collections.unmodifiableMap((HashMap>) conf.get("vAllowed")); + vSelfClosingTags = (String[]) conf.get("vSelfClosingTags"); + vNeedClosingTags = (String[]) conf.get("vNeedClosingTags"); + vDisallowed = (String[]) conf.get("vDisallowed"); + vAllowedProtocols = (String[]) conf.get("vAllowedProtocols"); + vProtocolAtts = (String[]) conf.get("vProtocolAtts"); + vRemoveBlanks = (String[]) conf.get("vRemoveBlanks"); + vAllowedEntities = (String[]) conf.get("vAllowedEntities"); + stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true; + encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true; + alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true; + } + + private void reset() { + vTagCounts.clear(); + } + + private void debug(final String msg) { + if (vDebug) { + Logger.getAnonymousLogger().info(msg); + } + } + + //--------------------------------------------------------------- + // my versions of some PHP library functions + public static String chr(final int decimal) { + return String.valueOf((char) decimal); + } + + public static String htmlSpecialChars(final String s) { + String result = s; + result = regexReplace(P_AMP, "&", result); + result = regexReplace(P_QUOTE, """, result); + result = regexReplace(P_LEFT_ARROW, "<", result); + result = regexReplace(P_RIGHT_ARROW, ">", result); + return result; + } + + //--------------------------------------------------------------- + /** + * given a user submitted input String, filter out any invalid or restricted + * html. + * + * @param input text (i.e. submitted by a user) than may contain html + * @return "clean" version of input, with only valid, whitelisted html elements allowed + */ + public String filter(final String input) { + reset(); + String s = input; + + debug("************************************************"); + debug(" INPUT: " + input); + + s = escapeComments(s); + debug(" escapeComments: " + s); + + s = balanceHTML(s); + debug(" balanceHTML: " + s); + + s = checkTags(s); + debug(" checkTags: " + s); + + s = processRemoveBlanks(s); + debug("processRemoveBlanks: " + s); + + s = validateEntities(s); + debug(" validateEntites: " + s); + + debug("************************************************\n\n"); + return s; + } + + public boolean isAlwaysMakeTags(){ + return alwaysMakeTags; + } + + public boolean isStripComments(){ + return stripComment; + } + + private String escapeComments(final String s) { + final Matcher m = P_COMMENTS.matcher(s); + final StringBuffer buf = new StringBuffer(); + if (m.find()) { + final String match = m.group(1); //(.*?) + m.appendReplacement(buf, Matcher.quoteReplacement("")); + } + m.appendTail(buf); + + return buf.toString(); + } + + private String balanceHTML(String s) { + if (alwaysMakeTags) { + // + // try and form html + // + s = regexReplace(P_END_ARROW, "", s); + s = regexReplace(P_BODY_TO_END, "<$1>", s); + s = regexReplace(P_XML_CONTENT, "$1<$2", s); + + } else { + // + // escape stray brackets + // + s = regexReplace(P_STRAY_LEFT_ARROW, "<$1", s); + s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2><", s); + + // + // the last regexp causes '<>' entities to appear + // (we need to do a lookahead assertion so that the last bracket can + // be used in the next pass of the regexp) + // + s = regexReplace(P_BOTH_ARROWS, "", s); + } + + return s; + } + + private String checkTags(String s) { + Matcher m = P_TAGS.matcher(s); + + final StringBuffer buf = new StringBuffer(); + while (m.find()) { + String replaceStr = m.group(1); + replaceStr = processTag(replaceStr); + m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr)); + } + m.appendTail(buf); + + s = buf.toString(); + + // these get tallied in processTag + // (remember to reset before subsequent calls to filter method) + for (String key : vTagCounts.keySet()) { + for (int ii = 0; ii < vTagCounts.get(key); ii++) { + s += ""; + } + } + + return s; + } + + private String processRemoveBlanks(final String s) { + String result = s; + for (String tag : vRemoveBlanks) { + if(!P_REMOVE_PAIR_BLANKS.containsKey(tag)){ + P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?>")); + } + result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result); + if(!P_REMOVE_SELF_BLANKS.containsKey(tag)){ + P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>")); + } + result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result); + } + + return result; + } + + private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s) { + Matcher m = regex_pattern.matcher(s); + return m.replaceAll(replacement); + } + + private String processTag(final String s) { + // ending tags + Matcher m = P_END_TAG.matcher(s); + if (m.find()) { + final String name = m.group(1).toLowerCase(); + if (allowed(name)) { + if (!inArray(name, vSelfClosingTags)) { + if (vTagCounts.containsKey(name)) { + vTagCounts.put(name, vTagCounts.get(name) - 1); + return ""; + } + } + } + } + + // starting tags + m = P_START_TAG.matcher(s); + if (m.find()) { + final String name = m.group(1).toLowerCase(); + final String body = m.group(2); + String ending = m.group(3); + + //debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" ); + if (allowed(name)) { + String params = ""; + + final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body); + final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body); + final List paramNames = new ArrayList(); + final List paramValues = new ArrayList(); + while (m2.find()) { + paramNames.add(m2.group(1)); //([a-z0-9]+) + paramValues.add(m2.group(3)); //(.*?) + } + while (m3.find()) { + paramNames.add(m3.group(1)); //([a-z0-9]+) + paramValues.add(m3.group(3)); //([^\"\\s']+) + } + + String paramName, paramValue; + for (int ii = 0; ii < paramNames.size(); ii++) { + paramName = paramNames.get(ii).toLowerCase(); + paramValue = paramValues.get(ii); + +// debug( "paramName='" + paramName + "'" ); +// debug( "paramValue='" + paramValue + "'" ); +// debug( "allowed? " + vAllowed.get( name ).contains( paramName ) ); + + if (allowedAttribute(name, paramName)) { + if (inArray(paramName, vProtocolAtts)) { + paramValue = processParamProtocol(paramValue); + } + params += " " + paramName + "=\"" + paramValue + "\""; + } + } + + if (inArray(name, vSelfClosingTags)) { + ending = " /"; + } + + if (inArray(name, vNeedClosingTags)) { + ending = ""; + } + + if (ending == null || ending.length() < 1) { + if (vTagCounts.containsKey(name)) { + vTagCounts.put(name, vTagCounts.get(name) + 1); + } else { + vTagCounts.put(name, 1); + } + } else { + ending = " /"; + } + return "<" + name + params + ending + ">"; + } else { + return ""; + } + } + + // comments + m = P_COMMENT.matcher(s); + if (!stripComment && m.find()) { + return "<" + m.group() + ">"; + } + + return ""; + } + + private String processParamProtocol(String s) { + s = decodeEntities(s); + final Matcher m = P_PROTOCOL.matcher(s); + if (m.find()) { + final String protocol = m.group(1); + if (!inArray(protocol, vAllowedProtocols)) { + // bad protocol, turn into local anchor link instead + s = "#" + s.substring(protocol.length() + 1, s.length()); + if (s.startsWith("#//")) { + s = "#" + s.substring(3, s.length()); + } + } + } + + return s; + } + + private String decodeEntities(String s) { + StringBuffer buf = new StringBuffer(); + + Matcher m = P_ENTITY.matcher(s); + while (m.find()) { + final String match = m.group(1); + final int decimal = Integer.decode(match).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + buf = new StringBuffer(); + m = P_ENTITY_UNICODE.matcher(s); + while (m.find()) { + final String match = m.group(1); + final int decimal = Integer.valueOf(match, 16).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + buf = new StringBuffer(); + m = P_ENCODE.matcher(s); + while (m.find()) { + final String match = m.group(1); + final int decimal = Integer.valueOf(match, 16).intValue(); + m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal))); + } + m.appendTail(buf); + s = buf.toString(); + + s = validateEntities(s); + return s; + } + + private String validateEntities(final String s) { + StringBuffer buf = new StringBuffer(); + + // validate entities throughout the string + Matcher m = P_VALID_ENTITIES.matcher(s); + while (m.find()) { + final String one = m.group(1); //([^&;]*) + final String two = m.group(2); //(?=(;|&|$)) + m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two))); + } + m.appendTail(buf); + + return encodeQuotes(buf.toString()); + } + + private String encodeQuotes(final String s){ + if(encodeQuotes){ + StringBuffer buf = new StringBuffer(); + Matcher m = P_VALID_QUOTES.matcher(s); + while (m.find()) { + final String one = m.group(1); //(>|^) + final String two = m.group(2); //([^<]+?) + final String three = m.group(3); //(<|$) + m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, """, two) + three)); + } + m.appendTail(buf); + return buf.toString(); + }else{ + return s; + } + } + + private String checkEntity(final String preamble, final String term) { + + return ";".equals(term) && isValidEntity(preamble) + ? '&' + preamble + : "&" + preamble; + } + + private boolean isValidEntity(final String entity) { + return inArray(entity, vAllowedEntities); + } + + private static boolean inArray(final String s, final String[] array) { + for (String item : array) { + if (item != null && item.equals(s)) { + return true; + } + } + return false; + } + + private boolean allowed(final String name) { + return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed); + } + + private boolean allowedAttribute(final String name, final String paramName) { + return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName)); + } +} \ No newline at end of file diff --git a/xjs-business/xjs-business-common/src/main/java/com/xjs/xss/SQLFilter.java b/xjs-business/xjs-business-common/src/main/java/com/xjs/xss/SQLFilter.java new file mode 100644 index 00000000..0834b91d --- /dev/null +++ b/xjs-business/xjs-business-common/src/main/java/com/xjs/xss/SQLFilter.java @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2016-2019 人人开源 All rights reserved. + * + * https://www.renren.io + * + * 版权所有,侵权必究! + */ + +package com.xjs.xss; + +import com.xjs.exception.RRException; +import org.apache.commons.lang.StringUtils; + +/** + * SQL过滤 + * + * @author Mark sunlightcs@gmail.com + */ +public class SQLFilter { + + /** + * SQL注入过滤 + * @param str 待验证的字符串 + */ + public static String sqlInject(String str){ + if(StringUtils.isBlank(str)){ + return null; + } + //去掉'|"|;|\字符 + str = StringUtils.replace(str, "'", ""); + str = StringUtils.replace(str, "\"", ""); + str = StringUtils.replace(str, ";", ""); + str = StringUtils.replace(str, "\\", ""); + + //转换成小写 + str = str.toLowerCase(); + + //非法字符 + String[] keywords = {"master", "truncate", "insert", "select", "delete", "update", "declare", "alter", "drop"}; + + //判断是否包含非法字符 + for(String keyword : keywords){ + if(str.indexOf(keyword) != -1){ + throw new RRException("包含非法字符"); + } + } + + return str; + } +}