mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-07-17 05:43:36 +00:00
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:
@@ -3,7 +3,7 @@ import express from "express";
|
||||
import type { Request, Response } from "express";
|
||||
import { databaseLogger } from "../../utils/logger.js";
|
||||
import { AuthManager } from "../../utils/auth-manager.js";
|
||||
import { sessionManager } from "../../hosts/terminal-session-manager.js";
|
||||
import { sessionManager } from "../../hosts/terminal/session-manager.js";
|
||||
import {
|
||||
getCurrentSettingValue,
|
||||
createCurrentOpenTabRepository,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,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;
|
||||
|
||||
|
||||
+3
-3
@@ -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>;
|
||||
+4
-4
@@ -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>;
|
||||
+4
-8
@@ -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,
|
||||
+4
-8
@@ -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
-1
@@ -1,4 +1,4 @@
|
||||
import { isWindowsSftpPath, sftpPathToLocalPath } from "./transfer-paths.js";
|
||||
import { isWindowsSftpPath, sftpPathToLocalPath } from "../transfer-paths.js";
|
||||
|
||||
export interface DeleteCommand {
|
||||
command: string;
|
||||
+4
-8
@@ -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
-2
@@ -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
-1
@@ -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"
|
||||
+3
-3
@@ -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";
|
||||
+2
-2
@@ -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";
|
||||
|
||||
+4
-4
@@ -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;
|
||||
+2
-2
@@ -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;
|
||||
+3
-3
@@ -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;
|
||||
+1
-1
@@ -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;
|
||||
+1
-1
@@ -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
-2
@@ -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");
|
||||
@@ -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";
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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;
|
||||
+2
-2
@@ -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";
|
||||
@@ -154,13 +154,13 @@ import {
|
||||
|
||||
const dbServer = await import("./database/database.js");
|
||||
await (dbServer as unknown as { serverReady: Promise<void> }).serverReady;
|
||||
await import("./hosts/terminal.js");
|
||||
await import("./hosts/terminal/index.js");
|
||||
await import("./hosts/tunnel/index.js");
|
||||
await import("./hosts/file-manager.js");
|
||||
await import("./hosts/host-metrics.js");
|
||||
await import("./hosts/file-manager/index.js");
|
||||
await import("./hosts/metrics/index.js");
|
||||
await import("./hosts/docker/index.js");
|
||||
await import("./hosts/docker/console.js");
|
||||
await import("./hosts/tmux-monitor.js"); // --- tmux-monitor ---
|
||||
await import("./hosts/tmux/index.js"); // --- tmux-monitor ---
|
||||
await import("./hosts/serial.js");
|
||||
await import("./services/dashboard.js");
|
||||
await import("./services/homepage.js");
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { buildDeleteCommand } from "../../hosts/file-manager-operation-commands.js";
|
||||
import { buildDeleteCommand } from "../../../hosts/file-manager/operation-commands.js";
|
||||
|
||||
describe("buildDeleteCommand", () => {
|
||||
it("builds a PowerShell 5.1 compatible delete command for Windows files", () => {
|
||||
+1
-1
@@ -6,7 +6,7 @@ import {
|
||||
getMimeType,
|
||||
detectBinary,
|
||||
parseLsDateToTimestamp,
|
||||
} from "../../hosts/file-manager-utils.js";
|
||||
} from "../../../hosts/file-manager/utils.js";
|
||||
|
||||
describe("isExecutableFile", () => {
|
||||
it("flags scripts with execute permission", () => {
|
||||
@@ -2,8 +2,8 @@ import { describe, it, expect } from "vitest";
|
||||
import {
|
||||
buildSudoCommand,
|
||||
shellSingleQuote,
|
||||
} from "../../../hosts/managers/exec-elevated.js";
|
||||
import { parsePlatformProbe } from "../../../hosts/managers/platform.js";
|
||||
} from "../../../hosts/metrics/managers/exec-elevated.js";
|
||||
import { parsePlatformProbe } from "../../../hosts/metrics/managers/platform.js";
|
||||
import {
|
||||
isValidSystemdUnit,
|
||||
isValidPid,
|
||||
@@ -15,47 +15,53 @@ import {
|
||||
isValidSignal,
|
||||
isValidServiceAction,
|
||||
isAllowedPath,
|
||||
} from "../../../hosts/managers/validation.js";
|
||||
} from "../../../hosts/metrics/managers/validation.js";
|
||||
import {
|
||||
parseServiceList,
|
||||
buildServiceActionCommand,
|
||||
} from "../../../hosts/managers/services.js";
|
||||
} from "../../../hosts/metrics/managers/services.js";
|
||||
import {
|
||||
parseProcessList,
|
||||
buildKillCommand,
|
||||
} from "../../../hosts/managers/processes.js";
|
||||
} from "../../../hosts/metrics/managers/processes.js";
|
||||
import {
|
||||
parseDfMounts,
|
||||
parseTopMemory,
|
||||
} from "../../../hosts/managers/simple-reads.js";
|
||||
} from "../../../hosts/metrics/managers/simple-reads.js";
|
||||
import {
|
||||
parseCrontab,
|
||||
serializeCrontab,
|
||||
isValidCronSchedule,
|
||||
buildApplyCrontabCommand,
|
||||
} from "../../../hosts/managers/cron.js";
|
||||
} from "../../../hosts/metrics/managers/cron.js";
|
||||
import {
|
||||
buildPackageActionCommand,
|
||||
parseUpgradable,
|
||||
buildListUpgradableCommand,
|
||||
} from "../../../hosts/managers/packages.js";
|
||||
} from "../../../hosts/metrics/managers/packages.js";
|
||||
import {
|
||||
buildIssueCommand,
|
||||
buildRenewCommand,
|
||||
buildRevokeCommand,
|
||||
isValidCertName,
|
||||
parseCertbotCertificates,
|
||||
} from "../../../hosts/managers/ssl.js";
|
||||
} from "../../../hosts/metrics/managers/ssl.js";
|
||||
import {
|
||||
buildIptablesRuleCommand,
|
||||
buildNftRuleCommand,
|
||||
} from "../../../hosts/managers/firewall.js";
|
||||
import { parsePasswd, parseSudoers } from "../../../hosts/managers/users.js";
|
||||
} from "../../../hosts/metrics/managers/firewall.js";
|
||||
import {
|
||||
parsePasswd,
|
||||
parseSudoers,
|
||||
} from "../../../hosts/metrics/managers/users.js";
|
||||
import {
|
||||
buildHealthCheckCommand,
|
||||
parseHealthResult,
|
||||
} from "../../../hosts/managers/health.js";
|
||||
import { buildTailCommand, clampLines } from "../../../hosts/managers/logs.js";
|
||||
} from "../../../hosts/metrics/managers/health.js";
|
||||
import {
|
||||
buildTailCommand,
|
||||
clampLines,
|
||||
} from "../../../hosts/metrics/managers/logs.js";
|
||||
|
||||
describe("exec-elevated", () => {
|
||||
it("single-quotes and escapes for the shell", () => {
|
||||
|
||||
+2
-2
@@ -4,8 +4,8 @@ import {
|
||||
supportsMetrics,
|
||||
isTcpPingEnabled,
|
||||
tcpPingThroughJumpHost,
|
||||
} from "../../hosts/host-metrics-helpers.js";
|
||||
import { createConnectionLog } from "../../hosts/connection-log.js";
|
||||
} from "../../../hosts/metrics/helpers.js";
|
||||
import { createConnectionLog } from "../../../hosts/connection-log.js";
|
||||
|
||||
describe("supportsMetrics", () => {
|
||||
it("supports plain ssh hosts", () => {
|
||||
+2
-2
@@ -1,14 +1,14 @@
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
|
||||
const execCommand = vi.fn();
|
||||
vi.mock("../../../hosts/widgets/common-utils.js", () => ({
|
||||
vi.mock("../../../../hosts/metrics/widgets/common-utils.js", () => ({
|
||||
execCommand: (...args: unknown[]) => execCommand(...args),
|
||||
}));
|
||||
|
||||
import {
|
||||
execElevated,
|
||||
ElevationError,
|
||||
} from "../../../hosts/managers/exec-elevated.js";
|
||||
} from "../../../../hosts/metrics/managers/exec-elevated.js";
|
||||
import type { Client } from "ssh2";
|
||||
|
||||
const fakeClient = {} as Client;
|
||||
+1
-1
@@ -2,7 +2,7 @@ import { describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
ConcurrentLimiter,
|
||||
HostPollCache,
|
||||
} from "../../hosts/host-metrics-state.js";
|
||||
} from "../../../hosts/metrics/state.js";
|
||||
|
||||
describe("ConcurrentLimiter", () => {
|
||||
it("never exceeds max concurrent runners", async () => {
|
||||
+4
-1
@@ -1,5 +1,8 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { toFixedNum, kibToGiB } from "../../../hosts/widgets/common-utils.js";
|
||||
import {
|
||||
toFixedNum,
|
||||
kibToGiB,
|
||||
} from "../../../../hosts/metrics/widgets/common-utils.js";
|
||||
|
||||
describe("toFixedNum", () => {
|
||||
it("rounds to the requested digit count", () => {
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { parseCpuLine } from "../../../hosts/widgets/cpu-collector.js";
|
||||
import { parseCpuLine } from "../../../../hosts/metrics/widgets/cpu-collector.js";
|
||||
|
||||
describe("parseCpuLine", () => {
|
||||
it("parses a standard /proc/stat cpu line", () => {
|
||||
+1
-1
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
parseSensorsOutput,
|
||||
parseSysfsThermalOutput,
|
||||
} from "../../../hosts/widgets/temperature-collector.js";
|
||||
} from "../../../../hosts/metrics/widgets/temperature-collector.js";
|
||||
|
||||
describe("temperature collectors", () => {
|
||||
it("parses sysfs thermal zone output", () => {
|
||||
+4
-4
@@ -4,18 +4,18 @@ import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
const mockCreate = vi.fn().mockResolvedValue({ id: 1 });
|
||||
const mockUpdateEnded = vi.fn().mockResolvedValue(undefined);
|
||||
|
||||
vi.mock("../../database/db/index.js", () => ({
|
||||
vi.mock("../../../database/db/index.js", () => ({
|
||||
getDb: () => ({}),
|
||||
}));
|
||||
|
||||
vi.mock("../../database/repositories/factory.js", () => ({
|
||||
vi.mock("../../../database/repositories/factory.js", () => ({
|
||||
createCurrentSessionRecordingRepository: () => ({
|
||||
create: mockCreate,
|
||||
updateEnded: mockUpdateEnded,
|
||||
}),
|
||||
}));
|
||||
|
||||
vi.mock("../../utils/logger.js", () => ({
|
||||
vi.mock("../../../utils/logger.js", () => ({
|
||||
sshLogger: {
|
||||
info: vi.fn(),
|
||||
warn: vi.fn(),
|
||||
@@ -50,7 +50,7 @@ vi.mock("fs", () => ({
|
||||
}));
|
||||
|
||||
const { sessionManager } =
|
||||
await import("../../hosts/terminal-session-manager.js");
|
||||
await import("../../../hosts/terminal/session-manager.js");
|
||||
|
||||
describe("TerminalSessionManager - session logging", () => {
|
||||
beforeEach(() => {
|
||||
+1
-1
@@ -5,7 +5,7 @@ import {
|
||||
detectTmux,
|
||||
tmuxCommand,
|
||||
withTmuxPath,
|
||||
} from "../../hosts/tmux-helper.js";
|
||||
} from "../../../hosts/tmux/helper.js";
|
||||
|
||||
describe("tmux command path handling", () => {
|
||||
it("adds common non-login shell tmux paths", () => {
|
||||
+1
-1
@@ -9,7 +9,7 @@ import {
|
||||
buildPaneMetrics,
|
||||
attachPanesToWindows,
|
||||
shellEscape,
|
||||
} from "../../hosts/tmux-monitor-helpers.js";
|
||||
} from "../../../hosts/tmux/monitor-helpers.js";
|
||||
|
||||
function join(...fields: (string | number)[]): string {
|
||||
return fields.join(SEP);
|
||||
Reference in New Issue
Block a user