diff --git a/broker/config/wildfirechat.conf b/broker/config/wildfirechat.conf index 75404bd2..551d8b0e 100755 --- a/broker/config/wildfirechat.conf +++ b/broker/config/wildfirechat.conf @@ -211,6 +211,12 @@ friend.request_expiration_duration 604800000 ##好友请求限制频率,一个用户24小时之内允许请求好友的次数,默认不限频。 friend.request_rate_limit 30 +##如果搜索电话号码,24小时内搜索错误号码几次就不再允许电话号码搜素。防止有人遍历搜索电话号码 +friend.search_mobile_empty_rate_limit 5 + +##如果搜索用户,24小时内搜索次数。防止有人遍历用户名或者用户ID乱加好友。另外可以禁止ID搜索friend.disable_user_id_search +friend.search_rate_limit 100 + ##请求添加机器人为好友时,机器人是否自动接受,默认为true friend.robot_auto_accept true diff --git a/broker/src/main/java/io/moquette/BrokerConstants.java b/broker/src/main/java/io/moquette/BrokerConstants.java index cd7287d3..4ab1f41a 100755 --- a/broker/src/main/java/io/moquette/BrokerConstants.java +++ b/broker/src/main/java/io/moquette/BrokerConstants.java @@ -190,6 +190,8 @@ public final class BrokerConstants { public static final String FRIEND_Reject_Request_Duration = "friend.reject_request_duration"; public static final String FRIEND_Request_Expiration_Duration = "friend.request_expiration_duration"; public static final String FRIEND_Request_Rate_Limit = "friend.request_rate_limit"; + public static final String FRIEND_Search_Mobile_Empty_Rate_Limit = "friend.search_mobile_empty_rate_limit"; + public static final String FRIEND_Search_Rate_Limit = "friend.search_rate_limit"; public static final String FRIEND_Request_Robot_Auto_Accept = "friend.robot_auto_accept"; diff --git a/broker/src/main/java/io/moquette/imhandler/UserSearchHandler.java b/broker/src/main/java/io/moquette/imhandler/UserSearchHandler.java index e0310637..609d5a41 100644 --- a/broker/src/main/java/io/moquette/imhandler/UserSearchHandler.java +++ b/broker/src/main/java/io/moquette/imhandler/UserSearchHandler.java @@ -15,13 +15,18 @@ import io.netty.buffer.ByteBuf; import cn.wildfirechat.common.ErrorCode; import win.liyufan.im.IMTopic; +import java.util.ArrayList; import java.util.List; @Handler(IMTopic.UserSearchTopic) public class UserSearchHandler extends IMHandler { @Override public ErrorCode action(ByteBuf ackPayload, String clientID, String fromUser, ProtoConstants.RequestSourceType requestSourceType, WFCMessage.SearchUserRequest request, Qos1PublishHandler.IMCallback callback) { - List users = m_messagesStore.searchUser(request.getKeyword(), request.getFuzzy(), request.getType(), request.getPage()); + List users = new ArrayList<>(); + ErrorCode errorCode = m_messagesStore.searchUser(fromUser, request.getKeyword(), request.getFuzzy(), request.getType(), request.getPage(), users); + if(errorCode != ErrorCode.ERROR_CODE_SUCCESS) { + return errorCode; + } WFCMessage.SearchUserResult.Builder builder = WFCMessage.SearchUserResult.newBuilder(); builder.addAllEntry(users); byte[] data = builder.build().toByteArray(); diff --git a/broker/src/main/java/io/moquette/persistence/MemoryMessagesStore.java b/broker/src/main/java/io/moquette/persistence/MemoryMessagesStore.java index 4e4e1f41..76f17c0c 100755 --- a/broker/src/main/java/io/moquette/persistence/MemoryMessagesStore.java +++ b/broker/src/main/java/io/moquette/persistence/MemoryMessagesStore.java @@ -58,6 +58,8 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.BiFunction; import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static cn.wildfirechat.common.IMExceptionEvent.EventType.EVENT_CALLBACK_Exception; import static cn.wildfirechat.proto.ProtoConstants.ChannelState.*; @@ -157,6 +159,8 @@ public class MemoryMessagesStore implements IMessagesStore { private long mFriendRejectDuration = 30 * 24 * 60 * 60 * 1000; private long mFriendRequestExpiration = 7 * 24 * 60 * 60 * 1000; private RateLimiter mFriendRateLimiter; + private RateLimiter mFriendSearchEmpthMobileRateLimiter; + private RateLimiter mFriendSearchRateLimiter; private boolean mFriendRobotAutoAccept = true; private long mPushExpiredTimes = 604800000L; @@ -380,6 +384,21 @@ public class MemoryMessagesStore implements IMessagesStore { } } catch (Exception e) { } + try { + int rateLimit = Integer.parseInt(m_Server.getConfig().getProperty(FRIEND_Search_Mobile_Empty_Rate_Limit, "0")); + if(rateLimit > 0) { + mFriendSearchEmpthMobileRateLimiter = new RateLimiter(86400, rateLimit); + } + } catch (Exception e) { + } + + try { + int rateLimit = Integer.parseInt(m_Server.getConfig().getProperty(FRIEND_Search_Rate_Limit, "0")); + if(rateLimit > 0) { + mFriendSearchRateLimiter = new RateLimiter(86400, rateLimit); + } + } catch (Exception e) { + } try { mFriendRobotAutoAccept = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.FRIEND_Request_Robot_Auto_Accept, "true")); @@ -3230,10 +3249,42 @@ public class MemoryMessagesStore implements IMessagesStore { return databaseStore.getAllUsers(count, offset); } + // 电话号码校验正则表达式(支持中国大陆手机号和固话) + private static final String PHONE_REGEX = "^\\s*" + // 允许开头空白 + "(?:" + + "(1[0-9])\\d{9}" + + "|" + + "((0\\d{2,3})|(\\(0\\d{2,3}\\)))" + + "[-\\s.]?" + + "\\d{7,8}" + + "|" + + "\\d{7,8}" + + ")\\s*$"; + + private static final Pattern PHONE_PATTERN = Pattern.compile(PHONE_REGEX); + private static final Pattern PHONE_PART_PATTERN = Pattern.compile("^1\\d{0,10}$"); + + public static boolean isPhoneNumber(String phone) { + if (phone == null || phone.trim().isEmpty()) { + return false; + } + Matcher matcher = PHONE_PATTERN.matcher(phone); + return matcher.matches(); + } + + public static boolean isPhoneNumberPart(String str) { + if (str == null || str.trim().isEmpty()) { + return false; + } + + Matcher matcher = PHONE_PART_PATTERN.matcher(str); + return matcher.matches(); + } + @Override - public List searchUser(String keyword, int searchType, int userType, int page) { + public ErrorCode searchUser(String userId, String keyword, int searchType, int userType, int page, List users) { if (mDisableSearch) { - return new ArrayList<>(); + return ErrorCode.ERROR_CODE_NOT_IMPLEMENT; } if (mDisableNicknameSearch && searchType == ProtoConstants.SearchUserType.SearchUserType_General) { @@ -3249,10 +3300,29 @@ public class MemoryMessagesStore implements IMessagesStore { } if(mDisableUserIdSearch && searchType == ProtoConstants.SearchUserType.SearchUserType_UserId) { - return new ArrayList<>(); + return ErrorCode.ERROR_CODE_NOT_IMPLEMENT; } - return databaseStore.searchUserFromDB(keyword, searchType, userType, page); + if(mFriendSearchRateLimiter != null && !isPhoneNumberPart(keyword)) { + //非电话号码,允许多少次搜索。 + if(!mFriendSearchRateLimiter.isGranted(userId)) { + LOG.error("User {} search user mobile over frequency, keyword {}, searchType {}", userId, keyword, searchType); + return ErrorCode.ERROR_CODE_OVER_FREQUENCY; + } + } + + List matchedUsers = databaseStore.searchUserFromDB(keyword, searchType, userType, page); + if(mFriendSearchEmpthMobileRateLimiter != null && matchedUsers.isEmpty() && isPhoneNumber(keyword)) { + //查电话号码为空 + if(!mFriendSearchEmpthMobileRateLimiter.isGranted(userId)) { + LOG.error("User {} search user over frequency, keyword {}, searchType {}", userId, keyword, searchType); + return ErrorCode.ERROR_CODE_OVER_FREQUENCY; + } + } + + users.addAll(matchedUsers); + + return ErrorCode.ERROR_CODE_SUCCESS; } @Override diff --git a/broker/src/main/java/io/moquette/spi/IMessagesStore.java b/broker/src/main/java/io/moquette/spi/IMessagesStore.java index 4ad51f07..f713fc9a 100755 --- a/broker/src/main/java/io/moquette/spi/IMessagesStore.java +++ b/broker/src/main/java/io/moquette/spi/IMessagesStore.java @@ -154,7 +154,7 @@ public interface IMessagesStore { WFCMessage.User getUserInfoByName(String name); WFCMessage.User getUserInfoByMobile(String mobile); List getUserInfosByEmail(String email); - List searchUser(String keyword, int searchType, int userType, int page); + ErrorCode searchUser(String userId, String keyword, int searchType, int userType, int page, List users); List getUserInfoList(int count, int offset); diff --git a/distribution/src/main/resources/wildfirechat.conf b/distribution/src/main/resources/wildfirechat.conf index ae0b729a..4cc0e59a 100755 --- a/distribution/src/main/resources/wildfirechat.conf +++ b/distribution/src/main/resources/wildfirechat.conf @@ -206,7 +206,13 @@ friend.reject_request_duration 2592000000 friend.request_expiration_duration 604800000 ##好友请求限制频率,一个用户24小时之内允许请求好友的次数,默认不限频。 -#friend.request_rate_limit 30 +friend.request_rate_limit 30 + +##如果搜索电话号码,24小时内搜索错误号码几次就不再允许电话号码搜素。防止有人遍历搜索电话号码 +friend.search_mobile_empty_rate_limit 5 + +##如果搜索用户,24小时内搜索次数。防止有人遍历用户名或者用户ID乱加好友。另外可以禁止ID搜索friend.disable_user_id_search +friend.search_rate_limit 100 ##请求添加机器人为好友时,机器人是否自动接受,默认为true friend.robot_auto_accept true