Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled
160 lines
4.8 KiB
TypeScript
160 lines
4.8 KiB
TypeScript
import type { GroupConfig } from "../domain/models";
|
|
import {
|
|
findProxyProfile,
|
|
hasIncompleteProxyIdentity,
|
|
hasMissingProxyIdentity,
|
|
hasUnreadableProxyCredential,
|
|
isCompleteProxyConfig,
|
|
normalizeManualProxyConfig,
|
|
} from "../domain/proxyProfiles";
|
|
import type { Host, Identity, ProxyConfig, ProxyProfile } from "../types";
|
|
import {
|
|
LINUX_DISTRO_OPTIONS,
|
|
NETWORK_DEVICE_OPTIONS,
|
|
POSIX_PLATFORM_OPTIONS,
|
|
} from "../domain/host";
|
|
|
|
export const parseOptionalPortInput = (value: string): number | undefined =>
|
|
value ? Number(value) : undefined;
|
|
|
|
export const resolvePrimaryProtocolSwitchPort = (
|
|
currentPort: number | undefined,
|
|
nextProtocol: "ssh" | "telnet",
|
|
hasGroupTelnetPortDefault: boolean,
|
|
hasGroupSshPortDefault: boolean,
|
|
): number | undefined => {
|
|
if (nextProtocol === "telnet") {
|
|
// Don't override if group provides a Telnet default
|
|
if (hasGroupTelnetPortDefault || hasGroupSshPortDefault) return currentPort;
|
|
if (currentPort === 22 || currentPort === undefined) return 23;
|
|
return currentPort;
|
|
}
|
|
if (nextProtocol === "ssh") {
|
|
if (hasGroupSshPortDefault) return currentPort;
|
|
if (currentPort === 23 || currentPort === undefined) return 22;
|
|
return currentPort;
|
|
}
|
|
return currentPort;
|
|
};
|
|
|
|
export const resolvePrimaryProtocolSavePort = (
|
|
protocol: Host["protocol"],
|
|
currentPort: number | undefined,
|
|
hasGroupSshPortDefault: boolean,
|
|
hasGroupTelnetPortDefault: boolean,
|
|
): number | undefined => {
|
|
if (protocol === "telnet") {
|
|
if (currentPort !== undefined) return currentPort;
|
|
if (hasGroupTelnetPortDefault || hasGroupSshPortDefault) return undefined;
|
|
return 23;
|
|
}
|
|
return currentPort ?? (hasGroupSshPortDefault ? undefined : 22);
|
|
};
|
|
|
|
export const resolveDetailsTelnetPort = (
|
|
host: Host,
|
|
groupDefaults?: Partial<GroupConfig>,
|
|
): number => {
|
|
if (host.telnetPort !== undefined && host.telnetPort !== null) return host.telnetPort;
|
|
if (groupDefaults?.telnetPort !== undefined && groupDefaults.telnetPort !== null) {
|
|
return groupDefaults.telnetPort;
|
|
}
|
|
if (host.protocol === "telnet") {
|
|
if (host.port !== undefined && host.port !== null) return host.port;
|
|
if (groupDefaults?.port !== undefined && groupDefaults.port !== null) return groupDefaults.port;
|
|
}
|
|
return 23;
|
|
};
|
|
|
|
export const resolveDetailsTelnetUsername = (
|
|
host: Host,
|
|
groupDefaults?: Partial<GroupConfig>,
|
|
): string =>
|
|
host.telnetUsername !== undefined
|
|
? host.telnetUsername
|
|
: groupDefaults?.telnetUsername !== undefined
|
|
? groupDefaults.telnetUsername
|
|
: host.username ?? groupDefaults?.username ?? "";
|
|
|
|
export const resolveDetailsTelnetPassword = (
|
|
host: Host,
|
|
groupDefaults?: Partial<GroupConfig>,
|
|
): string =>
|
|
host.telnetPassword !== undefined
|
|
? host.telnetPassword
|
|
: groupDefaults?.telnetPassword !== undefined
|
|
? groupDefaults.telnetPassword
|
|
: host.password ?? groupDefaults?.password ?? "";
|
|
|
|
export const prepareTelnetCredentialsForSave = (host: Host): Host =>
|
|
host.telnetIdentityId
|
|
? {
|
|
...host,
|
|
telnetUsername: undefined,
|
|
telnetPassword: undefined,
|
|
}
|
|
: host;
|
|
|
|
export const LINUX_DISTRO_OPTION_IDS = [
|
|
...LINUX_DISTRO_OPTIONS,
|
|
...POSIX_PLATFORM_OPTIONS,
|
|
...NETWORK_DEVICE_OPTIONS,
|
|
];
|
|
|
|
export type ProxySaveValidationError =
|
|
| "required"
|
|
| "port"
|
|
| "missingSaved"
|
|
| "missingIdentity"
|
|
| "incompleteIdentity"
|
|
| "unreadableIdentity";
|
|
|
|
export const validateProxyConfigForSave = ({
|
|
proxyConfig,
|
|
proxyProfileId,
|
|
proxyProfiles,
|
|
identities,
|
|
}: {
|
|
proxyConfig?: ProxyConfig;
|
|
proxyProfileId?: string;
|
|
proxyProfiles?: ProxyProfile[];
|
|
identities?: Identity[];
|
|
}): ProxySaveValidationError | null => {
|
|
const selectedProxyProfile = findProxyProfile(proxyProfileId, proxyProfiles ?? []);
|
|
if (proxyProfileId && !selectedProxyProfile) return "missingSaved";
|
|
|
|
const normalizedProxyConfig = normalizeManualProxyConfig(proxyConfig);
|
|
if (normalizedProxyConfig && !isCompleteProxyConfig(normalizedProxyConfig)) {
|
|
return normalizedProxyConfig.host ? "port" : "required";
|
|
}
|
|
|
|
const effectiveProxyConfig = selectedProxyProfile?.config ?? proxyConfig;
|
|
if (hasMissingProxyIdentity(effectiveProxyConfig, identities ?? [])) {
|
|
return "missingIdentity";
|
|
}
|
|
if (hasIncompleteProxyIdentity(effectiveProxyConfig, identities ?? [])) {
|
|
return "incompleteIdentity";
|
|
}
|
|
if (hasUnreadableProxyCredential(effectiveProxyConfig, identities ?? [])) {
|
|
return "unreadableIdentity";
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
export const prepareProxyConfigForSave = (params: {
|
|
proxyConfig?: ProxyConfig;
|
|
proxyProfileId?: string;
|
|
proxyProfiles?: ProxyProfile[];
|
|
identities?: Identity[];
|
|
}): {
|
|
error?: ProxySaveValidationError;
|
|
normalizedProxyConfig?: ProxyConfig;
|
|
} => {
|
|
const error = validateProxyConfigForSave(params);
|
|
if (error) return { error };
|
|
return {
|
|
normalizedProxyConfig: normalizeManualProxyConfig(params.proxyConfig),
|
|
};
|
|
};
|