fix: parse MySQL JDBC URL credentials (#556)
This commit is contained in:
parent
7c0ed986c1
commit
8ef4794105
|
|
@ -79,6 +79,30 @@ function queryParamValue(params: string, key: string): string | undefined {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
function extractMysqlCredentialParams(params: string): { username?: string; password?: string; urlParams: string } {
|
||||
let username: string | undefined;
|
||||
let password: string | undefined;
|
||||
let foundCredentialParam = false;
|
||||
const urlParams: string[] = [];
|
||||
|
||||
for (const part of params.split(/[&;]/)) {
|
||||
if (!part) continue;
|
||||
const [rawKey, ...rest] = part.split("=");
|
||||
const key = decodeUrlPart(rawKey).trim().toLowerCase();
|
||||
if (key === "user") {
|
||||
username = decodeUrlPart(rest.join("=")).trim();
|
||||
foundCredentialParam = true;
|
||||
} else if (key === "password") {
|
||||
password = decodeUrlPart(rest.join("=")).trim();
|
||||
foundCredentialParam = true;
|
||||
} else {
|
||||
urlParams.push(part);
|
||||
}
|
||||
}
|
||||
|
||||
return { username, password, urlParams: foundCredentialParam ? urlParams.join("&") : params };
|
||||
}
|
||||
|
||||
function urlParamsRequireTls(dbType: DatabaseType, params: string): boolean {
|
||||
if (dbType === "mysql") {
|
||||
const requireSsl = queryParamValue(params, "require_ssl")?.toLowerCase();
|
||||
|
|
@ -243,7 +267,8 @@ export function parseConnectionUrl(value: string, preferredProfile?: string): Pa
|
|||
if (jdbcOracle) return jdbcOracle;
|
||||
const jdbcSqlServer = parseJdbcSqlServerUrl(input);
|
||||
if (jdbcSqlServer) return jdbcSqlServer;
|
||||
const source = input.replace(/^jdbc:/i, "");
|
||||
const isJdbcUrl = /^jdbc:/i.test(input);
|
||||
const source = isJdbcUrl ? input.replace(/^jdbc:/i, "") : input;
|
||||
|
||||
let parsed: URL;
|
||||
try {
|
||||
|
|
@ -264,6 +289,9 @@ export function parseConnectionUrl(value: string, preferredProfile?: string): Pa
|
|||
profile.type === "redis" && normalizedFragment === "insecure"
|
||||
? [urlParams, "insecure=true"].filter(Boolean).join("&")
|
||||
: urlParams;
|
||||
const mysqlCredentials =
|
||||
isJdbcUrl && profile.type === "mysql" ? extractMysqlCredentialParams(parsedUrlParams) : undefined;
|
||||
const effectiveUrlParams = mysqlCredentials?.urlParams ?? parsedUrlParams;
|
||||
if (profile.type === "mongodb") {
|
||||
return {
|
||||
dbType: profile.type,
|
||||
|
|
@ -287,11 +315,11 @@ export function parseConnectionUrl(value: string, preferredProfile?: string): Pa
|
|||
driverLabel: profile.label,
|
||||
host: parsed.hostname,
|
||||
port: parsed.port ? Number(parsed.port) : profile.defaultPort,
|
||||
username: decodeUrlPart(parsed.username),
|
||||
password: decodeUrlPart(parsed.password),
|
||||
username: mysqlCredentials?.username ?? decodeUrlPart(parsed.username),
|
||||
password: mysqlCredentials?.password ?? decodeUrlPart(parsed.password),
|
||||
database: databaseFromPath(parsed.pathname),
|
||||
urlParams: parsedUrlParams,
|
||||
ssl: scheme === "rediss" || scheme === "https" || urlParamsRequireTls(profile.type, parsedUrlParams),
|
||||
urlParams: effectiveUrlParams,
|
||||
ssl: scheme === "rediss" || scheme === "https" || urlParamsRequireTls(profile.type, effectiveUrlParams),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,28 @@ test("parses mysql TLS URL params into the SSL switch state", () => {
|
|||
assert.equal(parseConnectionUrl("mysql://root@tidb.example.com:4000/test?require_ssl=true").ssl, true);
|
||||
});
|
||||
|
||||
test("parses MySQL JDBC user and password URL params as credentials", () => {
|
||||
const parsed = parseConnectionUrl(
|
||||
"jdbc:mysql://127.0.0.1:1234/example?user=admin&password=pwd&useUnicode=true&characterEncoding=UTF8&useSSL=false",
|
||||
);
|
||||
|
||||
assert.equal(parsed.dbType, "mysql");
|
||||
assert.equal(parsed.host, "127.0.0.1");
|
||||
assert.equal(parsed.port, 1234);
|
||||
assert.equal(parsed.username, "admin");
|
||||
assert.equal(parsed.password, "pwd");
|
||||
assert.equal(parsed.database, "example");
|
||||
assert.equal(parsed.urlParams, "useUnicode=true&characterEncoding=UTF8&useSSL=false");
|
||||
});
|
||||
|
||||
test("leaves non-JDBC MySQL user and password URL params untouched", () => {
|
||||
const parsed = parseConnectionUrl("mysql://127.0.0.1:1234/example?user=admin&password=pwd&charset=utf8mb4");
|
||||
|
||||
assert.equal(parsed.username, "");
|
||||
assert.equal(parsed.password, "");
|
||||
assert.equal(parsed.urlParams, "user=admin&password=pwd&charset=utf8mb4");
|
||||
});
|
||||
|
||||
test("parses Redis insecure TLS URL fragments into URL params", () => {
|
||||
const parsed = parseConnectionUrl("rediss://default:secret@redis.example.com:6379/0#insecure");
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue