fix(mongodb): use tls param for form connections
This commit is contained in:
parent
f385386284
commit
7b2156446c
|
|
@ -2510,13 +2510,13 @@ function openExternalUrl(url: string) {
|
|||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label class="text-right">{{ t("connection.host") }}</Label>
|
||||
<Input v-model="form.host" class="col-span-2" />
|
||||
<Input v-model.number="form.port" type="number" class="col-span-1" :disabled="form.ssl" />
|
||||
<Input v-model.number="form.port" type="number" class="col-span-1" />
|
||||
</div>
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<span />
|
||||
<label class="col-span-3 flex items-center gap-2 text-sm">
|
||||
<input type="checkbox" v-model="form.ssl" class="mr-0" />
|
||||
<span>SRV (MongoDB Atlas)</span>
|
||||
<span>{{ t("connection.sslEnable") }}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
|
|
|
|||
|
|
@ -15,6 +15,14 @@ export function setMongoUrlParam(urlParams: string | undefined, key: string, val
|
|||
}
|
||||
|
||||
export function mongodbAuthFailureHint(message: string): string {
|
||||
if (message.includes("no records found") && message.includes("_mongodb._tcp.")) {
|
||||
return `${message}\n\nMongoDB SRV URLs require a DNS hostname with SRV records. For an IP address or normal host:port endpoint, use mongodb://host:port instead of mongodb+srv://host.`;
|
||||
}
|
||||
|
||||
if (message.includes("ReplicaSetNoPrimary") && message.includes("127.0.0.1:27017")) {
|
||||
return `${message}\n\nThe replica set is advertising 127.0.0.1:27017, which points back to this app machine instead of the MongoDB server. Add directConnection=true for a single reachable endpoint, or reconfigure the replica set members to advertise addresses reachable from this app.`;
|
||||
}
|
||||
|
||||
if (message.includes("must be URL encoded") || message.includes("cannot contain unescaped %")) {
|
||||
return `${message}\n\nMongoDB URL mode requires reserved characters in usernames and passwords to be percent-encoded. For example, @ becomes %40, # becomes %23, / becomes %2F, : becomes %3A, and % becomes %25.`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -695,10 +695,7 @@ impl ConnectionConfig {
|
|||
suffix.push_str("&directConnection=true");
|
||||
}
|
||||
}
|
||||
let scheme = if self.ssl { "mongodb+srv" } else { "mongodb" };
|
||||
// SRV URLs resolve the port via DNS SRV records, so we omit the explicit port.
|
||||
let addr = if self.ssl { host.to_string() } else { format!("{host}:{port}") };
|
||||
format!("{scheme}://{addr}{db_part}{suffix}")
|
||||
format!("mongodb://{host}:{port}{db_part}{suffix}")
|
||||
}
|
||||
DatabaseType::Oracle => format!("oracle://{host}:{port}{db_part}"),
|
||||
DatabaseType::Elasticsearch => {
|
||||
|
|
@ -823,13 +820,10 @@ impl ConnectionConfig {
|
|||
suffix.push_str("&directConnection=true");
|
||||
}
|
||||
}
|
||||
let scheme = if self.ssl { "mongodb+srv" } else { "mongodb" };
|
||||
// SRV URLs resolve the port via DNS SRV records, so we omit the explicit port.
|
||||
let addr = if self.ssl { host.to_string() } else { format!("{host}:{port}") };
|
||||
if self.username.is_empty() {
|
||||
format!("{scheme}://{addr}{db_part}{suffix}")
|
||||
format!("mongodb://{host}:{port}{db_part}{suffix}")
|
||||
} else {
|
||||
format!("{scheme}://{username}:{password}@{addr}{db_part}{suffix}")
|
||||
format!("mongodb://{username}:{password}@{host}:{port}{db_part}{suffix}")
|
||||
}
|
||||
}
|
||||
DatabaseType::Oracle => {
|
||||
|
|
@ -975,7 +969,7 @@ impl ConnectionConfig {
|
|||
normalize_bare_mysql_url_params(value)
|
||||
}
|
||||
DatabaseType::Postgres | DatabaseType::Redshift => normalize_postgres_url_params(value, self.ssl),
|
||||
DatabaseType::MongoDb => value.trim_start_matches('?').to_string(),
|
||||
DatabaseType::MongoDb => normalize_mongo_url_params(value, self.ssl),
|
||||
_ => value.trim_start_matches('?').to_string(),
|
||||
}
|
||||
}
|
||||
|
|
@ -1065,6 +1059,18 @@ fn normalize_mysql_url_params(value: &str, force_tls: bool, accept_invalid_certs
|
|||
parts.join("&")
|
||||
}
|
||||
|
||||
fn normalize_mongo_url_params(value: &str, force_tls: bool) -> String {
|
||||
let value = value.trim_start_matches('?');
|
||||
let mut parts: Vec<String> = value.split('&').filter(|part| !part.is_empty()).map(str::to_string).collect();
|
||||
|
||||
if force_tls {
|
||||
parts.retain(|part| !url_param_key_is(part, "tls") && !url_param_key_is(part, "ssl"));
|
||||
parts.insert(0, "tls=true".to_string());
|
||||
}
|
||||
|
||||
parts.join("&")
|
||||
}
|
||||
|
||||
fn normalize_postgres_url_params(value: &str, force_tls: bool) -> String {
|
||||
let value = value.trim_start_matches('?');
|
||||
|
||||
|
|
@ -2011,6 +2017,24 @@ mod tests {
|
|||
assert!(!url.contains("secret"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mongodb_form_tls_uses_standard_scheme_and_tls_param() {
|
||||
let mut config = mongodb_config("root", "secret", Some("admin"));
|
||||
config.ssl = true;
|
||||
|
||||
assert_eq!(config.connection_url(), "mongodb://root:secret@10.1.2.3:17000/admin?tls=true");
|
||||
assert_eq!(config.redacted_connection_url(), "mongodb://10.1.2.3:17000/admin?tls=true");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mongodb_form_tls_replaces_existing_tls_params() {
|
||||
let mut config = mongodb_config("root", "secret", Some("admin"));
|
||||
config.ssl = true;
|
||||
config.url_params = Some("authSource=admin&ssl=false&tls=false".to_string());
|
||||
|
||||
assert_eq!(config.connection_url(), "mongodb://root:secret@10.1.2.3:17000/admin?tls=true&authSource=admin");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_mongo_first_host_replica_set() {
|
||||
let uri = "mongodb://user:pass@host1:27017,host2:27017,host3:27017/admin?replicaSet=rs0";
|
||||
|
|
|
|||
|
|
@ -29,6 +29,18 @@ test("adds a MongoDB URL encoding hint for reserved password characters", () =>
|
|||
assert.match(mongodbAuthFailureHint(message), /@ becomes %40/);
|
||||
});
|
||||
|
||||
test("adds a MongoDB SRV DNS hint for IP endpoints", () => {
|
||||
const message = 'MongoDB connection failed: Kind: An error occurred during DNS resolution: DNS error: no records found for Query { name: Name("_mongodb._tcp.172.17.0.1."), query_type: SRV }';
|
||||
|
||||
assert.match(mongodbAuthFailureHint(message), /use mongodb:\/\/host:port instead of mongodb\+srv:\/\/host/);
|
||||
});
|
||||
|
||||
test("adds a MongoDB replica set localhost advertisement hint", () => {
|
||||
const message = "MongoDB connection failed: Kind: Server selection timeout: No available servers. Topology: { Type: ReplicaSetNoPrimary, Set Name: LIMLIU, Servers: [ { Address: 127.0.0.1:27017, Type: Unknown, Error: Kind: I/O error: Connection refused (os error 111) } ] }";
|
||||
|
||||
assert.match(mongodbAuthFailureHint(message), /Add directConnection=true/);
|
||||
});
|
||||
|
||||
test("adds a MongoDB listDatabases permission hint", () => {
|
||||
const message = "Command failed with error 13 (Unauthorized): not authorized on admin to execute command { listDatabases: 1 }";
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue