require('./prototype.js') require('dotenv').config(); const express = require('express'); const http = require('http'); const axios = require("axios") const app = express(); const { spawn } = require('child_process') const path = require('path') const fs = require('fs') const FormData = require("form-data") const yts = require('yt-search') const { exec } = require("child_process") const util = require("util") const _exec = util.promisify(exec); const PORT = process.env.PORT || 7860; const PASSWORD = process.env.PASSWORD const { decrypt } = require('./lib/crypto.js') function getClientIP(req) { const trustedProxies = ['127.0.0.1', '::1']; const remoteAddress = req.connection.remoteAddress; const xForwardedFor = req.headers['x-forwarded-for']; if (trustedProxies.includes(remoteAddress) && xForwardedFor) { const forwardedIPs = xForwardedFor.split(',').map(ip => ip.trim()); return forwardedIPs[0] } else { return xForwardedFor ? xForwardedFor.split(',')[0].trim() : remoteAddress } } function auth(req, res, next) { const key = req.query.key; if (key !== PASSWORD) return res.status(403).json({ status: 403, message: 'Forbidden' }); next(); } app.use(express.json({limit: '50mb'})); app.use(express.urlencoded({limit: '50mb', extended: true, parameterLimit: 50000})); app.use((req, res, next) => { const startTime = Date.now(); const { method, url } = req; let ip = getClientIP(req) console.log(`\x1b[34m[${new Date().toISOString()}]\x1b[0m Incoming Request: \x1b[33m${method}\x1b[0m \x1b[36m${url}\x1b[0m from \x1b[32m${ip}\x1b[0m`); res.on('finish', () => { const duration = Date.now() - startTime; console.log(`\x1b[34m[${new Date().toISOString()}]\x1b[0m Response for \x1b[33m${method} ${url}\x1b[0m took \x1b[35m${duration}ms\x1b[0m - Status: \x1b[31m${res.statusCode}\x1b[0m`); }); next(); }); const fetchHandler = async (req, res) => { try { const url = req.body.url || req.query.url || req.params.url; const redirect = req.query.redirect; if (!url) return res.status(400).json({ error: 'URL is required!' }); const headers = { ...req.headers }; delete headers['host']; delete headers['connection']; delete headers['content-length']; const method = req.method.toUpperCase(); const isUrlEncoded = headers['content-type']?.includes('urlencoded'); const config = { method, headers, credentials: 'include', }; if (['POST', 'PUT', 'PATCH'].includes(method)) { config.body = isUrlEncoded ? new URLSearchParams(req.body) : JSON.stringify(req.body); } if (redirect) config.redirect = redirect; console.log(config); const response = await fetch(url, config); for (const [key, value] of response.headers.entries()) { if (["set-cookie", "authorization", "location"].includes(key.toLowerCase())) { res.setHeader(key, value); } } const contentType = response.headers.get('content-type'); if (contentType?.includes('text/event-stream')) { res.setHeader('Content-Type', contentType); res.setHeader('Cache-Control', 'no-cache'); res.setHeader('Connection', 'keep-alive'); res.status(response.status); if (response.body) { response.body.pipe(res); } else { res.end(); } return; } if (contentType?.includes('application/json')) { const data = await response.json(); return res.status(response.status).json(data); } const data = await response.text(); res.status(response.status).send(data); } catch (error) { console.error('Error during fetch:', error); res.status(500).json({ error: 'Failed to fetch the requested URL', details: error.message, }); } }; const axiosHandler = async (req, res) => { try { const url = req.body.url || req.query.url || req.params.url; const redirect = req.query.redirect; if (!url) return res.status(400).json({ error: 'URL is required!' }); const headers = { ...req.headers }; delete headers['host']; delete headers['connection']; delete headers['content-length']; let data = undefined; const method = req.method.toUpperCase(); const contentType = headers['content-type'] || ''; if (['POST', 'PUT', 'PATCH'].includes(method)) { if (contentType.includes('application/x-www-form-urlencoded')) { const urlEncoded = new URLSearchParams(req.body).toString(); data = urlEncoded; headers['content-type'] = 'application/x-www-form-urlencoded'; } else if (contentType.includes('multipart/form-data')) { const form = new FormData(); for (const key in req.body) { form.append(key, req.body[key]); } data = form; Object.assign(headers, form.getHeaders()); } else { data = req.body; headers['content-type'] = 'application/json'; } } const axiosConfig = { method, url, headers, data, maxRedirects: redirect === 'manual' ? 0 : 5, validateStatus: () => true, withCredentials: true, }; const response = await axios(axiosConfig); const forwardHeaders = ['set-cookie', 'authorization', 'location']; forwardHeaders.forEach((key) => { if (response.headers[key]) { res.setHeader(key, response.headers[key]); } }); const responseType = response.headers['content-type']; if (responseType?.includes('application/json')) { return res.status(response.status).json(response.data); } res.status(response.status).send(response.data); } catch (error) { console.error('Error during axios fetch:', error); res.status(500).json({ error: 'Failed to fetch the requested URL', details: error.message, }); } }; app.get("/api/forward/youtube/get", async (req, res) => { try { const v = decrypt(req.query.v) if (!v) return res.status(400).send("v is required"); const type = req.query.type; if (!type) return res.json("type is required!"); const token = decrypt(req.query.token); if (!token) return res.status(403).end(); let Token = await fetch(token).then(a => a.text()).then(a => a.un("utf16le").un("base64")) if (!["mp3", "mp4"].includes(type)) { return res.json({ status: false, msg: `Harap input type yang tersedia: mp3, mp4`, }); } let [id, t] = v.un("utf16le").un("charCode").un("base64").split("."); if (!id || !t || isNaN(t) || Date.now() - parseInt(t) >= 60000 * 5) { return res.status(403).end(); } const url = `http://www.youtube.com/watch?v=${id}`; const format = "mp4"// === "mp3" ? "bestaudio" : "bestvideo+bestaudio"; res.setHeader("Content-Type", type === "mp3" ? "audio/mpeg" : "video/mp4"); res.setHeader("Content-Disposition", `inline; filename="${id}.${type}"`); const ytdlp = spawn("yt-dlp", [ "-f", format, "-o", "-", "--add-header", `Cookie: ${Token}`, url, ]); let errorLog = ""; let stdoutChunks = []; ytdlp.stderr.on("data", (data) => { errorLog += data.toString(); console.error("yt-dlp stderr:", data.toString()); }); ytdlp.stdout.on("data", (chunk) => { stdoutChunks.push(chunk); }); ytdlp.on("error", (err) => { console.error("yt-dlp spawn error:", err); if (!res.headersSent) { res.status(500).json({ error: "yt-dlp failed to start." }); } else { res.end(); } }); ytdlp.on("close", (code) => { if (code !== 0) { const errorLine = errorLog.split("\n").find((line) => line.includes("ERROR:")); if (!res.headersSent) { res.status(500).json({ error: "Download failed", message: errorLine || `yt-dlp exited with code ${code}`, }); } else { res.end(); } } else { const finalBuffer = Buffer.concat(stdoutChunks); res.setHeader("Content-Type", "video/mp4"); res.send(finalBuffer); } }); } catch (err) { console.error(err); if (!res.headersSent) { res.status(500).json({ error: "Internal Server Error" }); } } }); async function handleE(req, res, action) { try { const q = req.method === 'POST' ? req.body.q : req.query.q; let result; if (action === 'eval') { result = await eval(q); } else if (action === 'exec') { const { stdout, stderr } = await _exec(q); result = stdout || stderr; } if (typeof result === 'object') { res.setHeader('Content-Type', 'application/json'); res.json(result); } else { res.setHeader('Content-Type', 'text/plain'); res.send(String(result)); } } catch (error) { res.status(500).json({ status: 500, message: `${action} error`, error: error.message }); } } app.all(['/api/proxy', '/proxy'], axiosHandler); app.use(['/api/fetch', '/fetch'], fetchHandler); app.get('/ev', auth, (req, res) => handleE(req, res, 'eval')); app.post('/ev', auth, (req, res) => handleE(req, res, 'eval')); app.get('/exec', auth, (req, res) => handleE(req, res, 'exec')); app.get('/restart', auth, (req, res) => { req.query.q = `node up ${req.headers.host.split('-')[0]}` handleE(req, res, 'exec') }); app.use((req, res, next) => { res.status(404).end() }); const server = http.createServer({ maxHeaderSize: 64 * 1024 }, app); server.listen(PORT, () => { console.log(`Server running on port ${PORT}`); });