cors / index.js
Rifd's picture
changed
6bc1af4
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}`);
});