diff --git a/modules/module-ci-process-api/src/main/java/cd/casic/ci/api/AflManagerController.java b/modules/module-ci-process-api/src/main/java/cd/casic/ci/api/AflManagerController.java index 10cb1da2..c251d36b 100644 --- a/modules/module-ci-process-api/src/main/java/cd/casic/ci/api/AflManagerController.java +++ b/modules/module-ci-process-api/src/main/java/cd/casic/ci/api/AflManagerController.java @@ -1,6 +1,8 @@ package cd.casic.ci.api; import cd.casic.ci.process.dto.req.aflManager.AflManagerReq; +import cd.casic.ci.process.dto.resp.aflManager.AflCrashesInfoResp; +import cd.casic.ci.process.dto.resp.aflManager.AflInfoResp; import cd.casic.ci.process.dto.resp.aflManager.SeedsCountResp; import cd.casic.ci.process.process.service.aflManager.AflCrashesInfoService; import cd.casic.ci.process.process.service.aflManager.AflInfoService; @@ -39,18 +41,45 @@ public class AflManagerController { @PostMapping(path="/saveAflInfo") public CommonResult saveAflInfo(@RequestBody @Valid AflManagerReq req) throws SftpUploadUtil.SftpUploadException { - String aflInfoId = aflInfoService.saveAflInfo(req); + String groupIdentifier = aflInfoService.saveAflInfo(req); - return CommonResult.success(aflInfoId); + return CommonResult.success(groupIdentifier); + } + + + @PostMapping(path="/findAflInfo") + public CommonResult findAflInfo(@RequestBody @Valid AflManagerReq req) throws SftpUploadUtil.SftpUploadException { + + AflInfoResp resp = aflInfoService.findAflInfo(req); + + return CommonResult.success(resp); + } + + + @PostMapping(path="/findAflInfoList") + public CommonResult> findAflInfoList(@RequestBody @Valid AflManagerReq req){ + + List respList = aflInfoService.findPipelineList(req); + + return CommonResult.success(respList); } @PostMapping(path="/saveAflCrashesInfo") - public CommonResult saveAflCrashesInfo(@RequestBody @Valid AflManagerReq req) throws SftpUploadUtil.SftpUploadException { + public CommonResult saveAflCrashesInfo(@RequestBody @Valid AflManagerReq req) throws SftpUploadUtil.SftpUploadException { - aflCrashesInfoService.saveAflCrashesInfo(req); + String groupIdentifier = aflCrashesInfoService.saveAflCrashesInfo(req); - return CommonResult.success(); + return CommonResult.success(groupIdentifier); + } + + + @PostMapping(path="/findAflCrashesInfoList") + public CommonResult> findAflCrashesInfoList(@RequestBody @Valid AflManagerReq req){ + + List respList = aflCrashesInfoService.findPipelineList(req); + + return CommonResult.success(respList); } diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/req/aflManager/AflManagerReq.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/req/aflManager/AflManagerReq.java index f25329c8..ff40c1da 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/req/aflManager/AflManagerReq.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/req/aflManager/AflManagerReq.java @@ -4,9 +4,12 @@ import lombok.Data; @Data public class AflManagerReq { + private String id; private String pipelineId; private String pipelineHistoryId; private String taskId; + //分组唯一标识 + private String groupIdentifier; /** * 主机地址 diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/resp/aflManager/AflCrashesInfoResp.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/resp/aflManager/AflCrashesInfoResp.java new file mode 100644 index 00000000..670ec816 --- /dev/null +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/resp/aflManager/AflCrashesInfoResp.java @@ -0,0 +1,275 @@ +package cd.casic.ci.process.dto.resp.aflManager; + +import lombok.Data; + +/** + * @ClassName ReportResp + * @Author hopeli + * @Date 2025/5/10 10:53 + * @Version 1.0 + */ +@Data +public class AflCrashesInfoResp { + private String id; + private String pipelineId; + private String pipelineHistoryId; + private String taskId; + //分组唯一标识 + private String groupIdentifier; + + /** + * 模糊测试进程的开始时间 + */ + private String startTime; + + /** + * 最后一次更新时间戳 + */ + private String lastUpdate; + + /** + * 总运行时间 + */ + private String runTime; + + /** + * 模糊器的进程 ID + */ + private String fuzzerPid; + + /** + * 已完成的循环次数 + */ + private String cyclesDone; + + /** + * 未发现新内容的循环次数 + */ + private String cyclesWoFinds; + + /** + * 未发现新内容的时间 + */ + private String timeWoFinds; + + /** + * 模糊测试所用时间 + */ + private String fuzzTime; + + /** + * 校准时间 + */ + private String calibrationTime; + + /** + * 比较日志时间 + */ + private String cmplogTime; + + /** + * 同步时间 + */ + private String syncTime; + + /** + * 裁剪时间 + */ + private String trimTime; + + /** + * 已执行的次数 + */ + private String execsDone; + + /** + * 每秒执行次数 + */ + private String execsPerSec; + + /** + * 上一分钟内的每秒执行次数 + */ + private String execsPsLastMin; + + /** + * 语料库中的条目数量 + */ + private String corpusCount; + + /** + * 语料库中被优先选择的条目 + */ + private String corpusFavored; + + /** + * 语料库中发现的条目 + */ + private String corpusFound; + + /** + * 导入到语料库的条目 + */ + private String corpusImported; + + /** + * 语料库中的可变条目 + */ + private String corpusVariable; + + /** + * 达到的最大深度 + */ + private String maxDepth; + + /** + * 当前处理的条目索引 + */ + private String curItem; + + /** + * 待处理的优先条目数 + */ + private String pendingFavs; + + /** + * 总待处理条目数 + */ + private String pendingTotal; + + /** + * 稳定性百分比 + */ + private String stability; + + /** + * 位图覆盖率百分比 + */ + private String bitmapCvg; + + /** + * 保存的崩溃次数 + */ + private String savedCrashes; + + /** + * 保存的挂起次数 + */ + private String savedHangs; + + /** + * 总超时次数 + */ + private String totalTmout; + + /** + * 上次发现的时间戳 + */ + private String lastFind; + + /** + * 上次崩溃的时间戳 + */ + private String lastCrash; + + /** + * 上次挂起的时间戳 + */ + private String lastHang; + + /** + * 自上次崩溃以来的执行次数 + */ + private String execsSinceCrash; + + /** + * 执行超时值 + */ + private String execTimeout; + + /** + * 最慢执行时间(毫秒) + */ + private String slowestExecMs; + + /** + * 峰值 RSS 内存使用量(MB) + */ + private String peakRssMb; + + /** + * CPU 亲和性设置 + */ + private String cpuAffinity; + + /** + * 发现的边数(edges) + */ + private String edgesFound; + + /** + * 总可用边数(edges) + */ + private String totalEdges; + + /** + * 可变字节计数 + */ + private String varByteCount; + + /** + * Havoc 扩展因子 + */ + private String havocExpansion; + + /** + * 自动词典条目数 + */ + private String autoDictEntries; + + /** + * 测试缓存大小 + */ + private String testcacheSize; + + /** + * 测试缓存条目数 + */ + private String testcacheCount; + + /** + * 测试缓存驱逐次数 + */ + private String testcacheEvict; + + /** + * 目标程序 banner + */ + private String aflBanner; + + /** + * 使用的 AFL 版本 + */ + private String aflVersion; + + /** + * 目标模式配置 + */ + private String targetMode; + + /** + * 执行使用的命令行 + */ + private String commandLine; + + /** + * 文件二进制内容 + */ + private String contentId; + + /** + * 文件地址路径 + */ + private String filePath; + +} diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/resp/aflManager/AflInfoResp.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/resp/aflManager/AflInfoResp.java new file mode 100644 index 00000000..a8b25a5a --- /dev/null +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/dto/resp/aflManager/AflInfoResp.java @@ -0,0 +1,275 @@ +package cd.casic.ci.process.dto.resp.aflManager; + +import lombok.Data; + +/** + * @ClassName ReportResp + * @Author hopeli + * @Date 2025/5/10 10:53 + * @Version 1.0 + */ +@Data +public class AflInfoResp { + private String id; + private String pipelineId; + private String pipelineHistoryId; + private String taskId; + //分组唯一标识 + private String groupIdentifier; + + /** + * 模糊测试进程的开始时间 + */ + private String startTime; + + /** + * 最后一次更新时间戳 + */ + private String lastUpdate; + + /** + * 总运行时间 + */ + private String runTime; + + /** + * 模糊器的进程 ID + */ + private String fuzzerPid; + + /** + * 已完成的循环次数 + */ + private String cyclesDone; + + /** + * 未发现新内容的循环次数 + */ + private String cyclesWoFinds; + + /** + * 未发现新内容的时间 + */ + private String timeWoFinds; + + /** + * 模糊测试所用时间 + */ + private String fuzzTime; + + /** + * 校准时间 + */ + private String calibrationTime; + + /** + * 比较日志时间 + */ + private String cmplogTime; + + /** + * 同步时间 + */ + private String syncTime; + + /** + * 裁剪时间 + */ + private String trimTime; + + /** + * 已执行的次数 + */ + private String execsDone; + + /** + * 每秒执行次数 + */ + private String execsPerSec; + + /** + * 上一分钟内的每秒执行次数 + */ + private String execsPsLastMin; + + /** + * 语料库中的条目数量 + */ + private String corpusCount; + + /** + * 语料库中被优先选择的条目 + */ + private String corpusFavored; + + /** + * 语料库中发现的条目 + */ + private String corpusFound; + + /** + * 导入到语料库的条目 + */ + private String corpusImported; + + /** + * 语料库中的可变条目 + */ + private String corpusVariable; + + /** + * 达到的最大深度 + */ + private String maxDepth; + + /** + * 当前处理的条目索引 + */ + private String curItem; + + /** + * 待处理的优先条目数 + */ + private String pendingFavs; + + /** + * 总待处理条目数 + */ + private String pendingTotal; + + /** + * 稳定性百分比 + */ + private String stability; + + /** + * 位图覆盖率百分比 + */ + private String bitmapCvg; + + /** + * 保存的崩溃次数 + */ + private String savedCrashes; + + /** + * 保存的挂起次数 + */ + private String savedHangs; + + /** + * 总超时次数 + */ + private String totalTmout; + + /** + * 上次发现的时间戳 + */ + private String lastFind; + + /** + * 上次崩溃的时间戳 + */ + private String lastCrash; + + /** + * 上次挂起的时间戳 + */ + private String lastHang; + + /** + * 自上次崩溃以来的执行次数 + */ + private String execsSinceCrash; + + /** + * 执行超时值 + */ + private String execTimeout; + + /** + * 最慢执行时间(毫秒) + */ + private String slowestExecMs; + + /** + * 峰值 RSS 内存使用量(MB) + */ + private String peakRssMb; + + /** + * CPU 亲和性设置 + */ + private String cpuAffinity; + + /** + * 发现的边数(edges) + */ + private String edgesFound; + + /** + * 总可用边数(edges) + */ + private String totalEdges; + + /** + * 可变字节计数 + */ + private String varByteCount; + + /** + * Havoc 扩展因子 + */ + private String havocExpansion; + + /** + * 自动词典条目数 + */ + private String autoDictEntries; + + /** + * 测试缓存大小 + */ + private String testcacheSize; + + /** + * 测试缓存条目数 + */ + private String testcacheCount; + + /** + * 测试缓存驱逐次数 + */ + private String testcacheEvict; + + /** + * 目标程序 banner + */ + private String aflBanner; + + /** + * 使用的 AFL 版本 + */ + private String aflVersion; + + /** + * 目标模式配置 + */ + private String targetMode; + + /** + * 执行使用的命令行 + */ + private String commandLine; + + /** + * 文件二进制内容 + */ + private String contentId; + + /** + * 文件地址路径 + */ + private String filePath; + +} diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/converter/AflManagerConverter.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/converter/AflManagerConverter.java new file mode 100644 index 00000000..54b8d37b --- /dev/null +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/converter/AflManagerConverter.java @@ -0,0 +1,29 @@ +package cd.casic.ci.process.process.converter; + +import cd.casic.ci.process.dto.resp.aflManager.AflCrashesInfoResp; +import cd.casic.ci.process.dto.resp.aflManager.AflInfoResp; +import cd.casic.ci.process.process.dataObject.aflManager.AflCrashesInfo; +import cd.casic.ci.process.process.dataObject.aflManager.AflInfo; +import org.mapstruct.Mapper; +import org.mapstruct.NullValuePropertyMappingStrategy; +import org.mapstruct.factory.Mappers; + +import java.util.List; + +/** + * @author HopeLi + * @version v1.0 + * @ClassName PipelineConverter + * @Date: 2025/5/13 14:39 + * @Description: + */ +@Mapper(componentModel = "spring",nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) +public interface AflManagerConverter { + AflManagerConverter INSTANCE = Mappers.getMapper(AflManagerConverter.class); + + AflInfoResp toAflInfoResp(AflInfo aflInfo); + + List toAflInfoRespList(List aflInfos); + + List toAflCrashesInfoRespList(List aflCrashesInfos); +} diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/aflManager/AflCrashesInfo.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/aflManager/AflCrashesInfo.java index 1895ac04..3c93955a 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/aflManager/AflCrashesInfo.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/aflManager/AflCrashesInfo.java @@ -17,6 +17,8 @@ public class AflCrashesInfo extends PipBaseElement { private String pipelineHistoryId; private String taskId; + //分组唯一标识 + private String groupIdentifier; /** diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/aflManager/AflInfo.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/aflManager/AflInfo.java index d5d65c5b..461738eb 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/aflManager/AflInfo.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/aflManager/AflInfo.java @@ -12,6 +12,8 @@ public class AflInfo extends PipBaseElement { private String pipelineId; private String pipelineHistoryId; private String taskId; + //分组唯一标识 + private String groupIdentifier; /** * 模糊测试进程的开始时间 diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/aflManager/AflSeedInfo.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/aflManager/AflSeedInfo.java index 345c63f7..285ca533 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/aflManager/AflSeedInfo.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/dataObject/aflManager/AflSeedInfo.java @@ -18,9 +18,11 @@ public class AflSeedInfo extends PipBaseElement { private String pipelineId; private String pipelineHistoryId; private String taskId; + //分组唯一标识 + private String groupIdentifier; /** - * 最后一次更新时间戳 + * 生成种子数量 */ private String seedAmount; @@ -29,4 +31,10 @@ public class AflSeedInfo extends PipBaseElement { */ private String filePath; + + /** + * 执行分钟数 + */ + private Integer minutesDifference; + } diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/AflCrashesInfoService.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/AflCrashesInfoService.java index c5994064..ee1fab4b 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/AflCrashesInfoService.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/AflCrashesInfoService.java @@ -1,10 +1,13 @@ package cd.casic.ci.process.process.service.aflManager; import cd.casic.ci.process.dto.req.aflManager.AflManagerReq; +import cd.casic.ci.process.dto.resp.aflManager.AflCrashesInfoResp; import cd.casic.ci.process.process.dataObject.aflManager.AflCrashesInfo; import com.baomidou.mybatisplus.extension.service.IService; import jakarta.validation.Valid; +import java.util.List; + /** * @author HopeLi * @version v1.0 @@ -14,5 +17,9 @@ import jakarta.validation.Valid; */ public interface AflCrashesInfoService extends IService { - void saveAflCrashesInfo(@Valid AflManagerReq req); + String saveAflCrashesInfo(@Valid AflManagerReq req); + + void updateHistoryPipelineIdByAflCrashesInfo(@Valid AflManagerReq req); + + List findPipelineList(@Valid AflManagerReq req); } diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/AflInfoService.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/AflInfoService.java index 66e7d710..1caf1666 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/AflInfoService.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/AflInfoService.java @@ -1,11 +1,14 @@ package cd.casic.ci.process.process.service.aflManager; import cd.casic.ci.process.dto.req.aflManager.AflManagerReq; +import cd.casic.ci.process.dto.resp.aflManager.AflInfoResp; import cd.casic.ci.process.process.dataObject.aflManager.AflInfo; import cd.casic.ci.process.util.SftpUploadUtil; import com.baomidou.mybatisplus.extension.service.IService; import jakarta.validation.Valid; +import java.util.List; + /** * @author HopeLi * @version v1.0 @@ -16,4 +19,10 @@ import jakarta.validation.Valid; public interface AflInfoService extends IService { String saveAflInfo(@Valid AflManagerReq req) throws SftpUploadUtil.SftpUploadException; + + void updateHistoryPipelineIdByAflInfo(@Valid AflManagerReq req); + + AflInfoResp findAflInfo(@Valid AflManagerReq req) throws SftpUploadUtil.SftpUploadException; + + List findPipelineList(@Valid AflManagerReq req); } diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/AflSeedInfoService.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/AflSeedInfoService.java index 7857ff95..e8c72567 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/AflSeedInfoService.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/AflSeedInfoService.java @@ -21,4 +21,6 @@ public interface AflSeedInfoService extends IService { List findSeedsCount(@Valid AflManagerReq req) throws SftpUploadUtil.SftpUploadException; void saveAflSeedInfo(@Valid AflManagerReq req); + + void updateHistoryPipelineIdByAflSeedInfo(@Valid AflManagerReq req); } diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/impl/AflCrashesInfoServiceImpl.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/impl/AflCrashesInfoServiceImpl.java index 6fd43a6c..bb224dd4 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/impl/AflCrashesInfoServiceImpl.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/impl/AflCrashesInfoServiceImpl.java @@ -1,18 +1,33 @@ package cd.casic.ci.process.process.service.aflManager.impl; import cd.casic.ci.process.dto.req.aflManager.AflManagerReq; +import cd.casic.ci.process.dto.resp.aflManager.AflCrashesInfoResp; +import cd.casic.ci.process.dto.resp.resource.ResourceFindResp; +import cd.casic.ci.process.engine.constant.PipelineVariableConstant; +import cd.casic.ci.process.engine.manager.RunContextManager; +import cd.casic.ci.process.engine.runContext.BaseRunContext; +import cd.casic.ci.process.process.converter.AflManagerConverter; import cd.casic.ci.process.process.dao.aflManager.AflCrashesInfoDao; import cd.casic.ci.process.process.dataObject.aflManager.AflCrashesInfo; +import cd.casic.ci.process.process.dataObject.resource.PipResourceMachine; import cd.casic.ci.process.process.service.aflManager.AflCrashesInfoService; +import cd.casic.ci.process.process.service.resource.ResourceManagerService; import cd.casic.ci.process.util.SftpUploadUtil; +import cd.casic.framework.commons.exception.ServiceException; +import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import de.danielbechler.util.Collections; +import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; import java.util.ArrayList; import java.util.List; +import java.util.UUID; /** * @author HopeLi @@ -28,18 +43,42 @@ public class AflCrashesInfoServiceImpl extends ServiceImpl files = SftpUploadUtil.listFilesInRemoteDirectory( - req.getMachineHost(), Integer.parseInt(req.getSshPort()), req.getUsername(), req.getPassword(), null, remoteFilePath + "PIP_" + req.getPipelineId() + crashesFilePath); + resourceMachine.getMachineHost(), Integer.parseInt(resourceMachine.getSshPort()), resourceMachine.getUsername(), resourceMachine.getPassword(), null, remoteFilePath + "PIP_" + req.getPipelineId() + crashesFilePath); if (!CollectionUtils.isEmpty(files)) { // 步骤2:批量复制文件到目标目录 - List copiedFiles = SftpUploadUtil.copyRemoteFile( - req.getMachineHost(), Integer.parseInt(req.getSshPort()), req.getUsername(), req.getPassword(), null, files, remoteFilePath + "PIP_" + req.getPipelineId() + "/crashes_result/"); + List copiedFiles = SftpUploadUtil.copyRemoteFilesToLocal( + resourceMachine.getMachineHost(), Integer.parseInt(resourceMachine.getSshPort()), resourceMachine.getUsername(), resourceMachine.getPassword(), null, files, "/home/ops/opsFile/crashes_result/" + UUID.randomUUID() + "/"); System.out.println("共复制 " + copiedFiles.size() + " 个文件"); if (!CollectionUtils.isEmpty(copiedFiles)){ @@ -55,6 +94,7 @@ public class AflCrashesInfoServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); + wrapper.eq("group_identifier", req.getGroupIdentifier()); + List aflCrashesInfos = baseMapper.selectList(wrapper); + if (!Collections.isEmpty(aflCrashesInfos)){ + aflCrashesInfos.forEach(o->{ + o.setPipelineHistoryId(req.getPipelineHistoryId()); + }); + } + baseMapper.updateBatch(aflCrashesInfos); + } + + @Override + public List findPipelineList(AflManagerReq req) { + QueryWrapper wrapper = new QueryWrapper<>(); + if (!ObjectUtils.isEmpty(req.getId())){ + wrapper.eq("id",req.getId()); + } + if (!ObjectUtils.isEmpty(req.getPipelineId())){ + wrapper.eq("pipeline_id",req.getPipelineId()); + } + if (!ObjectUtils.isEmpty(req.getPipelineHistoryId())){ + wrapper.eq("pipeline_history_id",req.getPipelineHistoryId()); + } + if (!ObjectUtils.isEmpty(req.getTaskId())){ + wrapper.eq("task_id",req.getTaskId()); + } + if (!ObjectUtils.isEmpty(req.getGroupIdentifier())){ + wrapper.eq("group_identifier",req.getGroupIdentifier()); + } + + List aflCrashesInfos = baseMapper.selectList(wrapper); + if (ObjectUtils.isEmpty(aflCrashesInfos)){ + return new ArrayList<>(0); + } + + return AflManagerConverter.INSTANCE.toAflCrashesInfoRespList(aflCrashesInfos); + } } diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/impl/AflInfoServiceImpl.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/impl/AflInfoServiceImpl.java index 1d8c5b3a..fdddf722 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/impl/AflInfoServiceImpl.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/impl/AflInfoServiceImpl.java @@ -1,17 +1,28 @@ package cd.casic.ci.process.process.service.aflManager.impl; import cd.casic.ci.process.dto.req.aflManager.AflManagerReq; +import cd.casic.ci.process.dto.resp.aflManager.AflInfoResp; +import cd.casic.ci.process.dto.resp.resource.ResourceFindResp; +import cd.casic.ci.process.engine.constant.PipelineVariableConstant; +import cd.casic.ci.process.engine.manager.RunContextManager; +import cd.casic.ci.process.engine.runContext.BaseRunContext; +import cd.casic.ci.process.process.converter.AflManagerConverter; import cd.casic.ci.process.process.dao.aflManager.AflInfoDao; import cd.casic.ci.process.process.dataObject.aflManager.AflInfo; import cd.casic.ci.process.process.dataObject.resource.PipResourceMachine; import cd.casic.ci.process.process.service.aflManager.AflInfoService; +import cd.casic.ci.process.process.service.resource.ResourceManagerService; import cd.casic.ci.process.util.SftpUploadUtil; import cd.casic.framework.commons.exception.ServiceException; import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import de.danielbechler.util.Collections; +import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; +import org.springframework.util.ObjectUtils; import java.util.ArrayList; import java.util.List; @@ -29,22 +40,37 @@ import java.util.UUID; public class AflInfoServiceImpl extends ServiceImpl implements AflInfoService { private static final String remoteFilePath = "/home/casic/706/yunqi/"; + @Resource + private RunContextManager runContextManager; + + @Resource + private ResourceManagerService resourceManagerService; + @Override public String saveAflInfo(AflManagerReq req) throws SftpUploadUtil.SftpUploadException { - if (StringUtils.isEmpty(req.getPipelineId())){ - throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"pipelineId不能为空"); + if (StringUtils.isEmpty(req.getPipelineId()) || StringUtils.isEmpty(req.getTaskId())){ + throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"pipelineId或者taskId不能为空"); } - PipResourceMachine pipResourceMachine = new PipResourceMachine(); - pipResourceMachine.setMachineHost(req.getMachineHost()); - pipResourceMachine.setSshPort(req.getSshPort()); - pipResourceMachine.setUsername(req.getUsername()); - pipResourceMachine.setPassword(req.getPassword()); - AflInfo aflInfo = SftpUploadUtil.downloadFileSftpForInputStreamAndSetAflInfo(req.getMachineHost(), Integer.parseInt(req.getSshPort()), req.getUsername(), req.getPassword(),null, remoteFilePath + "PIP_" + req.getPipelineId() + "/ai_afl/default/fuzzer_stats"); - //创建一个新文件夹,将远程文件复制一份过去 + + BaseRunContext runContext = runContextManager.getContext(req.getPipelineId()); + String resourceId = runContext.getGlobalVariables().get(PipelineVariableConstant.AFL_RESOURCE_MANAGER_ID_KEY) instanceof String ? ((String) runContext.getGlobalVariables().get(PipelineVariableConstant.AFL_RESOURCE_MANAGER_ID_KEY)) : null; + if (StringUtils.isEmpty(resourceId)){ + throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"未找到资源"); + } + + ResourceFindResp resourceById = resourceManagerService.findResourceById(resourceId); + if (resourceById == null || resourceById.getResourceMachine() == null) { + throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"资源信息错误"); + } + + PipResourceMachine resourceMachine = resourceById.getResourceMachine(); + + AflInfo aflInfo = SftpUploadUtil.downloadFileSftpForInputStreamAndSetAflInfo(resourceMachine.getMachineHost(), Integer.parseInt(resourceMachine.getSshPort()), resourceMachine.getUsername(), resourceMachine.getPassword(),null, remoteFilePath + "PIP_" + req.getPipelineId() + "/ai_afl/default/fuzzer_stats"); + //在本地创建一个新文件夹,将远程文件复制一份过去 List sourceFilePaths = new ArrayList<>(); sourceFilePaths.add(remoteFilePath + "PIP_" + req.getPipelineId() + "/ai_afl/default/fuzzer_stats"); - List strings = SftpUploadUtil.copyRemoteFile(pipResourceMachine.getMachineHost(), Integer.parseInt(pipResourceMachine.getSshPort()), pipResourceMachine.getUsername(), pipResourceMachine.getPassword(), null, sourceFilePaths, remoteFilePath + "PIP_" + req.getPipelineId() + "/fuzzer/" + UUID.randomUUID() + "/"); + List strings = SftpUploadUtil.copyRemoteFilesToLocal(resourceMachine.getMachineHost(), Integer.parseInt(resourceMachine.getSshPort()), resourceMachine.getUsername(), resourceMachine.getPassword(), null, sourceFilePaths, "/home/ops/opsFile/fuzzer_result/" + UUID.randomUUID() + "/"); aflInfo.setFilePath(strings.get(0)); aflInfo.setPipelineId(req.getPipelineId()); @@ -54,11 +80,77 @@ public class AflInfoServiceImpl extends ServiceImpl impleme if (!StringUtils.isEmpty(req.getPipelineHistoryId())){ aflInfo.setPipelineHistoryId(req.getPipelineHistoryId()); } + aflInfo.setGroupIdentifier(UUID.randomUUID().toString()); baseMapper.insert(aflInfo); - return aflInfo.getId(); + return aflInfo.getGroupIdentifier(); } + @Override + public void updateHistoryPipelineIdByAflInfo(AflManagerReq req) { + if (!StringUtils.isEmpty(req.getGroupIdentifier())){ + throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"groupIdentifier不能为空"); + } + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.eq("group_identifier", req.getGroupIdentifier()); + List aflInfos = baseMapper.selectList(wrapper); + if (!Collections.isEmpty(aflInfos)){ + aflInfos.forEach(o->{ + o.setPipelineHistoryId(req.getPipelineHistoryId()); + }); + } + baseMapper.updateBatch(aflInfos); + } + + @Override + public AflInfoResp findAflInfo(AflManagerReq req) throws SftpUploadUtil.SftpUploadException { + if (StringUtils.isEmpty(req.getPipelineId()) || StringUtils.isEmpty(req.getTaskId())){ + throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"pipelineId或者taskId不能为空"); + } + + BaseRunContext runContext = runContextManager.getContext(req.getPipelineId()); + String resourceId = runContext.getGlobalVariables().get(PipelineVariableConstant.AFL_RESOURCE_MANAGER_ID_KEY) instanceof String ? ((String) runContext.getGlobalVariables().get(PipelineVariableConstant.AFL_RESOURCE_MANAGER_ID_KEY)) : null; + if (StringUtils.isEmpty(resourceId)){ + throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"未找到资源"); + } + + ResourceFindResp resourceById = resourceManagerService.findResourceById(resourceId); + if (resourceById == null || resourceById.getResourceMachine() == null) { + throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"资源信息错误"); + } + + PipResourceMachine resourceMachine = resourceById.getResourceMachine(); + AflInfo aflInfo = SftpUploadUtil.downloadFileSftpForInputStreamAndSetAflInfo(resourceMachine.getMachineHost(), Integer.parseInt(resourceMachine.getSshPort()), resourceMachine.getUsername(), resourceMachine.getPassword(),null, remoteFilePath + "PIP_" + req.getPipelineId() + "/ai_afl/default/fuzzer_stats"); + + return AflManagerConverter.INSTANCE.toAflInfoResp(aflInfo); + } + + @Override + public List findPipelineList(AflManagerReq req) { + QueryWrapper wrapper = new QueryWrapper<>(); + if (!ObjectUtils.isEmpty(req.getId())){ + wrapper.eq("id",req.getId()); + } + if (!ObjectUtils.isEmpty(req.getPipelineId())){ + wrapper.eq("pipeline_id",req.getPipelineId()); + } + if (!ObjectUtils.isEmpty(req.getPipelineHistoryId())){ + wrapper.eq("pipeline_history_id",req.getPipelineHistoryId()); + } + if (!ObjectUtils.isEmpty(req.getTaskId())){ + wrapper.eq("task_id",req.getTaskId()); + } + if (!ObjectUtils.isEmpty(req.getGroupIdentifier())){ + wrapper.eq("group_identifier",req.getGroupIdentifier()); + } + + List aflInfos = baseMapper.selectList(wrapper); + if (ObjectUtils.isEmpty(aflInfos)){ + return new ArrayList<>(0); + } + + return AflManagerConverter.INSTANCE.toAflInfoRespList(aflInfos); + } /** diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/impl/AflSeedInfoServiceImpl.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/impl/AflSeedInfoServiceImpl.java index 6db7034a..5f6474cb 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/impl/AflSeedInfoServiceImpl.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/process/service/aflManager/impl/AflSeedInfoServiceImpl.java @@ -2,15 +2,21 @@ package cd.casic.ci.process.process.service.aflManager.impl; import cd.casic.ci.process.dto.req.aflManager.AflManagerReq; import cd.casic.ci.process.dto.resp.aflManager.SeedsCountResp; +import cd.casic.ci.process.dto.resp.resource.ResourceFindResp; +import cd.casic.ci.process.engine.constant.PipelineVariableConstant; import cd.casic.ci.process.engine.manager.RunContextManager; import cd.casic.ci.process.engine.runContext.BaseRunContext; import cd.casic.ci.process.process.dao.aflManager.AflSeedInfoDao; import cd.casic.ci.process.process.dataObject.aflManager.AflSeedInfo; +import cd.casic.ci.process.process.dataObject.resource.PipResourceMachine; import cd.casic.ci.process.process.service.aflManager.AflSeedInfoService; +import cd.casic.ci.process.process.service.resource.ResourceManagerService; import cd.casic.ci.process.util.SftpUploadUtil; import cd.casic.framework.commons.exception.ServiceException; import cd.casic.framework.commons.exception.enums.GlobalErrorCodeConstants; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import de.danielbechler.util.Collections; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -23,6 +29,7 @@ import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; +import java.util.UUID; /** * @author HopeLi @@ -38,6 +45,9 @@ public class AflSeedInfoServiceImpl extends ServiceImpl resultList = SftpUploadUtil.findSeedCount(req.getMachineHost(), Integer.parseInt(req.getSshPort()), req.getUsername(), req.getPassword(), null, remoteFilePath + "PIP_" + req.getPipelineId() + "/ai_afl/default/queue/"); + + BaseRunContext pipelineRunContext = runContextManager.getContext(req.getPipelineId()); + String resourceId = pipelineRunContext.getGlobalVariables().get(PipelineVariableConstant.AFL_RESOURCE_MANAGER_ID_KEY) instanceof String ? ((String) pipelineRunContext.getGlobalVariables().get(PipelineVariableConstant.AFL_RESOURCE_MANAGER_ID_KEY)) : null; + if (StringUtils.isEmpty(resourceId)){ + throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"未找到资源"); + } + + ResourceFindResp resourceById = resourceManagerService.findResourceById(resourceId); + if (resourceById == null || resourceById.getResourceMachine() == null) { + throw new ServiceException(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"资源信息错误"); + } + + PipResourceMachine resourceMachine = resourceById.getResourceMachine(); + + List resultList = SftpUploadUtil.findSeedCount(resourceMachine.getMachineHost(), Integer.parseInt(resourceMachine.getSshPort()), resourceMachine.getUsername(), resourceMachine.getPassword(), null, remoteFilePath + "PIP_" + req.getPipelineId() + "/ai_afl/default/queue/"); //解析resultList @@ -89,8 +113,8 @@ public class AflSeedInfoServiceImpl extends ServiceImpl files = SftpUploadUtil.listFilesInRemoteDirectory( - req.getMachineHost(), Integer.parseInt(req.getSshPort()), req.getUsername(), req.getPassword(), null, remoteFilePath + "PIP_" + req.getPipelineId() + seedFilePath); + resourceMachine.getMachineHost(), Integer.parseInt(resourceMachine.getSshPort()), resourceMachine.getUsername(), resourceMachine.getPassword(), null, remoteFilePath + "PIP_" + req.getPipelineId() + seedFilePath); if (!CollectionUtils.isEmpty(files)) { // 步骤2:批量复制文件到目标目录 - List copiedFiles = SftpUploadUtil.copyRemoteFile( - req.getMachineHost(), Integer.parseInt(req.getSshPort()), req.getUsername(), req.getPassword(), null, files, remoteFilePath + "PIP_" + req.getPipelineId() + "/seed_result/"); + List copiedFiles = SftpUploadUtil.copyRemoteFilesToLocal( + resourceMachine.getMachineHost(), Integer.parseInt(resourceMachine.getSshPort()), resourceMachine.getUsername(), resourceMachine.getPassword(), null, files, "/home/ops/opsFile/seed_result/" + UUID.randomUUID() + "/"); System.out.println("共复制 " + copiedFiles.size() + " 个文件"); if (!CollectionUtils.isEmpty(copiedFiles)){ @@ -150,9 +192,12 @@ public class AflSeedInfoServiceImpl extends ServiceImpl{ AflSeedInfo aflSeedInfo = new AflSeedInfo(); - // 提取文件名部分(queue/之后的内容) + // 提取文件名部分(seed_result/之后的内容) String fileNamePart = o.substring(o.indexOf("seed_result/") + 12); + //截取最后一个斜杠后的内容,即文件信息部分 + fileNamePart = fileNamePart.substring(fileNamePart.lastIndexOf("/") + 1); + // 使用正则匹配 id: 开头的内容 java.util.regex.Pattern patternId = java.util.regex.Pattern.compile("id:([^,]+)"); java.util.regex.Matcher matcherId = patternId.matcher(fileNamePart); @@ -179,6 +224,7 @@ public class AflSeedInfoServiceImpl extends ServiceImpl wrapper = new QueryWrapper<>(); + wrapper.eq("group_identifier", req.getGroupIdentifier()); + List aflSeedInfos = baseMapper.selectList(wrapper); + if (!Collections.isEmpty(aflSeedInfos)){ + aflSeedInfos.forEach(o->{ + o.setPipelineHistoryId(req.getPipelineHistoryId()); + }); + } + baseMapper.updateBatch(aflSeedInfos); + } } diff --git a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/util/SftpUploadUtil.java b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/util/SftpUploadUtil.java index eea6a403..e95a96bb 100644 --- a/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/util/SftpUploadUtil.java +++ b/modules/module-ci-process-biz/src/main/java/cd/casic/ci/process/util/SftpUploadUtil.java @@ -485,7 +485,6 @@ public class SftpUploadUtil { currentDir.append("/").append(dir); try { channelSftp.cd(currentDir.toString()); - // System.out.println("目录已存在: " + currentDir.toString()); } catch (SftpException e) { if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) { // 目录不存在,创建它 @@ -1011,81 +1010,12 @@ public class SftpUploadUtil { } - - private static AflInfo setAflinfo(Map statsMap) { - //映射到 AflInfo 实体 - AflInfo aflInfo = new AflInfo(); - - aflInfo.setStartTime(statsMap.get("start_time")); - aflInfo.setLastUpdate(statsMap.get("last_update")); - aflInfo.setRunTime(statsMap.get("run_time")); - aflInfo.setFuzzerPid(statsMap.get("fuzzer_pid")); - aflInfo.setCyclesDone(statsMap.get("cycles_done")); - aflInfo.setCyclesWoFinds(statsMap.get("cycles_wo_finds")); - aflInfo.setTimeWoFinds(statsMap.get("time_wo_finds")); - aflInfo.setFuzzTime(statsMap.get("fuzz_time")); - aflInfo.setCalibrationTime(statsMap.get("calibration_time")); - aflInfo.setCmplogTime(statsMap.get("cmplog_time")); - aflInfo.setSyncTime(statsMap.get("sync_time")); - aflInfo.setTrimTime(statsMap.get("trim_time")); - aflInfo.setExecsDone(statsMap.get("execs_done")); - aflInfo.setExecsPerSec(statsMap.get("execs_per_sec")); - aflInfo.setExecsPsLastMin(statsMap.get("execs_ps_last_min")); - aflInfo.setCorpusCount(statsMap.get("corpus_count")); - aflInfo.setCorpusFavored(statsMap.get("corpus_favored")); - aflInfo.setCorpusFound(statsMap.get("corpus_found")); - aflInfo.setCorpusImported(statsMap.get("corpus_imported")); - aflInfo.setCorpusVariable(statsMap.get("corpus_variable")); - aflInfo.setMaxDepth(statsMap.get("max_depth")); - aflInfo.setCurItem(statsMap.get("cur_item")); - aflInfo.setPendingFavs(statsMap.get("pending_favs")); - aflInfo.setPendingTotal(statsMap.get("pending_total")); - aflInfo.setStability(statsMap.get("stability")); - aflInfo.setBitmapCvg(statsMap.get("bitmap_cvg")); - aflInfo.setSavedCrashes(statsMap.get("saved_crashes")); - aflInfo.setSavedHangs(statsMap.get("saved_hangs")); - aflInfo.setTotalTmout(statsMap.get("total_tmout")); - aflInfo.setLastFind(statsMap.get("last_find")); - aflInfo.setLastCrash(statsMap.get("last_crash")); - aflInfo.setLastHang(statsMap.get("last_hang")); - aflInfo.setExecsSinceCrash(statsMap.get("execs_since_crash")); - aflInfo.setExecTimeout(statsMap.get("exec_timeout")); - aflInfo.setSlowestExecMs(statsMap.get("slowest_exec_ms")); - aflInfo.setPeakRssMb(statsMap.get("peak_rss_mb")); - aflInfo.setCpuAffinity(statsMap.get("cpu_affinity")); - aflInfo.setEdgesFound(statsMap.get("edges_found")); - aflInfo.setTotalEdges(statsMap.get("total_edges")); - aflInfo.setVarByteCount(statsMap.get("var_byte_count")); - aflInfo.setHavocExpansion(statsMap.get("havoc_expansion")); - aflInfo.setAutoDictEntries(statsMap.get("auto_dict_entries")); - aflInfo.setTestcacheSize(statsMap.get("testcache_size")); - aflInfo.setTestcacheCount(statsMap.get("testcache_count")); - aflInfo.setTestcacheEvict(statsMap.get("testcache_evict")); - aflInfo.setAflBanner(statsMap.get("afl_banner")); - aflInfo.setAflVersion(statsMap.get("afl_version")); - aflInfo.setTargetMode(statsMap.get("target_mode")); - aflInfo.setCommandLine(statsMap.get("command_line")); - - return aflInfo; - } - - - - private static boolean thisDirectory(ChannelSftp channelSftp, String fullPath) { - try { - SftpATTRS attrs = channelSftp.lstat(fullPath); - return attrs.isDir(); - } catch (SftpException e) { - return false; - } - } - public static List findSeedCount(String remoteHost, - Integer remotePort, - String username, - String password, - String sshKeyPath, - String remoteDir) throws SftpUploadException { + Integer remotePort, + String username, + String password, + String sshKeyPath, + String remoteDir) throws SftpUploadException { Session session = null; @@ -1193,8 +1123,198 @@ public class SftpUploadUtil { } + public static List copyRemoteFilesToLocal(String remoteHost, + Integer remotePort, + String username, + String password, + String sshKeyPath, + List remoteFilePaths, + String localDir) throws SftpUploadException { - // 自定义异常类,用于封装上传过程中的错误 + List copiedLocalPaths = new ArrayList<>(); + + Session session = null; + Channel channel = null; + ChannelSftp channelSftp = null; + InputStream inputStream = null; + + try { + JSch jsch = new JSch(); + + // 1. 添加身份认证信息 (密码或密钥) + if (sshKeyPath != null && !sshKeyPath.trim().isEmpty()) { + // 使用 SSH Key 认证 + File sshKeyFile = new File(sshKeyPath); + if (!sshKeyFile.exists() || !sshKeyFile.isFile()) { + throw new SftpUploadException("SSH Key 文件不存在或不是一个有效文件: " + sshKeyPath); + } + jsch.addIdentity(sshKeyPath); + System.out.println("使用 SSH Key 认证: " + sshKeyPath); + } else if (password == null || password.trim().isEmpty()) { + // 如果没有提供密码或密钥路径,则认证信息不全 + throw new SftpUploadException("必须提供密码或 SSH Key 路径进行 SFTP 认证."); + } + // 如果提供了密码,将在 getSession 后设置,因为 getSession 需要用户名、主机和端口先建立连接意图 + + + // 2. 获取 Session + int port = (remotePort != null && remotePort > 0) ? remotePort : DEFAULT_SFTP_PORT; + session = jsch.getSession(username, remoteHost, port); + System.out.println("尝试连接 SFTP 服务器: " + username + "@" + remoteHost + ":" + port); + + + // 如果使用密码认证且提供了密码 + if (password != null && !password.trim().isEmpty() && (sshKeyPath == null || sshKeyPath.trim().isEmpty())) { + session.setPassword(password); + System.out.println("使用密码认证."); + } + + // 设置连接不进行主机密钥检查 (生产环境不推荐,应该配置 known_hosts) + // 在实际应用中,应该引导用户信任主机密钥或提前将主机密钥加入 known_hosts + java.util.Properties config = new java.util.Properties(); + config.put("StrictHostKeyChecking", "no"); // !!! 生产环境请谨慎使用或配置正确的主机密钥检查 !!! + session.setConfig(config); + + // 3. 连接 Session + session.connect(); + System.out.println("SFTP Session 连接成功."); + + // 4. 打开 SFTP Channel + channel = session.openChannel("sftp"); + channel.connect(); + System.out.println("SFTP Channel 打开成功."); + + channelSftp = (ChannelSftp) channel; + + // 创建本地目录 + File localDirectory = new File(localDir); + if (!localDirectory.exists()) { + localDirectory.mkdirs(); + } + + // 遍历远程文件路径并下载 + for (String remoteFile : remoteFilePaths) { + String fileName = new File(remoteFile).getName(); + String localFilePath = localDir + File.separator + fileName; + + try (InputStream in = channelSftp.get(remoteFile); + FileOutputStream out = new FileOutputStream(localFilePath)) { + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = in.read(buffer)) > 0) { + out.write(buffer, 0, bytesRead); + } + copiedLocalPaths.add(localFilePath); // 添加本地路径 + } catch (Exception e) { + throw new RuntimeException("文件复制失败: " + remoteFile, e); + } + } + return copiedLocalPaths; + } catch (JSchException e) { + throw new SftpUploadException("SFTP 连接或认证失败: " + e.getMessage(), e); + } catch (SftpUploadException e) { + // 重新抛出自定义异常 + throw e; + } catch (Exception e) { + // 捕获其他未知异常 + throw new SftpUploadException("SFTP 上传过程中发生未知异常: " + e.getMessage(), e); + } finally { + // 9. 关闭资源 (确保在任何情况下都关闭) + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + System.err.println("关闭本地文件流失败: " + e.getMessage()); + e.printStackTrace(); // 打印堆栈以便调试 + } + } + if (channelSftp != null) { + channelSftp.disconnect(); + System.out.println("SFTP Channel 已断开."); + } + if (channel != null) { + channel.disconnect(); + System.out.println("SFTP Channel 资源已释放."); + } + if (session != null) { + session.disconnect(); + System.out.println("SFTP Session 已断开."); + } + } + } + + + + private static AflInfo setAflinfo(Map statsMap) { + //映射到 AflInfo 实体 + AflInfo aflInfo = new AflInfo(); + + aflInfo.setStartTime(statsMap.get("start_time")); + aflInfo.setLastUpdate(statsMap.get("last_update")); + aflInfo.setRunTime(statsMap.get("run_time")); + aflInfo.setFuzzerPid(statsMap.get("fuzzer_pid")); + aflInfo.setCyclesDone(statsMap.get("cycles_done")); + aflInfo.setCyclesWoFinds(statsMap.get("cycles_wo_finds")); + aflInfo.setTimeWoFinds(statsMap.get("time_wo_finds")); + aflInfo.setFuzzTime(statsMap.get("fuzz_time")); + aflInfo.setCalibrationTime(statsMap.get("calibration_time")); + aflInfo.setCmplogTime(statsMap.get("cmplog_time")); + aflInfo.setSyncTime(statsMap.get("sync_time")); + aflInfo.setTrimTime(statsMap.get("trim_time")); + aflInfo.setExecsDone(statsMap.get("execs_done")); + aflInfo.setExecsPerSec(statsMap.get("execs_per_sec")); + aflInfo.setExecsPsLastMin(statsMap.get("execs_ps_last_min")); + aflInfo.setCorpusCount(statsMap.get("corpus_count")); + aflInfo.setCorpusFavored(statsMap.get("corpus_favored")); + aflInfo.setCorpusFound(statsMap.get("corpus_found")); + aflInfo.setCorpusImported(statsMap.get("corpus_imported")); + aflInfo.setCorpusVariable(statsMap.get("corpus_variable")); + aflInfo.setMaxDepth(statsMap.get("max_depth")); + aflInfo.setCurItem(statsMap.get("cur_item")); + aflInfo.setPendingFavs(statsMap.get("pending_favs")); + aflInfo.setPendingTotal(statsMap.get("pending_total")); + aflInfo.setStability(statsMap.get("stability")); + aflInfo.setBitmapCvg(statsMap.get("bitmap_cvg")); + aflInfo.setSavedCrashes(statsMap.get("saved_crashes")); + aflInfo.setSavedHangs(statsMap.get("saved_hangs")); + aflInfo.setTotalTmout(statsMap.get("total_tmout")); + aflInfo.setLastFind(statsMap.get("last_find")); + aflInfo.setLastCrash(statsMap.get("last_crash")); + aflInfo.setLastHang(statsMap.get("last_hang")); + aflInfo.setExecsSinceCrash(statsMap.get("execs_since_crash")); + aflInfo.setExecTimeout(statsMap.get("exec_timeout")); + aflInfo.setSlowestExecMs(statsMap.get("slowest_exec_ms")); + aflInfo.setPeakRssMb(statsMap.get("peak_rss_mb")); + aflInfo.setCpuAffinity(statsMap.get("cpu_affinity")); + aflInfo.setEdgesFound(statsMap.get("edges_found")); + aflInfo.setTotalEdges(statsMap.get("total_edges")); + aflInfo.setVarByteCount(statsMap.get("var_byte_count")); + aflInfo.setHavocExpansion(statsMap.get("havoc_expansion")); + aflInfo.setAutoDictEntries(statsMap.get("auto_dict_entries")); + aflInfo.setTestcacheSize(statsMap.get("testcache_size")); + aflInfo.setTestcacheCount(statsMap.get("testcache_count")); + aflInfo.setTestcacheEvict(statsMap.get("testcache_evict")); + aflInfo.setAflBanner(statsMap.get("afl_banner")); + aflInfo.setAflVersion(statsMap.get("afl_version")); + aflInfo.setTargetMode(statsMap.get("target_mode")); + aflInfo.setCommandLine(statsMap.get("command_line")); + + return aflInfo; + } + + + + private static boolean thisDirectory(ChannelSftp channelSftp, String fullPath) { + try { + SftpATTRS attrs = channelSftp.lstat(fullPath); + return attrs.isDir(); + } catch (SftpException e) { + return false; + } + } + + + // 自定义异常类,用于封装上传过程中的错误 public static class SftpUploadException extends Exception { public SftpUploadException(String message) { super(message);