Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions electron/src/apps/local-app-launcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ function dbxUrl(payload) {
return `dbx://connection/new?${query.toString().replaceAll("*", "%2A")}`;
}

function mongodbUri(payload) {
const user = encodeURIComponent(username(payload));
const password = encodeURIComponent(String(payload.token?.value || ""));
const database = encodeURIComponent(String(payload.asset?.info?.db_name || ""));
const host = String(payload.endpoint?.host || "");
const port = String(payload.endpoint?.port || "");
return `mongodb://${user}:${password}@${host}:${port}/${database}?authSource=admin&loadBalanced=true&retryWrites=false`;
}

function valuesFor(payload): Record<string, string> {
const dmConnection = `${username(payload)}/${String(payload.token?.value || "")}@${String(payload.endpoint?.host || "")}:${String(payload.endpoint?.port || "")}`;
return {
Expand All @@ -57,6 +66,7 @@ function valuesFor(payload): Record<string, string> {
port: String(payload.endpoint?.port || ""),
dbname: payload.protocol === "oracle" ? username(payload) : String(payload.asset?.info?.db_name || ""),
dameng_disql: shellQuote(dmConnection),
mongodb_shell_uri: payload.protocol === "mongodb" ? shellQuote(mongodbUri(payload)) : "",
dbeaver_protocol: payload.protocol === "sqlserver" ? "mssql_jdbc_ms_new" : payload.protocol,
dbx_url: dbxUrl(payload),
url: navicatUrl(payload)
Expand Down
53 changes: 53 additions & 0 deletions electron/tests/application-config.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import assert from "node:assert/strict";
import { spawnSync } from "node:child_process";
import { once } from "node:events";
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import { createServer } from "node:net";
Expand Down Expand Up @@ -492,6 +493,58 @@ test("launches RDP connection files without endpoint fields", async () => {
assert.deepEqual(launchedPayload, payload);
});

for (const platform of ["macos", "linux"]) {
test(`${platform}/terminal-db quotes and encodes MongoDB connection values`, async (context) => {
if (process.platform === "win32") return context.skip("POSIX shell test");
const config = JSON.parse(
await readFile(path.join(projectRoot, "plugins", platform, `${platform}.terminal-db`, "connect.json"), "utf8")
);
const application = {
name: "terminal-db",
protocol: ["mongodb"],
is_set: true,
match_first: ["mongodb"],
launch_type: config.launch.type,
launch_driver: config.launch.driver,
arg_format: config.launch.template,
protocol_templates: config.launch.protocol_templates
};
const launcher = new LocalApplicationLauncher(
{ isPackaged: false },
projectRoot,
{ getConfig: async () => ({ databases: [application] }) },
null
);
const user = "token:id@/";
const password = ["space value", "$HOME", "`printf injected`", "'", '"', ";", "&", "/", "\\", "?", "#"].join("");
const database = "data /?#";
const expectedUri = `mongodb://${encodeURIComponent(user)}:${encodeURIComponent(password)}@gateway.example.com:5525/${encodeURIComponent(database)}?authSource=admin&loadBalanced=true&retryWrites=false`;
let launched = false;
launcher.launchTerminal = async (_selected, command) => {
const result = spawnSync("bash", ["-lc", `mongosh() { printf '%s\\n' "$@"; }\n${command}`], {
encoding: "utf8"
});
assert.equal(result.status, 0, result.stderr);
assert.equal(result.stdout, `${expectedUri}\n`);
const parsed = new URL(expectedUri);
assert.equal(decodeURIComponent(parsed.username), user);
assert.equal(decodeURIComponent(parsed.password), password);
assert.equal(decodeURIComponent(parsed.pathname.slice(1)), database);
assert.equal(parsed.searchParams.get("authSource"), "admin");
launched = true;
};
const payload = {
protocol: "mongodb",
name: "MongoDB",
endpoint: { host: "gateway.example.com", port: 5525 },
token: { id: user, value: password },
asset: { info: { db_name: database } }
};
await launcher.launch(`jms2://${Buffer.from(JSON.stringify(payload)).toString("base64")}`);
assert.equal(launched, true);
});
}

for (const [platform, plugin, expected] of [
["macos", "dbeaver", "driver=mysql"],
["linux", "dbeaver", "driver=mysql"],
Expand Down
2 changes: 1 addition & 1 deletion plugins/linux/linux.terminal-db/connect.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"mysql": "mysql -u {username} -p{value} -h {host} -P {port} {dbname}",
"mariadb": "mysql -u {username} -p{value} -h {host} -P {port} {dbname}",
"sqlserver": "sqlcmd -S {host},{port} -U {username} -P {value} -d {dbname}",
"mongodb": "mongosh mongodb://{username}:{value}@{host}:{port}/{dbname}"
"mongodb": "mongosh {mongodb_shell_uri}"
}
},
"display_name": "Terminal"
Expand Down
2 changes: 1 addition & 1 deletion plugins/macos/macos.terminal-db/connect.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"mysql": "mysql -u {username} -p{value} -h {host} -P {port} {dbname}",
"mariadb": "mysql -u {username} -p{value} -h {host} -P {port} {dbname}",
"sqlserver": "sqlcmd -S {host},{port} -U {username} -P {value} -d {dbname}",
"mongodb": "mongosh mongodb://{username}:{value}@{host}:{port}/{dbname}"
"mongodb": "mongosh {mongodb_shell_uri}"
}
},
"display_name": "Terminal"
Expand Down
Loading