refactor(hosts): group host modules into per-feature directories

file-manager/, metrics/ (incl. widgets, managers, alert-engine),
terminal/, tmux/ and tunnel/ each own their files; docker/ gains
container-runtime. Genuinely shared helpers (jump-host chain, host
resolver, connection pool, opkssh, vault, serial) stay at hosts/ root.
Pure file moves with import path updates; mirrored test paths follow.
This commit is contained in:
LukeGus
2026-07-16 04:34:22 -05:00
parent 7f43932429
commit 9c8528e4d2
82 changed files with 233 additions and 232 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ import {
containerCommand,
getContainerRuntimeConfig,
type ContainerRuntime,
} from "../container-runtime.js";
} from "./container-runtime.js";
import { resolveSshConnectConfigHost } from "../ssh-dns.js";
const sshLogger = systemLogger;
+1 -1
View File
@@ -3,7 +3,7 @@ import { logger } from "../../utils/logger.js";
import {
containerCommand,
type ContainerRuntime,
} from "../container-runtime.js";
} from "./container-runtime.js";
const sshLogger = logger;
+1 -1
View File
@@ -28,7 +28,7 @@ import {
containerCommand,
getContainerRuntimeConfig,
getRuntimeLabel,
} from "../container-runtime.js";
} from "./container-runtime.js";
import { resolveSshConnectConfigHost } from "../ssh-dns.js";
import {
type SSHSession,
+1 -1
View File
@@ -1,6 +1,6 @@
import { Client as SSHClient } from "ssh2";
import { logger } from "../../utils/logger.js";
import type { ContainerRuntime } from "../container-runtime.js";
import type { ContainerRuntime } from "./container-runtime.js";
const sshLogger = logger;
@@ -1,7 +1,7 @@
import type { Express } from "express";
import type { AuthenticatedRequest } from "../../types/index.js";
import { fileLogger } from "../utils/logger.js";
import { execChannel, type SSHSession } from "./file-manager-session.js";
import type { AuthenticatedRequest } from "../../../types/index.js";
import { fileLogger } from "../../utils/logger.js";
import { execChannel, type SSHSession } from "./session.js";
type FileActionRoutesDeps = {
sshSessions: Record<string, SSHSession>;
@@ -1,15 +1,15 @@
import type { Express, Request, Response } from "express";
import Busboy from "busboy";
import type { AuthenticatedRequest } from "../../types/index.js";
import { fileLogger } from "../utils/logger.js";
import type { AuthenticatedRequest } from "../../../types/index.js";
import { fileLogger } from "../../utils/logger.js";
import {
execChannel,
execWithSudo,
execWithSudoBuffer,
getSessionSftp,
type SSHSession,
} from "./file-manager-session.js";
import { detectBinary } from "./file-manager-utils.js";
} from "./session.js";
import { detectBinary } from "./utils.js";
type FileContentRoutesDeps = {
sshSessions: Record<string, SSHSession>;
@@ -1,12 +1,8 @@
import type { Express } from "express";
import type { AuthenticatedRequest } from "../../types/index.js";
import { fileLogger } from "../utils/logger.js";
import { getMimeType } from "./file-manager-utils.js";
import {
execChannel,
getSessionSftp,
type SSHSession,
} from "./file-manager-session.js";
import type { AuthenticatedRequest } from "../../../types/index.js";
import { fileLogger } from "../../utils/logger.js";
import { getMimeType } from "./utils.js";
import { execChannel, getSessionSftp, type SSHSession } from "./session.js";
type FileDownloadRoutesDeps = {
sshSessions: Record<string, SSHSession>;
@@ -1,21 +1,24 @@
import express from "express";
import { createCorsMiddleware } from "../utils/cors-config.js";
import { createCorsMiddleware } from "../../utils/cors-config.js";
import cookieParser from "cookie-parser";
import axios from "axios";
import { Client as SSHClient } from "ssh2";
import { SSH_ALGORITHMS } from "../utils/ssh-algorithms.js";
import { createCurrentHostResolutionRepository } from "../database/repositories/factory.js";
import { fileLogger } from "../utils/logger.js";
import { AuthManager } from "../utils/auth-manager.js";
import type { AuthenticatedRequest, ProxyNode } from "../../types/index.js";
import { SSH_ALGORITHMS } from "../../utils/ssh-algorithms.js";
import { createCurrentHostResolutionRepository } from "../../database/repositories/factory.js";
import { fileLogger } from "../../utils/logger.js";
import { AuthManager } from "../../utils/auth-manager.js";
import type { AuthenticatedRequest, ProxyNode } from "../../../types/index.js";
import {
createSocks5Connection,
type SOCKS5Config,
} from "../utils/socks5-helper.js";
import type { LogEntry, ConnectionStage } from "../../types/connection-log.js";
import { SSHHostKeyVerifier } from "./host-key-verifier.js";
import { resolveHostById } from "./host-resolver.js";
import type { SSHHost } from "../../types/index.js";
} from "../../utils/socks5-helper.js";
import type {
LogEntry,
ConnectionStage,
} from "../../../types/connection-log.js";
import { SSHHostKeyVerifier } from "../host-key-verifier.js";
import { resolveHostById } from "../host-resolver.js";
import type { SSHHost } from "../../../types/index.js";
import {
startHostTransfer,
getTransferStatus,
@@ -26,24 +29,24 @@ import {
retryHostTransfer,
previewArchiveTransferMethod,
type HostTransferDeps,
} from "./host-transfer.js";
import { registerFileContentRoutes } from "./file-manager-content-routes.js";
import { createConnectionLog } from "./connection-log.js";
import { createJumpHostChain } from "./jump-host-chain.js";
import { preparePrivateKeyForSSH2 } from "../utils/ssh-key-utils.js";
} from "./transfer-engine.js";
import { registerFileContentRoutes } from "./content-routes.js";
import { createConnectionLog } from "../connection-log.js";
import { createJumpHostChain } from "../jump-host-chain.js";
import { preparePrivateKeyForSSH2 } from "../../utils/ssh-key-utils.js";
import {
ChannelOpenSerializer,
execChannel,
getSessionSftp,
type PendingTOTPSession,
type SSHSession,
} from "./file-manager-session.js";
import { registerFileListingRoutes } from "./file-manager-list-routes.js";
import { registerFileOperationRoutes } from "./file-manager-operation-routes.js";
import { resolveSshConnectConfigHost } from "./ssh-dns.js";
import { registerFileDownloadRoutes } from "./file-manager-download-routes.js";
import { registerFileActionRoutes } from "./file-manager-action-routes.js";
import { applyAgentAuth } from "./terminal-auth-helpers.js";
} from "./session.js";
import { registerFileListingRoutes } from "./list-routes.js";
import { registerFileOperationRoutes } from "./operation-routes.js";
import { resolveSshConnectConfigHost } from "../ssh-dns.js";
import { registerFileDownloadRoutes } from "./download-routes.js";
import { registerFileActionRoutes } from "./action-routes.js";
import { applyAgentAuth } from "../terminal-auth-helpers.js";
const app = express();
@@ -209,14 +212,14 @@ async function buildDedicatedTransferConnectConfig(
}
config.password = host.password;
} else if (authType === "opkssh") {
const { getOPKSSHToken } = await import("./opkssh-auth.js");
const { getOPKSSHToken } = await import("../opkssh-auth.js");
const token = await getOPKSSHToken(userId, host.id);
if (!token) {
throw new Error(
"OPKSSH authentication required. Open a Terminal connection to this host first.",
);
}
const { setupOPKSSHCertAuth } = await import("./opkssh-cert-auth.js");
const { setupOPKSSHCertAuth } = await import("../opkssh-cert-auth.js");
await setupOPKSSHCertAuth(
config as import("ssh2").ConnectConfig,
client,
@@ -747,7 +750,7 @@ app.post("/ssh/file_manager/ssh/connect", async (req, res) => {
let resolvedSocks5ProxyChain = socks5ProxyChain;
if (hostId && userId && !password && !sshKey) {
try {
const { resolveHostById } = await import("./host-resolver.js");
const { resolveHostById } = await import("../host-resolver.js");
const resolvedHost = await resolveHostById(hostId, userId);
if (resolvedHost) {
resolvedIp = resolvedHost.ip;
@@ -806,7 +809,7 @@ app.post("/ssh/file_manager/ssh/connect", async (req, res) => {
} else if (credentialId && hostId && userId) {
// Legacy: credential resolution from credentialId
try {
const { resolveHostById } = await import("./host-resolver.js");
const { resolveHostById } = await import("../host-resolver.js");
const resolvedHost = await resolveHostById(hostId, userId);
if (resolvedHost) {
resolvedIp = resolvedHost.ip;
@@ -998,7 +1001,7 @@ app.post("/ssh/file_manager/ssh/connect", async (req, res) => {
);
} else if (resolvedCredentials.authType === "opkssh") {
try {
const { getOPKSSHToken } = await import("./opkssh-auth.js");
const { getOPKSSHToken } = await import("../opkssh-auth.js");
const token = await getOPKSSHToken(userId, hostId);
if (!token) {
@@ -1017,7 +1020,7 @@ app.post("/ssh/file_manager/ssh/connect", async (req, res) => {
});
}
const { setupOPKSSHCertAuth } = await import("./opkssh-cert-auth.js");
const { setupOPKSSHCertAuth } = await import("../opkssh-cert-auth.js");
await setupOPKSSHCertAuth(
config as import("ssh2").ConnectConfig,
client,
@@ -1,17 +1,13 @@
import type { Express } from "express";
import type { AuthenticatedRequest } from "../../types/index.js";
import { fileLogger } from "../utils/logger.js";
import {
execChannel,
getSessionSftp,
type SSHSession,
} from "./file-manager-session.js";
import type { AuthenticatedRequest } from "../../../types/index.js";
import { fileLogger } from "../../utils/logger.js";
import { execChannel, getSessionSftp, type SSHSession } from "./session.js";
import {
formatMtime,
isExecutableFile,
modeToPermissions,
parseLsDateToTimestamp,
} from "./file-manager-utils.js";
} from "./utils.js";
type FileListingRoutesDeps = {
sshSessions: Record<string, SSHSession>;
@@ -1,4 +1,4 @@
import { isWindowsSftpPath, sftpPathToLocalPath } from "./transfer-paths.js";
import { isWindowsSftpPath, sftpPathToLocalPath } from "../transfer-paths.js";
export interface DeleteCommand {
command: string;
@@ -1,12 +1,8 @@
import type { Express } from "express";
import type { AuthenticatedRequest } from "../../types/index.js";
import { fileLogger } from "../utils/logger.js";
import {
execChannel,
execWithSudo,
type SSHSession,
} from "./file-manager-session.js";
import { buildDeleteCommand } from "./file-manager-operation-commands.js";
import type { AuthenticatedRequest } from "../../../types/index.js";
import { fileLogger } from "../../utils/logger.js";
import { execChannel, execWithSudo, type SSHSession } from "./session.js";
import { buildDeleteCommand } from "./operation-commands.js";
type FileOperationRoutesDeps = {
sshSessions: Record<string, SSHSession>;
@@ -2,7 +2,7 @@ import { randomUUID } from "crypto";
import { networkInterfaces } from "os";
import { performance } from "node:perf_hooks";
import type { ClientChannel } from "ssh2";
import { fileLogger } from "../utils/logger.js";
import { fileLogger } from "../../utils/logger.js";
import {
basename,
buildPathFromSegments,
@@ -15,7 +15,7 @@ import {
sftpPathToLocalPath,
splitPathSegments,
type TransferPlatform,
} from "./transfer-paths.js";
} from "../transfer-paths.js";
import {
buildTransferScanSummary,
getArchiveTransferReasonKey,
@@ -1,4 +1,4 @@
import type { TransferPlatform } from "./transfer-paths.js";
import type { TransferPlatform } from "../transfer-paths.js";
export type TransferMethodPreference = "auto" | "tar" | "item_sftp";
@@ -1,10 +1,10 @@
import { createCurrentAlertRepository } from "../database/repositories/factory.js";
import { statsLogger } from "../utils/logger.js";
import { createCurrentAlertRepository } from "../../database/repositories/factory.js";
import { statsLogger } from "../../utils/logger.js";
import {
sendNotification,
type AlertPayload,
type NotificationChannel,
} from "../utils/notification-sender.js";
} from "../../utils/notification-sender.js";
type AlertTriggerType =
| "host_offline"
@@ -1,7 +1,7 @@
import type { Express, RequestHandler } from "express";
import type { AuthenticatedRequest } from "../../types/index.js";
import { createCurrentHostMetricsHistoryRepository } from "../database/repositories/factory.js";
import { statsLogger } from "../utils/logger.js";
import type { AuthenticatedRequest } from "../../../types/index.js";
import { createCurrentHostMetricsHistoryRepository } from "../../database/repositories/factory.js";
import { statsLogger } from "../../utils/logger.js";
type HistoryRoutesDeps = {
validateHostId: RequestHandler;
@@ -1,24 +1,27 @@
import express from "express";
import net from "net";
import { createCorsMiddleware } from "../utils/cors-config.js";
import { createCorsMiddleware } from "../../utils/cors-config.js";
import cookieParser from "cookie-parser";
import { Client, type ConnectConfig } from "ssh2";
import { SSH_ALGORITHMS } from "../utils/ssh-algorithms.js";
import { SSH_ALGORITHMS } from "../../utils/ssh-algorithms.js";
import {
pickResolvedPassword,
pickResolvedUsername,
} from "./credential-username.js";
} from "../credential-username.js";
import {
getCurrentSettingValue,
createCurrentHostMetricsHistoryRepository,
createCurrentHostResolutionRepository,
} from "../database/repositories/factory.js";
import { statsLogger } from "../utils/logger.js";
import { DataCrypto } from "../utils/data-crypto.js";
import { AuthManager } from "../utils/auth-manager.js";
import { PermissionManager } from "../utils/permission-manager.js";
import type { AuthenticatedRequest, ProxyNode } from "../../types/index.js";
import type { LogEntry, ConnectionStage } from "../../types/connection-log.js";
} from "../../database/repositories/factory.js";
import { statsLogger } from "../../utils/logger.js";
import { DataCrypto } from "../../utils/data-crypto.js";
import { AuthManager } from "../../utils/auth-manager.js";
import { PermissionManager } from "../../utils/permission-manager.js";
import type { AuthenticatedRequest, ProxyNode } from "../../../types/index.js";
import type {
LogEntry,
ConnectionStage,
} from "../../../types/connection-log.js";
import { collectCpuMetrics } from "./widgets/cpu-collector.js";
import { collectMemoryMetrics } from "./widgets/memory-collector.js";
import { collectDiskMetrics } from "./widgets/disk-collector.js";
@@ -32,26 +35,26 @@ import { collectFirewallMetrics } from "./widgets/firewall-collector.js";
import {
createSocks5Connection,
type SOCKS5Config,
} from "../utils/socks5-helper.js";
import { preparePrivateKeyForSSH2 } from "../utils/ssh-key-utils.js";
import { SSHHostKeyVerifier } from "./host-key-verifier.js";
import { connectionPool, withConnection } from "./ssh-connection-pool.js";
import { registerHostMetricsSettingsRoutes } from "./host-metrics-settings-routes.js";
import { registerHostMetricsViewerRoutes } from "./host-metrics-viewer-routes.js";
import { registerHostMetricsPreferencesRoutes } from "./host-metrics-preferences-routes.js";
import { registerHostMetricsHistoryRoutes } from "./host-metrics-history-routes.js";
} from "../../utils/socks5-helper.js";
import { preparePrivateKeyForSSH2 } from "../../utils/ssh-key-utils.js";
import { SSHHostKeyVerifier } from "../host-key-verifier.js";
import { connectionPool, withConnection } from "../ssh-connection-pool.js";
import { registerHostMetricsSettingsRoutes } from "./settings-routes.js";
import { registerHostMetricsViewerRoutes } from "./viewer-routes.js";
import { registerHostMetricsPreferencesRoutes } from "./preferences-routes.js";
import { registerHostMetricsHistoryRoutes } from "./history-routes.js";
import { AlertEngine } from "./alert-engine.js";
import { registerManagerRoutes } from "./managers/index.js";
import { resolveSshConnectConfigHost } from "./ssh-dns.js";
import { resolveSshConnectConfigHost } from "../ssh-dns.js";
import { AccessDeniedError } from "./managers/route-helpers.js";
import type { ManagerHost } from "./managers/types.js";
import { createJumpHostChain } from "./jump-host-chain.js";
import { createJumpHostChain } from "../jump-host-chain.js";
import {
isTcpPingEnabled,
supportsMetrics,
tcpPingThroughJumpHost,
} from "./host-metrics-helpers.js";
import { createConnectionLog } from "./connection-log.js";
} from "./helpers.js";
import { createConnectionLog } from "../connection-log.js";
import {
cleanupMetricsSession,
getSessionKey,
@@ -59,7 +62,7 @@ import {
pendingTOTPSessions,
scheduleMetricsSessionCleanup,
type MetricsViewer,
} from "./host-metrics-sessions.js";
} from "./sessions.js";
import {
authFailureTracker,
hostPollCache,
@@ -68,7 +71,7 @@ import {
pollingBackoff,
requestQueue,
statusPollLimiter,
} from "./host-metrics-state.js";
} from "./state.js";
const authManager = AuthManager.getInstance();
const permissionManager = PermissionManager.getInstance();
@@ -989,7 +992,7 @@ async function resolveHostCredentials(
if (isSharedHost) {
const { SharedCredentialManager } =
await import("../utils/shared-credential-manager.js");
await import("../../utils/shared-credential-manager.js");
const sharedCredManager = SharedCredentialManager.getInstance();
const sharedCred = await sharedCredManager.getSharedCredentialForUser(
host.id as number,
@@ -1255,18 +1258,18 @@ function createSshFactory(host: SSHHostWithCredentials): () => Promise<Client> {
// Set up OPKSSH cert auth if needed (requires client instance)
if (host.authType === "opkssh" && host.userId) {
const { getOPKSSHToken } = await import("./opkssh-auth.js");
const { getOPKSSHToken } = await import("../opkssh-auth.js");
const token = await getOPKSSHToken(host.userId, host.id);
if (!token) {
throw new Error(
"OPKSSH authentication required. Please open a Terminal connection first.",
);
}
const { setupOPKSSHCertAuth } = await import("./opkssh-cert-auth.js");
const { setupOPKSSHCertAuth } = await import("../opkssh-cert-auth.js");
await setupOPKSSHCertAuth(config, client, token, host.username);
} else if (host.authType === "vault") {
const { setupVaultSshSignerAuth } =
await import("./vault-ssh-connect.js");
await import("../vault-ssh-connect.js");
await setupVaultSshSignerAuth(config, client, host);
}
@@ -2123,7 +2126,7 @@ app.post("/metrics/start/:id", validateHostId, async (req, res) => {
const client = new Client();
if (host.authType === "opkssh" && host.userId) {
const { getOPKSSHToken } = await import("./opkssh-auth.js");
const { getOPKSSHToken } = await import("../opkssh-auth.js");
const token = await getOPKSSHToken(host.userId, host.id);
if (!token) {
connectionLogs.push(
@@ -2139,11 +2142,11 @@ app.post("/metrics/start/:id", validateHostId, async (req, res) => {
connectionLogs,
});
}
const { setupOPKSSHCertAuth } = await import("./opkssh-cert-auth.js");
const { setupOPKSSHCertAuth } = await import("../opkssh-cert-auth.js");
await setupOPKSSHCertAuth(config, client, token, host.username);
} else if (host.authType === "vault") {
const { setupVaultSshSignerAuth } =
await import("./vault-ssh-connect.js");
await import("../vault-ssh-connect.js");
await setupVaultSshSignerAuth(config, client, host);
}
@@ -2792,7 +2795,8 @@ app.post("/internal/login-alert", async (req, res) => {
) {
return res.status(403).json({ error: "Forbidden" });
}
const systemCrypto = (await import("../utils/system-crypto.js")).SystemCrypto;
const systemCrypto = (await import("../../utils/system-crypto.js"))
.SystemCrypto;
const expectedToken = await systemCrypto.getInstance().getInternalAuthToken();
const token = req.headers["x-internal-auth"];
if (!token || token !== expectedToken) {
@@ -1,8 +1,8 @@
import type { Express } from "express";
import type { Client } from "ssh2";
import type { AuthenticatedRequest } from "../../../types/index.js";
import type { AuthenticatedRequest } from "../../../../types/index.js";
import { execCommand } from "../widgets/common-utils.js";
import { createCurrentHostHealthRepository } from "../../database/repositories/factory.js";
import { createCurrentHostHealthRepository } from "../../../database/repositories/factory.js";
import { managerHandler, ManagerInputError } from "./route-helpers.js";
import { shellSingleQuote } from "./exec-elevated.js";
import { isValidPort } from "./validation.js";
@@ -1,7 +1,7 @@
import type { Request, Response } from "express";
import type { Client } from "ssh2";
import type { AuthenticatedRequest } from "../../../types/index.js";
import { statsLogger } from "../../utils/logger.js";
import type { AuthenticatedRequest } from "../../../../types/index.js";
import { statsLogger } from "../../../utils/logger.js";
import { ElevationError } from "./exec-elevated.js";
import type { ManagerHost, RunOnHost } from "./types.js";
@@ -1,12 +1,12 @@
import type { Express, RequestHandler } from "express";
import type { AuthenticatedRequest } from "../../types/index.js";
import { createCurrentHostMetricsPreferenceRepository } from "../database/repositories/factory.js";
import { statsLogger } from "../utils/logger.js";
import type { AuthenticatedRequest } from "../../../types/index.js";
import { createCurrentHostMetricsPreferenceRepository } from "../../database/repositories/factory.js";
import { statsLogger } from "../../utils/logger.js";
import {
deriveEnabledWidgets,
defaultLayoutFromWidgets,
type HostMetricsLayout,
} from "../../types/host-metrics.js";
} from "../../../types/host-metrics.js";
interface PrefStatsConfig {
enabledWidgets?: string[];
@@ -1,5 +1,5 @@
import type { Client, ConnectConfig } from "ssh2";
import { statsLogger } from "../utils/logger.js";
import { statsLogger } from "../../utils/logger.js";
export interface MetricsSession {
client: Client;
@@ -1,6 +1,6 @@
import type { Express, RequestHandler } from "express";
import { statsLogger } from "../utils/logger.js";
import { createCurrentSettingsRepository } from "../database/repositories/factory.js";
import { statsLogger } from "../../utils/logger.js";
import { createCurrentSettingsRepository } from "../../database/repositories/factory.js";
type HostMetricsSettingsConfig = {
statusCheckInterval: number;
@@ -1,7 +1,7 @@
import type { Express } from "express";
import type { AuthenticatedRequest } from "../../types/index.js";
import { statsLogger } from "../utils/logger.js";
import { DataCrypto } from "../utils/data-crypto.js";
import type { AuthenticatedRequest } from "../../../types/index.js";
import { statsLogger } from "../../utils/logger.js";
import { DataCrypto } from "../../utils/data-crypto.js";
type ViewerStatsConfig = {
metricsEnabled: boolean;
@@ -4,7 +4,7 @@ import type {
FirewallMetrics,
FirewallChain,
FirewallRule,
} from "../../../types/stats-widgets.js";
} from "../../../../types/stats-widgets.js";
function parseIptablesRule(line: string): FirewallRule | null {
if (!line.startsWith("-A ")) return null;
@@ -3,7 +3,7 @@ import { execCommand } from "./common-utils.js";
import type {
PortsMetrics,
ListeningPort,
} from "../../../types/stats-widgets.js";
} from "../../../../types/stats-widgets.js";
function parseSsOutput(output: string): ListeningPort[] {
const ports: ListeningPort[] = [];
@@ -5,36 +5,36 @@ import ssh2Pkg, {
type PseudoTtyOptions,
} from "ssh2";
const { Client, utils: ssh2Utils } = ssh2Pkg;
import { buildSSHAlgorithms } from "../utils/ssh-algorithms.js";
import { buildSSHAlgorithms } from "../../utils/ssh-algorithms.js";
import axios from "axios";
import { createCurrentHostResolutionRepository } from "../database/repositories/factory.js";
import { sshLogger, authLogger } from "../utils/logger.js";
import { logAudit } from "../utils/audit-logger.js";
import { AuthManager } from "../utils/auth-manager.js";
import { DataCrypto } from "../utils/data-crypto.js";
import { createCurrentHostResolutionRepository } from "../../database/repositories/factory.js";
import { sshLogger, authLogger } from "../../utils/logger.js";
import { logAudit } from "../../utils/audit-logger.js";
import { AuthManager } from "../../utils/auth-manager.js";
import { DataCrypto } from "../../utils/data-crypto.js";
import {
createSocks5Connection,
type SOCKS5Config,
} from "../utils/socks5-helper.js";
import { SSHAuthManager } from "./auth-manager.js";
import type { ProxyNode } from "../../types/index.js";
import { SSHHostKeyVerifier } from "./host-key-verifier.js";
import { createJumpHostChain } from "./jump-host-chain.js";
import { sessionManager } from "./terminal-session-manager.js";
} from "../../utils/socks5-helper.js";
import { SSHAuthManager } from "../auth-manager.js";
import type { ProxyNode } from "../../../types/index.js";
import { SSHHostKeyVerifier } from "../host-key-verifier.js";
import { createJumpHostChain } from "../jump-host-chain.js";
import { sessionManager } from "./session-manager.js";
import {
detectTmux,
attachOrCreateTmuxSession,
waitForTmuxSession,
} from "./tmux-helper.js";
} from "../tmux/helper.js";
import {
MemoryAgent,
performPortKnocking,
resolveAgentSocket,
} from "./terminal-auth-helpers.js";
import { isWindowsSftpPath, sftpPathToLocalPath } from "./transfer-paths.js";
import { preparePrivateKeyForSSH2 } from "../utils/ssh-key-utils.js";
import { triggerLoginAlert } from "../utils/alert-trigger.js";
import { isRetriableDnsError, resolveHostForSshConnect } from "./ssh-dns.js";
} from "../terminal-auth-helpers.js";
import { isWindowsSftpPath, sftpPathToLocalPath } from "../transfer-paths.js";
import { preparePrivateKeyForSSH2 } from "../../utils/ssh-key-utils.js";
import { triggerLoginAlert } from "../../utils/alert-trigger.js";
import { isRetriableDnsError, resolveHostForSshConnect } from "../ssh-dns.js";
interface ConnectToHostData {
cols: number;
@@ -781,9 +781,9 @@ wss.on("connection", async (ws: WebSocket, req) => {
case "opkssh_start_auth": {
const opksshData = data as { hostId: number };
try {
const { startOPKSSHAuth } = await import("./opkssh-auth.js");
const { startOPKSSHAuth } = await import("../opkssh-auth.js");
const { getRequestOrigin } =
await import("../utils/request-origin.js");
await import("../../utils/request-origin.js");
const host =
await createCurrentHostResolutionRepository().findHostById(
opksshData.hostId,
@@ -836,7 +836,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
case "opkssh_cancel": {
const cancelData = data as { requestId: string };
try {
const { cancelAuthSession } = await import("./opkssh-auth.js");
const { cancelAuthSession } = await import("../opkssh-auth.js");
cancelAuthSession(cancelData.requestId);
resetConnectionState();
} catch (error) {
@@ -898,9 +898,9 @@ wss.on("connection", async (ws: WebSocket, req) => {
const vaultData = data as { hostId: number };
try {
const { loadVaultProfileForHost, startVaultAuth } =
await import("./vault-oidc-auth.js");
await import("../vault-oidc-auth.js");
const { getRequestOrigin } =
await import("../utils/request-origin.js");
await import("../../utils/request-origin.js");
const profile = await loadVaultProfileForHost(
vaultData.hostId,
userId,
@@ -947,7 +947,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
const cancelData = data as { hostId: number };
try {
const { cancelVaultAuthByHost } =
await import("./vault-oidc-auth.js");
await import("../vault-oidc-auth.js");
cancelVaultAuthByHost(userId, cancelData.hostId);
resetConnectionState();
} catch (error) {
@@ -1155,7 +1155,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
if (id && userId) {
try {
const { resolveHostById } = await import("./host-resolver.js");
const { resolveHostById } = await import("../host-resolver.js");
resolvedHostData = (await resolveHostById(
id,
userId,
@@ -1892,7 +1892,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
(async () => {
try {
const { invalidateOPKSSHToken } = await import("./opkssh-auth.js");
const { invalidateOPKSSHToken } = await import("../opkssh-auth.js");
await invalidateOPKSSHToken(userId, id, "SSH auth failed");
} catch (invalidateError) {
sshLogger.error("Failed to invalidate OPKSSH token", {
@@ -1945,7 +1945,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
)?.id;
if (profileId) {
const { deleteVaultCert } =
await import("./vault-signer-auth.js");
await import("../vault-signer-auth.js");
await deleteVaultCert(userId, profileId);
}
} catch (invalidateError) {
@@ -2377,7 +2377,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
resolvedCredentials.certPublicKey.trim()
) {
try {
const { setupCACertAuth } = await import("./opkssh-cert-auth.js");
const { setupCACertAuth } = await import("../opkssh-cert-auth.js");
await setupCACertAuth(
connectConfig,
sshConn,
@@ -2440,7 +2440,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
} else if (resolvedCredentials.authType === "opkssh") {
sendLog("auth", "info", "Using OPKSSH certificate authentication");
try {
const { getOPKSSHToken } = await import("./opkssh-auth.js");
const { getOPKSSHToken } = await import("../opkssh-auth.js");
const token = await getOPKSSHToken(userId, id);
if (!token) {
@@ -2460,7 +2460,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
sendLog("auth", "info", "Using cached OPKSSH certificate");
const { setupOPKSSHCertAuth } = await import("./opkssh-cert-auth.js");
const { setupOPKSSHCertAuth } = await import("../opkssh-cert-auth.js");
await setupOPKSSHCertAuth(connectConfig, sshConn, token, username);
} catch (opksshError) {
sshLogger.error("OPKSSH authentication error", opksshError, {
@@ -2490,7 +2490,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
throw new Error("Host has no Vault signer profile configured");
}
const { getVaultCert } = await import("./vault-signer-auth.js");
const { getVaultCert } = await import("../vault-signer-auth.js");
const cert = await getVaultCert(userId, vaultProfile.id);
if (!cert) {
@@ -2510,7 +2510,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
sendLog("auth", "info", "Using cached Vault-signed certificate");
const { setupOPKSSHCertAuth } = await import("./opkssh-cert-auth.js");
const { setupOPKSSHCertAuth } = await import("../opkssh-cert-auth.js");
await setupOPKSSHCertAuth(
connectConfig,
sshConn,
@@ -2,11 +2,11 @@ import { type Client, type ClientChannel } from "ssh2";
import { WebSocket } from "ws";
import fs from "fs";
import path from "path";
import { sshLogger } from "../utils/logger.js";
import { sshLogger } from "../../utils/logger.js";
import {
getCurrentSettingValue,
createCurrentSessionRecordingRepository,
} from "../database/repositories/factory.js";
} from "../../database/repositories/factory.js";
const MAX_BUFFER_BYTES = 512 * 1024;
const DATA_DIR = process.env.DATA_DIR ?? "./db/data";
@@ -1,5 +1,5 @@
import type { Client, ClientChannel } from "ssh2";
import { sshLogger } from "../utils/logger.js";
import { sshLogger } from "../../utils/logger.js";
export interface TmuxSessionInfo {
name: string;
@@ -1,28 +1,28 @@
import express from "express";
import cookieParser from "cookie-parser";
import { Client, type ConnectConfig } from "ssh2";
import { createCorsMiddleware } from "../utils/cors-config.js";
import { AuthManager } from "../utils/auth-manager.js";
import { DataCrypto } from "../utils/data-crypto.js";
import { createCorsMiddleware } from "../../utils/cors-config.js";
import { AuthManager } from "../../utils/auth-manager.js";
import { DataCrypto } from "../../utils/data-crypto.js";
import {
createCurrentTmuxSessionTagRepository,
createCurrentUserRepository,
} from "../database/repositories/factory.js";
import { logAudit, getRequestMeta } from "../utils/audit-logger.js";
import { sshLogger } from "../utils/logger.js";
import { SSH_ALGORITHMS } from "../utils/ssh-algorithms.js";
import { preparePrivateKeyForSSH2 } from "../utils/ssh-key-utils.js";
import { SSHHostKeyVerifier } from "./host-key-verifier.js";
import { resolveHostById, checkHostAccess } from "./host-resolver.js";
import { createJumpHostChain } from "./jump-host-chain.js";
import { applyAgentAuth } from "./terminal-auth-helpers.js";
} from "../../database/repositories/factory.js";
import { logAudit, getRequestMeta } from "../../utils/audit-logger.js";
import { sshLogger } from "../../utils/logger.js";
import { SSH_ALGORITHMS } from "../../utils/ssh-algorithms.js";
import { preparePrivateKeyForSSH2 } from "../../utils/ssh-key-utils.js";
import { SSHHostKeyVerifier } from "../host-key-verifier.js";
import { resolveHostById, checkHostAccess } from "../host-resolver.js";
import { createJumpHostChain } from "../jump-host-chain.js";
import { applyAgentAuth } from "../terminal-auth-helpers.js";
import {
createSocks5Connection,
type SOCKS5Config,
} from "../utils/socks5-helper.js";
import { withConnection } from "./ssh-connection-pool.js";
import { resolveSshConnectConfigHost } from "./ssh-dns.js";
import { execCommand, tmuxCommand } from "./tmux-helper.js";
} from "../../utils/socks5-helper.js";
import { withConnection } from "../ssh-connection-pool.js";
import { resolveSshConnectConfigHost } from "../ssh-dns.js";
import { execCommand, tmuxCommand } from "./helper.js";
import {
SEP,
parseSessions,
@@ -37,8 +37,8 @@ import {
type TmuxSessionSummary,
type TmuxWindow,
type PaneMetrics,
} from "./tmux-monitor-helpers.js";
import type { SSHHost, AuthenticatedRequest } from "../../types/index.js";
} from "./monitor-helpers.js";
import type { SSHHost, AuthenticatedRequest } from "../../../types/index.js";
const PANE_ID_RE = /^%\d+$/;
// tmux session names cannot contain ":" or "."; keep to a conservative
@@ -124,7 +124,7 @@ export function connectToHost(host: SSHHost): () => Promise<Client> {
if (host.authType === "vault") {
const { setupVaultSshSignerAuth } =
await import("./vault-ssh-connect.js");
await import("../vault-ssh-connect.js");
await setupVaultSshSignerAuth(config, client, host);
}
@@ -1,9 +1,9 @@
import { Client, type ClientChannel } from "ssh2";
import type { WebSocket } from "ws";
import type { TunnelConfig } from "../../types/index.js";
import { createSocks5Connection } from "../utils/socks5-helper.js";
import { tunnelLogger } from "../utils/logger.js";
import { PermissionManager } from "../utils/permission-manager.js";
import type { TunnelConfig } from "../../../types/index.js";
import { createSocks5Connection } from "../../utils/socks5-helper.js";
import { tunnelLogger } from "../../utils/logger.js";
import { PermissionManager } from "../../utils/permission-manager.js";
import {
applyAuthOptions,
bindForwardIn,
@@ -11,12 +11,9 @@ import {
forwardOut,
getManagedTunnelAlgorithms,
unbindForwardIn,
} from "./tunnel-ssh-primitives.js";
import {
sendC2SMessage,
writeC2SRemoteChunk,
} from "./tunnel-c2s-relay-utils.js";
import { getTunnelMode } from "./tunnel-utils.js";
} from "./ssh-primitives.js";
import { sendC2SMessage, writeC2SRemoteChunk } from "./c2s-relay-utils.js";
import { getTunnelMode } from "./utils.js";
export type C2SOpenMessage = {
type: "open" | "test";
@@ -45,7 +42,7 @@ async function resolveC2STunnelSource(
throw new Error("Access denied to this host");
}
const { resolveHostById } = await import("./host-resolver.js");
const { resolveHostById } = await import("../host-resolver.js");
const resolvedHost = await resolveHostById(tunnelConfig.sourceHostId, userId);
if (!resolvedHost) {
throw new Error("Endpoint SSH host not found");
+2 -2
View File
@@ -12,12 +12,12 @@ import {
describeC2SRelayError,
extractRequestToken,
sendC2SError,
} from "../tunnel-c2s-relay-utils.js";
} from "./c2s-relay-utils.js";
import {
handleC2SRelayOpen,
handleC2SRelayTest,
type C2SOpenMessage,
} from "../tunnel-c2s-relay.js";
} from "./c2s-relay.js";
import { registerTunnelRoutes } from "./routes.js";
import { initializeAutoStartTunnels } from "./manager.js";
+3 -3
View File
@@ -31,7 +31,7 @@ import {
getManagedTunnelAlgorithms,
pipeTunnelStreams,
unbindForwardIn,
} from "../tunnel-ssh-primitives.js";
} from "./ssh-primitives.js";
import {
classifyTunnelError,
getTunnelBindHost,
@@ -39,10 +39,10 @@ import {
getTunnelMode,
getTunnelScope,
normalizeTunnelName,
} from "../tunnel-utils.js";
} from "./utils.js";
import { resolveSshConnectConfigHost } from "../ssh-dns.js";
import { handleSocks5Connect } from "../tunnel-socks5-relay.js";
import { handleSocks5Connect } from "./socks5-relay.js";
export const activeTunnels = new Map<string, Client>();
export const retryCounters = new Map<string, number>();
+1 -1
View File
@@ -12,7 +12,7 @@ import { SystemCrypto } from "../../utils/system-crypto.js";
import { AuthManager } from "../../utils/auth-manager.js";
import { PermissionManager } from "../../utils/permission-manager.js";
import { getTunnelMode, validateTunnelConfig } from "../tunnel-utils.js";
import { getTunnelMode, validateTunnelConfig } from "./utils.js";
import {
tunnelConfigs,
@@ -1,5 +1,5 @@
import type { Duplex } from "stream";
import { tunnelLogger } from "../utils/logger.js";
import { tunnelLogger } from "../../utils/logger.js";
function parseSocksAddress(buffer: Buffer): {
address: string;
@@ -1,7 +1,7 @@
import { Client, type ClientChannel } from "ssh2";
import type { Duplex } from "stream";
import { SSH_ALGORITHMS } from "../utils/ssh-algorithms.js";
import { tunnelLogger } from "../utils/logger.js";
import { SSH_ALGORITHMS } from "../../utils/ssh-algorithms.js";
import { tunnelLogger } from "../../utils/logger.js";
export function getManagedTunnelAlgorithms() {
return {
@@ -1,5 +1,5 @@
import type { ErrorType, TunnelConfig } from "../../types/index.js";
import { tunnelLogger } from "../utils/logger.js";
import type { ErrorType, TunnelConfig } from "../../../types/index.js";
import { tunnelLogger } from "../../utils/logger.js";
export function classifyTunnelError(errorMessage: string): ErrorType {
if (!errorMessage) return "UNKNOWN";