diff --git a/modules/agent/src/main/java/io/jpom/controller/IndexController.java b/modules/agent/src/main/java/io/jpom/controller/IndexController.java index 53548a864..8262dbea9 100644 --- a/modules/agent/src/main/java/io/jpom/controller/IndexController.java +++ b/modules/agent/src/main/java/io/jpom/controller/IndexController.java @@ -35,7 +35,7 @@ public class IndexController extends BaseAgentController { @RequestMapping(value = {"index", "", "index.html", "/"}, produces = MediaType.TEXT_PLAIN_VALUE) @NotAuthorize public String index() { - return "Jpom-Agent"; + return "Jpom-Agent,Can't access directly,Please configure it to JPOM server"; } @RequestMapping(value = "info", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) diff --git a/modules/agent/src/main/java/io/jpom/controller/manage/ProjectFileControl.java b/modules/agent/src/main/java/io/jpom/controller/manage/ProjectFileControl.java index 642a50e3a..3f4150dc0 100644 --- a/modules/agent/src/main/java/io/jpom/controller/manage/ProjectFileControl.java +++ b/modules/agent/src/main/java/io/jpom/controller/manage/ProjectFileControl.java @@ -8,6 +8,7 @@ import cn.hutool.core.thread.ThreadUtil; import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.extra.servlet.ServletUtil; +import cn.hutool.http.HttpUtil; import cn.jiangzeyin.common.DefaultSystemLog; import cn.jiangzeyin.common.JsonMessage; import cn.jiangzeyin.controller.multipart.MultipartFileBuilder; @@ -28,9 +29,7 @@ import io.jpom.util.FileUtils; import io.jpom.util.StringUtil; import org.springframework.http.MediaType; import org.springframework.util.Assert; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.io.File; @@ -39,6 +38,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; /** * 项目文件管理 @@ -295,7 +295,7 @@ public class ProjectFileControl extends BaseAgentController { * @param filename 读取的文件名 * @return json */ - @RequestMapping(value = "read_file", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @GetMapping(value = "read_file", produces = MediaType.APPLICATION_JSON_VALUE) public String readFile(String filePath, String filename) { ProjectInfoModel pim = getProjectInfoModel(); filePath = StrUtil.emptyToDefault(filePath, File.separator); @@ -314,7 +314,7 @@ public class ProjectFileControl extends BaseAgentController { * @param fileText 文件内容 * @return json */ - @RequestMapping(value = "update_config_file", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + @PostMapping(value = "update_config_file", produces = MediaType.APPLICATION_JSON_VALUE) public String updateConfigFile(String filePath, String filename, String fileText) { ProjectInfoModel pim = getProjectInfoModel(); filePath = StrUtil.emptyToDefault(filePath, File.separator); @@ -325,7 +325,15 @@ public class ProjectFileControl extends BaseAgentController { } - @RequestMapping(value = "download", method = RequestMethod.GET) + /** + * 将执行文件下载到客户端 本地 + * + * @param id 项目id + * @param filename 文件名 + * @param levelName 文件夹名 + * @return 正常情况返回文件流,非正在返回 text plan + */ + @GetMapping(value = "download", produces = MediaType.APPLICATION_JSON_VALUE) public String download(String id, String filename, String levelName) { String safeFileName = pathSafe(filename); if (StrUtil.isEmpty(safeFileName)) { @@ -333,12 +341,7 @@ public class ProjectFileControl extends BaseAgentController { } try { ProjectInfoModel pim = projectInfoService.getItem(id); - File file; - if (StrUtil.isEmpty(levelName)) { - file = FileUtil.file(pim.allLib(), filename); - } else { - file = FileUtil.file(pim.allLib(), levelName, filename); - } + File file = FileUtil.file(pim.allLib(), StrUtil.emptyToDefault(levelName, FileUtil.FILE_SEPARATOR), filename); if (file.isDirectory()) { return "暂不支持下载文件夹"; } @@ -349,4 +352,33 @@ public class ProjectFileControl extends BaseAgentController { return "下载失败。请刷新页面后重试"; } + /** + * 下载远程文件 + * + * @param id 项目id + * @param url 远程 url 地址 + * @param levelName 保存的文件夹 + * @return json + */ + @GetMapping(value = "remote_download", produces = MediaType.APPLICATION_JSON_VALUE) + public String remoteDownload(String id, String url, String levelName) { + if (StrUtil.isEmpty(url)) { + return JsonMessage.getString(405, "请输入正确的远程地址"); + } + AgentWhitelist whitelist = whitelistDirectoryService.getWhitelist(); + Set allowRemoteDownloadHost = whitelist.getAllowRemoteDownloadHost(); + Assert.state(CollUtil.isNotEmpty(allowRemoteDownloadHost), "还没有配置运行的远程地址"); + List collect = allowRemoteDownloadHost.stream().filter(s -> StrUtil.startWith(url, s)).collect(Collectors.toList()); + Assert.state(CollUtil.isNotEmpty(collect), "不允许下载当前地址的文件"); + try { + ProjectInfoModel pim = projectInfoService.getItem(id); + File file = FileUtil.file(pim.allLib(), StrUtil.emptyToDefault(levelName, FileUtil.FILE_SEPARATOR)); + long downloadFile = HttpUtil.downloadFile(url, file); + return JsonMessage.getString(200, "下次成功文件大小:" + FileUtil.readableFileSize(downloadFile)); + } catch (Exception e) { + DefaultSystemLog.getLog().error("下载远程文件异常", e); + return JsonMessage.getString(500, "下载远程文件失败:" + e.getMessage()); + } + } + } diff --git a/modules/agent/src/main/java/io/jpom/controller/system/WhitelistDirectoryController.java b/modules/agent/src/main/java/io/jpom/controller/system/WhitelistDirectoryController.java index b9e16a1aa..b22e85c64 100644 --- a/modules/agent/src/main/java/io/jpom/controller/system/WhitelistDirectoryController.java +++ b/modules/agent/src/main/java/io/jpom/controller/system/WhitelistDirectoryController.java @@ -1,8 +1,10 @@ package io.jpom.controller.system; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.RegexPool; import cn.hutool.core.text.StrSplitter; import cn.hutool.core.util.CharsetUtil; +import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.StrUtil; import cn.jiangzeyin.common.JsonMessage; import io.jpom.common.BaseJpomController; @@ -46,7 +48,7 @@ public class WhitelistDirectoryController extends BaseJpomController { @RequestMapping(value = "whitelistDirectory_submit", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) - public String whitelistDirectorySubmit(String project, String certificate, String nginx, String allowEditSuffix) { + public String whitelistDirectorySubmit(String project, String certificate, String nginx, String allowEditSuffix, String allowRemoteDownloadHost) { if (StrUtil.isEmpty(project)) { return JsonMessage.getString(401, "项目路径白名单不能为空"); } @@ -55,7 +57,8 @@ public class WhitelistDirectoryController extends BaseJpomController { List certificateList = this.parseToList(certificate, "证书路径白名单不能为空"); List nList = this.parseToList(nginx, "nginx路径白名单不能为空"); List allowEditSuffixList = this.parseToList(allowEditSuffix, "运行编辑的文件后缀不能为空"); - return save(list, certificateList, nList, allowEditSuffixList).toString(); + List allowRemoteDownloadHostList = this.parseToList(allowRemoteDownloadHost, "运行远程下载的 host 不能配置为空"); + return save(list, certificateList, nList, allowEditSuffixList, allowRemoteDownloadHostList).toString(); } // // private JsonMessage save(String project, List certificate, List nginx, List allowEditSuffixList) { @@ -64,7 +67,11 @@ public class WhitelistDirectoryController extends BaseJpomController { // } - private JsonMessage save(List projects, List certificate, List nginx, List allowEditSuffixList) { + private JsonMessage save(List projects, + List certificate, + List nginx, + List allowEditSuffixList, + List allowRemoteDownloadHostList) { List projectArray; { projectArray = AgentWhitelist.covertToArray(projects); @@ -121,10 +128,14 @@ public class WhitelistDirectoryController extends BaseJpomController { } } } - AgentWhitelist agentWhitelist = whitelistDirectoryService.getWhitelist(); - if (agentWhitelist == null) { - agentWhitelist = new AgentWhitelist(); + if (CollUtil.isNotEmpty(allowRemoteDownloadHostList)) { + for (String s : allowRemoteDownloadHostList) { + Assert.state(ReUtil.isMatch(RegexPool.URL_HTTP, s), "配置的远程地址不规范,请重新填写:" + s); + } } + + AgentWhitelist agentWhitelist = whitelistDirectoryService.getWhitelist(); + agentWhitelist.setProject(projectArray); agentWhitelist.setCertificate(certificateArray); agentWhitelist.setNginx(nginxArray); diff --git a/modules/common/src/main/java/io/jpom/model/data/AgentWhitelist.java b/modules/common/src/main/java/io/jpom/model/data/AgentWhitelist.java index 84f0089ad..e4967915a 100644 --- a/modules/common/src/main/java/io/jpom/model/data/AgentWhitelist.java +++ b/modules/common/src/main/java/io/jpom/model/data/AgentWhitelist.java @@ -12,6 +12,7 @@ import io.jpom.system.ExtConfigBean; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * 白名单 @@ -38,6 +39,19 @@ public class AgentWhitelist extends BaseJsonModel { */ private List allowEditSuffix; + /** + * 运行远程下载的 host + */ + private Set allowRemoteDownloadHost; + + public Set getAllowRemoteDownloadHost() { + return allowRemoteDownloadHost; + } + + public void setAllowRemoteDownloadHost(Set allowRemoteDownloadHost) { + this.allowRemoteDownloadHost = allowRemoteDownloadHost; + } + public List getAllowEditSuffix() { return allowEditSuffix; } diff --git a/modules/common/src/main/java/io/jpom/plugin/MethodFeature.java b/modules/common/src/main/java/io/jpom/plugin/MethodFeature.java index 77cb96c26..6608b92dc 100644 --- a/modules/common/src/main/java/io/jpom/plugin/MethodFeature.java +++ b/modules/common/src/main/java/io/jpom/plugin/MethodFeature.java @@ -7,40 +7,41 @@ package io.jpom.plugin; * @date 2019/8/13 */ public enum MethodFeature { - /** - * 没有 - */ - NULL(""), - /** - * 文件管理 - */ - FILE("文件管理"), - EDIT("修改"), - DEL("删除"), - INSTALL("安装"), - LIST("列表"), - TERMINAL("终端"), - DOWNLOAD("下载"), - LOG("日志"), - UPLOAD("上传"), - // WHITELIST("白名单"), - EXECUTE("执行"), - DEL_FILE("删除文件"), - CACHE("缓存"), - DEL_LOG("删除日志"), - CONFIG("配置"), - READ_FILE("读取文件"), - GET_FILE_FOMAT("获取在线编辑文件格式"), - UPDATE_CONFIG_FILE("更新文件"), - ; + /** + * 没有 + */ + NULL(""), + /** + * 文件管理 + */ + FILE("文件管理"), + EDIT("修改"), + DEL("删除"), + INSTALL("安装"), + LIST("列表"), + TERMINAL("终端"), + DOWNLOAD("下载"), + LOG("日志"), + UPLOAD("上传"), + // WHITELIST("白名单"), + EXECUTE("执行"), + DEL_FILE("删除文件"), + CACHE("缓存"), + DEL_LOG("删除日志"), + CONFIG("配置"), + READ_FILE("读取文件"), + // GET_FILE_FOMAT("获取在线编辑文件格式"), + UPDATE_CONFIG_FILE("更新文件"), + REMOTE_DOWNLOAD("下载远程文件"), + ; - private String name; + private final String name; - public String getName() { - return name; - } + public String getName() { + return name; + } - MethodFeature(String name) { - this.name = name; - } + MethodFeature(String name) { + this.name = name; + } } diff --git a/modules/common/src/main/java/io/jpom/system/ConfigBean.java b/modules/common/src/main/java/io/jpom/system/ConfigBean.java index ea61a8e8e..c3332f2a1 100644 --- a/modules/common/src/main/java/io/jpom/system/ConfigBean.java +++ b/modules/common/src/main/java/io/jpom/system/ConfigBean.java @@ -20,113 +20,114 @@ import java.io.File; */ @Configuration public class ConfigBean { - /** - * 用户名header - */ - public static final String JPOM_SERVER_USER_NAME = "Jpom-Server-UserName"; - public static final String JPOM_AGENT_AUTHORIZE = "Jpom-Agent-Authorize"; + /** + * 用户名header + */ + public static final String JPOM_SERVER_USER_NAME = "Jpom-Server-UserName"; - public static final String DATA = "data"; + public static final String JPOM_AGENT_AUTHORIZE = "Jpom-Agent-Authorize"; - public static final int AUTHORIZE_ERROR = 900; + public static final String DATA = "data"; - /** - * 授权信息 - */ - public static final String AUTHORIZE = "agent_authorize.json"; - /** - * - */ - public static final String AUTHORIZE_USER_KEY = "jpom.authorize.agentName"; - /** - * - */ - public static final String AUTHORIZE_PWD_KEY = "jpom.authorize.agentPwd"; - /** - * 程序升级信息文件 - */ - public static final String UPGRADE = "upgrade.json"; - /** - * Jpom 程序运行的 application 标识 - */ - @Value("${jpom.applicationTag:}") - public String applicationTag; - /** - * 程序端口 - */ - @Value("${server.port}") - private int port; + public static final int AUTHORIZE_ERROR = 900; - private static ConfigBean configBean; + /** + * 授权信息 + */ + public static final String AUTHORIZE = "agent_authorize.json"; + /** + * + */ + public static final String AUTHORIZE_USER_KEY = "jpom.authorize.agentName"; + /** + * + */ + public static final String AUTHORIZE_PWD_KEY = "jpom.authorize.agentPwd"; + /** + * 程序升级信息文件 + */ + public static final String UPGRADE = "upgrade.json"; + /** + * Jpom 程序运行的 application 标识 + */ + @Value("${jpom.applicationTag:}") + public String applicationTag; + /** + * 程序端口 + */ + @Value("${server.port}") + private int port; - /** - * 单利模式 - * - * @return config - */ - public static ConfigBean getInstance() { - if (configBean == null) { - configBean = SpringUtil.getBean(ConfigBean.class); - } - return configBean; - } + private static ConfigBean configBean; - public int getPort() { - return port; - } + /** + * 单利模式 + * + * @return config + */ + public static ConfigBean getInstance() { + if (configBean == null) { + configBean = SpringUtil.getBean(ConfigBean.class); + } + return configBean; + } - /** - * 获取项目运行数据存储文件夹路径 - * - * @return 文件夹路径 - */ - public String getDataPath() { - String dataPath = FileUtil.normalize(ExtConfigBean.getInstance().getPath() + "/" + DATA); - FileUtil.mkdir(dataPath); - return dataPath; - } + public int getPort() { + return port; + } - /** - * 获取pid文件 - * - * @return file - */ - public File getPidFile() { - return new File(getDataPath(), StrUtil.format("pid.{}.{}", - JpomApplication.getAppType().name(), JpomManifest.getInstance().getPid())); - } + /** + * 获取项目运行数据存储文件夹路径 + * + * @return 文件夹路径 + */ + public String getDataPath() { + String dataPath = FileUtil.normalize(ExtConfigBean.getInstance().getPath() + "/" + DATA); + FileUtil.mkdir(dataPath); + return dataPath; + } - /** - * 获取当前项目全局 运行信息文件路径 - * - * @param type 程序类型 - * @return file - */ - public File getApplicationJpomInfo(Type type) { - return FileUtil.file(SystemUtil.getUserInfo().getTempDir(), "jpom", type.name()); - } + /** + * 获取pid文件 + * + * @return file + */ + public File getPidFile() { + return new File(getDataPath(), StrUtil.format("pid.{}.{}", + JpomApplication.getAppType().name(), JpomManifest.getInstance().getPid())); + } - /** - * 获取 agent 端自动生成的授权文件路径 - * - * @param dataPath 指定数据路径 - * @return file - */ - public String getAgentAutoAuthorizeFile(String dataPath) { - return FileUtil.normalize(dataPath + "/" + ConfigBean.AUTHORIZE); - } + /** + * 获取当前项目全局 运行信息文件路径 + * + * @param type 程序类型 + * @return file + */ + public File getApplicationJpomInfo(Type type) { + return FileUtil.file(SystemUtil.getUserInfo().getTempDir(), "jpom", type.name()); + } + + /** + * 获取 agent 端自动生成的授权文件路径 + * + * @param dataPath 指定数据路径 + * @return file + */ + public String getAgentAutoAuthorizeFile(String dataPath) { + return FileUtil.normalize(dataPath + "/" + ConfigBean.AUTHORIZE); + } - /** - * 获取临时文件存储路径 - * - * @return file - */ - public File getTempPath() { - File file = new File(ConfigBean.getInstance().getDataPath()); - file = new File(file.getPath() + "/temp/"); - FileUtil.mkdir(file); - return file; - } + /** + * 获取临时文件存储路径 + * + * @return file + */ + public File getTempPath() { + File file = new File(ConfigBean.getInstance().getDataPath()); + file = new File(file.getPath() + "/temp/"); + FileUtil.mkdir(file); + return file; + } } diff --git a/modules/server/src/main/java/io/jpom/common/forward/NodeUrl.java b/modules/server/src/main/java/io/jpom/common/forward/NodeUrl.java index 5c600ffbf..416ae7541 100644 --- a/modules/server/src/main/java/io/jpom/common/forward/NodeUrl.java +++ b/modules/server/src/main/java/io/jpom/common/forward/NodeUrl.java @@ -82,7 +82,7 @@ public enum NodeUrl { Manage_File_ReadFile("/manage/file/read_file"), - Get_File_Format("/manage/file/getFileFormat"), + Manage_File_Remote_Download("/manage/file/remote_download"), Manage_File_Download("/manage/file/download"), @@ -185,7 +185,7 @@ public enum NodeUrl { /** * 相对请求地址 */ - private String url; + private final String url; private int timeOut; public String getUrl() { diff --git a/modules/server/src/main/java/io/jpom/controller/node/manage/file/ProjectFileControl.java b/modules/server/src/main/java/io/jpom/controller/node/manage/file/ProjectFileControl.java index 5519c8761..ee3d1771a 100644 --- a/modules/server/src/main/java/io/jpom/controller/node/manage/file/ProjectFileControl.java +++ b/modules/server/src/main/java/io/jpom/controller/node/manage/file/ProjectFileControl.java @@ -1,7 +1,5 @@ package io.jpom.controller.node.manage.file; -import cn.jiangzeyin.common.JsonMessage; -import com.alibaba.fastjson.JSONObject; import io.jpom.common.BaseServerController; import io.jpom.common.forward.NodeForward; import io.jpom.common.forward.NodeUrl; @@ -11,12 +9,11 @@ import io.jpom.plugin.ClassFeature; import io.jpom.plugin.Feature; import io.jpom.plugin.MethodFeature; import io.jpom.service.node.manage.ProjectInfoService; -import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; -import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; @@ -25,15 +22,15 @@ import javax.annotation.Resource; * * @author Administrator */ -@Controller +@RestController @RequestMapping(value = "/node/manage/file/") @Feature(cls = ClassFeature.PROJECT) public class ProjectFileControl extends BaseServerController { @Resource private ProjectInfoService projectInfoService; - @Value("${fileFormat}") - private String fileFormat; +// @Value("${fileFormat}") +// private String fileFormat; // /** // * 文件管理页面 // * @@ -129,17 +126,30 @@ public class ProjectFileControl extends BaseServerController { } /** - * 获取可编辑文件格式 + * 下载远程文件 * * @return json */ - @RequestMapping(value = "geFileFormat", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) - @ResponseBody - @Feature(method = MethodFeature.GET_FILE_FOMAT) - public String geFileFormat() { - String[] file = fileFormat.split("\\|"); - JSONObject jsonObject = new JSONObject(); - jsonObject.put("fileFormat", file); - return JsonMessage.getString(200, "获取成功", jsonObject); + @RequestMapping(value = "remote_download", method = RequestMethod.GET) + @Feature(method = MethodFeature.REMOTE_DOWNLOAD) + public String remoteDownload() { + return NodeForward.request(getNode(), getRequest(), NodeUrl.Manage_File_Remote_Download).toString(); + } + + +// /** +// * 获取可编辑文件格式 +// * +// * @return json +// */ +// @RequestMapping(value = "geFileFormat", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) +// @ResponseBody +// @Feature(method = MethodFeature.GET_FILE_FOMAT) +// public String geFileFormat() { +// String[] file = fileFormat.split("\\|"); +// JSONObject jsonObject = new JSONObject(); +// jsonObject.put("fileFormat", file); +// return JsonMessage.getString(200, "获取成功", jsonObject); +// } } diff --git a/modules/server/src/main/resources/application.yml b/modules/server/src/main/resources/application.yml index 830f81595..2635b5bb1 100644 --- a/modules/server/src/main/resources/application.yml +++ b/modules/server/src/main/resources/application.yml @@ -32,4 +32,4 @@ request: trimAll: true parameterXss: false #在线编辑格式 -fileFormat: txt|yml|conf|properties|ini \ No newline at end of file +#fileFormat: txt|yml|conf|properties|ini