feat: 添加安全管理工具

This commit is contained in:
502647092 2016-03-31 20:31:38 +08:00
parent 776820e4b7
commit d298c2c6a6
8 changed files with 94 additions and 51 deletions

View File

@ -11,8 +11,10 @@ import cn.citycraft.PluginHelper.config.FileConfig;
import cn.citycraft.PluginHelper.utils.VersionChecker; import cn.citycraft.PluginHelper.utils.VersionChecker;
import pw.yumc.Yum.api.YumAPI; import pw.yumc.Yum.api.YumAPI;
import pw.yumc.Yum.commands.FileCommand; import pw.yumc.Yum.commands.FileCommand;
import pw.yumc.Yum.commands.NetCommand;
import pw.yumc.Yum.commands.YumCommand; import pw.yumc.Yum.commands.YumCommand;
import pw.yumc.Yum.manager.NetworkManager; import pw.yumc.Yum.manager.NetworkManager;
import pw.yumc.Yum.manager.SecurityManager;
/** /**
* MC插件仓库 * MC插件仓库
@ -21,7 +23,7 @@ import pw.yumc.Yum.manager.NetworkManager;
* @since 2015年8月21日下午5:14:39 * @since 2015年8月21日下午5:14:39
*/ */
public class Yum extends JavaPlugin { public class Yum extends JavaPlugin {
public FileConfig config; FileConfig config;
NetworkManager netmgr; NetworkManager netmgr;
@Override @Override
@ -38,7 +40,9 @@ public class Yum extends JavaPlugin {
public void onEnable() { public void onEnable() {
new YumAPI(this); new YumAPI(this);
new YumCommand(this); new YumCommand(this);
new NetCommand(this);
new FileCommand(this); new FileCommand(this);
new SecurityManager(this);
new VersionChecker(this); new VersionChecker(this);
YumAPI.updaterepo(Bukkit.getConsoleSender()); YumAPI.updaterepo(Bukkit.getConsoleSender());
YumAPI.updatecheck(Bukkit.getConsoleSender()); YumAPI.updatecheck(Bukkit.getConsoleSender());

View File

@ -28,7 +28,7 @@ public class FileCommand implements HandlerCommands {
plugin = yum; plugin = yum;
dl = YumAPI.getDownload(); dl = YumAPI.getDownload();
final InvokeSubCommand cmdhandler = new InvokeSubCommand(yum, "file"); final InvokeSubCommand cmdhandler = new InvokeSubCommand(yum, "file");
cmdhandler.setAllCommandOnlyConsole(yum.config.getBoolean("onlyFileCommandConsole", true)); cmdhandler.setAllCommandOnlyConsole(yum.getConfig().getBoolean("onlyFileCommandConsole", true));
cmdhandler.registerCommands(this); cmdhandler.registerCommands(this);
} }
@ -131,7 +131,7 @@ public class FileCommand implements HandlerCommands {
sender.sendMessage("§d路径 §e" + file.getAbsolutePath() + " §c是一个文件 请使用file delete!"); sender.sendMessage("§d路径 §e" + file.getAbsolutePath() + " §c是一个文件 请使用file delete!");
return; return;
} }
for (final String name : plugin.config.getStringList("blacklist")) { for (final String name : plugin.getConfig().getStringList("blacklist")) {
if (file.getAbsolutePath().toLowerCase().endsWith(name)) { if (file.getAbsolutePath().toLowerCase().endsWith(name)) {
sender.sendMessage("§d路径 §e" + file.getAbsolutePath() + " §c不允许被删除!"); sender.sendMessage("§d路径 §e" + file.getAbsolutePath() + " §c不允许被删除!");
return; return;

View File

@ -7,9 +7,10 @@ import cn.citycraft.PluginHelper.commands.InvokeSubCommand;
import pw.yumc.Yum.Yum; import pw.yumc.Yum.Yum;
public class NetCommand implements HandlerCommands { public class NetCommand implements HandlerCommands {
public NetCommand(final Yum yum) { public NetCommand(final Yum yum) {
final InvokeSubCommand cmdhandler = new InvokeSubCommand(yum, "net"); final InvokeSubCommand cmdhandler = new InvokeSubCommand(yum, "net");
cmdhandler.setAllCommandOnlyConsole(yum.config.getBoolean("onlyNetCommandConsole", false)); cmdhandler.setAllCommandOnlyConsole(yum.getConfig().getBoolean("onlyNetCommandConsole", false));
cmdhandler.registerCommands(this); cmdhandler.registerCommands(this);
} }

View File

@ -45,7 +45,7 @@ public class YumCommand implements HandlerCommands, Listener {
plugman = YumAPI.getPlugman(); plugman = YumAPI.getPlugman();
Bukkit.getPluginManager().registerEvents(this, yum); Bukkit.getPluginManager().registerEvents(this, yum);
final InvokeSubCommand cmdhandler = new InvokeSubCommand(yum, "yum"); final InvokeSubCommand cmdhandler = new InvokeSubCommand(yum, "yum");
cmdhandler.setAllCommandOnlyConsole(yum.config.getBoolean("onlyCommandConsole", false)); cmdhandler.setAllCommandOnlyConsole(yum.getConfig().getBoolean("onlyCommandConsole", false));
cmdhandler.registerCommands(this); cmdhandler.registerCommands(this);
} }

View File

@ -5,7 +5,6 @@ import java.net.Proxy;
import java.net.ProxySelector; import java.net.ProxySelector;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.net.URI; import java.net.URI;
import java.util.HashMap;
import java.util.List; import java.util.List;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -13,6 +12,7 @@ import org.bukkit.plugin.Plugin;
import cn.citycraft.PluginHelper.config.FileConfig; import cn.citycraft.PluginHelper.config.FileConfig;
import cn.citycraft.PluginHelper.kit.ExceptionKit; import cn.citycraft.PluginHelper.kit.ExceptionKit;
import cn.citycraft.PluginHelper.kit.PluginKit;
import pw.yumc.Yum.Yum; import pw.yumc.Yum.Yum;
/** /**
@ -24,7 +24,7 @@ import pw.yumc.Yum.Yum;
public class NetworkManager { public class NetworkManager {
public NetworkManager register(final Yum plugin) { public NetworkManager register(final Yum plugin) {
Bukkit.getConsoleSender().sendMessage("§6[§bYum-网络管理§6] §a注入网络管理系统 将托管服务器网络!"); Bukkit.getConsoleSender().sendMessage("§6[§bYum §a网络管理§6] §a注入网络管理系统 将托管服务器网络!");
ProxySelector.setDefault(new YumProxySelector(ProxySelector.getDefault(), plugin)); ProxySelector.setDefault(new YumProxySelector(ProxySelector.getDefault(), plugin));
return this; return this;
} }
@ -41,7 +41,6 @@ public class NetworkManager {
private final boolean allowPrimaryThread; private final boolean allowPrimaryThread;
private final FileConfig config; private final FileConfig config;
private final ProxySelector defaultSelector; private final ProxySelector defaultSelector;
private final HashMap<ClassLoader, Plugin> pluginMap = new HashMap<>();
public YumProxySelector(final ProxySelector defaultSelector, final Yum plugin) { public YumProxySelector(final ProxySelector defaultSelector, final Yum plugin) {
this.config = plugin.getConfig(); this.config = plugin.getConfig();
@ -61,19 +60,17 @@ public class NetworkManager {
@Override @Override
public List<Proxy> select(final URI uri) { public List<Proxy> select(final URI uri) {
if (debug || Bukkit.isPrimaryThread()) { final boolean isPrimaryThread = Bukkit.isPrimaryThread();
final Plugin plugin = this.getRequestingPlugin(); if (debug || isPrimaryThread) {
final Plugin plugin = PluginKit.getOperatePlugin();
final String urlinfo = uri.toString(); final String urlinfo = uri.toString();
if (!urlinfo.startsWith("socket") && !urlinfo.toLowerCase().contains("yumc") && !urlinfo.toLowerCase().contains("pom.xml")) { if (!urlinfo.startsWith("socket") && !urlinfo.toLowerCase().contains("yumc") && !urlinfo.toLowerCase().contains("pom.xml") && !urlinfo.toLowerCase().contains("502647092")) {
final String str = debug ? "§6[§bYum-网络监控§6] §c插件 §6%s §c尝试访问 §e%s §c请注意服务器网络安全!" : "§6[§bYum-网络管理§6] §c插件 §6%s §c尝试在主线程访问 §e%s §4可能会导致服务器卡顿或无响应!"; final String str = isPrimaryThread ? "§6[§bYum §a网络管理§6] §c插件 §6%s §c尝试在主线程访问 §e%s §4可能会导致服务器卡顿或无响应!" : "§6[§bYum §a网络监控§6] §c插件 §6%s §c尝试访问 §e%s §c请注意服务器网络安全!";
if (plugin == null) { if (plugin != null) {
Bukkit.getConsoleSender().sendMessage(String.format(str, "未知(请查看堆栈)", urlinfo));
Thread.dumpStack();
} else if (!plugin.getName().equalsIgnoreCase("Yum")) {
Bukkit.getConsoleSender().sendMessage(String.format(str, plugin.getName(), urlinfo)); Bukkit.getConsoleSender().sendMessage(String.format(str, plugin.getName(), urlinfo));
if (!allowPrimaryThread) { if (!allowPrimaryThread && isPrimaryThread) {
Bukkit.getConsoleSender().sendMessage("§6[§bYum-网络管理§6] §4已阻止插件 §b" + plugin.getName() + " §4在主线程访问网络!"); Bukkit.getConsoleSender().sendMessage("§6[§bYum §a网络管理§6] §4已阻止插件 §b" + plugin.getName() + " §4在主线程访问网络!");
ExceptionKit.throwException(new IOException("[Yum-网络管理] 已开启网络防护 不允许在主线程访问网络!")); ExceptionKit.throwException(new IOException("[Yum 网络防护] 已开启网络防护 不允许在主线程访问网络!"));
} }
} }
} }
@ -81,32 +78,6 @@ public class NetworkManager {
return defaultSelector.select(uri); return defaultSelector.select(uri);
} }
private void collectPlugin() {
if (Bukkit.getPluginManager().getPlugins().length != pluginMap.keySet().size() - 1) {
pluginMap.clear();
for (final Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
pluginMap.put(plugin.getClass().getClassLoader(), plugin);
}
}
}
private Plugin getRequestingPlugin() {
collectPlugin();
final StackTraceElement[] stacktrace = new Exception().getStackTrace();
for (final StackTraceElement element : stacktrace) {
try {
final ClassLoader loader = Class.forName(element.getClassName(), false, getClass().getClassLoader()).getClassLoader();
if (pluginMap.containsKey(loader)) {
final Plugin p = pluginMap.get(loader);
if (element.getClassName().contains("pw.yumc.Yum.utils.") || !p.getName().equalsIgnoreCase("Yum")) {
return p;
}
}
} catch (final ClassNotFoundException ex) {
}
}
return null;
}
} }
} }

View File

@ -15,6 +15,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import java.util.regex.Pattern;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -30,6 +31,7 @@ import org.bukkit.plugin.PluginDescriptionFile;
import org.bukkit.plugin.PluginLoader; import org.bukkit.plugin.PluginLoader;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.UnknownDependencyException; import org.bukkit.plugin.UnknownDependencyException;
import org.bukkit.plugin.java.JavaPluginLoader;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
@ -536,8 +538,7 @@ public class PluginsManager {
List<Plugin> plugins = null; List<Plugin> plugins = null;
Map<String, Plugin> lookupNames = null; Map<String, Plugin> lookupNames = null;
Map<String, Command> knownCommands = null; Map<String, Command> knownCommands = null;
// ###移除类加载器后会导致插件无法载入### final Map<Pattern, JavaPluginLoader> fileAssociations = null;
// Map<Pattern, PluginLoader> fileAssociations = null;
if (pluginManager == null) { if (pluginManager == null) {
sender.sendMessage("§4异常: §c插件管理类反射获取失败!"); sender.sendMessage("§4异常: §c插件管理类反射获取失败!");
return false; return false;
@ -558,11 +559,11 @@ public class PluginsManager {
final Field knownCommandsField = commandMap.getClass().getDeclaredField("knownCommands"); final Field knownCommandsField = commandMap.getClass().getDeclaredField("knownCommands");
knownCommandsField.setAccessible(true); knownCommandsField.setAccessible(true);
knownCommands = (Map<String, Command>) knownCommandsField.get(commandMap); knownCommands = (Map<String, Command>) knownCommandsField.get(commandMap);
// XXX 暂时用不到
// ###移除类加载器后会导致插件无法载入###
// final Field fileAssociationsField = pluginManager.getClass().getDeclaredField("fileAssociations"); // final Field fileAssociationsField = pluginManager.getClass().getDeclaredField("fileAssociations");
// fileAssociationsField.setAccessible(true); // fileAssociationsField.setAccessible(true);
// fileAssociations = (Map<Pattern, PluginLoader>) fileAssociationsField.get(pluginManager); // fileAssociations = (Map<Pattern, JavaPluginLoader>) fileAssociationsField.get(pluginManager);
} catch (final Exception e) { } catch (final Exception e) {
sender.sendMessage("§4异常: §c" + e.getMessage() + " 插件 §b" + name + " §c卸载失败!"); sender.sendMessage("§4异常: §c" + e.getMessage() + " 插件 §b" + name + " §c卸载失败!");
return false; return false;
@ -592,16 +593,39 @@ public class PluginsManager {
} }
} }
} }
// try {
// if (fileAssociations != null) {
// // XXX 不能移除 会导致无法加载
// for (final Iterator<Entry<Pattern, JavaPluginLoader>> filter = fileAssociations.entrySet().iterator(); filter.hasNext();) {
// final Entry<Pattern, JavaPluginLoader> entry = filter.next();
// final Matcher match = entry.getKey().matcher(getPluginFile(next).getName());
// if (match.find()) {
// final JavaPluginLoader pluginLoader = entry.getValue();
// final Field loadersField = pluginLoader.getClass().getDeclaredField("loaders");
// loadersField.setAccessible(true);
// final Map<String, URLClassLoader> loaders = (Map<String, URLClassLoader>) loadersField.get(pluginLoader);
// // XXX 不能移除 会导致无法调用其他插件
// loaders.clear();
// sender.sendMessage("§6卸载: §a移除插件 §b" + name + " §a的类实例缓存!");
// }
// }
// }
// } catch (final Exception e) {
// e.printStackTrace();
// }
sender.sendMessage("§6卸载: §a注销插件 §b" + name + " §a的所有命令!"); sender.sendMessage("§6卸载: §a注销插件 §b" + name + " §a的所有命令!");
final ClassLoader cl = next.getClass().getClassLoader(); final ClassLoader cl = next.getClass().getClassLoader();
try { try {
((URLClassLoader) cl).close(); ((URLClassLoader) cl).close();
} catch (final IOException ex) { } catch (final IOException ex) {
ex.printStackTrace();
} }
System.gc(); System.gc();
} }
} }
if (!pluginVersion.isEmpty()) { if (!pluginVersion.isEmpty())
{
sender.sendMessage("§6卸载: §a插件 §b" + name + " §a版本 §d" + pluginVersion + " §a已成功卸载!"); sender.sendMessage("§6卸载: §a插件 §b" + name + " §a版本 §d" + pluginVersion + " §a已成功卸载!");
return true; return true;
} }

View File

@ -0,0 +1,36 @@
package pw.yumc.Yum.manager;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.plugin.Plugin;
import cn.citycraft.PluginHelper.kit.PluginKit;
import pw.yumc.Yum.Yum;
import pw.yumc.injected.event.SetOpEvent;
/**
*
* @since 2016年3月31日 下午3:01:22
* @author
*/
public class SecurityManager implements Listener {
public String warn = "§6[§bYum §a安全系统§6] §c插件 §e%s §c已设置玩家 §a%s §c为OP §4请注意服务器安全!";
public String prevent = "§6[§bYum §a安全系统§6] §c黑名单插件 §e%s §c尝试设置玩家 §a%s §c为OP §a安全系统已成功拦截!";
public SecurityManager(final Yum yum) {
Bukkit.getPluginManager().registerEvents(this, yum);
}
@EventHandler
public void setop(final SetOpEvent event) {
final Plugin plugin = PluginKit.getOperatePlugin();
if (plugin != null) {
if (plugin.getName().equalsIgnoreCase("BukkitInjectedTools")) {
Bukkit.getConsoleSender().sendMessage(String.format(prevent, plugin, event.getOfflinePlayer().getName()));
} else {
Bukkit.getConsoleSender().sendMessage(String.format(warn, plugin, event.getOfflinePlayer().getName()));
}
}
}
}

View File

@ -2,6 +2,7 @@ name: ${project.artifactId}
description: ${project.description} description: ${project.description}
main: ${project.groupId}.${project.artifactId}.${project.artifactId} main: ${project.groupId}.${project.artifactId}.${project.artifactId}
version: ${project.version}-git-${env.GIT_COMMIT} version: ${project.version}-git-${env.GIT_COMMIT}
load: STARTUP
author: 喵♂呜 author: 喵♂呜
website: ${ciManagement.url} website: ${ciManagement.url}
commands: commands:
@ -23,6 +24,12 @@ commands:
usage: §6使用§a/file help§6查看帮助! usage: §6使用§a/file help§6查看帮助!
permission: file.use permission: file.use
permission-message: §c你没有 <permission> 的权限来执行此命令! permission-message: §c你没有 <permission> 的权限来执行此命令!
security:
description: MC安全管理命令
aliases: [f]
usage: §6使用§a/security help§6查看帮助!
permission: file.use
permission-message: §c你没有 <permission> 的权限来执行此命令!
permissions: permissions:
yum.use: yum.use:
description: 插件管理系统使用权限! description: 插件管理系统使用权限!