Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,5 @@ out/
# 临时环境变量文件
.env
*.sqlite
AGENTS.md
.vscode/launch.json
26 changes: 24 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>xin.ctkqiang</groupId>
<artifactId>exploitdb</artifactId>
<version>1.0-SNAPSHOT</version>
Expand Down Expand Up @@ -42,6 +41,14 @@
<mainClass>xin.ctkqiang.Main</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<configuration>
<mainClass>xin.ctkqiang.gui.App</mainClass>
</configuration>
</plugin>
</plugins>
</build>

Expand Down Expand Up @@ -102,6 +109,21 @@
<version>1.10.0</version>
</dependency>

<!-- JavaFX 核心 -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11.0.2</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>11.0.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.36</version>
</dependency>
</dependencies>

</project>
48 changes: 42 additions & 6 deletions src/main/java/xin/ctkqiang/config/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ public class Configuration {
private static String DatabaseMode = Database.MYSQL.getValue();

public static final String DB_NAME = "ExploitDB";
public static final String DB_URL = "jdbc:mysql://localhost:3306/" + DB_NAME

// MySQL 配置(可修改)
private static String DB_URL = "jdbc:mysql://localhost:3306/" + DB_NAME
+ "?serverTimezone=UTC&allowPublicKeyRetrieval=true&useSSL=false";
private static String DB_USER = "root";
private static String DB_PASSWORD = "";

// SQLite 配置(可修改)
private static String DB_SQLITE_URL = "jdbc:sqlite:ling.sqlite";

public static final String DB_SQLITE_URL = "jdbc:sqlite:ling.sqlite";

public static final String DB_USER = "root";
public static final String DB_PASSWORD = "";
public static final String DB_DRIVER = "com.mysql.cj.jdbc.Driver";

public static final boolean DEBUG = false;

public static String getDatabaseMode() {
Expand All @@ -25,4 +27,38 @@ public static void setDatabaseMode(Database databaseMode) {
DatabaseMode = databaseMode.getValue();
System.out.println(String.format("🎀 你当前选择的数据库模式是:「%s」~酱酱 ♪(๑˃ᴗ˂)ﻭ \n", getDatabaseMode()));
}

// Getters
public static String getDbUrl() {
return DB_URL;
}

public static String getDbUser() {
return DB_USER;
}

public static String getDbPassword() {
return DB_PASSWORD;
}

public static String getDbSqliteUrl() {
return DB_SQLITE_URL;
}

// Setters
public static void setDbUrl(String url) {
DB_URL = url;
}

public static void setDbUser(String user) {
DB_USER = user;
}

public static void setDbPassword(String password) {
DB_PASSWORD = password;
}

public static void setDbSqliteUrl(String url) {
DB_SQLITE_URL = url;
}
}
74 changes: 49 additions & 25 deletions src/main/java/xin/ctkqiang/controller/DatabaseController.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
Expand Down Expand Up @@ -35,21 +36,9 @@ public class DatabaseController {
/** 数据库名称 */
protected final static String DB_NAME = Configuration.DB_NAME;

/** MYSQL 数据库连接URL */
protected final static String DB_URL = Configuration.DB_URL;

/** 数据库用户名 */
protected final static String DB_USER = Configuration.DB_USER;

/** 数据库密码 */
protected final static String DB_PASSWORD = Configuration.DB_PASSWORD;

/** 数据库驱动类名 */
protected final static String DB_DRIVER = Configuration.DB_DRIVER;

/** SQLITE 数据库连接URL */
protected final static String DB_SQLITE_URL = Configuration.DB_SQLITE_URL;

/**
* 静态初始化块
* 在类加载时尝试加载数据库驱动
Expand All @@ -68,7 +57,7 @@ public class DatabaseController {
* @return 数据库连接对象
* @throws SQLException 如果连接数据库时发生错误
*/
protected Connection getConnection() throws SQLException {
public Connection getConnection() throws SQLException {
String mode = Configuration.getDatabaseMode();
String upperMode = mode.toUpperCase();
System.out.println("💡 切换数据库模式 -> " + upperMode);
Expand All @@ -82,21 +71,21 @@ protected Connection getConnection() throws SQLException {
System.err.println("❌ 哎呀呀!SQLite JDBC 驱动不见惹~人家找不到驱动怎么贴贴数据库嘛喵呜呜。゚(゚´ω`゚)゚。");
throw new SQLException("找不到 SQLite 驱动喵~要不要检查一下依赖有没有加对呀?");
}
return DriverManager.getConnection(DatabaseController.DB_SQLITE_URL);
return DriverManager.getConnection(Configuration.getDbSqliteUrl());

case "MYSQL":
default:
try {
Class.forName(DatabaseController.DB_DRIVER);
Class.forName(DB_DRIVER);
System.out.println("📦 MySQL 驱动加载完成!我打扮好了,要去连接数据库小哥哥啦~(๑•̀ㅂ•́)و✧");
} catch (ClassNotFoundException e) {
System.err.println("❌ 呜呜呜 MySQL JDBC 驱动不见了~是不是打包的时候忘记带灵儿一起走啦 >///< ");
throw new SQLException("MySQL 驱动加载失败了喵~快检查一下 `.jar` 有没有遗漏吧!");
}
return DriverManager.getConnection(
DatabaseController.DB_URL,
DatabaseController.DB_USER,
DatabaseController.DB_PASSWORD);
Configuration.getDbUrl(),
Configuration.getDbUser(),
Configuration.getDbPassword());
}
}

Expand Down Expand Up @@ -165,7 +154,7 @@ public void CreateTableIfNotExists() {
Class.forName("org.sqlite.JDBC");

// 构建连接(数据库文件叫 ling.sqlite)
try (Connection conn = DriverManager.getConnection(DatabaseController.DB_SQLITE_URL);
try (Connection conn = DriverManager.getConnection(Configuration.getDbSqliteUrl());
Statement stmt = conn.createStatement()) {
stmt.execute(query);
System.out.println("🎀 SQLite 模式下,表结构初始化好啦!已经准备好可爱的记录了喵~");
Expand All @@ -175,13 +164,13 @@ public void CreateTableIfNotExists() {
case MYSQL:
default:
// 确保数据库驱动已加载
Class.forName(DatabaseController.DB_DRIVER);
Class.forName(DB_DRIVER);

// 创建数据库连接并执行建表语句
try (Connection conn = DriverManager.getConnection(
DatabaseController.DB_URL,
DatabaseController.DB_USER,
DatabaseController.DB_PASSWORD);
Configuration.getDbUrl(),
Configuration.getDbUser(),
Configuration.getDbPassword());
Statement stmt = conn.createStatement()) {
stmt.execute(query);
System.out.println("💾 MySQL 模式下,数据表【内容信息】初始化成功~♡");
Expand Down Expand Up @@ -273,7 +262,7 @@ public List<Exploit> GetAllExploits() {
Class.forName(DB_DRIVER);

// 创建数据库连接并执行查询
try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
try (Connection conn = DriverManager.getConnection(Configuration.getDbUrl(), Configuration.getDbUser(), Configuration.getDbPassword());
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query)) {

Expand Down Expand Up @@ -434,7 +423,7 @@ public int ExportToSQL(List<Exploit> exploits) {
* @return 完整的文件路径
*/
private String FilePath(int size, String extension) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH:mm:ss");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss");
LocalDateTime now = LocalDateTime.now();

return "output/Exploits_" + size + "_" + formatter.format(now) + extension;
Expand Down Expand Up @@ -480,6 +469,41 @@ public int ExportToCSV(List<Exploit> exploits) {
return 0;
}

/**
* 数据库分页查询
*
* @param offset 起始位置
* @param limit 查询数量
* @return
*/
public List<Exploit> GetExploitsByPage(int offset, int limit) {
String query = "SELECT * FROM records ORDER BY created_at DESC LIMIT ? OFFSET ?";
List<Exploit> exploits = new ArrayList<>();

try (Connection conn = getConnection();
PreparedStatement stmt = conn.prepareStatement(query)) {
stmt.setInt(1, limit);
stmt.setInt(2, offset);

try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
Exploit e = new Exploit();
e.setId(rs.getString("id"));
e.setDescription(rs.getString("description"));
e.setDate(rs.getString("date"));
e.setAuthor(rs.getString("author"));
e.setType(rs.getString("type"));
e.setPlatform(rs.getString("platform"));
e.setCve(rs.getString("cve"));
exploits.add(e);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return exploits;
}

/**
* 转义SQL字符串中的特殊字符
* 主要处理单引号,防止SQL注入
Expand Down
57 changes: 48 additions & 9 deletions src/main/java/xin/ctkqiang/controller/ExploitDbController.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import org.apache.commons.text.StringEscapeUtils;

/**
Expand All @@ -39,6 +40,10 @@ public class ExploitDbController extends DatabaseController {
private static final List<String> BLOCK_KEYWORDS = Arrays.asList(
"firewall", "access denied", "blocked", "forbidden", "connection refused");

public interface CrawlCallback {
void onPageLoaded(List<Exploit> pageData, int currentCount, int totalCount, int PageNumber);
}

/**
* 获取数据库中所有的漏洞信息
*
Expand Down Expand Up @@ -85,6 +90,18 @@ private int create(String id, String description, String date, String author, St
* @param extension 导出文件的扩展名(支持:csv, json, sql)
*/
public void Crawl(int pageSize, boolean isExport, String extension) {
Crawl(pageSize, isExport, extension, null);
}

/**
* 爬取Exploit-DB网站的漏洞信息
*
* @param pageSize 每页获取的记录数量
* @param isExport 是否导出数据
* @param extension 导出文件的扩展名(支持:csv, json, sql)
* @param callback 爬取完成后的回调函数
*/
public void Crawl(int pageSize, boolean isExport, String extension, CrawlCallback callback) {
// 获取数据总条数
int total = 0;
try {
Expand All @@ -107,7 +124,8 @@ public void Crawl(int pageSize, boolean isExport, String extension) {
}
// 构建API请求URL,包含分页参数
int want = Math.min(pageSize, total);
// String url = String.format(ExploitDbController.URL + "search?draw=1&start=%d&length=%d", start, pageSize);
// String url = String.format(ExploitDbController.URL +
// "search?draw=1&start=%d&length=%d", start, pageSize);

// 初始化状态码和结果列表
int Status = 0;
Expand Down Expand Up @@ -136,7 +154,7 @@ public void Crawl(int pageSize, boolean isExport, String extension) {

// 调试模式下打印响应预览
if (debug) {
System.out.println("响应内容预览:" + Response.body().substring(0, 500));
System.out.println("响应内容预览:" + Response.body().substring(0, 500));
}

// 解析JSON响应
Expand All @@ -153,7 +171,6 @@ public void Crawl(int pageSize, boolean isExport, String extension) {
System.out.println("共找到 " + Data.size() + " 条记录。");
System.out.println("正在写入数据库...");


// 调试模式下打印完整数据
if (debug) {
System.out.println(Data);
Expand Down Expand Up @@ -225,13 +242,23 @@ public void Crawl(int pageSize, boolean isExport, String extension) {
}
}

// 添加到结果列表
exploits.add(exploit);
// 添加到结果列表
exploits.add(exploit);
}
int previousCount = 0;

if (callback != null) {
List<Exploit> currentPageData = new ArrayList<>(
exploits.subList(previousCount, exploits.size()));
callback.onPageLoaded(currentPageData, exploits.size(), want, pageSize);
previousCount = exploits.size(); // 更新计数
}

if (exploits.size() >= want)
break;
Thread.sleep(1000);
}
if (exploits.size() >= want) break;
Thread.sleep(1000);
}
} catch (IOException | InterruptedException e) {
} catch (IOException | InterruptedException e) {
String msg = e.getMessage();

if (msg != null && BLOCK_KEYWORDS.stream().anyMatch(k -> msg.toLowerCase().contains(k))) {
Expand Down Expand Up @@ -410,4 +437,16 @@ private void ExportStatus(int status, String ext) {
System.out.println(msg);
}

// public ObservableList<Exploit> loadPage(int offset, int pageSize) {
// String sql = "SELECT * FROM exploits LIMIT ? OFFSET ?";
// ObservableList<Exploit> list = FXCollections.observableArrayList();
// try (
// Connection conn = super.getConnection();
// PreparedStatement ps = conn.prepareStatement(sql)) {
// ps.setInt(1, pageSize);
// } catch (SQLException e) {

// }
// }

}
Loading