mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 06:05:24 +00:00
feat: add allowlisted host view for plugins
An allowlist rather than a list of fields to strip. A blocklist rots: the moment a new secret-bearing column lands on SSHHost it starts leaking silently. With an allowlist a new field stays invisible to plugins until someone adds it here on purpose.
This commit is contained in:
1 parent
248698f62d
commit
9f4a2d3951
1 file changed
+68
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* The only shape of a host a plugin ever sees.
|
||||
*
|
||||
* This is an ALLOWLIST, deliberately, not a list of fields to strip. A
|
||||
* blocklist rots: the moment someone adds a new secret-bearing column to
|
||||
* SSHHost, a blocklist silently starts leaking it, and nothing fails. With an
|
||||
* allowlist a new field is invisible to plugins until someone consciously adds
|
||||
* it here.
|
||||
*
|
||||
* resolveHostById returns an object carrying password, key, keyPassword,
|
||||
* certPublicKey, sudoPassword and the autostart* secrets in plaintext. None of
|
||||
* them are in this list, and none of them may ever be.
|
||||
*/
|
||||
|
||||
export interface PluginHostView {
|
||||
id: number;
|
||||
name: string | null;
|
||||
ip: string;
|
||||
port: number;
|
||||
username: string;
|
||||
folder: string | null;
|
||||
tags: string[];
|
||||
authType: string | null;
|
||||
enableTerminal: boolean;
|
||||
enableTunnel: boolean;
|
||||
enableFileManager: boolean;
|
||||
createdAt: string | null;
|
||||
updatedAt: string | null;
|
||||
}
|
||||
|
||||
const NUMBER_FIELDS = ["id", "port"] as const;
|
||||
const STRING_FIELDS = [
|
||||
"name",
|
||||
"ip",
|
||||
"username",
|
||||
"folder",
|
||||
"authType",
|
||||
"createdAt",
|
||||
"updatedAt",
|
||||
] as const;
|
||||
const BOOLEAN_FIELDS = [
|
||||
"enableTerminal",
|
||||
"enableTunnel",
|
||||
"enableFileManager",
|
||||
] as const;
|
||||
|
||||
export function toPluginHostView(
|
||||
host: Record<string, unknown>,
|
||||
): PluginHostView {
|
||||
const view: Record<string, unknown> = {};
|
||||
|
||||
for (const field of NUMBER_FIELDS) {
|
||||
view[field] = Number(host[field] ?? 0);
|
||||
}
|
||||
for (const field of STRING_FIELDS) {
|
||||
const value = host[field];
|
||||
view[field] = typeof value === "string" ? value : null;
|
||||
}
|
||||
for (const field of BOOLEAN_FIELDS) {
|
||||
view[field] = Boolean(host[field]);
|
||||
}
|
||||
|
||||
view.tags = Array.isArray(host.tags)
|
||||
? host.tags.filter((tag): tag is string => typeof tag === "string")
|
||||
: [];
|
||||
|
||||
return view as unknown as PluginHostView;
|
||||
}
|
||||
Reference in new issue
Block a user