const smb2 = require("@awo00/smb2"); const express = require("express"); const crypto = require("crypto"); const SessionPool = require("./session_pool"); const utility = require("./utility"); require("./polyfill.js"); const host = process.argv[2]; if (!host) { console.error("Please provide a host as a command line argument."); process.exit(1); } const app = express(); const formMiddleware = express.urlencoded({ extended: true }); /** * @typedef {import("@awo00/smb2/dist/client/Session").default} Session */ /** * @type {SessionPool} */ const sessionPool = new SessionPool(60000); app.post("/", formMiddleware, async (req, res) => { try { const username = req.body.username; const password = req.body.password; const domain = req.body.domain; const client = new smb2.Client(host); const session = await client.authenticate({ username, password, domain }); const sessionId = crypto.randomUUID(); session.trees = {} sessionPool.createSession(sessionId, session, async (session) => await session.logoff()); res.setHeader("Content-Type", "application/json; charset=utf-8"); res.end(JSON.stringify({ "error": null, "sessionId": sessionId })); } catch (error) { res.status(500).json({ error: error.message }); res.end(); } }); // Define routes for file operations app.get("/:sessionId/:shareName/*", async (req, res) => { try { const sessionId = req.params.sessionId; const shareName = req.params.shareName; /** * @type {string} */ const filePath = "/" + req.params[0]; const session = sessionPool.getSession(sessionId); const tree = await utility.getTree(session, shareName); if (filePath.endsWith("/")) { const entries = await tree.readDirectory(filePath); res.json({ error: null, entries }); res.end(); } else { const readStream = await tree.createFileReadStream(filePath); readStream.pipe(res); readStream.on("error", (error) => { res.status(500).json({ error: error.message }); res.end(); }); } } catch (error) { res.status(500).json({ error: error.message }); res.end(); } }); app.post("/:sessionId/:shareName/*", async (req, res) => { try { const sessionId = req.params.sessionId; const shareName = req.params.shareName; /** * @type {string} */ const filePath = "/" + req.params[0]; const session = sessionPool.getSession(sessionId); const tree = await utility.getTree(session, shareName); // Check if the file already exists const fileExists = await tree.exists(filePath); // Check if the force parameter is provided in the form const force = req.query.force; if (fileExists && !force) { res.status(200).json({ error: null, exists: true }); res.end(); } else { // Create a write stream to the destination file if (fileExists) await tree.removeFile(filePath); const writeStream = await tree.createFileWriteStream(filePath); console.log("stream created"); // Pipe the uploaded file to the write stream req.pipe(writeStream); // Handle events for the write stream writeStream.on("finish", () => { res.json({ error: null }); res.end(); }); writeStream.on("error", (error) => { res.status(500).json({ error: error.message }); res.end(); }); } } catch (error) { console.error("upload error", error); res.status(500).json({ error: error.message }); res.end(); } }); app.put("/:sessionId/:shareName/*", async (req, res) => { try { const sessionId = req.params.sessionId; const shareName = req.params.shareName; /** * @type {string} */ const filePath = "/" + req.params[0]; const session = sessionPool.getSession(sessionId); const tree = await utility.getTree(session, shareName); // Check if the folder already exists const folderExists = await tree.exists(filePath); if (folderExists) { res.status(200).json({ error: null, exists: true }); res.end(); } else { // Create the folder await tree.createDirectory(filePath); res.json({ error: null }); res.end(); } } catch (error) { res.status(500).json({ error: error.message }); res.end(); } }); // Start the server const port = 8082; app.listen(port, () => { console.log(`Server is running on port ${port}`); });