mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-21 05:10:26 +00:00
fix(jdbc): support encrypted sqlite with managed runtime
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
set -eu
|
||||
DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
|
||||
|
||||
if [ -n "${JAVA_HOME:-}" ] && [ -x "$JAVA_HOME/bin/java" ]; then
|
||||
if [ -n "${DBX_JAVA_BIN:-}" ] && [ -x "$DBX_JAVA_BIN" ]; then
|
||||
JAVA_BIN="$DBX_JAVA_BIN"
|
||||
elif [ -n "${JAVA_HOME:-}" ] && [ -x "$JAVA_HOME/bin/java" ]; then
|
||||
JAVA_BIN="$JAVA_HOME/bin/java"
|
||||
elif [ -x "/opt/homebrew/opt/openjdk/bin/java" ]; then
|
||||
JAVA_BIN="/opt/homebrew/opt/openjdk/bin/java"
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
@echo off
|
||||
setlocal
|
||||
|
||||
if defined DBX_JAVA_BIN (
|
||||
if exist "%DBX_JAVA_BIN%" (
|
||||
set "JAVA_BIN=%DBX_JAVA_BIN%"
|
||||
goto :run
|
||||
)
|
||||
)
|
||||
|
||||
if defined JAVA_HOME (
|
||||
if exist "%JAVA_HOME%\bin\java.exe" (
|
||||
set "JAVA_BIN=%JAVA_HOME%\bin\java.exe"
|
||||
|
||||
@@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URLEncoder;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
@@ -180,7 +181,7 @@ public final class DbxJdbcPlugin {
|
||||
}
|
||||
|
||||
private static Connection openConnection(JsonNode connection) throws SQLException {
|
||||
String url = optionalText(connection, "connection_string");
|
||||
String url = jdbcUrlWithPasswordKey(optionalText(connection, "connection_string"), optionalText(connection, "password"));
|
||||
if (url == null) {
|
||||
throw new IllegalArgumentException("JDBC URL is required.");
|
||||
}
|
||||
@@ -547,6 +548,46 @@ public final class DbxJdbcPlugin {
|
||||
return url != null && url.regionMatches(true, 0, "jdbc:oracle:", 0, 12);
|
||||
}
|
||||
|
||||
static String jdbcUrlWithPasswordKey(String url, String password) {
|
||||
if (url == null || password == null || password.isBlank() || !isSqliteUrl(url)) {
|
||||
return url;
|
||||
}
|
||||
if (!urlHasQueryParam(url, "cipher") || urlHasQueryParam(url, "key")) {
|
||||
return url;
|
||||
}
|
||||
return appendJdbcUrlParam(url, "key", password);
|
||||
}
|
||||
|
||||
private static boolean isSqliteUrl(String url) {
|
||||
return url.regionMatches(true, 0, "jdbc:sqlite:", 0, 12);
|
||||
}
|
||||
|
||||
private static boolean urlHasQueryParam(String url, String key) {
|
||||
int queryStart = url.indexOf('?');
|
||||
if (queryStart < 0) {
|
||||
return false;
|
||||
}
|
||||
int fragmentStart = url.indexOf('#', queryStart + 1);
|
||||
String query = fragmentStart < 0 ? url.substring(queryStart + 1) : url.substring(queryStart + 1, fragmentStart);
|
||||
for (String part : query.split("[&;]")) {
|
||||
int equals = part.indexOf('=');
|
||||
String name = equals < 0 ? part : part.substring(0, equals);
|
||||
if (name.equalsIgnoreCase(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String appendJdbcUrlParam(String url, String key, String value) {
|
||||
int fragmentStart = url.indexOf('#');
|
||||
String base = fragmentStart < 0 ? url : url.substring(0, fragmentStart);
|
||||
String fragment = fragmentStart < 0 ? "" : url.substring(fragmentStart);
|
||||
String separator = base.contains("?") ? (base.endsWith("?") || base.endsWith("&") ? "" : "&") : "?";
|
||||
String encodedValue = URLEncoder.encode(value, StandardCharsets.UTF_8);
|
||||
return base + separator + key + "=" + encodedValue + fragment;
|
||||
}
|
||||
|
||||
private static String oracleEffectiveSchema(Connection conn, String schema) throws SQLException {
|
||||
if (schema != null && !schema.isBlank()) {
|
||||
return schema.toUpperCase();
|
||||
|
||||
@@ -92,6 +92,36 @@ final class DbxJdbcPluginTest {
|
||||
assertEquals(false, DbxJdbcPlugin.driverQuirks(h2).useOracleMetadata());
|
||||
}
|
||||
|
||||
@Test
|
||||
void sqliteCipherUrlUsesPasswordAsKeyWhenKeyIsMissing() {
|
||||
String url = DbxJdbcPlugin.jdbcUrlWithPasswordKey(
|
||||
"jdbc:sqlite:/tmp/library.db?cipher=chacha20",
|
||||
"my password"
|
||||
);
|
||||
|
||||
assertEquals("jdbc:sqlite:/tmp/library.db?cipher=chacha20&key=my+password", url);
|
||||
}
|
||||
|
||||
@Test
|
||||
void sqliteCipherUrlKeepsExplicitKey() {
|
||||
String url = DbxJdbcPlugin.jdbcUrlWithPasswordKey(
|
||||
"jdbc:sqlite:/tmp/library.db?cipher=chacha20&key=from-url",
|
||||
"from-password"
|
||||
);
|
||||
|
||||
assertEquals("jdbc:sqlite:/tmp/library.db?cipher=chacha20&key=from-url", url);
|
||||
}
|
||||
|
||||
@Test
|
||||
void nonSqliteUrlDoesNotUsePasswordAsKey() {
|
||||
String url = DbxJdbcPlugin.jdbcUrlWithPasswordKey(
|
||||
"jdbc:h2:mem:dbx_cipher?cipher=sqlcipher",
|
||||
"secret"
|
||||
);
|
||||
|
||||
assertEquals("jdbc:h2:mem:dbx_cipher?cipher=sqlcipher", url);
|
||||
}
|
||||
|
||||
@Test
|
||||
void listTablesFallsBackWhenCatalogFiltersEverything() throws Exception {
|
||||
request("executeQuery", """
|
||||
|
||||
Reference in New Issue
Block a user