| const fs = require('fs-extra'); |
| const path = require('path'); |
|
|
| |
| const USERS_DIR = path.join(__dirname, 'users'); |
|
|
| |
| try { |
| fs.ensureDirSync(USERS_DIR); |
| console.log('β
Users directory ready'); |
| } catch (err) { |
| console.error('β Failed to setup users directory:', err); |
| process.exit(1); |
| } |
|
|
| |
| const express = require('express'); |
| const { spawn, exec } = require('child_process'); |
| const fs = require('fs-extra'); |
| const path = require('path'); |
| const app = express(); |
| const http = require('http').createServer(app); |
| const io = require('socket.io')(http); |
| const crypto = require('crypto'); |
| const fetch = require('node-fetch'); |
|
|
| |
| const PORT = process.env.PORT || 7860; |
| const USERS_DIR = path.join(__dirname, 'users'); |
| const SESSIONS_FILE = path.join(__dirname, 'sessions.json'); |
| const BANNED_FILE = path.join(__dirname, 'banned.json'); |
| const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || crypto.randomBytes(16).toString('hex'); |
|
|
| |
| fs.ensureDirSync(USERS_DIR); |
| if (!fs.existsSync(SESSIONS_FILE)) fs.writeFileSync(SESSIONS_FILE, '{}'); |
| if (!fs.existsSync(BANNED_FILE)) fs.writeFileSync(BANNED_FILE, '[]'); |
|
|
| |
| const activeProcesses = {}; |
|
|
| |
| app.use(express.static('public')); |
| app.use(express.json()); |
|
|
| |
| const loadBannedUsers = () => JSON.parse(fs.readFileSync(BANNED_FILE)); |
| const isBanned = (ip) => loadBannedUsers().includes(ip); |
|
|
| |
| io.on('connection', (socket) => { |
| const clientIp = socket.handshake.address; |
| console.log(`New connection from ${clientIp}`); |
|
|
| |
| if (isBanned(clientIp)) { |
| socket.emit('output', 'β You are banned from this service'); |
| socket.disconnect(true); |
| return; |
| } |
|
|
| |
| const sessionId = crypto.randomBytes(8).toString('hex'); |
| const sessionDir = path.join(USERS_DIR, sessionId); |
| |
| |
| fs.ensureDirSync(sessionDir); |
|
|
| |
| const sessions = JSON.parse(fs.readFileSync(SESSIONS_FILE)); |
| sessions[sessionId] = { |
| ip: clientIp, |
| createdAt: new Date().toISOString(), |
| lastActivity: new Date().toISOString() |
| }; |
| fs.writeFileSync(SESSIONS_FILE, JSON.stringify(sessions, null, 2)); |
|
|
| |
| socket.on('clone', (repoUrl) => { |
| if (!repoUrl.startsWith('https://github.com/')) { |
| return socket.emit('output', 'β Invalid GitHub repository URL'); |
| } |
|
|
| socket.emit('output', `π Cloning ${repoUrl}...`); |
| |
| |
| fs.emptyDirSync(sessionDir); |
|
|
| const gitClone = spawn('git', ['clone', repoUrl, '.'], { cwd: sessionDir }); |
|
|
| gitClone.stdout.on('data', (data) => socket.emit('output', data.toString())); |
| gitClone.stderr.on('data', (data) => socket.emit('output', data.toString())); |
|
|
| gitClone.on('close', (code) => { |
| if (code === 0) { |
| socket.emit('output', 'β
Repository cloned successfully!'); |
| socket.emit('clone-complete'); |
| } else { |
| socket.emit('output', 'β Failed to clone repository'); |
| } |
| }); |
| }); |
|
|
| |
| socket.on('install', (packageManager) => { |
| if (!['npm', 'yarn'].includes(packageManager)) { |
| return socket.emit('output', 'β Invalid package manager'); |
| } |
|
|
| socket.emit('output', `π¦ Installing dependencies with ${packageManager}...`); |
| |
| const installProcess = spawn(packageManager, ['install'], { cwd: sessionDir }); |
|
|
| installProcess.stdout.on('data', (data) => socket.emit('output', data.toString())); |
| installProcess.stderr.on('data', (data) => socket.emit('output', data.toString())); |
|
|
| installProcess.on('close', (code) => { |
| if (code === 0) { |
| socket.emit('output', 'β
Dependencies installed successfully!'); |
| } else { |
| socket.emit('output', 'β Failed to install dependencies'); |
| } |
| }); |
| }); |
|
|
| |
| socket.on('start', (command) => { |
| if (!command) return socket.emit('output', 'β No command provided'); |
| |
| |
| if (activeProcesses[sessionId]) { |
| activeProcesses[sessionId].kill(); |
| delete activeProcesses[sessionId]; |
| } |
|
|
| socket.emit('output', `π Starting: ${command}`); |
| |
| const [cmd, ...args] = command.split(' '); |
| const process = spawn(cmd, args, { cwd: sessionDir }); |
|
|
| activeProcesses[sessionId] = process; |
|
|
| process.stdout.on('data', (data) => socket.emit('output', data.toString())); |
| process.stderr.on('data', (data) => socket.emit('output', data.toString())); |
|
|
| process.on('close', (code) => { |
| socket.emit('output', `π΄ Process exited with code ${code}`); |
| delete activeProcesses[sessionId]; |
| }); |
| }); |
|
|
| |
| socket.on('pm2', (subcommand) => { |
| if (!['start', 'stop', 'restart', 'list', 'logs'].includes(subcommand)) { |
| return socket.emit('output', 'β Invalid PM2 command'); |
| } |
|
|
| socket.emit('output', `β‘ Executing: pm2 ${subcommand}`); |
| |
| const pm2Process = spawn('pm2', [subcommand], { cwd: sessionDir }); |
|
|
| pm2Process.stdout.on('data', (data) => socket.emit('output', data.toString())); |
| pm2Process.stderr.on('data', (data) => socket.emit('output', data.toString())); |
|
|
| pm2Process.on('close', (code) => { |
| socket.emit('output', `PM2 ${subcommand} completed with code ${code}`); |
| }); |
| }); |
|
|
| |
| socket.on('read-file', (filePath, callback) => { |
| const fullPath = path.join(sessionDir, filePath); |
| |
| fs.readFile(fullPath, 'utf8', (err, data) => { |
| if (err) return callback({ error: err.message }); |
| callback({ content: data }); |
| }); |
| }); |
|
|
| socket.on('write-file', ({ filePath, content }, callback) => { |
| const fullPath = path.join(sessionDir, filePath); |
| |
| fs.writeFile(fullPath, content, 'utf8', (err) => { |
| if (err) return callback({ error: err.message }); |
| callback({ success: true }); |
| }); |
| }); |
|
|
| |
| socket.on('list-files', (dirPath, callback) => { |
| const fullPath = path.join(sessionDir, dirPath || ''); |
| |
| fs.readdir(fullPath, (err, files) => { |
| if (err) return callback({ error: err.message }); |
| callback({ files }); |
| }); |
| }); |
|
|
| |
| socket.on('admin', ({ password, command }) => { |
| if (password !== ADMIN_PASSWORD) { |
| return socket.emit('output', 'β Invalid admin password'); |
| } |
|
|
| if (command === 'ban') { |
| const banned = loadBannedUsers(); |
| if (!banned.includes(clientIp)) { |
| banned.push(clientIp); |
| fs.writeFileSync(BANNED_FILE, JSON.stringify(banned)); |
| socket.emit('output', `β
Banned IP: ${clientIp}`); |
| } else { |
| socket.emit('output', 'β οΈ IP already banned'); |
| } |
| } |
| |
| }); |
|
|
| |
| socket.on('disconnect', () => { |
| console.log(`Client disconnected: ${clientIp}`); |
| |
| if (activeProcesses[sessionId]) { |
| activeProcesses[sessionId].kill(); |
| delete activeProcesses[sessionId]; |
| } |
| }); |
| }); |
|
|
| |
| http.listen(PORT, () => { |
| console.log(`π Server running on port ${PORT}`); |
| console.log(`π Admin password: ${ADMIN_PASSWORD}`); |
| }); |
|
|
| |
| process.on('uncaughtException', (err) => { |
| console.error('Uncaught Exception:', err); |
| }); |
|
|
| process.on('unhandledRejection', (reason, promise) => { |
| console.error('Unhandled Rejection at:', promise, 'reason:', reason); |
| }); |