revert(sqlite): remove RC4 Legacy database support

This commit is contained in:
github-actions[bot] committed 2026-08-26 02:46:04 +08:00
1 parent d362c8efb8
commit 706334434a
19 files changed
+49 -187

No files matched your search

+1 -1
View File
@@ -1661,7 +1661,7 @@ async function openDbFilePath(path: string) {
password: "",
};
await connectionStore.addConnection(config);
await connectionStore.connect(config);
void connectionStore.connect(config);
toast(t("welcome.fileOpened", { name }));
} catch (e: any) {
toast(t("toolbar.sqlOpenFailed", { message: e?.message || String(e) }), 5000);
+2 -2
View File
@@ -109,10 +109,10 @@ export function useFileDrop() {
};
try {
await connectionStore.addConnection(config);
await connectionStore.connect(config);
void connectionStore.connect(config);
toast(t("welcome.fileOpened", { name }));
} catch (e: any) {
toast(t("welcome.fileOpenFailed", { name, message: e?.message || String(e) }), 5000);
toast(t("connection.saveFailed", { message: e?.message || String(e) }), 5000);
}
}
});
+1 -1
View File
@@ -436,7 +436,7 @@ export default {
createDuckDbFile: "Create DuckDB file",
createSqliteFile: "Create SQLite database",
memoryDatabasePathHint: "Use :memory: to create an in-memory SQLite or DuckDB database.",
sqliteCipherKey: "SQLite Encryption Key",
sqliteCipherKey: "SQLCipher Key",
sqliteCipherKeyPlaceholder: "Leave empty for unencrypted SQLite",
sqliteExtensions: "SQLite Extensions",
sqliteExtensionsPlaceholder: "/path/to/regexp.dylib\n/path/to/text.dylib|sqlite3_text_init",
+1 -1
View File
@@ -438,7 +438,7 @@ export default withEnglishFallback({
createDuckDbFile: "Crear archivo DuckDB",
createSqliteFile: "Crear base de datos SQLite",
memoryDatabasePathHint: "Usa :memory: para crear una base de datos SQLite o DuckDB en memoria.",
sqliteCipherKey: "Clave de cifrado de SQLite",
sqliteCipherKey: "Clave SQLCipher",
sqliteCipherKeyPlaceholder: "Déjalo vacío para SQLite sin cifrar",
sqliteExtensions: "Extensiones de SQLite",
sqliteExtensionsPlaceholder: "/ruta/a/regexp.dylib\n/ruta/a/text.dylib|sqlite3_text_init",
+1 -1
View File
@@ -437,7 +437,7 @@ export default withEnglishFallback({
createDuckDbFile: "Crea file DuckDB",
createSqliteFile: "Crea database SQLite",
memoryDatabasePathHint: "Usa :memory: per creare un database SQLite o DuckDB in memoria.",
sqliteCipherKey: "Chiave di crittografia SQLite",
sqliteCipherKey: "Chiave SQLCipher",
sqliteCipherKeyPlaceholder: "Lascia vuoto per SQLite non cifrato",
sqliteExtensions: "Estensioni SQLite",
sqliteExtensionsPlaceholder: "/percorso/per/regexp.dylib\n/percorso/per/text.dylib|sqlite3_text_init",
+1 -1
View File
@@ -437,7 +437,7 @@ export default withEnglishFallback({
createDuckDbFile: "DuckDBファイルを作成",
createSqliteFile: "SQLiteデータベースを作成",
memoryDatabasePathHint: "インメモリのSQLiteまたはDuckDBデータベースを作成するには :memory: を使用してください。",
sqliteCipherKey: "SQLite暗号化キー",
sqliteCipherKey: "SQLCipherキー",
sqliteCipherKeyPlaceholder: "暗号化されていないSQLiteでは空のままにします",
sqliteExtensions: "SQLite拡張",
sqliteExtensionsPlaceholder: "/path/to/regexp.dylib\n/path/to/text.dylib|sqlite3_text_init",
+1 -1
View File
@@ -430,7 +430,7 @@ export default withEnglishFallback({
createDuckDbFile: "DuckDB 파일 만들기",
createSqliteFile: "SQLite 데이터베이스 만들기",
memoryDatabasePathHint: "인메모리 SQLite 또는 DuckDB 데이터베이스를 만들려면 :memory:를 사용하세요.",
sqliteCipherKey: "SQLite 암호화 키",
sqliteCipherKey: "SQLCipher 키",
sqliteCipherKeyPlaceholder: "암호화하지 않은 SQLite는 비워 두세요",
sqliteExtensions: "SQLite 확장",
sqliteExtensionsPlaceholder: "/path/to/regexp.dylib\n/path/to/text.dylib|sqlite3_text_init",
+1 -1
View File
@@ -438,7 +438,7 @@ export default withEnglishFallback({
createDuckDbFile: "Criar arquivo DuckDB",
createSqliteFile: "Criar banco de dados SQLite",
memoryDatabasePathHint: "Use :memory: para criar um banco de dados SQLite ou DuckDB na memória.",
sqliteCipherKey: "Chave de criptografia do SQLite",
sqliteCipherKey: "Chave SQLCipher",
sqliteCipherKeyPlaceholder: "Deixe vazio para SQLite não criptografado",
sqliteExtensions: "Extensões SQLite",
sqliteExtensionsPlaceholder: "/caminho/para/regexp.dylib\n/caminho/para/text.dylib|sqlite3_text_init",
+1 -1
View File
@@ -361,7 +361,7 @@ export default withEnglishFallback({
createDuckDbFile: "新建 DuckDB 文件",
createSqliteFile: "新建 SQLite 数据库",
memoryDatabasePathHint: "输入 :memory: 可创建 SQLite 或 DuckDB 内存数据库。",
sqliteCipherKey: "SQLite 加密密码",
sqliteCipherKey: "SQLCipher 密码(密钥)",
sqliteCipherKeyPlaceholder: "未加密 SQLite 留空",
sqliteExtensions: "SQLite 扩展库",
sqliteExtensionsPlaceholder: "/path/to/regexp.dylib\n/path/to/text.dylib|sqlite3_text_init",
+1 -1
View File
@@ -438,7 +438,7 @@ export default withEnglishFallback({
createDuckDbFile: "建立 DuckDB 檔案",
createSqliteFile: "建立 SQLite 資料庫",
memoryDatabasePathHint: "輸入 :memory: 可建立 SQLite 或 DuckDB 記憶體資料庫。",
sqliteCipherKey: "SQLite 加密密碼",
sqliteCipherKey: "SQLCipher 密碼(密鑰)",
sqliteCipherKeyPlaceholder: "未加密 SQLite 留空",
sqliteExtensions: "SQLite 擴充庫",
sqliteExtensionsPlaceholder: "/path/to/regexp.dylib\n/path/to/text.dylib|sqlite3_text_init",
@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { appendConnectionErrorHints, isSqliteMissingEncryptionPasswordFailure } from "@/lib/connection/connectionErrorHints";
import { appendConnectionErrorHints } from "@/lib/connection/connectionErrorHints";
import type { ConnectionConfig } from "@/types/database";
function mysqlConfig(urlParams: string | undefined): ConnectionConfig {
@@ -40,14 +40,6 @@ const t = (key: string) => {
};
describe("appendConnectionErrorHints", () => {
it("recognizes an encrypted SQLite file that was first opened without a password", () => {
const config = { ...mysqlConfig(undefined), db_type: "sqlite" as const, host: "/tmp/encrypted.db", port: 0 };
expect(isSqliteMissingEncryptionPasswordFailure(config, "Selected file is not a valid SQLite database file.")).toBe(true);
expect(isSqliteMissingEncryptionPasswordFailure({ ...config, password: "wrong" }, "Selected file is not a valid SQLite database file.")).toBe(false);
expect(isSqliteMissingEncryptionPasswordFailure(config, "SQLite connection failed: unable to open database file")).toBe(false);
});
it("adds a MySQL TLS hint for non-disabled TLS failures", () => {
const message = appendConnectionErrorHints(mysqlConfig("ssl-mode=preferred"), "MySQL connection failed: TLS handshake failed", t);
@@ -72,11 +72,6 @@ export function isMysqlMissingPasswordFailure(config: ConnectionConfig, message:
return /access denied for user[\s\S]*using password:\s*no/i.test(message);
}
export function isSqliteMissingEncryptionPasswordFailure(config: ConnectionConfig, message: string): boolean {
if (config.db_type !== "sqlite" || config.password) return false;
return /Selected file is not a valid SQLite database file/i.test(message);
}
export function isJdbcMissingRuntimeDependencyError(message: string): boolean {
return /Missing Java class|NoClassDefFoundError|ClassNotFoundException/i.test(message);
}
@@ -297,35 +297,6 @@ describe("connectionStore save_password opt-out", () => {
expect(store.getConfig("mysql-1")?.password).toBe("typed-pw");
});
it("prompts and retries when an encrypted SQLite file is opened without a password", async () => {
const connectDb = vi.fn().mockRejectedValueOnce(new Error("Selected file is not a valid SQLite database file.")).mockResolvedValueOnce("sqlite-1");
installApiMocks({ connectDb });
installPasswordPromptMock();
requestPassword.mockResolvedValue({ password: "123456", rememberPassword: true });
const { useConnectionStore } = await import("@/stores/connectionStore");
const store = useConnectionStore();
const connection = postgresConnection({
id: "sqlite-1",
name: "Encrypted SQLite",
db_type: "sqlite",
host: "/tmp/encrypted.db",
port: 0,
username: "",
database: undefined,
save_password: true,
password: "",
});
store.connections = [connection];
await store.connect(connection);
expect(requestPassword).toHaveBeenCalledWith({ connectionId: "sqlite-1", connectionName: "Encrypted SQLite" });
expect(connectDb).toHaveBeenCalledTimes(2);
expect(connectDb).toHaveBeenNthCalledWith(1, expect.objectContaining({ password: "" }), expect.any(Number));
expect(connectDb).toHaveBeenNthCalledWith(2, expect.objectContaining({ password: "123456" }), expect.any(Number));
expect(store.getConfig("sqlite-1")?.password).toBe("123456");
});
it("does not persist a recovered password after the connection config changes", async () => {
const connected = deferred<string>();
const connectDb = vi
+5 -6
View File
@@ -141,7 +141,7 @@ import { REDIS_SCAN_PAGE_SIZE_DEFAULT } from "@/lib/redis/redisKeyPattern";
import { normalizeRedisDatabaseAliases, redisDatabaseAlias, redisDatabaseLabel } from "@/lib/redis/redisDatabaseAlias";
import { normalizeRedisKeyTemplates } from "@/lib/redis/redisKeyTemplates";
import { appendAgentDriverUpdateHint, hasAgentDriverUpdate, hasInstalledAgentVersion, type AgentDriverInstallState } from "@/lib/connection/agentDriverInstallHint";
import { appendConnectionErrorHints, isMysqlMissingPasswordFailure, isSqliteMissingEncryptionPasswordFailure } from "@/lib/connection/connectionErrorHints";
import { appendConnectionErrorHints, isMysqlMissingPasswordFailure } from "@/lib/connection/connectionErrorHints";
import { connectionNeedsPasswordPrompt } from "@/lib/connection/connectionPassword";
import { appendVisibleDatabaseSelection } from "@/lib/connection/connectionVisibleDatabases";
import { buildXuguTypeMemberNodes, isXuguTypeMemberContainer } from "@/lib/sidebar/xuguTypeMembers";
@@ -3630,13 +3630,12 @@ export const useConnectionStore = defineStore("connection", () => {
rebuildTreeNodes();
}
async function connectDbWithPasswordRetry(config: ConnectionConfig, localAttempt: number): Promise<{ config: ConnectionConfig; id: string; rememberPassword: boolean }> {
async function connectDbWithMissingPasswordRetry(config: ConnectionConfig, localAttempt: number): Promise<{ config: ConnectionConfig; id: string; rememberPassword: boolean }> {
try {
const id = await withConnectionAttemptTimeout(api.connectDb(config, localAttempt), config);
return { config, id, rememberPassword: false };
} catch (error) {
const message = connectionErrorMessage(error);
if (!isMysqlMissingPasswordFailure(config, message) && !isSqliteMissingEncryptionPasswordFailure(config, message)) throw error;
if (!isMysqlMissingPasswordFailure(config, connectionErrorMessage(error))) throw error;
const prompted = await ensureConnectionPassword(config, true);
config = prompted.config;
ensureLocalConnectionAttemptActive(config.id, localAttempt);
@@ -3662,7 +3661,7 @@ export const useConnectionStore = defineStore("connection", () => {
await ensureSqlServerLegacyCompatibilityComponentInstalled(config);
}
ensureLocalConnectionAttemptActive(config.id, localAttempt);
const connection = await connectDbWithPasswordRetry(config, localAttempt);
const connection = await connectDbWithMissingPasswordRetry(config, localAttempt);
config = connection.config;
rememberPassword ||= connection.rememberPassword;
const id = connection.id;
@@ -3905,7 +3904,7 @@ export const useConnectionStore = defineStore("connection", () => {
await ensureSqlServerLegacyCompatibilityComponentInstalled(config);
}
ensureLocalConnectionAttemptActive(connectionId, localAttempt);
const connection = await connectDbWithPasswordRetry(config, localAttempt);
const connection = await connectDbWithMissingPasswordRetry(config, localAttempt);
config = connection.config;
rememberPassword ||= connection.rememberPassword;
const id = connection.id;