实现了挂机时间的追踪以及活跃度计算
修改了Yag部分接口存在的bug 目前可以实现注册、登录游戏、生成邀请码、验证邀请码、统计在线时间活跃度 (注册时的身份证信息暂时没有做实名认证,仅仅进行存储与重复校验) 下一步计划加入实名认证接口及相关配置
This commit is contained in:
parent
ab7afe3fc0
commit
ed74cf9aca
24
README.md
24
README.md
@ -1,9 +1,24 @@
|
||||
# IdentityVerification
|
||||
|
||||
外置登录与实名认证(带web后台)
|
||||
|
||||
## 功能介绍 (TODO List)
|
||||
## 🔏 隐私声明
|
||||
|
||||
### 外置登录服务器
|
||||
1. 本系统不会收集任何用户的个人信息,包括但不限于:姓名、身份证号、密码、IP地址、设备信息、浏览器信息、操作系统信息、地理位置信息等。
|
||||
2. 实名认证调用由[苏州云亿互通信息服务有限公司](https://yunyidata.com)提供的身份证实名认证查询校验接口。
|
||||
3. 本系统不会在后台保存任何身份证信息,仅对身份证号做哈希计算后(无法逆向得到真实身份证号码)存库用于唯一性验证。(可参见源码的[SignWhiteList接口](https://github.com/ColdeZhang/IdentityVerification/blob/main/src/main/java/site/deercloud/identityverification/HttpServer/Api/SignWhiteList.java)设计)
|
||||
4. 任何使用本系统的个人或组织都有义务保证用户的个人信息安全,不得明文存储用户个人信息或将用户的个人信息泄露给任何第三方。
|
||||
5. 使用本系统请确保从本项目的Release页面下载并校验md5或自行拉取源码编译,不要下载任何第三方修改的版本,否则可能会造成信息泄露。
|
||||
|
||||
## 🧾 功能介绍 (TODO List)
|
||||
|
||||
### 系统功能部分
|
||||
|
||||
- [x] 非白名单拦截
|
||||
- [x] 黑名单(封禁)拦截
|
||||
- [x] 活跃度计算
|
||||
|
||||
### 外置登录服务部分
|
||||
|
||||
- [x] 用户登录
|
||||
- [x] 刷新令牌
|
||||
@ -16,10 +31,11 @@
|
||||
- [ ] 材质(皮肤)上传/删除
|
||||
- [ ] 多角色支持
|
||||
|
||||
### Web服务器
|
||||
### Web服务部分
|
||||
|
||||
- [x] 用户注册
|
||||
- [ ] 邀请码生成
|
||||
- [x] 邀请码生成、管理
|
||||
- [x] 邮箱验证码
|
||||
- [ ] 实名认证白名单
|
||||
- [ ] 用户管理
|
||||
- [ ] 用户登录
|
||||
|
@ -14,7 +14,7 @@ public class Commands implements TabExecutor {
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
switch (args[0]) {
|
||||
case "reload":
|
||||
IdentityVerification.getInstance().getConfigManager().reload(sender);
|
||||
IdentityVerification.configManager.reload(sender);
|
||||
break;
|
||||
case "genCode":
|
||||
// TODO: 需要校验玩家是否符合活跃度要求
|
||||
|
@ -1,8 +1,12 @@
|
||||
package site.deercloud.identityverification.Controller;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import site.deercloud.identityverification.HttpServer.model.GameSession;
|
||||
import site.deercloud.identityverification.IdentityVerification;
|
||||
import site.deercloud.identityverification.Utils.MyLogger;
|
||||
import site.deercloud.identityverification.Utils.UnsignedUUID;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@ -24,74 +28,75 @@ public class AFKTracker {
|
||||
|
||||
public long getAfkThreshold() {
|
||||
if (afkThresholdMs == null) {
|
||||
afkThresholdMs = 1000L * 10L;
|
||||
afkThresholdMs = 1000L * 30L;
|
||||
}
|
||||
return afkThresholdMs;
|
||||
}
|
||||
|
||||
public void hasIgnorePermission(String playerUUID) {
|
||||
storeLastMovement(playerUUID, IGNORES_AFK);
|
||||
public void hasIgnorePermission(Player player) {
|
||||
storeLastMovement(player, IGNORES_AFK);
|
||||
}
|
||||
|
||||
private void storeLastMovement(String playerUUID, long time) {
|
||||
GameSessionCache.getCacheSession(playerUUID)
|
||||
.ifPresent(gameSession -> gameSession.setLastMovement(time));
|
||||
private void storeLastMovement(Player player, long time) {
|
||||
String playerUUID = UnsignedUUID.UnUUIDof(player);
|
||||
GameSessionCache.getCacheSession(playerUUID).ifPresent(gameSession -> gameSession.setLastMovement(time));
|
||||
}
|
||||
|
||||
private long getLastMovement(String playerUUID, long time) {
|
||||
return getLastMovement(playerUUID)
|
||||
.orElse(time);
|
||||
private long getLastMovement(Player player, long time) {
|
||||
return getLastMovement(player).orElse(time);
|
||||
}
|
||||
|
||||
private Optional<Long> getLastMovement(String playerUUID) {
|
||||
return GameSessionCache.getCacheSession(playerUUID)
|
||||
.map(GameSession::getLastMovement);
|
||||
private Optional<Long> getLastMovement(Player player) {
|
||||
String playerUUID = UnsignedUUID.UnUUIDof(player);
|
||||
return GameSessionCache.getCacheSession(playerUUID).map(GameSession::getLastMovement);
|
||||
}
|
||||
|
||||
public void usedAfkCommand(String playerUUID, long time) {
|
||||
long lastMoved = getLastMovement(playerUUID, time);
|
||||
public void usedAfkCommand(Player player, long time) {
|
||||
String playerUUID = UnsignedUUID.UnUUIDof(player);
|
||||
long lastMoved = getLastMovement(player, time);
|
||||
if (lastMoved == IGNORES_AFK) {
|
||||
return;
|
||||
}
|
||||
usedAFKCommand.add(playerUUID);
|
||||
storeLastMovement(playerUUID, time - getAfkThreshold());
|
||||
storeLastMovement(player, time - getAfkThreshold());
|
||||
}
|
||||
|
||||
public long performedAction(String playerUUID, long time) {
|
||||
long lastMoved = getLastMovement(playerUUID, time);
|
||||
public long performedAction(Player player, long time) {
|
||||
String playerUUID = UnsignedUUID.UnUUIDof(player);
|
||||
long lastMoved = getLastMovement(player, time);
|
||||
// Ignore afk permission
|
||||
if (lastMoved == IGNORES_AFK) {
|
||||
return 0L;
|
||||
}
|
||||
storeLastMovement(playerUUID, time);
|
||||
storeLastMovement(player, time);
|
||||
|
||||
try {
|
||||
if (time - lastMoved < getAfkThreshold()) {
|
||||
// Threshold not crossed, no action required.
|
||||
return 0L;
|
||||
}
|
||||
|
||||
long removeAfkCommandEffect = usedAFKCommand.contains(playerUUID) ? getAfkThreshold() : 0;
|
||||
long timeAFK = time - lastMoved - removeAfkCommandEffect;
|
||||
|
||||
GameSessionCache.getCacheSession(playerUUID)
|
||||
.ifPresent(gameSession -> gameSession.addAfkTime(timeAFK));
|
||||
MyLogger.debug(player.getName() + " 本次挂机时间:" + timeAFK / 1000 / 60 + "分" + time / 1000 % 60 + "秒");
|
||||
GameSessionCache.getCacheSession(playerUUID).ifPresent(gameSession -> gameSession.addAfkTime(timeAFK));
|
||||
return timeAFK;
|
||||
} finally {
|
||||
usedAFKCommand.remove(playerUUID);
|
||||
}
|
||||
}
|
||||
|
||||
public long loggedOut(String uuid, long time) {
|
||||
long timeAFK = performedAction(uuid, time);
|
||||
usedAFKCommand.remove(uuid);
|
||||
public long loggedOut(Player player, long time) {
|
||||
long timeAFK = performedAction(player, time);
|
||||
String playerUUID = UnsignedUUID.UnUUIDof(player);
|
||||
usedAFKCommand.remove(playerUUID);
|
||||
return timeAFK;
|
||||
}
|
||||
|
||||
public boolean isAfk(String playerUUID) {
|
||||
public boolean isAfk(Player player) {
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
Optional<Long> lastMoved = getLastMovement(playerUUID);
|
||||
Optional<Long> lastMoved = getLastMovement(player);
|
||||
if (lastMoved.isEmpty() || lastMoved.get() == IGNORES_AFK) {
|
||||
return false;
|
||||
}
|
||||
|
@ -0,0 +1,108 @@
|
||||
package site.deercloud.identityverification.Controller;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import site.deercloud.identityverification.HttpServer.model.ActiveIndex;
|
||||
import site.deercloud.identityverification.HttpServer.model.PlayTimeStatics;
|
||||
import site.deercloud.identityverification.SQLite.ActiveIndexDAO;
|
||||
import site.deercloud.identityverification.SQLite.PlayTimeDAO;
|
||||
import site.deercloud.identityverification.Utils.MyLogger;
|
||||
import site.deercloud.identityverification.Utils.UnsignedUUID;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ActiveIndexManager {
|
||||
|
||||
public ActiveIndexManager() {
|
||||
try {
|
||||
ArrayList<ActiveIndex> activityRecords = ActiveIndexDAO.selectActivityRecords();
|
||||
if (activityRecords.size() == 0) {
|
||||
// 没有活跃玩家则默认每周游戏时间2小时
|
||||
playtimeMsThreshold = 1000L * 60 * 60 * 2;
|
||||
} else {
|
||||
// 计算活跃玩家的平均每周游戏时间
|
||||
Long sum = 0L;
|
||||
for (ActiveIndex record : activityRecords) {
|
||||
sum += record.recentWeek;
|
||||
}
|
||||
playtimeMsThreshold = sum / activityRecords.size();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
MyLogger.debug(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Long playtimeMsThreshold = 1000L * 60 * 30;
|
||||
|
||||
public static final double VERY_ACTIVE = 3.75;
|
||||
public static final double ACTIVE = 3.0;
|
||||
public static final double REGULAR = 2.0;
|
||||
public static final double IRREGULAR = 1.0;
|
||||
|
||||
public double getActiveIndex(Player player) {
|
||||
try {
|
||||
String uuid = UnsignedUUID.UnUUIDof(player);
|
||||
ActiveIndex activeIndex = ActiveIndexDAO.query(uuid);
|
||||
if (activeIndex == null) {
|
||||
return 0.0;
|
||||
} else {
|
||||
return activeIndex.index;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
MyLogger.debug(e);
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
public double updateIndex(Player player) {
|
||||
String uuid = UnsignedUUID.UnUUIDof(player);
|
||||
|
||||
long current = System.currentTimeMillis();
|
||||
|
||||
long sevenDays = 1000L * 60 * 60 * 24 * 7;
|
||||
long weekAgo = current - sevenDays;
|
||||
long twoWeeksAgo = weekAgo - sevenDays;
|
||||
long threeWeeksAgo = twoWeeksAgo - sevenDays;
|
||||
|
||||
try {
|
||||
if (PlayTimeDAO.countsOfPlayer(uuid, threeWeeksAgo, current) <= 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
ArrayList<PlayTimeStatics> weekOne = PlayTimeDAO.selectByTime(uuid, weekAgo, current);
|
||||
ArrayList<PlayTimeStatics> weekTwo = PlayTimeDAO.selectByTime(uuid, twoWeeksAgo, weekAgo);
|
||||
ArrayList<PlayTimeStatics> weekThree = PlayTimeDAO.selectByTime(uuid, threeWeeksAgo, twoWeeksAgo);
|
||||
|
||||
Long playtime1 = PlayTimeStatics.totalActivityTimeOf(weekOne);
|
||||
Long playtime2 = PlayTimeStatics.totalActivityTimeOf(weekTwo);
|
||||
Long playtime3 = PlayTimeStatics.totalActivityTimeOf(weekThree);
|
||||
|
||||
double indexW1 = 1.0 / (Math.PI / 2.0 * ((double) playtime1 / playtimeMsThreshold) + 1.0);
|
||||
double indexW2 = 1.0 / (Math.PI / 2.0 * ((double) playtime2 / playtimeMsThreshold) + 1.0);
|
||||
double indexW3 = 1.0 / (Math.PI / 2.0 * ((double) playtime3 / playtimeMsThreshold) + 1.0);
|
||||
|
||||
double average = (indexW1 + indexW2 + indexW3) / 3.0;
|
||||
|
||||
ActiveIndex activeIndex = new ActiveIndex();
|
||||
activeIndex.playerUuid = uuid;
|
||||
activeIndex.recentWeek = playtime1;
|
||||
activeIndex.oneWeekAgo = playtime2;
|
||||
activeIndex.twoWeekAgo = playtime3;
|
||||
activeIndex.index = Math.round((5.0 - (5.0 * average)) * 100) / 100.0;
|
||||
MyLogger.debug("\t" + player.getName() + "当前的活跃度为" + activeIndex.index);
|
||||
|
||||
if (ActiveIndexDAO.query(uuid) == null) {
|
||||
ActiveIndexDAO.insert(activeIndex);
|
||||
} else {
|
||||
ActiveIndexDAO.update(activeIndex);
|
||||
}
|
||||
|
||||
return 5.0 - (5.0 * average);
|
||||
} catch (SQLException e) {
|
||||
MyLogger.debug(e);
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
}
|
@ -45,6 +45,7 @@ public class ConfigManager {
|
||||
m_Description = config.getString("Web.Description");
|
||||
m_YagdrasilUrl = config.getString("Web.YagdrasilUrl");
|
||||
m_ServerUrl = config.getString("Web.ServerUrl");
|
||||
m_WhiteList = config.getBoolean("WhiteList");
|
||||
MyLogger.info("配置文件加载完成。");
|
||||
}
|
||||
|
||||
@ -258,6 +259,15 @@ public class ConfigManager {
|
||||
plugin.saveConfig();
|
||||
}
|
||||
|
||||
public Boolean getWhiteList() {
|
||||
return m_WhiteList;
|
||||
}
|
||||
public void setWhiteList(Boolean whiteList) {
|
||||
m_WhiteList = whiteList;
|
||||
config.set("WhiteList", whiteList);
|
||||
plugin.saveConfig();
|
||||
}
|
||||
|
||||
private String m_ServerName;
|
||||
private String m_ImplementationName;
|
||||
private String m_ImplementationVersion;
|
||||
@ -283,6 +293,7 @@ public class ConfigManager {
|
||||
private String m_Description;
|
||||
private String m_YagdrasilUrl;
|
||||
private String m_ServerUrl;
|
||||
private Boolean m_WhiteList;
|
||||
|
||||
IdentityVerification plugin;
|
||||
FileConfiguration config;
|
||||
|
@ -23,12 +23,12 @@ public class EmailCodeCache {
|
||||
}
|
||||
|
||||
public static boolean isEmailCodeExpired(String email) {
|
||||
if (IdentityVerification.getInstance().getConfigManager().getDebug()) return false;
|
||||
if (IdentityVerification.configManager.getDebug()) return false;
|
||||
return getEmailCode(email).map(EmailCode::isExpired).orElse(true);
|
||||
}
|
||||
|
||||
public static boolean isEmailCodeValid(String email, String code) {
|
||||
if (IdentityVerification.getInstance().getConfigManager().getDebug()) return true;
|
||||
if (IdentityVerification.configManager.getDebug()) return true;
|
||||
return getEmailCode(email).map(emailCode -> emailCode.code.equals(code)).orElse(false);
|
||||
}
|
||||
}
|
||||
|
@ -2,8 +2,12 @@ package site.deercloud.identityverification.Controller;
|
||||
|
||||
|
||||
import site.deercloud.identityverification.HttpServer.model.GameSession;
|
||||
import site.deercloud.identityverification.HttpServer.model.PlayTimeStatics;
|
||||
import site.deercloud.identityverification.IdentityVerification;
|
||||
import site.deercloud.identityverification.SQLite.PlayTimeDAO;
|
||||
import site.deercloud.identityverification.Utils.MyLogger;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@ -15,12 +19,32 @@ public class GameSessionCache {
|
||||
}
|
||||
|
||||
public static void addSession(String playerUUID) {
|
||||
MyLogger.debug("添加缓存会话,开始记录活动状态:" + playerUUID);
|
||||
ACTIVE_SESSIONS.put(playerUUID, new GameSession());
|
||||
}
|
||||
|
||||
public static void removeSession(String playerUUID) {
|
||||
// TODO: save to database
|
||||
|
||||
// 存库 (活跃时间、挂机时间)
|
||||
PlayTimeStatics statics = new PlayTimeStatics();
|
||||
if (getCacheSession(playerUUID).isEmpty()) {
|
||||
return;
|
||||
}
|
||||
GameSession session = getCacheSession(playerUUID).get();
|
||||
statics.joinTime = session.joinTime;
|
||||
statics.quitTime = System.currentTimeMillis();
|
||||
statics.onlineTime = statics.quitTime - statics.joinTime;
|
||||
statics.afkTime = session.afkTime;
|
||||
statics.activeTime = statics.onlineTime - statics.afkTime;
|
||||
statics.playerUuid = playerUUID;
|
||||
MyLogger.debug(playerUUID + "\n\t本次游戏在线时间: " + statics.onlineTime / 1000 / 60 + "min" + statics.onlineTime / 1000 % 60 + "s"
|
||||
+ "\n\t本次游戏挂机时间: " + statics.afkTime / 1000 / 60 + "min" + statics.afkTime / 1000 % 60 + "s"
|
||||
+ "\n\t本次游戏活跃时间: " + statics.activeTime / 1000 / 60 + "min" + statics.activeTime / 1000 % 60 + "s"
|
||||
+ "\n\t本次游戏挂机率: " + (double) Math.round((double) statics.afkTime / statics.onlineTime * 10000) / 100 + "%");
|
||||
try {
|
||||
PlayTimeDAO.insert(statics);
|
||||
} catch (SQLException e) {
|
||||
MyLogger.debug(e);
|
||||
}
|
||||
ACTIVE_SESSIONS.remove(playerUUID);
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,7 @@ package site.deercloud.identityverification;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.*;
|
||||
import site.deercloud.identityverification.Controller.GameSessionCache;
|
||||
import site.deercloud.identityverification.SQLite.BanListDAO;
|
||||
import site.deercloud.identityverification.SQLite.WhiteListDAO;
|
||||
@ -21,8 +20,9 @@ public class Events implements Listener {
|
||||
Player player = event.getPlayer();
|
||||
String uuid = UnsignedUUID.UnUUIDof(player);
|
||||
MyLogger.debug(uuid);
|
||||
if (!WhiteListDAO.isUuidInWhiteList(uuid)) {
|
||||
if (!WhiteListDAO.isUuidInWhiteList(uuid) && IdentityVerification.configManager.getWhiteList()) {
|
||||
player.kickPlayer("你没有完成白名单实名认证,请前往 " + configManager.getHomePageUrl() + " 进行认证。");
|
||||
return;
|
||||
}
|
||||
Integer ban_record_id = BanListDAO.isBanned(uuid);
|
||||
if (ban_record_id > 0) {
|
||||
@ -30,20 +30,27 @@ public class Events implements Listener {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
String ban_time = sdf.format(BanListDAO.getBanTimeById(ban_record_id));
|
||||
player.kickPlayer("你已被封禁,请联系管理员。原因:[ " + ban_reason + " ]" + " 至:" + ban_time);
|
||||
return;
|
||||
}
|
||||
GameSessionCache.addSession(UnsignedUUID.UnUUIDof(event.getPlayer()));
|
||||
IdentityVerification.activeIndexManager.updateIndex(player);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerJoinEvent event) throws SQLException {
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
IdentityVerification.afkTracker.performedAction(event.getPlayer(), System.currentTimeMillis());
|
||||
GameSessionCache.removeSession(UnsignedUUID.UnUUIDof(event.getPlayer()));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerMove(PlayerMoveEvent event) throws SQLException {
|
||||
Player player = event.getPlayer();
|
||||
IdentityVerification.getAfkTracker().performedAction(UnsignedUUID.UnUUIDof(event.getPlayer()), System.currentTimeMillis());
|
||||
public void onPlayerMove(PlayerMoveEvent event) {
|
||||
IdentityVerification.afkTracker.performedAction(event.getPlayer(), System.currentTimeMillis());
|
||||
}
|
||||
|
||||
ConfigManager configManager = IdentityVerification.getInstance().getConfigManager();
|
||||
@EventHandler
|
||||
public void onPlayerChat(AsyncPlayerChatEvent event) {
|
||||
IdentityVerification.afkTracker.performedAction(event.getPlayer(), System.currentTimeMillis());
|
||||
}
|
||||
|
||||
ConfigManager configManager = IdentityVerification.configManager;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ public class GetEmailCode implements HttpHandler {
|
||||
jsonResponse(exchange, 400, "此邮箱已被注册。", null);
|
||||
return;
|
||||
}
|
||||
if (!EmailCodeCache.isEmailCodeExpired(email) && !IdentityVerification.getInstance().getConfigManager().getDebug()) {
|
||||
if (!EmailCodeCache.isEmailCodeExpired(email) && !IdentityVerification.configManager.getDebug()) {
|
||||
jsonResponse(exchange, 500, "禁止频繁操作!", null);
|
||||
return;
|
||||
}
|
||||
|
@ -16,11 +16,11 @@ public class WebMeta implements HttpHandler {
|
||||
public void handle(HttpExchange exchange){
|
||||
try {
|
||||
requestHeader(exchange, "GET");
|
||||
String title = IdentityVerification.getInstance().getConfigManager().getServerName();
|
||||
String description = IdentityVerification.getInstance().getConfigManager().getDescription();
|
||||
String version = IdentityVerification.getInstance().getConfigManager().getImplementationName() + "-" + IdentityVerification.getInstance().getConfigManager().getImplementationVersion();
|
||||
String yagUrl = IdentityVerification.getInstance().getConfigManager().getYagdrasilUrl();
|
||||
String serverUrl = IdentityVerification.getInstance().getConfigManager().getServerUrl();
|
||||
String title = IdentityVerification.configManager.getServerName();
|
||||
String description = IdentityVerification.configManager.getDescription();
|
||||
String version = IdentityVerification.configManager.getImplementationName() + "-" + IdentityVerification.configManager.getImplementationVersion();
|
||||
String yagUrl = IdentityVerification.configManager.getYagdrasilUrl();
|
||||
String serverUrl = IdentityVerification.configManager.getServerUrl();
|
||||
Boolean use_yag = true; // 是否使用外置登录
|
||||
Boolean use_genuine = true; // 是否使用正版验证
|
||||
Boolean need_invite = true; // 是否需要邀请码
|
||||
|
@ -37,7 +37,7 @@ import java.util.concurrent.TimeUnit;
|
||||
public class HttpServerManager {
|
||||
|
||||
public HttpServerManager(IdentityVerification plugin) {
|
||||
configManager = plugin.getConfigManager();
|
||||
configManager = IdentityVerification.configManager;
|
||||
// 注册路由
|
||||
try {
|
||||
|
||||
|
@ -18,15 +18,16 @@ public class WebServer implements HttpHandler {
|
||||
}
|
||||
String file_type = uri.substring(uri.lastIndexOf(".") + 1);
|
||||
|
||||
InputStream file = IdentityVerification.getInstance().getResource("web" + uri);
|
||||
InputStream file = IdentityVerification.instance.getResource("web" + uri);
|
||||
if (file == null){
|
||||
MyLogger.debug("File not found: " + uri);
|
||||
exchange.sendResponseHeaders(404, 0);
|
||||
exchange.close();
|
||||
return;
|
||||
}
|
||||
String file_content = new String(file.readAllBytes()).replace("127.0.0.1:11520",
|
||||
IdentityVerification.getInstance().getConfigManager().getHomePageUrl());
|
||||
String file_content = new String(file.readAllBytes()).replace("http://127.0.0.1:11520",
|
||||
IdentityVerification.configManager.getHomePageUrl()).
|
||||
replace("XXXXX_Server", IdentityVerification.configManager.getServerName());
|
||||
switch (file_type) {
|
||||
case "js" -> exchange.getResponseHeaders().add("Content-Type", "application/javascript; charset=UTF-8");
|
||||
case "css" -> exchange.getResponseHeaders().add("Content-Type", "text/css; charset=UTF-8");
|
||||
|
@ -16,7 +16,7 @@ public class WebTest implements HttpHandler {
|
||||
String uri = exchange.getRequestURI().toString();
|
||||
// 按照uri从resource中读取文件返回
|
||||
|
||||
InputStream file = IdentityVerification.getInstance().getResource("web" + uri);
|
||||
InputStream file = IdentityVerification.instance.getResource("web" + uri);
|
||||
if (file == null){
|
||||
MyLogger.debug("File not found: " + uri);
|
||||
exchange.sendResponseHeaders(404, 0);
|
||||
|
@ -22,7 +22,7 @@ public class MetaData implements HttpHandler {
|
||||
Response.err_method_not_allowed(exchange);
|
||||
return;
|
||||
}
|
||||
ConfigManager configManager = IdentityVerification.getInstance().getConfigManager();
|
||||
ConfigManager configManager = IdentityVerification.configManager;
|
||||
JSONObject meta_json = new JSONObject();
|
||||
meta_json.put("serverName", configManager.getServerName());
|
||||
meta_json.put("implementationName", configManager.getImplementationName());
|
||||
|
@ -24,6 +24,7 @@ public class Authenticate implements HttpHandler {
|
||||
@Override
|
||||
public void handle(HttpExchange exchange){
|
||||
try {
|
||||
MyLogger.debug("Authenticate post 接口触发");
|
||||
exchange.getResponseHeaders().add("Content-Type", "application/json; charset=UTF-8");
|
||||
if (!exchange.getRequestMethod().equals("POST")){
|
||||
Response.err_method_not_allowed(exchange);
|
||||
|
@ -18,6 +18,7 @@ public class Invalidate implements HttpHandler {
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) {
|
||||
try {
|
||||
MyLogger.debug("Invalidate post 接口触发");
|
||||
exchange.getResponseHeaders().add("Content-Type", "application/json; charset=UTF-8");
|
||||
if (!exchange.getRequestMethod().equals("POST")) {
|
||||
Response.err_method_not_allowed(exchange);
|
||||
|
@ -23,6 +23,7 @@ public class Refresh implements HttpHandler {
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) {
|
||||
try {
|
||||
MyLogger.debug("Refresh post 接口触发");
|
||||
// 设置响应头
|
||||
exchange.getResponseHeaders().add("Content-Type", "application/json; charset=UTF-8");
|
||||
if (!exchange.getRequestMethod().equals("POST")) {
|
||||
|
@ -23,6 +23,7 @@ public class SignOut implements HttpHandler {
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) {
|
||||
try {
|
||||
MyLogger.debug("SignOut post 接口触发");
|
||||
exchange.getResponseHeaders().add("Content-Type", "application/json; charset=UTF-8");
|
||||
if (!exchange.getRequestMethod().equals("POST")) {
|
||||
Response.err_method_not_allowed(exchange);
|
||||
|
@ -20,6 +20,7 @@ public class Validate implements HttpHandler {
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) throws IOException {
|
||||
try {
|
||||
MyLogger.debug("Validate post 接口触发");
|
||||
exchange.getResponseHeaders().add("Content-Type", "application/json; charset=UTF-8");
|
||||
if (!exchange.getRequestMethod().equals("POST")){
|
||||
Response.err_method_not_allowed(exchange);
|
||||
|
@ -19,22 +19,27 @@ public class GetProfile implements HttpHandler {
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) {
|
||||
try {
|
||||
MyLogger.debug("GetProfile get 接口触发");
|
||||
exchange.getResponseHeaders().add("Content-Type", "application/json; charset=UTF-8");
|
||||
if (!exchange.getRequestMethod().equals("GET")) {
|
||||
Response.err_method_not_allowed(exchange);
|
||||
return;
|
||||
}
|
||||
String uuid = exchange.getRequestURI().getPath().split("/")[4];
|
||||
String uuid = exchange.getRequestURI().getPath().split("/")[5];
|
||||
MyLogger.debug("GetProfile Path: " + exchange.getRequestURI().getPath());
|
||||
Map<String, String> request = getQuery(exchange);
|
||||
boolean unsigned = true;
|
||||
if (request.containsKey("unsigned")) {
|
||||
unsigned = Boolean.parseBoolean(request.get("unsigned"));
|
||||
}
|
||||
MyLogger.debug("uuid: " + uuid);
|
||||
MyLogger.debug("unsigned: " + unsigned);
|
||||
Profile profile = ProfileDAO.selectByUuid(uuid);
|
||||
if (profile == null) {
|
||||
Response.success_no_content(exchange);
|
||||
return;
|
||||
}
|
||||
MyLogger.debug("Profile 信息: " + profile.serialToJSONObject(true, unsigned).toString());
|
||||
Response.success_200(exchange, profile.serialToJSONObject(true, unsigned));
|
||||
} catch (IOException | SQLException e) {
|
||||
exchange.close();
|
||||
|
@ -22,6 +22,7 @@ public class HasJoined implements HttpHandler {
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) {
|
||||
try {
|
||||
MyLogger.debug("HasJoined get 接口触发");
|
||||
exchange.getResponseHeaders().add("Content-Type", "application/json; charset=UTF-8");
|
||||
if (!exchange.getRequestMethod().equals("GET")) {
|
||||
Response.err_method_not_allowed(exchange);
|
||||
@ -31,31 +32,38 @@ public class HasJoined implements HttpHandler {
|
||||
String username = query.get("username");
|
||||
String serverId = query.get("serverId");
|
||||
String ip = query.get("ip");
|
||||
|
||||
if (username == null || serverId == null) {
|
||||
Response.success_no_content(exchange);
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证缓存令牌有效性
|
||||
if (HttpServerManager.getSessionCache().verifyIsExpire(serverId, ip)) {
|
||||
MyLogger.debug("缓存令牌已过期");
|
||||
Response.success_no_content(exchange);
|
||||
return;
|
||||
}
|
||||
// 获取缓存令牌对应令牌
|
||||
String accessToken = HttpServerManager.getSessionCache().getToken(serverId);
|
||||
Token token = TokenDAO.selectByAccessToken(accessToken);
|
||||
if (token == null || token.profileUUID == null || !token.profileUUID.equals(username)) {
|
||||
if (token == null) {
|
||||
MyLogger.debug("找不到令牌:" + accessToken);
|
||||
Response.success_no_content(exchange);
|
||||
return;
|
||||
}
|
||||
// 获取令牌对应的角色
|
||||
Profile profile = ProfileDAO.selectByUuid(token.profileUUID);
|
||||
if (profile == null) {
|
||||
MyLogger.debug("找不到角色:" + token.profileUUID);
|
||||
Response.success_no_content(exchange);
|
||||
return;
|
||||
}
|
||||
// 检查角色名是否一致
|
||||
if (!Objects.equals(username, profile.name)) {
|
||||
if (!profile.name.equals(username)) {
|
||||
MyLogger.debug("角色名不匹配:" + profile.name + " " + username);
|
||||
Response.success_no_content(exchange);
|
||||
return;
|
||||
}
|
||||
MyLogger.debug("HasJoined 信息: " + profile.serialToJSONObject(true, true).toString());
|
||||
Response.success_200(exchange, profile.serialToJSONObject(true, true));
|
||||
} catch (Exception e) {
|
||||
exchange.close();
|
||||
|
@ -20,6 +20,7 @@ public class Join implements HttpHandler {
|
||||
@Override
|
||||
public void handle(HttpExchange exchange){
|
||||
try {
|
||||
MyLogger.debug("Join post 接口触发");
|
||||
exchange.getResponseHeaders().add("Content-Type", "application/json; charset=UTF-8");
|
||||
if (!exchange.getRequestMethod().equals("POST")){
|
||||
Response.err_method_not_allowed(exchange);
|
||||
@ -29,15 +30,19 @@ public class Join implements HttpHandler {
|
||||
String accessToken = request.getString("accessToken");
|
||||
String selectedProfile = request.getString("selectedProfile");
|
||||
String serverId = request.getString("serverId");
|
||||
MyLogger.debug("获取到的信息: accessToken: " + accessToken + " selectedProfile: " + selectedProfile + " serverId: " + serverId);
|
||||
|
||||
Token token = TokenDAO.selectByAccessToken(accessToken);
|
||||
if (token == null || token.profileUUID == null || !token.profileUUID.equals(selectedProfile)){
|
||||
MyLogger.debug("令牌无效:" + selectedProfile);
|
||||
Response.err_invalid_token(exchange, "无效的令牌", "无效的令牌");
|
||||
return;
|
||||
}
|
||||
// 缓存到内存中
|
||||
HttpServerManager.getSessionCache().add(serverId, token.accessToken, exchange.getRemoteAddress().getHostString());
|
||||
MyLogger.debug("缓存令牌:" + token.accessToken + " serverID:" + serverId);
|
||||
|
||||
MyLogger.debug("准备返回204");
|
||||
Response.success_no_content(exchange);
|
||||
} catch (IOException | SQLException e) {
|
||||
exchange.close();
|
||||
|
@ -1,14 +1,18 @@
|
||||
package site.deercloud.identityverification.HttpServer.Yggdrasil.sessionserver;
|
||||
|
||||
import site.deercloud.identityverification.Utils.MyLogger;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class SessionTokenCache {
|
||||
private Map<String, String> serverID_token;
|
||||
private Map<String, String> serverID_ip;
|
||||
private Map<String, Long> serverID_time;
|
||||
private final Map<String, String> serverID_token = new HashMap<>();
|
||||
private final Map<String, String> serverID_ip = new HashMap<>();
|
||||
private final Map<String, Long> serverID_time = new HashMap<>();
|
||||
|
||||
public void add(String serverID, String token, String ip){
|
||||
MyLogger.debug("添加缓存令牌:" + serverID + " " + token + " " + ip);
|
||||
serverID_token.put(serverID, token);
|
||||
serverID_ip.put(serverID, ip);
|
||||
serverID_time.put(serverID, System.currentTimeMillis() + 30000);
|
||||
|
@ -0,0 +1,32 @@
|
||||
package site.deercloud.identityverification.HttpServer.model;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ActiveIndex {
|
||||
public String playerUuid;
|
||||
|
||||
public Long recentWeek = 0L;
|
||||
public Long oneWeekAgo = 0L;
|
||||
public Long twoWeekAgo = 0L;
|
||||
|
||||
public Double index = 0.0;
|
||||
|
||||
public Long update_time;
|
||||
|
||||
public static ArrayList<ActiveIndex> fillListWithSqlRes(ResultSet res) throws SQLException {
|
||||
ArrayList<ActiveIndex> activeIndexArrayList = new ArrayList<>();
|
||||
while (res.next()) {
|
||||
ActiveIndex activeIndex = new ActiveIndex();
|
||||
activeIndex.playerUuid = res.getString("player_uuid");
|
||||
activeIndex.recentWeek = res.getLong("recent_week");
|
||||
activeIndex.oneWeekAgo = res.getLong("one_week_ago");
|
||||
activeIndex.twoWeekAgo = res.getLong("two_week_ago");
|
||||
activeIndex.index = res.getDouble("index");
|
||||
activeIndex.update_time = res.getLong("update_time");
|
||||
activeIndexArrayList.add(activeIndex);
|
||||
}
|
||||
return activeIndexArrayList;
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package site.deercloud.identityverification.HttpServer.model;
|
||||
|
||||
import site.deercloud.identityverification.Utils.MyLogger;
|
||||
|
||||
public class GameSession {
|
||||
public GameSession() {
|
||||
joinTime = System.currentTimeMillis();
|
||||
@ -8,6 +10,7 @@ public class GameSession {
|
||||
}
|
||||
|
||||
public void addAfkTime(long time) {
|
||||
MyLogger.debug("addAfkTime:" + time);
|
||||
afkTime += time;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,30 @@
|
||||
package site.deercloud.identityverification.HttpServer.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class PlayTimeStatics {
|
||||
|
||||
public Integer id;
|
||||
|
||||
public String playerUuid;
|
||||
|
||||
public Long afkTime;
|
||||
|
||||
public Long activeTime;
|
||||
|
||||
public Long onlineTime;
|
||||
|
||||
public Long joinTime;
|
||||
|
||||
public Long quitTime;
|
||||
|
||||
public Long recordTime;
|
||||
|
||||
public static Long totalActivityTimeOf(ArrayList<PlayTimeStatics> list) {
|
||||
Long total = 0L;
|
||||
for (PlayTimeStatics item : list) {
|
||||
total += item.activeTime;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@ package site.deercloud.identityverification.HttpServer.model;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import site.deercloud.identityverification.Utils.MyLogger;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@ -56,6 +57,7 @@ public class Response {
|
||||
}
|
||||
|
||||
public static void success_no_content(HttpExchange exchange) throws IOException {
|
||||
MyLogger.debug("返回204");
|
||||
exchange.sendResponseHeaders(204, -1);
|
||||
exchange.getResponseBody().close();
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public class Texture {
|
||||
|
||||
public String sign() throws Exception {
|
||||
// 使用SHA1withRSA算法签名
|
||||
String private_key_str = IdentityVerification.getInstance().getConfigManager().getSignaturePrivateKey();
|
||||
String private_key_str = IdentityVerification.configManager.getSignaturePrivateKey();
|
||||
return SignatureUtil.sign(serialWithBase64(), private_key_str);
|
||||
}
|
||||
}
|
||||
|
@ -3,18 +3,15 @@ package site.deercloud.identityverification;
|
||||
import java.io.File;
|
||||
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import site.deercloud.identityverification.Controller.ActiveIndexManager;
|
||||
import site.deercloud.identityverification.HttpServer.HttpServerManager;
|
||||
import site.deercloud.identityverification.HttpServer.model.User;
|
||||
import site.deercloud.identityverification.SQLite.SqlManager;
|
||||
import site.deercloud.identityverification.SQLite.UserDAO;
|
||||
import site.deercloud.identityverification.Controller.AFKTracker;
|
||||
import site.deercloud.identityverification.Controller.ConfigManager;
|
||||
import site.deercloud.identityverification.Utils.FileToString;
|
||||
import site.deercloud.identityverification.Utils.MyLogger;
|
||||
import site.deercloud.identityverification.Controller.GameSessionCache;
|
||||
import site.deercloud.identityverification.Utils.UnsignedUUID;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class IdentityVerification extends JavaPlugin {
|
||||
@ -27,9 +24,10 @@ public final class IdentityVerification extends JavaPlugin {
|
||||
httpServerManager = new HttpServerManager(this);
|
||||
gameSessionCache = new GameSessionCache(this);
|
||||
afkTracker = new AFKTracker(this);
|
||||
|
||||
// 初始化数据表
|
||||
sqlManager = new SqlManager();
|
||||
// 初始化活跃度管理器
|
||||
activeIndexManager = new ActiveIndexManager();
|
||||
|
||||
// 初始化RSA
|
||||
File publicKeyPath = new File(this.getDataFolder(), configManager.getPublicKeyFileName());
|
||||
@ -39,10 +37,7 @@ public final class IdentityVerification extends JavaPlugin {
|
||||
if (pubKeyContent == null || priKeyContent == null) {
|
||||
MyLogger.error("RSA文件不存在, 插件退出。");
|
||||
this.getServer().getPluginManager().disablePlugin(this);
|
||||
}else {
|
||||
// pubKeyContent = pubKeyContent.replace("-----BEGIN PUBLIC KEY-----", "")
|
||||
// .replace("-----END PUBLIC KEY-----", "")
|
||||
// .replace("\n", "");
|
||||
} else {
|
||||
priKeyContent = priKeyContent.replace("-----BEGIN PRIVATE KEY-----", "")
|
||||
.replace("-----END PRIVATE KEY-----", "")
|
||||
.replace("\n", "");
|
||||
@ -67,26 +62,11 @@ public final class IdentityVerification extends JavaPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
public ConfigManager getConfigManager() {
|
||||
return configManager;
|
||||
}
|
||||
public static IdentityVerification getInstance() {
|
||||
return instance;
|
||||
}
|
||||
public static GameSessionCache getSessionCache() {
|
||||
return gameSessionCache;
|
||||
}
|
||||
public static AFKTracker getAfkTracker() {
|
||||
return afkTracker;
|
||||
}
|
||||
public static SqlManager getSqlManager() {
|
||||
return sqlManager;
|
||||
}
|
||||
|
||||
private HttpServerManager httpServerManager;
|
||||
private ConfigManager configManager;
|
||||
private static SqlManager sqlManager;
|
||||
private static GameSessionCache gameSessionCache;
|
||||
private static AFKTracker afkTracker;
|
||||
private static IdentityVerification instance;
|
||||
public static HttpServerManager httpServerManager;
|
||||
public static ConfigManager configManager;
|
||||
public static SqlManager sqlManager;
|
||||
public static GameSessionCache gameSessionCache;
|
||||
public static AFKTracker afkTracker;
|
||||
public static IdentityVerification instance;
|
||||
public static ActiveIndexManager activeIndexManager;
|
||||
}
|
||||
|
@ -0,0 +1,69 @@
|
||||
package site.deercloud.identityverification.SQLite;
|
||||
|
||||
import site.deercloud.identityverification.HttpServer.model.ActiveIndex;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ActiveIndexDAO {
|
||||
public static void createTable() throws SQLException {
|
||||
String sql = "CREATE TABLE IF NOT EXISTS active_index (\n"
|
||||
+ " player_uuid text NOT NULL,\n"
|
||||
+ " recent_week integer NOT NULL,\n"
|
||||
+ " one_week_ago integer NOT NULL,\n"
|
||||
+ " two_week_ago integer NOT NULL,\n"
|
||||
+ " 'index' double NOT NULL,\n"
|
||||
+ " update_time integer NOT NULL,\n"
|
||||
+ " PRIMARY KEY(player_uuid)\n"
|
||||
+ ");";
|
||||
PreparedStatement preparedStatement = SqlManager.session.prepareStatement(sql);
|
||||
preparedStatement.execute();
|
||||
}
|
||||
|
||||
public static void insert(ActiveIndex activeIndex) throws SQLException {
|
||||
String sql = "INSERT INTO active_index(player_uuid,recent_week,one_week_ago,two_week_ago,'index',update_time) VALUES(?,?,?,?,?,?)";
|
||||
PreparedStatement preparedStatement = SqlManager.session.prepareStatement(sql);
|
||||
preparedStatement.setString(1, activeIndex.playerUuid);
|
||||
preparedStatement.setLong(2, activeIndex.recentWeek);
|
||||
preparedStatement.setLong(3, activeIndex.oneWeekAgo);
|
||||
preparedStatement.setLong(4, activeIndex.twoWeekAgo);
|
||||
preparedStatement.setDouble(5, activeIndex.index);
|
||||
preparedStatement.setLong(6, System.currentTimeMillis());
|
||||
preparedStatement.execute();
|
||||
}
|
||||
|
||||
public static ActiveIndex query(String playerUuid) throws SQLException {
|
||||
String sql = "SELECT * FROM active_index WHERE player_uuid = ?";
|
||||
PreparedStatement preparedStatement = SqlManager.session.prepareStatement(sql);
|
||||
preparedStatement.setString(1, playerUuid);
|
||||
ResultSet res = preparedStatement.executeQuery();
|
||||
ArrayList<ActiveIndex> list = ActiveIndex.fillListWithSqlRes(res);
|
||||
if (list.size() == 1) {
|
||||
return list.get(0);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void update(ActiveIndex activeIndex) throws SQLException {
|
||||
String sql = "UPDATE active_index SET recent_week = ?,one_week_ago = ?,two_week_ago = ?,'index' = ?,update_time = ? WHERE player_uuid = ?";
|
||||
PreparedStatement preparedStatement = SqlManager.session.prepareStatement(sql);
|
||||
preparedStatement.setLong(1, activeIndex.recentWeek);
|
||||
preparedStatement.setLong(2, activeIndex.oneWeekAgo);
|
||||
preparedStatement.setLong(3, activeIndex.twoWeekAgo);
|
||||
preparedStatement.setDouble(4, activeIndex.index);
|
||||
preparedStatement.setLong(5, System.currentTimeMillis());
|
||||
preparedStatement.setString(6, activeIndex.playerUuid);
|
||||
preparedStatement.execute();
|
||||
}
|
||||
|
||||
public static ArrayList<ActiveIndex> selectActivityRecords() throws SQLException {
|
||||
long current_time = System.currentTimeMillis();
|
||||
String sql = "SELECT * FROM active_index WHERE 'index' < 3.75 AND 'index' > 3.0 AND update_time > ?";
|
||||
PreparedStatement preparedStatement = SqlManager.session.prepareStatement(sql);
|
||||
preparedStatement.setLong(1, current_time - 1000 * 60 * 60 * 24 * 7);
|
||||
ResultSet res = preparedStatement.executeQuery();
|
||||
return ActiveIndex.fillListWithSqlRes(res);
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package site.deercloud.identityverification.SQLite;
|
||||
|
||||
import site.deercloud.identityverification.HttpServer.model.PlayTimeStatics;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class PlayTimeDAO {
|
||||
|
||||
public static void createTable() throws SQLException {
|
||||
String sql = "CREATE TABLE IF NOT EXISTS play_time_static (\n"
|
||||
+ " id integer PRIMARY KEY,\n" // ID
|
||||
+ " player_uuid text NOT NULL,\n" // 玩家UUID
|
||||
+ " afk_time integer NOT NULL,\n" // AFK时间
|
||||
+ " active_time integer NOT NULL,\n" // 活跃时间
|
||||
+ " online_time integer NOT NULL,\n" // 在线时间
|
||||
+ " join_time integer NOT NULL,\n" // 加入时间
|
||||
+ " quit_time integer NOT NULL,\n" // 离开时间
|
||||
+ " record_time integer NOT NULL\n" // 记录创建时间
|
||||
+ ");";
|
||||
PreparedStatement preparedStatement = SqlManager.session.prepareStatement(sql);
|
||||
preparedStatement.execute();
|
||||
}
|
||||
|
||||
public static void insert(PlayTimeStatics statics) throws SQLException {
|
||||
String sql = "INSERT INTO play_time_static(player_uuid,afk_time,active_time,online_time,join_time,quit_time,record_time) VALUES(?,?,?,?,?,?,?)";
|
||||
PreparedStatement preparedStatement = SqlManager.session.prepareStatement(sql);
|
||||
preparedStatement.setString(1, statics.playerUuid);
|
||||
preparedStatement.setLong(2, statics.afkTime);
|
||||
preparedStatement.setLong(3, statics.activeTime);
|
||||
preparedStatement.setLong(4, statics.onlineTime);
|
||||
preparedStatement.setLong(5, statics.joinTime);
|
||||
preparedStatement.setLong(6, statics.quitTime);
|
||||
preparedStatement.setLong(7, System.currentTimeMillis());
|
||||
preparedStatement.execute();
|
||||
}
|
||||
|
||||
public static ArrayList<PlayTimeStatics> selectByTime(String uuid, Long from, Long to) throws SQLException {
|
||||
String sql = "SELECT * FROM play_time_static WHERE player_uuid = ? AND record_time >= ? AND record_time <= ?";
|
||||
PreparedStatement preparedStatement = SqlManager.session.prepareStatement(sql);
|
||||
preparedStatement.setString(1, uuid);
|
||||
preparedStatement.setLong(2, from);
|
||||
preparedStatement.setLong(3, to);
|
||||
ResultSet res = preparedStatement.executeQuery();
|
||||
ArrayList<PlayTimeStatics> returnList = new ArrayList<>();
|
||||
while (res.next()) {
|
||||
PlayTimeStatics statics = new PlayTimeStatics();
|
||||
statics.id = res.getInt("id");
|
||||
statics.playerUuid = res.getString("player_uuid");
|
||||
statics.afkTime = res.getLong("afk_time");
|
||||
statics.activeTime = res.getLong("active_time");
|
||||
statics.onlineTime = res.getLong("online_time");
|
||||
statics.joinTime = res.getLong("join_time");
|
||||
statics.quitTime = res.getLong("quit_time");
|
||||
statics.recordTime = res.getLong("record_time");
|
||||
returnList.add(statics);
|
||||
}
|
||||
return returnList;
|
||||
}
|
||||
|
||||
public static Integer countsOfPlayer(String uuid, Long from, Long to) throws SQLException {
|
||||
String sql = "SELECT COUNT(*) FROM play_time_static WHERE player_uuid = ? AND record_time >= ? AND record_time <= ?";
|
||||
PreparedStatement preparedStatement = SqlManager.session.prepareStatement(sql);
|
||||
preparedStatement.setString(1, uuid);
|
||||
preparedStatement.setLong(2, from);
|
||||
preparedStatement.setLong(3, to);
|
||||
ResultSet res = preparedStatement.executeQuery();
|
||||
return res.getInt(1);
|
||||
}
|
||||
|
||||
}
|
@ -5,7 +5,6 @@ import org.bukkit.entity.Player;
|
||||
import org.sqlite.SQLiteConfig;
|
||||
import org.sqlite.SQLiteDataSource;
|
||||
import site.deercloud.identityverification.HttpServer.model.User;
|
||||
import site.deercloud.identityverification.IdentityVerification;
|
||||
import site.deercloud.identityverification.Utils.MyLogger;
|
||||
import site.deercloud.identityverification.Utils.UnsignedUUID;
|
||||
|
||||
@ -20,7 +19,7 @@ public class SqlManager {
|
||||
config.enableRecursiveTriggers(true);
|
||||
SQLiteDataSource ds = new SQLiteDataSource(config);
|
||||
String url = System.getProperty("user.dir"); // 获取工作目录
|
||||
ds.setUrl("jdbc:sqlite:"+url+"/plugins/IdentityVerification/"+"IV-Database.db");
|
||||
ds.setUrl("jdbc:sqlite:"+url+"/plugins/IdentityVerification/"+"iv_database.db");
|
||||
session = ds.getConnection();
|
||||
createTables();
|
||||
|
||||
@ -52,6 +51,8 @@ public class SqlManager {
|
||||
ProfileDAO.createTable();
|
||||
WhiteListDAO.createTable();
|
||||
TokenDAO.createTable();
|
||||
PlayTimeDAO.createTable();
|
||||
ActiveIndexDAO.createTable();
|
||||
} catch (SQLException e) {
|
||||
MyLogger.debug(e);
|
||||
}
|
||||
|
@ -10,11 +10,11 @@ import java.util.Properties;
|
||||
|
||||
public class EmailSender {
|
||||
|
||||
static String host = IdentityVerification.getInstance().getConfigManager().getEmailHost(); // smtp服务器
|
||||
static String port = IdentityVerification.getInstance().getConfigManager().getEmailPort(); // 端口
|
||||
static String from = IdentityVerification.getInstance().getConfigManager().getEmailFrom(); // 发件人的email
|
||||
static String account = IdentityVerification.getInstance().getConfigManager().getEmailUsername(); // 账号
|
||||
static String password = IdentityVerification.getInstance().getConfigManager().getEmailPassword(); // 密码
|
||||
static String host = IdentityVerification.configManager.getEmailHost(); // smtp服务器
|
||||
static String port = IdentityVerification.configManager.getEmailPort(); // 端口
|
||||
static String from = IdentityVerification.configManager.getEmailFrom(); // 发件人的email
|
||||
static String account = IdentityVerification.configManager.getEmailUsername(); // 账号
|
||||
static String password = IdentityVerification.configManager.getEmailPassword(); // 密码
|
||||
|
||||
public static boolean sendTestEmail(String to) {
|
||||
String subject = "测试邮件";
|
||||
@ -52,7 +52,7 @@ public class EmailSender {
|
||||
|
||||
// 2. 根据配置创建会话对象, 用于和邮件服务器交互
|
||||
Session session = Session.getInstance(props);
|
||||
session.setDebug(IdentityVerification.getInstance().getConfigManager().getDebug()); // 设置为debug模式, 可以查看详细的发送 log
|
||||
session.setDebug(IdentityVerification.configManager.getDebug()); // 设置为debug模式, 可以查看详细的发送 log
|
||||
|
||||
// 3. 创建一封邮件
|
||||
MimeMessage message = new MimeMessage(session);
|
||||
@ -78,7 +78,7 @@ public class EmailSender {
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
MyLogger.debug(e);
|
||||
MyLogger.error("请检查邮箱配置是否正确,可能的问题解决方案:\n\t1.通常来说国内的邮箱服务要求发信人与账号保持一致,请检查是否一致;\n\t2.前往java的安装路径,找到jre/lib/security/java.security,删去 jdk.tls.disabledAlgorithms 部分的SSLv3, TLSv1, TLSv1.1;");
|
||||
MyLogger.error("请检查邮箱配置是否正确,可能的问题解决方案:\n\t1.通常来说国内的邮箱服务要求发信人与账号保持一致,请检查是否一致;\n\t2.前往java的安装路径,找到conf/security/java.security,删去 jdk.tls.disabledAlgorithms 部分的SSLv3, TLSv1, TLSv1.1;");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -5,51 +5,50 @@ import org.bukkit.command.CommandSender;
|
||||
import site.deercloud.identityverification.IdentityVerification;
|
||||
|
||||
public class MyLogger {
|
||||
private static IdentityVerification plugin = IdentityVerification.getInstance();
|
||||
|
||||
public static void info(String message) {
|
||||
plugin.getLogger().info(ChatColor.GREEN + "| " +message);
|
||||
IdentityVerification.instance.getLogger().info(ChatColor.GREEN + "| " +message);
|
||||
}
|
||||
|
||||
public static void warn(String message) {
|
||||
plugin.getLogger().warning(ChatColor.YELLOW + "| " +message);
|
||||
IdentityVerification.instance.getLogger().warning(ChatColor.YELLOW + "| " +message);
|
||||
}
|
||||
|
||||
public static void error(String message) {
|
||||
plugin.getLogger().severe(ChatColor.RED + "| " +message);
|
||||
IdentityVerification.instance.getLogger().severe(ChatColor.RED + "| " +message);
|
||||
}
|
||||
|
||||
public static void debug(String message) {
|
||||
if (plugin.getConfigManager().getDebug()) {
|
||||
plugin.getLogger().info(ChatColor.AQUA + "| " +message);
|
||||
if (IdentityVerification.configManager.getDebug()) {
|
||||
IdentityVerification.instance.getLogger().info(ChatColor.AQUA + "| " +message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void debug(Exception e) {
|
||||
if (plugin.getConfigManager().getDebug()) {
|
||||
plugin.getLogger().info(ChatColor.AQUA + "| " + e.getMessage());
|
||||
if (IdentityVerification.configManager.getDebug()) {
|
||||
IdentityVerification.instance.getLogger().info(ChatColor.AQUA + "| " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void info(CommandSender sender, String message) {
|
||||
plugin.getLogger().info(ChatColor.GREEN + "[ 来自 " + sender.getName() + " 的消息 ] " + message);
|
||||
IdentityVerification.instance.getLogger().info(ChatColor.GREEN + "[ 来自 " + sender.getName() + " 的消息 ] " + message);
|
||||
sender.sendMessage(ChatColor.GREEN + "| " +message);
|
||||
}
|
||||
|
||||
public static void warn(CommandSender sender, String message) {
|
||||
plugin.getLogger().warning(ChatColor.YELLOW + "[ 来自 " + sender.getName() + " 的消息 ] " + message);
|
||||
IdentityVerification.instance.getLogger().warning(ChatColor.YELLOW + "[ 来自 " + sender.getName() + " 的消息 ] " + message);
|
||||
sender.sendMessage(ChatColor.YELLOW + "| " +message);
|
||||
}
|
||||
|
||||
public static void error(CommandSender sender, String message) {
|
||||
plugin.getLogger().severe(ChatColor.RED + "[ 来自 " + sender.getName() + " 的消息 ] " + message);
|
||||
IdentityVerification.instance.getLogger().severe(ChatColor.RED + "[ 来自 " + sender.getName() + " 的消息 ] " + message);
|
||||
sender.sendMessage(ChatColor.RED + "| " +message);
|
||||
}
|
||||
|
||||
public static void debug(CommandSender sender, String message) {
|
||||
if (plugin.getConfigManager().getDebug()) {
|
||||
plugin.getLogger().info(ChatColor.AQUA + "[ 来自 " + sender.getName() + " 的消息 ] " + message);
|
||||
if (IdentityVerification.configManager.getDebug()) {
|
||||
IdentityVerification.instance.getLogger().info(ChatColor.AQUA + "[ 来自 " + sender.getName() + " 的消息 ] " + message);
|
||||
sender.sendMessage(ChatColor.AQUA + "| " +message);
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ Yggdrasil:
|
||||
# RSA 私钥文件路径
|
||||
RsaPrivateKey: id_rsa
|
||||
|
||||
|
||||
# 邮箱配置
|
||||
Email:
|
||||
# 邮箱服务器地址
|
||||
@ -46,4 +47,7 @@ Email:
|
||||
|
||||
# 实名认证API配置
|
||||
|
||||
# 是否启用白名单
|
||||
WhiteList: true
|
||||
# 调试模式(如果出现了问题 请打开调试并将报错复制以提交ISSUE)
|
||||
Debug: false
|
||||
|
File diff suppressed because one or more lines are too long
667
src/main/resources/web/assets/NewJoin.5f79d440.js
Normal file
667
src/main/resources/web/assets/NewJoin.5f79d440.js
Normal file
File diff suppressed because one or more lines are too long
729
src/main/resources/web/assets/index.09896eef.js
Normal file
729
src/main/resources/web/assets/index.09896eef.js
Normal file
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
header[data-v-121f739e]{position:fixed;width:100%;top:-10px;left:0%;height:65px;color:#130a0a;background-color:#ffffffe6;padding:1em;z-index:100;filter:blur(5px)}headerText[data-v-121f739e]{position:fixed;width:100%;top:0;left:0%;color:#130a0a;padding:1em;padding-left:5rem;z-index:101}menuBtn[data-v-121f739e]{top:0;left:0;padding:2em;font-size:larger;font-weight:700}main[data-v-121f739e]{margin:auto;padding:1em;position:flex;margin-top:5rem}:root{--vt-c-white: #ffffff;--vt-c-white-soft: #f8f8f8;--vt-c-white-mute: #f2f2f2;--vt-c-black: #181818;--vt-c-black-soft: #222222;--vt-c-black-mute: #282828;--vt-c-indigo: #2c3e50;--vt-c-divider-light-1: rgba(60, 60, 60, .29);--vt-c-divider-light-2: rgba(60, 60, 60, .12);--vt-c-divider-dark-1: rgba(84, 84, 84, .65);--vt-c-divider-dark-2: rgba(84, 84, 84, .48);--vt-c-text-light-1: var(--vt-c-indigo);--vt-c-text-light-2: rgba(60, 60, 60, .66);--vt-c-text-dark-1: var(--vt-c-white);--vt-c-text-dark-2: rgba(235, 235, 235, .64)}:root{--color-background: var(--vt-c-white);--color-background-soft: var(--vt-c-white-soft);--color-background-mute: var(--vt-c-white-mute);--color-border: var(--vt-c-divider-light-2);--color-border-hover: var(--vt-c-divider-light-1);--color-heading: var(--vt-c-text-light-1);--color-text: var(--vt-c-text-light-1);--section-gap: 160px}@media (prefers-color-scheme: dark){:root{--color-background: var(--vt-c-black);--color-background-soft: var(--vt-c-black-soft);--color-background-mute: var(--vt-c-black-mute);--color-border: var(--vt-c-divider-dark-2);--color-border-hover: var(--vt-c-divider-dark-1);--color-heading: var(--vt-c-text-dark-1);--color-text: var(--vt-c-text-dark-2)}}*,*:before,*:after{box-sizing:border-box;margin:0;position:relative;font-weight:400}body{min-height:100vh;color:var(--color-text);background:var(--color-background);transition:color .5s,background-color .5s;line-height:1.6;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:15px;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#app{max-width:1280px;margin:0 auto;padding:0rem;margin-top:5rem;font-weight:400}a,.green{text-decoration:none;color:#45b791;transition:.4s}@media (hover: hover){a:hover{background-color:#00bd7e33}}body{display:flex;place-items:center}@media (min-width: 1024px){body{display:flex;place-items:center}#app{display:flex;margin:auto;padding:0 2rem}}
|
||||
header[data-v-cabd705f]{position:fixed;width:100%;top:-10px;left:0%;height:65px;color:#130a0a;background-color:#ffffffe6;padding:1em;z-index:100;filter:blur(5px)}headerText[data-v-cabd705f]{position:fixed;width:100%;top:0;left:0%;color:#130a0a;padding:1em;padding-left:2rem;z-index:101}menuBtn[data-v-cabd705f]{top:0;left:0;padding:1em;font-size:larger;font-weight:700}main[data-v-cabd705f]{margin:auto;padding:1em;position:flex;margin-top:5rem}:root{--vt-c-white: #ffffff;--vt-c-white-soft: #f8f8f8;--vt-c-white-mute: #f2f2f2;--vt-c-black: #181818;--vt-c-black-soft: #222222;--vt-c-black-mute: #282828;--vt-c-indigo: #2c3e50;--vt-c-divider-light-1: rgba(60, 60, 60, .29);--vt-c-divider-light-2: rgba(60, 60, 60, .12);--vt-c-divider-dark-1: rgba(84, 84, 84, .65);--vt-c-divider-dark-2: rgba(84, 84, 84, .48);--vt-c-text-light-1: var(--vt-c-indigo);--vt-c-text-light-2: rgba(60, 60, 60, .66);--vt-c-text-dark-1: var(--vt-c-white);--vt-c-text-dark-2: rgba(235, 235, 235, .64)}:root{--color-background: var(--vt-c-white);--color-background-soft: var(--vt-c-white-soft);--color-background-mute: var(--vt-c-white-mute);--color-border: var(--vt-c-divider-light-2);--color-border-hover: var(--vt-c-divider-light-1);--color-heading: var(--vt-c-text-light-1);--color-text: var(--vt-c-text-light-1);--section-gap: 160px}@media (prefers-color-scheme: dark){:root{--color-background: var(--vt-c-black);--color-background-soft: var(--vt-c-black-soft);--color-background-mute: var(--vt-c-black-mute);--color-border: var(--vt-c-divider-dark-2);--color-border-hover: var(--vt-c-divider-dark-1);--color-heading: var(--vt-c-text-dark-1);--color-text: var(--vt-c-text-dark-2)}}*,*:before,*:after{box-sizing:border-box;margin:0;position:relative;font-weight:400}body{min-height:100vh;color:var(--color-text);background:var(--color-background);transition:color .5s,background-color .5s;line-height:1.6;font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:15px;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}#app{max-width:1280px;margin:0 auto;padding:0rem;margin-top:5rem;font-weight:400}a,.green{text-decoration:none;color:#45b791;transition:.4s}@media (hover: hover){a:hover{background-color:#00bd7e33}}body{display:flex;place-items:center}@media (min-width: 1024px){body{display:flex;place-items:center}#app{display:flex;margin:auto;padding:0 2rem}}
|
File diff suppressed because one or more lines are too long
@ -4,9 +4,9 @@
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Vite App</title>
|
||||
<script type="module" crossorigin src="/assets/index.dd68120c.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index.ccc73206.css">
|
||||
<title>XXXXX_Server</title>
|
||||
<script type="module" crossorigin src="/assets/index.09896eef.js"></script>
|
||||
<link rel="stylesheet" href="/assets/index.a6ce675f.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Vite App</title>
|
||||
<title>XXXXX_Server</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
@ -4,12 +4,16 @@
|
||||
<header>
|
||||
</header>
|
||||
<headerText>
|
||||
|<RouterLink to="/"> <menuBtn>主页</menuBtn></RouterLink>|
|
||||
<RouterLink to="/newjoin"><menuBtn>注册外置登录</menuBtn></RouterLink>|
|
||||
<RouterLink to="/newjoin"><menuBtn>实名认证白名单</menuBtn></RouterLink>|
|
||||
<n-grid x-gap="12">
|
||||
<n-grid-item :span="6">
|
||||
<RouterLink to="/">主页</RouterLink>
|
||||
</n-grid-item>
|
||||
<n-grid-item :span="6">
|
||||
<RouterLink to="/newjoin">注册</RouterLink>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</headerText>
|
||||
<main>
|
||||
|
||||
<n-dialog-provider>
|
||||
<n-notification-provider>
|
||||
<RouterView />
|
||||
@ -23,7 +27,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { RouterLink, RouterView } from 'vue-router'
|
||||
import { NDialogProvider, NNotificationProvider, NConfigProvider, useOsTheme, darkTheme, NH2 } from 'naive-ui';
|
||||
import { NDialogProvider, NNotificationProvider, NConfigProvider, useOsTheme, darkTheme, NH2, NGrid, NGridItem } from 'naive-ui';
|
||||
import axios from "axios";
|
||||
import { computed } from 'vue';
|
||||
|
||||
@ -56,14 +60,14 @@ headerText {
|
||||
left: 0%;
|
||||
color: rgb(19, 10, 10);
|
||||
padding: 1em;
|
||||
padding-left: 5rem;
|
||||
padding-left: 2rem;
|
||||
z-index: 101;
|
||||
}
|
||||
|
||||
menuBtn{
|
||||
menuBtn {
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding: 2em;
|
||||
padding: 1em;
|
||||
font-size: larger;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
<n-h3>{{server_url}}</n-h3>
|
||||
<n-h2>{{server_description}}</n-h2>
|
||||
|
||||
<n-button @click="join" strong secondary type="primary" size="large" >加入游戏</n-button>
|
||||
<n-button @click="$router.push('/newjoin')" strong secondary type="primary" size="large" >加入游戏</n-button>
|
||||
|
||||
</template>
|
||||
|
||||
@ -30,8 +30,5 @@ onMounted(() => {
|
||||
});
|
||||
});
|
||||
|
||||
function join(){
|
||||
window.location.href = '/newjoin'
|
||||
}
|
||||
|
||||
</script>
|
Loading…
Reference in New Issue
Block a user