Skip to content

Commit 4a49f88

Browse files
authored
Merge pull request #1749 from jumpserver/pr@dev@fix_mongodb_field
fix: quote MongoDB terminal connection URI
2 parents 00339ed + f15aac5 commit 4a49f88

4 files changed

Lines changed: 65 additions & 2 deletions

File tree

‎electron/src/apps/local-app-launcher.ts‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,15 @@ function dbxUrl(payload) {
4646
return `dbx://connection/new?${query.toString().replaceAll("*", "%2A")}`;
4747
}
4848

49+
function mongodbUri(payload) {
50+
const user = encodeURIComponent(username(payload));
51+
const password = encodeURIComponent(String(payload.token?.value || ""));
52+
const database = encodeURIComponent(String(payload.asset?.info?.db_name || ""));
53+
const host = String(payload.endpoint?.host || "");
54+
const port = String(payload.endpoint?.port || "");
55+
return `mongodb://${user}:${password}@${host}:${port}/${database}?authSource=admin&loadBalanced=true&retryWrites=false`;
56+
}
57+
4958
function valuesFor(payload): Record<string, string> {
5059
const dmConnection = `${username(payload)}/${String(payload.token?.value || "")}@${String(payload.endpoint?.host || "")}:${String(payload.endpoint?.port || "")}`;
5160
return {
@@ -57,6 +66,7 @@ function valuesFor(payload): Record<string, string> {
5766
port: String(payload.endpoint?.port || ""),
5867
dbname: payload.protocol === "oracle" ? username(payload) : String(payload.asset?.info?.db_name || ""),
5968
dameng_disql: shellQuote(dmConnection),
69+
mongodb_shell_uri: payload.protocol === "mongodb" ? shellQuote(mongodbUri(payload)) : "",
6070
dbeaver_protocol: payload.protocol === "sqlserver" ? "mssql_jdbc_ms_new" : payload.protocol,
6171
dbx_url: dbxUrl(payload),
6272
url: navicatUrl(payload)

‎electron/tests/application-config.test.ts‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import assert from "node:assert/strict";
2+
import { spawnSync } from "node:child_process";
23
import { once } from "node:events";
34
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
45
import { createServer } from "node:net";
@@ -492,6 +493,58 @@ test("launches RDP connection files without endpoint fields", async () => {
492493
assert.deepEqual(launchedPayload, payload);
493494
});
494495

496+
for (const platform of ["macos", "linux"]) {
497+
test(`${platform}/terminal-db quotes and encodes MongoDB connection values`, async (context) => {
498+
if (process.platform === "win32") return context.skip("POSIX shell test");
499+
const config = JSON.parse(
500+
await readFile(path.join(projectRoot, "plugins", platform, `${platform}.terminal-db`, "connect.json"), "utf8")
501+
);
502+
const application = {
503+
name: "terminal-db",
504+
protocol: ["mongodb"],
505+
is_set: true,
506+
match_first: ["mongodb"],
507+
launch_type: config.launch.type,
508+
launch_driver: config.launch.driver,
509+
arg_format: config.launch.template,
510+
protocol_templates: config.launch.protocol_templates
511+
};
512+
const launcher = new LocalApplicationLauncher(
513+
{ isPackaged: false },
514+
projectRoot,
515+
{ getConfig: async () => ({ databases: [application] }) },
516+
null
517+
);
518+
const user = "token:id@/";
519+
const password = ["space value", "$HOME", "`printf injected`", "'", '"', ";", "&", "/", "\\", "?", "#"].join("");
520+
const database = "data /?#";
521+
const expectedUri = `mongodb://${encodeURIComponent(user)}:${encodeURIComponent(password)}@gateway.example.com:5525/${encodeURIComponent(database)}?authSource=admin&loadBalanced=true&retryWrites=false`;
522+
let launched = false;
523+
launcher.launchTerminal = async (_selected, command) => {
524+
const result = spawnSync("bash", ["-lc", `mongosh() { printf '%s\\n' "$@"; }\n${command}`], {
525+
encoding: "utf8"
526+
});
527+
assert.equal(result.status, 0, result.stderr);
528+
assert.equal(result.stdout, `${expectedUri}\n`);
529+
const parsed = new URL(expectedUri);
530+
assert.equal(decodeURIComponent(parsed.username), user);
531+
assert.equal(decodeURIComponent(parsed.password), password);
532+
assert.equal(decodeURIComponent(parsed.pathname.slice(1)), database);
533+
assert.equal(parsed.searchParams.get("authSource"), "admin");
534+
launched = true;
535+
};
536+
const payload = {
537+
protocol: "mongodb",
538+
name: "MongoDB",
539+
endpoint: { host: "gateway.example.com", port: 5525 },
540+
token: { id: user, value: password },
541+
asset: { info: { db_name: database } }
542+
};
543+
await launcher.launch(`jms2://${Buffer.from(JSON.stringify(payload)).toString("base64")}`);
544+
assert.equal(launched, true);
545+
});
546+
}
547+
495548
for (const [platform, plugin, expected] of [
496549
["macos", "dbeaver", "driver=mysql"],
497550
["linux", "dbeaver", "driver=mysql"],

‎plugins/linux/linux.terminal-db/connect.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"mysql": "mysql -u {username} -p{value} -h {host} -P {port} {dbname}",
2121
"mariadb": "mysql -u {username} -p{value} -h {host} -P {port} {dbname}",
2222
"sqlserver": "sqlcmd -S {host},{port} -U {username} -P {value} -d {dbname}",
23-
"mongodb": "mongosh mongodb://{username}:{value}@{host}:{port}/{dbname}"
23+
"mongodb": "mongosh {mongodb_shell_uri}"
2424
}
2525
},
2626
"display_name": "Terminal"

‎plugins/macos/macos.terminal-db/connect.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"mysql": "mysql -u {username} -p{value} -h {host} -P {port} {dbname}",
2222
"mariadb": "mysql -u {username} -p{value} -h {host} -P {port} {dbname}",
2323
"sqlserver": "sqlcmd -S {host},{port} -U {username} -P {value} -d {dbname}",
24-
"mongodb": "mongosh mongodb://{username}:{value}@{host}:{port}/{dbname}"
24+
"mongodb": "mongosh {mongodb_shell_uri}"
2525
}
2626
},
2727
"display_name": "Terminal"

0 commit comments

Comments
 (0)