chore: implement constants
This commit is contained in:
parent
13fd49e008
commit
5a65b6e91d
9 changed files with 122 additions and 38 deletions
15
app/app.js
15
app/app.js
|
@ -2,7 +2,6 @@
|
|||
// app/app.js
|
||||
|
||||
const express = require("express")
|
||||
const path = require("path")
|
||||
const config = require("./config")
|
||||
const socketHandler = require("./socket")
|
||||
const sshRoutes = require("./routes")
|
||||
|
@ -11,6 +10,7 @@ const { createServer, startServer } = require("./server")
|
|||
const { configureSocketIO } = require("./io")
|
||||
const { handleError, ConfigError } = require("./errors")
|
||||
const { createNamespacedDebug } = require("./logger")
|
||||
const { DEFAULTS, MESSAGES } = require("./constants")
|
||||
|
||||
const debug = createNamespacedDebug("app")
|
||||
|
||||
|
@ -23,14 +23,7 @@ function createApp() {
|
|||
|
||||
try {
|
||||
// Resolve the correct path to the webssh2_client module
|
||||
const clientPath = path.resolve(
|
||||
__dirname,
|
||||
"..",
|
||||
"node_modules",
|
||||
"webssh2_client",
|
||||
"client",
|
||||
"public"
|
||||
)
|
||||
const clientPath = DEFAULTS.WEBSSH2_CLIENT_PATH
|
||||
|
||||
// Apply middleware
|
||||
const { sessionMiddleware } = applyMiddleware(app, config)
|
||||
|
@ -43,7 +36,9 @@ function createApp() {
|
|||
|
||||
return { app: app, sessionMiddleware: sessionMiddleware }
|
||||
} catch (err) {
|
||||
throw new ConfigError(`Failed to configure Express app: ${err.message}`)
|
||||
throw new ConfigError(
|
||||
`${MESSAGES.EXPRESS_APP_CONFIG_ERROR}: ${err.message}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,13 +5,14 @@ const Ajv = require("ajv")
|
|||
const { deepMerge, generateSecureSecret } = require("./utils")
|
||||
const { createNamespacedDebug } = require("./logger")
|
||||
const { ConfigError, handleError } = require("./errors")
|
||||
const { DEFAULTS } = require("./constants")
|
||||
|
||||
const debug = createNamespacedDebug("config")
|
||||
|
||||
const defaultConfig = {
|
||||
listen: {
|
||||
ip: "0.0.0.0",
|
||||
port: 2222
|
||||
port: DEFAULTS.LISTEN_PORT
|
||||
},
|
||||
http: {
|
||||
origins: ["*:*"]
|
||||
|
@ -22,8 +23,8 @@ const defaultConfig = {
|
|||
},
|
||||
ssh: {
|
||||
host: null,
|
||||
port: 22,
|
||||
term: "xterm-color",
|
||||
port: DEFAULTS.SSH_PORT,
|
||||
term: DEFAULTS.SSH_TERM,
|
||||
readyTimeout: 20000,
|
||||
keepaliveInterval: 120000,
|
||||
keepaliveCountMax: 10
|
||||
|
@ -61,7 +62,7 @@ const defaultConfig = {
|
|||
compress: ["none", "zlib@openssh.com", "zlib"]
|
||||
},
|
||||
session: {
|
||||
secret: generateSecureSecret(),
|
||||
secret: process.env.WEBSSH_SESSION_SECRET || generateSecureSecret(),
|
||||
name: "webssh2.sid"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
const fs = require("fs")
|
||||
const path = require("path")
|
||||
const { createNamespacedDebug } = require("./logger")
|
||||
const { HTTP, MESSAGES, DEFAULTS } = require("./constants")
|
||||
|
||||
const debug = createNamespacedDebug("connectionHandler")
|
||||
/**
|
||||
|
@ -34,7 +35,9 @@ function handleFileRead(filePath, config, res) {
|
|||
// eslint-disable-next-line consistent-return
|
||||
fs.readFile(filePath, "utf8", function(err, data) {
|
||||
if (err) {
|
||||
return res.status(500).send("Error loading client file")
|
||||
return res
|
||||
.status(HTTP.INTERNAL_SERVER_ERROR)
|
||||
.send(MESSAGES.CLIENT_FILE_ERROR)
|
||||
}
|
||||
|
||||
const modifiedHtml = modifyHtml(data, config)
|
||||
|
@ -67,7 +70,7 @@ function handleConnection(req, res) {
|
|||
autoConnect: req.path.startsWith("/host/") // Automatically connect if path starts with /host/
|
||||
}
|
||||
|
||||
const filePath = path.join(clientPath, "client.htm")
|
||||
const filePath = path.join(clientPath, DEFAULTS.CLIENT_FILE)
|
||||
handleFileRead(filePath, tempConfig, res)
|
||||
}
|
||||
|
||||
|
|
77
app/constants.js
Normal file
77
app/constants.js
Normal file
|
@ -0,0 +1,77 @@
|
|||
// server
|
||||
// app/constants.js
|
||||
|
||||
const crypto = require("crypto")
|
||||
const path = require("path")
|
||||
|
||||
/**
|
||||
* Error messages
|
||||
*/
|
||||
const MESSAGES = {
|
||||
INVALID_CREDENTIALS: "Invalid credentials format",
|
||||
SSH_CONNECTION_ERROR: "SSH CONNECTION ERROR",
|
||||
SHELL_ERROR: "SHELL ERROR",
|
||||
CONFIG_ERROR: "CONFIG_ERROR",
|
||||
UNEXPECTED_ERROR: "An unexpected error occurred",
|
||||
EXPRESS_APP_CONFIG_ERROR: "Failed to configure Express app",
|
||||
CLIENT_FILE_ERROR: "Error loading client file"
|
||||
}
|
||||
|
||||
/**
|
||||
* Default values
|
||||
*/
|
||||
const DEFAULTS = {
|
||||
SSH_PORT: 22,
|
||||
LISTEN_PORT: 2222,
|
||||
SSH_TERM: "xterm-color",
|
||||
IO_PING_TIMEOUT: 60000, // 1 minute
|
||||
IO_PING_INTERVAL: 25000, // 25 seconds
|
||||
IO_PATH: "/ssh/socket.io",
|
||||
WEBSSH2_CLIENT_PATH: path.resolve(
|
||||
__dirname,
|
||||
"..",
|
||||
"node_modules",
|
||||
"webssh2_client",
|
||||
"client",
|
||||
"public"
|
||||
),
|
||||
CLIENT_FILE: "client.htm"
|
||||
}
|
||||
|
||||
/**
|
||||
* Socket events
|
||||
*/
|
||||
const SOCKET_EVENTS = {
|
||||
CONNECTION: "connection",
|
||||
DISCONNECT: "disconnect",
|
||||
AUTHENTICATE: "authenticate",
|
||||
AUTHENTICATION: "authentication",
|
||||
TERMINAL: "terminal",
|
||||
DATA: "data",
|
||||
RESIZE: "resize",
|
||||
CONTROL: "control"
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP Related
|
||||
*/
|
||||
const HTTP = {
|
||||
OK: 200,
|
||||
UNAUTHORIZED: 401,
|
||||
INTERNAL_SERVER_ERROR: 500,
|
||||
AUTHENTICATE: "WWW-Authenticate",
|
||||
REALM: 'Basic realm="WebSSH2"',
|
||||
AUTH_REQUIRED: "Authentication required.",
|
||||
COOKIE: "basicauth",
|
||||
PATH: "/ssh/host/",
|
||||
SAMESITE: "Strict",
|
||||
SESSION_SID: "webssh2_sid",
|
||||
CREDS_CLEARED: "Credentials cleared."
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
MESSAGES,
|
||||
DEFAULTS,
|
||||
SOCKET_EVENTS,
|
||||
HTTP
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
const util = require("util")
|
||||
const { logError, createNamespacedDebug } = require("./logger")
|
||||
const { HTTP, MESSAGES } = require("./constants")
|
||||
|
||||
const debug = createNamespacedDebug("errors")
|
||||
|
||||
|
@ -25,7 +26,7 @@ util.inherits(WebSSH2Error, Error)
|
|||
* @param {string} message - The error message
|
||||
*/
|
||||
function ConfigError(message) {
|
||||
WebSSH2Error.call(this, message, "CONFIG_ERROR")
|
||||
WebSSH2Error.call(this, message, MESSAGES.CONFIG_ERROR)
|
||||
}
|
||||
|
||||
util.inherits(ConfigError, WebSSH2Error)
|
||||
|
@ -35,7 +36,7 @@ util.inherits(ConfigError, WebSSH2Error)
|
|||
* @param {string} message - The error message
|
||||
*/
|
||||
function SSHConnectionError(message) {
|
||||
WebSSH2Error.call(this, message, "SSH_CONNECTION_ERROR")
|
||||
WebSSH2Error.call(this, message, MESSAGES.SSH_CONNECTION_ERROR)
|
||||
}
|
||||
|
||||
util.inherits(SSHConnectionError, WebSSH2Error)
|
||||
|
@ -50,13 +51,17 @@ function handleError(err, res) {
|
|||
logError(err.message, err)
|
||||
debug(err.message)
|
||||
if (res) {
|
||||
res.status(500).json({ error: err.message, code: err.code })
|
||||
res
|
||||
.status(HTTP.INTERNAL_SERVER_ERROR)
|
||||
.json({ error: err.message, code: err.code })
|
||||
}
|
||||
} else {
|
||||
logError("An unexpected error occurred", err)
|
||||
debug("Unexpected error: %O", err)
|
||||
logError(MESSAGES.UNEXPECTED_ERROR, err)
|
||||
debug(`handleError: ${MESSAGES.UNEXPECTED_ERROR}: %O`, err)
|
||||
if (res) {
|
||||
res.status(500).json({ error: "An unexpected error occurred" })
|
||||
res
|
||||
.status(HTTP.INTERNAL_SERVER_ERROR)
|
||||
.json({ error: MESSAGES.UNEXPECTED_ERROR })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
const socketIo = require("socket.io")
|
||||
const sharedsession = require("express-socket.io-session")
|
||||
const { createNamespacedDebug } = require("./logger")
|
||||
const { DEFAULTS } = require("./constants")
|
||||
|
||||
const debug = createNamespacedDebug("app")
|
||||
|
||||
|
@ -14,9 +15,9 @@ const debug = createNamespacedDebug("app")
|
|||
function configureSocketIO(server, sessionMiddleware, config) {
|
||||
const io = socketIo(server, {
|
||||
serveClient: false,
|
||||
path: "/ssh/socket.io",
|
||||
pingTimeout: 60000, // 1 minute
|
||||
pingInterval: 25000, // 25 seconds
|
||||
path: DEFAULTS.IO_PATH,
|
||||
pingTimeout: DEFAULTS.IO_PING_TIMEOUT,
|
||||
pingInterval: DEFAULTS.IO_PING_INTERVAL,
|
||||
cors: config.getCorsConfig()
|
||||
})
|
||||
|
||||
|
@ -27,7 +28,7 @@ function configureSocketIO(server, sessionMiddleware, config) {
|
|||
})
|
||||
)
|
||||
|
||||
debug("Socket.IO configured")
|
||||
debug("IO configured")
|
||||
|
||||
return io
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ function createNamespacedDebug(namespace) {
|
|||
function logError(message, error) {
|
||||
console.error(message)
|
||||
if (error) {
|
||||
console.error(`ERROR:\n\n ${error}`)
|
||||
console.error(`ERROR: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ const session = require("express-session")
|
|||
const bodyParser = require("body-parser")
|
||||
|
||||
const debug = createDebug("webssh2:middleware")
|
||||
const { HTTP } = require("./constants")
|
||||
|
||||
/**
|
||||
* Creates and configures session middleware
|
||||
|
@ -14,10 +15,10 @@ const debug = createDebug("webssh2:middleware")
|
|||
*/
|
||||
function createSessionMiddleware(config) {
|
||||
return session({
|
||||
secret: config.session.secret || "webssh2_secret",
|
||||
secret: config.session.secret,
|
||||
resave: false,
|
||||
saveUninitialized: true,
|
||||
name: config.session.name || "webssh2.sid"
|
||||
name: config.session.name
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -40,10 +41,10 @@ function createCookieMiddleware() {
|
|||
host: req.session.sshCredentials.host,
|
||||
port: req.session.sshCredentials.port
|
||||
}
|
||||
res.cookie("basicauth", JSON.stringify(cookieData), {
|
||||
res.cookie(HTTP.COOKIE, JSON.stringify(cookieData), {
|
||||
httpOnly: false,
|
||||
path: "/ssh/host/",
|
||||
sameSite: "Strict"
|
||||
path: HTTP.PATH,
|
||||
sameSite: HTTP.SAMESITE
|
||||
})
|
||||
}
|
||||
next()
|
||||
|
@ -63,7 +64,7 @@ function applyMiddleware(app, config) {
|
|||
app.use(createBodyParserMiddleware())
|
||||
app.use(createCookieMiddleware())
|
||||
|
||||
debug("Middleware applied")
|
||||
debug("applyMiddleware")
|
||||
|
||||
return { sessionMiddleware }
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// server
|
||||
// /app/routes.js
|
||||
// app/routes.js
|
||||
|
||||
const express = require("express")
|
||||
const basicAuth = require("basic-auth")
|
||||
|
@ -13,6 +13,7 @@ const {
|
|||
const handleConnection = require("./connectionHandler")
|
||||
const { createNamespacedDebug } = require("./logger")
|
||||
const { ConfigError, handleError } = require("./errors")
|
||||
const { HTTP } = require("./constants")
|
||||
|
||||
const debug = createNamespacedDebug("routes")
|
||||
const router = express.Router()
|
||||
|
@ -22,8 +23,8 @@ function auth(req, res, next) {
|
|||
debug("auth: Basic Auth")
|
||||
const credentials = basicAuth(req)
|
||||
if (!credentials) {
|
||||
res.setHeader("WWW-Authenticate", 'Basic realm="WebSSH2"')
|
||||
return res.status(401).send("Authentication required.")
|
||||
res.setHeader(HTTP.AUTHENTICATE, HTTP.REALM)
|
||||
return res.status(HTTP.UNAUTHORIZED).send(HTTP.AUTH_REQUIRED)
|
||||
}
|
||||
// Validate and sanitize credentials
|
||||
req.session.sshCredentials = {
|
||||
|
@ -75,12 +76,12 @@ router.get("/host/:host", auth, function(req, res) {
|
|||
// Clear credentials route
|
||||
router.get("/clear-credentials", function(req, res) {
|
||||
req.session.sshCredentials = null
|
||||
res.status(200).send("Credentials cleared.")
|
||||
res.status(HTTP.OK).send(HTTP.CREDENTIALS_CLEARED)
|
||||
})
|
||||
|
||||
router.get("/force-reconnect", function(req, res) {
|
||||
req.session.sshCredentials = null
|
||||
res.status(401).send("Authentication required.")
|
||||
res.status(HTTP.UNAUTHORIZED).send(HTTP.AUTH_REQUIRED)
|
||||
})
|
||||
|
||||
module.exports = router
|
||||
|
|
Loading…
Reference in a new issue