Compare commits

..
11 Commits
17 changed files with 113 additions and 34 deletions
+4
View File
@@ -13,6 +13,10 @@
</join>
</network>
<properties>
<property name="hazelcast.logging.type">slf4j</property>
</properties>
<!-- map eviction -->
<!-- http://docs.hazelcast.org/docs/latest-development/manual/html/Distributed_Data_Structures/Map/Map_Eviction.html -->
<map name="messages_map">
+10 -1
View File
@@ -74,6 +74,10 @@ message.blacklist.strategy 0
##是否禁止服务器端消息搜索,该功能暂未实现。目前的影响是如果打开,则存储消息时不单独保存_searchable_content字段
message.disable_remote_search false
##是否数据库中加密消息内容。注意这个开关在服务运行起来后不能改变了,避免读取数据库时无法恢复历史消息。
##如果要避免数据库中明文存储消息内容,请打开这个开关和message.disable_remote_search开关
message.encrypt_message_content false
##允许客户端撤回用户自己发送的消息时限,单位是秒。群组管理员或群主撤回群成员消息、server api不受此限制,可以撤回任意时限内的消息
message.recall_time_limit 120
@@ -197,10 +201,15 @@ local.media.storage.root media
# local.media.storage.remote_server_url https://example.com/media
# 是否支持多端登陆,为true时支持任意平台任意多个客户端同时登录;为false时每个平台只支持一个端登录,但不同平台可以同时登录。
# Android/iOS为移动平台,windows/mac/linux为pc平台,web为web平台,小程序为小程序平台。
server.multi_endpoint false
# 多平台连接状态通知(仅当multi_endpoint为false时有效),true时移动端可以收到pc或web端登录的通知。
server.multi_platform_notification false
server.multi_platform_notification true
# 当pc或者web在线时,手机是否默认静音,默认为true。注意仅影响默认值,用户可以手动切换是否静音。
# 如果这里改为false,客户端那边需要同步修改pc在线默认通知状态,方法是client的setDefaultSilentWhenPcOnline函数。
server.mobile_default_silent_when_pc_online true
#*********************************************************************
# Push server configuration
+1 -1
View File
@@ -5,7 +5,7 @@
<relativePath>../</relativePath>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>0.67</version>
<version>0.68</version>
</parent>
<artifactId>moquette-broker</artifactId>
@@ -46,21 +46,28 @@ public class FileAction extends Action {
return true;
}
final File file = getFileByPath(request.getPath());
Logger.debug("Client [{}] get file [{}]", request.getIp(), file.getPath());
File file = null;
try {
file = getFileByPath(request.getPath());
} catch (Exception e) {
response.sendError(HttpResponseStatus.NOT_FOUND, "404 File not found!");
return true;
}
// 隐藏文件,跳过
if (file.isHidden() || !file.exists()) {
// 隐藏文件或不存在,跳过
if (file == null || file.isHidden() || !file.exists()) {
response.sendError(HttpResponseStatus.NOT_FOUND, "404 File not found!");
return true;
}
// 非文件,跳过
if (false == file.isFile()) {
if (!file.isFile()) {
response.sendError(HttpResponseStatus.FORBIDDEN, "403 Forbidden!");
return true;
}
Logger.debug("Client [{}] get file [{}]", request.getIp(), file.getPath());
// Cache Validation
String ifModifiedSince = request.getHeader(HttpHeaderNames.IF_MODIFIED_SINCE.toString());
if (StrUtil.isNotBlank(ifModifiedSince)) {
@@ -132,6 +132,7 @@ public final class BrokerConstants {
public static final String SERVER_MULTI_ENDPOINT = "server.multi_endpoint";
public static final String SERVER_MULTI_PLATFROM_NOTIFICATION = "server.multi_platform_notification";
public static final String SERVER_MOBILE_DEFAULT_SILENT_WHEN_PC_ONLINE = "server.mobile_default_silent_when_pc_online";
public static final String MESSAGE_ROAMING = "message.roaming";
public static final String MESSAGE_Remote_History_Message = "message.remote_history_message";
@@ -167,6 +168,8 @@ public final class BrokerConstants {
public static final String MESSAGES_GLOBAL_MUTE_EXCEPTION_TYPES = "message.global_mute_exception_types";
public static final String MESSAGES_DISABLE_REMOTE_SEARCH = "message.disable_remote_search";
public static final String MESSAGES_ENCRYPT_MESSAGE_CONTENT = "message.encrypt_message_content";
public static final String MESSAGES_RECALL_TIME_LIMIT = "message.recall_time_limit";
public static final String MESSAGES_DISABLE_GROUP_MANAGER_RECALL = "message.disable_group_manager_recall";
@@ -37,7 +37,9 @@ public class HandleFriendRequestHandler extends IMHandler<WFCMessage.HandleFrien
long timestamp = System.currentTimeMillis();
builder.setMessageId(messageId);
builder.setServerTimestamp(timestamp);
saveAndPublish(request.getTargetUid(), null, builder.build());
if(!StringUtil.isNullOrEmpty(builder.getContent().getSearchableContent())) {
saveAndPublish(request.getTargetUid(), null, builder.build());
}
MemorySessionStore.Session session = m_sessionsStore.getSession(clientID);
String language = "zh_CN";
@@ -8,11 +8,11 @@
package io.moquette.persistence;
import cn.wildfirechat.common.IMExceptionEvent;
import cn.wildfirechat.pojos.SystemSettingPojo;
import cn.wildfirechat.proto.ProtoConstants;
import cn.wildfirechat.proto.WFCMessage;
import cn.wildfirechat.server.ThreadPoolExecutorWrapper;
import com.google.protobuf.InvalidProtocolBufferException;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.core.MultiMap;
import com.hazelcast.util.StringUtil;
@@ -26,7 +26,9 @@ import win.liyufan.im.MessageBundle;
import win.liyufan.im.MessageShardingUtil;
import win.liyufan.im.Utility;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.sql.*;
import java.util.*;
@@ -42,10 +44,15 @@ public class DatabaseStore {
private static final Logger LOG = LoggerFactory.getLogger(DatabaseStore.class);
private final ThreadPoolExecutorWrapper mScheduler;
private boolean disableRemoteMessageSearch = false;
private boolean encryptMessage = false;
public void setDisableRemoteMessageSearch(boolean disableRemoteMessageSearch) {
this.disableRemoteMessageSearch = disableRemoteMessageSearch;
}
public void setEncryptMessage(boolean encryptMessage) {
this.encryptMessage = encryptMessage;
}
public DatabaseStore(ThreadPoolExecutorWrapper scheduler) {
this.mScheduler = scheduler;
}
@@ -537,7 +544,7 @@ public class DatabaseStore {
statement.setString(index++, message.getConversation().getTarget());
statement.setInt(index++, message.getConversation().getLine());
Blob blob = connection.createBlob();
blob.setBytes(1, message.getContent().toByteArray());
blob.setBytes(1, encryptMessageContent(message.getContent().toByteArray(), false));
statement.setBlob(index++, blob);
if (!disableRemoteMessageSearch) {
statement.setString(index++, searchableContent);
@@ -571,6 +578,15 @@ public class DatabaseStore {
});
}
byte[] encryptMessageContent(byte[] in, boolean force) {
if(in != null && (encryptMessage || force)) {
for (int i = 0; i < in.length; i++) {
in[i] ^= 0xBD;
}
}
return in;
}
void persistSensitiveMessage(final WFCMessage.Message message) {
if(message.getContent().getPersistFlag() == Transparent) {
return;
@@ -599,7 +615,7 @@ public class DatabaseStore {
statement.setString(index++, message.getConversation().getTarget());
statement.setInt(index++, message.getConversation().getLine());
Blob blob = connection.createBlob();
blob.setBytes(1, message.getContent().toByteArray());
blob.setBytes(1, encryptMessageContent(message.getContent().toByteArray(), false));
statement.setBlob(index++, blob);
statement.setString(index++, searchableContent);
statement.setTimestamp(index++, new Timestamp(message.getServerTimestamp()));
@@ -668,7 +684,7 @@ public class DatabaseStore {
builder.setConversation(cb.build());
Blob blob = resultSet.getBlob(index++);
WFCMessage.MessageContent messageContent = WFCMessage.MessageContent.parseFrom(blob.getBinaryStream());
WFCMessage.MessageContent messageContent = WFCMessage.MessageContent.parseFrom(encryptMessageContent(toByteArray(blob.getBinaryStream()), false));
builder.setContent(messageContent);
builder.setServerTimestamp(resultSet.getTimestamp(index++).getTime());
WFCMessage.Message message = builder.build();
@@ -702,6 +718,16 @@ public class DatabaseStore {
return out;
}
public byte[] toByteArray(InputStream input) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
}
return output.toByteArray();
}
MessageBundle getMessage(long messageId) {
String sql = "select `_from`, `_type`, `_target`, `_line`, `_data`, `_dt` from " + MessageShardingUtil.getMessageTable(messageId) +" where _mid = ? order by `_dt` DESC limit 1";
Connection connection = null;
@@ -724,7 +750,7 @@ public class DatabaseStore {
builder.setConversation(cb.build());
Blob blob = resultSet.getBlob(index++);
WFCMessage.MessageContent messageContent = WFCMessage.MessageContent.parseFrom(blob.getBinaryStream());
WFCMessage.MessageContent messageContent = WFCMessage.MessageContent.parseFrom(encryptMessageContent(toByteArray(blob.getBinaryStream()), false));
builder.setContent(messageContent);
builder.setServerTimestamp(resultSet.getTimestamp(index++).getTime());
WFCMessage.Message message = builder.build();
@@ -829,7 +855,8 @@ public class DatabaseStore {
builder.setConversation(cb.build());
Blob blob = resultSet.getBlob(index++);
WFCMessage.MessageContent messageContent = WFCMessage.MessageContent.parseFrom(blob.getBinaryStream());
WFCMessage.MessageContent messageContent = WFCMessage.MessageContent.parseFrom(encryptMessageContent(toByteArray(blob.getBinaryStream()), false));
builder.setContent(messageContent);
builder.setServerTimestamp(resultSet.getTimestamp(index++).getTime());
@@ -133,6 +133,7 @@ public class MemoryMessagesStore implements IMessagesStore {
private boolean mFriendNewWelcomeMessage = true;
private boolean mMultiPlatformNotification = false;
private boolean mMobileDefaultSilentWhenPCOnline = true;
private boolean mDisableStrangerChat = false;
private long mChatroomParticipantIdleTime = 900000;
@@ -183,6 +184,12 @@ public class MemoryMessagesStore implements IMessagesStore {
printMissConfigLog(SERVER_MULTI_PLATFROM_NOTIFICATION, mMultiPlatformNotification + "");
}
try {
mMobileDefaultSilentWhenPCOnline = Boolean.parseBoolean(m_Server.getConfig().getProperty(SERVER_MOBILE_DEFAULT_SILENT_WHEN_PC_ONLINE, "true"));
} catch (Exception e) {
e.printStackTrace();
}
try {
mDisableSearch = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.FRIEND_Disable_Search));
} catch (Exception e) {
@@ -268,6 +275,12 @@ public class MemoryMessagesStore implements IMessagesStore {
} catch (Exception e) {
}
try {
boolean encryptMessage = Boolean.parseBoolean(m_Server.getConfig().getProperty(BrokerConstants.MESSAGES_ENCRYPT_MESSAGE_CONTENT, "false"));
databaseStore.setEncryptMessage(encryptMessage);
} catch (Exception e) {
}
try {
mRecallTimeLimit = Long.parseLong(m_Server.getConfig().getProperty(BrokerConstants.MESSAGES_RECALL_TIME_LIMIT));
} catch (Exception e) {
@@ -3394,9 +3407,9 @@ public class MemoryMessagesStore implements IMessagesStore {
public boolean getSilentWhenPcOnline(String userId) {
WFCMessage.UserSettingEntry entry = getUserSetting(userId, UserSettingScope.kUserSettingMuteWhenPCOnline, null);
if (entry != null && "1".equals(entry.getValue())) {
return true;
return !mMobileDefaultSilentWhenPCOnline;
} else {
return false;
return mMobileDefaultSilentWhenPCOnline;
}
}
private Date getTodayDate() {
@@ -108,7 +108,7 @@ public class DBUtil {
Flyway flyway = Flyway.configure().dataSource(comboPooledDataSource).locations(migrateLocation).baselineOnMigrate(true).load();
if(!IsEmbedDB && (flyway.info().current() == null || flyway.info().current().getVersion().getMajor().intValue() < 43)) {
System.out.println("数据库升级需要较长时间,可能长达数分钟或更长,请耐心等待,不要中断。。。");
System.out.println("数据库执行初始化或升级需要较长时间,可能长达数分钟或更长,请耐心等待,不要中断。。。");
}
flyway.migrate();
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>0.67</version>
<version>0.68</version>
</parent>
<modelVersion>4.0.0</modelVersion>
+1 -1
View File
@@ -6,7 +6,7 @@
<!--<relativePath>../pom.xml</relativePath>-->
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>0.67</version>
<version>0.68</version>
</parent>
<artifactId>distribution</artifactId>
@@ -9,6 +9,10 @@
</join>
</network>
<properties>
<property name="hazelcast.logging.type">slf4j</property>
</properties>
<!-- map eviction -->
<!-- http://docs.hazelcast.org/docs/latest-development/manual/html/Distributed_Data_Structures/Map/Map_Eviction.html -->
<map name="messages_map">
@@ -69,6 +69,10 @@ message.blacklist.strategy 0
##是否禁止服务器端消息搜索,该功能暂未实现。目前的影响是如果打开,则存储消息时不单独保存_searchable_content字段
message.disable_remote_search false
##是否数据库中加密消息内容。注意这个开关在服务运行起来后不能改变了,避免读取数据库时无法恢复历史消息。
##如果要避免数据库中明文存储消息内容,请打开这个开关和message.disable_remote_search开关
message.encrypt_message_content false
##允许客户端撤回用户自己发送的消息时限,单位是秒。群组管理员或群主撤回群成员消息、server api不受此限制,可以撤回任意时限内的消息
message.recall_time_limit 120
@@ -194,10 +198,15 @@ local.media.storage.root ./media
# local.media.storage.remote_server_url https://example.com/media
# 是否支持多端登陆,为true时支持任意平台任意多个客户端同时登录;为false时每个平台只支持一个端登录,但不同平台可以同时登录。
# Android/iOS为移动平台,windows/mac/linux为pc平台,web为web平台,小程序为小程序平台。
server.multi_endpoint false
# 多平台连接状态通知(仅当multi_endpoint为false时有效),true时移动端可以收到pc或web端登录的通知。
server.multi_platform_notification false
server.multi_platform_notification true
# 当pc或者web在线时,手机是否默认静音,默认为true。注意仅影响默认值,用户可以手动切换是否静音。
# 如果这里改为false,客户端那边需要同步修改pc在线默认通知状态,方法是client的setDefaultSilentWhenPcOnline函数。
server.mobile_default_silent_when_pc_online true
#*********************************************************************
# Push server configuration
+10 -8
View File
@@ -72,18 +72,20 @@ JAVA_OPTS="$JAVA_OPTS -XX:MaxGCPauseMillis=500"
### GC logging options -- uncomment to enable
JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDetails"
#JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDetails"
#JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCDateStamps"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintHeapAtGC"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintTenuringDistribution"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCApplicationStoppedTime"
JAVA_OPTS="$JAVA_OPTS -XX:+PrintPromotionFailure"
#JAVA_OPTS="$JAVA_OPTS -XX:+PrintHeapAtGC"
#JAVA_OPTS="$JAVA_OPTS -XX:+PrintTenuringDistribution"
#JAVA_OPTS="$JAVA_OPTS -XX:+PrintGCApplicationStoppedTime"
#JAVA_OPTS="$JAVA_OPTS -XX:+PrintPromotionFailure"
#JAVA_OPTS="$JAVA_OPTS -XX:PrintFLSStatistics=1"
JAVA_OPTS="$JAVA_OPTS -XX:+UseGCLogFileRotation"
JAVA_OPTS="$JAVA_OPTS -XX:NumberOfGCLogFiles=10"
JAVA_OPTS="$JAVA_OPTS -XX:GCLogFileSize=10M"
#JAVA_OPTS="$JAVA_OPTS -XX:+UseGCLogFileRotation"
#JAVA_OPTS="$JAVA_OPTS -XX:NumberOfGCLogFiles=10"
#JAVA_OPTS="$JAVA_OPTS -XX:GCLogFileSize=10M"
echo ""
echo "请设置JVM参数Xmx和Xms!!!"
echo ""
#JAVA_OPTS="$JAVA_OPTS -Xmx2G"
#JAVA_OPTS="$JAVA_OPTS -Xms2G"
+1 -1
View File
@@ -12,7 +12,7 @@
<artifactId>wildfirechat-parent</artifactId>
<packaging>pom</packaging>
<version>0.67</version>
<version>0.68</version>
<name>Wildfire Chat</name>
<description>Wildfire Chat Server</description>
<inceptionYear>2019</inceptionYear>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>wildfirechat-parent</artifactId>
<groupId>cn.wildfirechat</groupId>
<version>0.67</version>
<version>0.68</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -43,9 +43,8 @@ public class GeneralAdmin {
out.result = result.result != null && "1".equals(result.result.getValue());
return out;
}
private static IMResult<UserSettingPojo> getUserSetting(String userId, int scope, String key) throws Exception {
public static IMResult<UserSettingPojo> getUserSetting(String userId, int scope, String key) throws Exception {
String path = APIPath.User_Get_Setting;
UserSettingPojo pojo = new UserSettingPojo();
pojo.setUserId(userId);
@@ -54,7 +53,7 @@ public class GeneralAdmin {
return AdminHttpUtils.httpJsonPost(path, pojo, UserSettingPojo.class);
}
private static IMResult<Void> setUserSetting(String userId, int scope, String key, String value) throws Exception {
public static IMResult<Void> setUserSetting(String userId, int scope, String key, String value) throws Exception {
String path = APIPath.User_Put_Setting;
UserSettingPojo pojo = new UserSettingPojo();
pojo.setUserId(userId);