mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-11-01 08:05:23 +00:00
fix(hosts): display protocol credential usernames for non-SSH hosts (#1572)
This commit is contained in:
1 parent
bb4b345feb
commit
42c5682243
4 files changed
+88
-4
No files matched your search
@@ -434,12 +434,25 @@ export async function loadProtocolAuthSummaries(
|
|||||||
const rows =
|
const rows =
|
||||||
await createCurrentHostProtocolAuthRepository().listRowsForHosts(ids);
|
await createCurrentHostProtocolAuthRepository().listRowsForHosts(ids);
|
||||||
const keys = new Map<string, Buffer | null>();
|
const keys = new Map<string, Buffer | null>();
|
||||||
|
const usernames = new Map<string, string | null>();
|
||||||
for (const row of rows) {
|
for (const row of rows) {
|
||||||
if (!keys.has(row.userId)) {
|
if (!keys.has(row.userId)) {
|
||||||
keys.set(row.userId, DataCrypto.getUserDataKey(row.userId));
|
keys.set(row.userId, DataCrypto.getUserDataKey(row.userId));
|
||||||
}
|
}
|
||||||
const own = result.get(row.hostId) ?? {};
|
const own = result.get(row.hostId) ?? {};
|
||||||
own[row.protocol] = summarize(row, keys.get(row.userId) ?? null);
|
const summary = summarize(row, keys.get(row.userId) ?? null);
|
||||||
|
if (row.authType === "credential" && row.credentialId) {
|
||||||
|
const key = `${row.userId}:${row.credentialId}`;
|
||||||
|
if (!usernames.has(key)) {
|
||||||
|
const credential = await findUsableCredential(
|
||||||
|
row.credentialId,
|
||||||
|
row.userId,
|
||||||
|
);
|
||||||
|
usernames.set(key, credential?.username || null);
|
||||||
|
}
|
||||||
|
summary.username = usernames.get(key) ?? null;
|
||||||
|
}
|
||||||
|
own[row.protocol] = summary;
|
||||||
result.set(row.hostId, own);
|
result.set(row.hostId, own);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -329,6 +329,23 @@ describe("a plugin protocol core does not know", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("summarizes the usable credential username without exposing its secret", async () => {
|
||||||
|
const patch = readProtocolAuthPayload({
|
||||||
|
protocolAuth: { spice: { authType: "credential", credentialId: 6 } },
|
||||||
|
});
|
||||||
|
await writeProtocolAuth("owner", HOST_ID, patch!, { isOwner: true });
|
||||||
|
const summaries = await loadProtocolAuthSummaries([{ id: HOST_ID }]);
|
||||||
|
expect(summaries.get(HOST_ID)?.spice.username).toBe("cred-user");
|
||||||
|
expect(JSON.stringify(summaries.get(HOST_ID))).not.toContain("cred-pass");
|
||||||
|
const recipient = sanitizeHostForRecipient(
|
||||||
|
{ protocolAuth: summaries.get(HOST_ID) },
|
||||||
|
"connect",
|
||||||
|
);
|
||||||
|
expect(recipient.protocolAuth).toEqual({
|
||||||
|
spice: { authType: "credential" },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("lets a shared editor change the login but not its credential", async () => {
|
it("lets a shared editor change the login but not its credential", async () => {
|
||||||
await storeLogin();
|
await storeLogin();
|
||||||
const rename = readProtocolAuthPayload({
|
const rename = readProtocolAuthPayload({
|
||||||
|
|||||||
@@ -148,10 +148,19 @@ const DOUBLE_CLICK_WINDOW_MS = 250;
|
|||||||
const DEFAULT_ROW_FIELDS = defaultHostRowFields();
|
const DEFAULT_ROW_FIELDS = defaultHostRowFields();
|
||||||
|
|
||||||
export function formatHostAddress(
|
export function formatHostAddress(
|
||||||
host: Pick<Host, "username" | "ip" | "port">,
|
host: Pick<Host, "username" | "ip" | "port"> &
|
||||||
|
Partial<Pick<Host, "enableSsh" | "pluginSettings" | "protocolAuth">>,
|
||||||
fields: Pick<HostRowFields, "showUsername" | "showPort">,
|
fields: Pick<HostRowFields, "showUsername" | "showPort">,
|
||||||
): string {
|
): string {
|
||||||
const user = fields.showUsername && host.username ? `${host.username}@` : "";
|
const protocol =
|
||||||
|
host.enableSsh === false ? enabledHostProtocols(host)[0] : undefined;
|
||||||
|
const username =
|
||||||
|
host.enableSsh === false
|
||||||
|
? protocol
|
||||||
|
? host.protocolAuth?.[protocol.id]?.username
|
||||||
|
: undefined
|
||||||
|
: host.username;
|
||||||
|
const user = fields.showUsername && username ? `${username}@` : "";
|
||||||
const port = fields.showPort && host.port ? `:${host.port}` : "";
|
const port = fields.showPort && host.port ? `:${host.port}` : "";
|
||||||
return `${user}${host.ip}${port}`;
|
return `${user}${host.ip}${port}`;
|
||||||
}
|
}
|
||||||
@@ -787,7 +796,12 @@ export function HostItem({
|
|||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
writeClipboardText(`${host.username}@${host.ip}`);
|
writeClipboardText(
|
||||||
|
formatHostAddress(host, {
|
||||||
|
showUsername: true,
|
||||||
|
showPort: false,
|
||||||
|
}),
|
||||||
|
);
|
||||||
toast.success(t("hosts.copiedToClipboard"));
|
toast.success(t("hosts.copiedToClipboard"));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { registerHostProtocol } from "@/sidebar/host-protocols";
|
||||||
import {
|
import {
|
||||||
act,
|
act,
|
||||||
cleanup,
|
cleanup,
|
||||||
@@ -402,3 +403,42 @@ describe("HostItem row fields", () => {
|
|||||||
).toBe("root@10.0.0.5");
|
).toBe("root@10.0.0.5");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("uses the enabled protocol username for non-SSH hosts", () => {
|
||||||
|
const dispose = registerHostProtocol({
|
||||||
|
id: "rdp",
|
||||||
|
pluginId: "remote-desktop",
|
||||||
|
settingKey: "enableRdp",
|
||||||
|
defaultPort: 3389,
|
||||||
|
titleKey: "rdp",
|
||||||
|
icon: () => null,
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
const host: Host = {
|
||||||
|
...baseHost,
|
||||||
|
enableSsh: false,
|
||||||
|
pluginSettings: { "remote-desktop": { enableRdp: true } },
|
||||||
|
protocolAuth: {
|
||||||
|
rdp: {
|
||||||
|
authType: "credential",
|
||||||
|
credentialId: 6,
|
||||||
|
username: "Administrator",
|
||||||
|
fields: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const fields = { showUsername: true, showPort: false };
|
||||||
|
expect(formatHostAddress(host, fields)).toBe("Administrator@10.0.0.5");
|
||||||
|
expect(formatHostAddress({ ...host, enableSsh: true }, fields)).toBe(
|
||||||
|
"root@10.0.0.5",
|
||||||
|
);
|
||||||
|
expect(formatHostAddress({ ...host, protocolAuth: {} }, fields)).toBe(
|
||||||
|
"10.0.0.5",
|
||||||
|
);
|
||||||
|
expect(formatHostAddress(host, { ...fields, showUsername: false })).toBe(
|
||||||
|
"10.0.0.5",
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
Reference in new issue
Block a user