From 472be801d9e5463b2ffef220e8e755a2020a6567 Mon Sep 17 00:00:00 2001 From: ErikrafT <139592038+erikraft@users.noreply.github.com> Date: Tue, 6 May 2025 21:01:40 -0300 Subject: [PATCH] Update proxy-server.js --- server/proxy-server.js | 329 ++++++++++++++++------------------------- 1 file changed, 128 insertions(+), 201 deletions(-) diff --git a/server/proxy-server.js b/server/proxy-server.js index fcf836d..5a3da28 100644 --- a/server/proxy-server.js +++ b/server/proxy-server.js @@ -1,210 +1,137 @@ -const express = require('express'); -const { createProxyMiddleware } = require('http-proxy-middleware'); -const bodyParser = require('body-parser'); -const multer = require('multer'); -const tf = require('@tensorflow/tfjs-node'); -const fs = require('fs'); -const path = require('path'); +import express from 'express'; +import { createProxyMiddleware } from 'http-proxy-middleware'; +import multer from 'multer'; +import bodyParser from 'body-parser'; +import * as tf from '@tensorflow/tfjs-node'; +import fs from 'fs'; +import path from 'path'; -class ProxyServer { - constructor() { - this.app = express(); - this.port = process.env.PROXY_PORT || 3001; - this.nsfwModel = null; - this.setupMiddleware(); - this.setupRoutes(); - this.initNSFWModel(); +const app = express(); +const upload = multer({ storage: multer.memoryStorage() }); + +// Configurações do modelo NSFW +const NSFW_THRESHOLD = 0.3; // Reduzido para ser mais sensível +const NSFW_CATEGORIES = ['porn', 'sexy', 'hentai', 'drawings', 'neutral']; + +// Lista expandida de palavras-chave bloqueadas +const BLOCKED_KEYWORDS = [ + 'porn', 'sex', 'xxx', 'adult', 'nude', 'naked', 'nsfw', '18+', + 'pornografia', 'sexo', 'adulto', 'nu', 'nua', 'nudez', 'erótico', + 'erotico', 'sensual', 'proibido', 'proibida', 'privado', 'privada', + 'intimo', 'íntimo', 'intima', 'íntima', 'mulher', 'homem', 'corpo', + 'peito', 'bunda', 'pernas', 'lingerie', 'biquini', 'calcinha', 'cueca' +]; + +// Lista expandida de domínios bloqueados +const BLOCKED_DOMAINS = [ + 'pornhub.com', 'xvideos.com', 'xnxx.com', 'redtube.com', + 'youporn.com', 'xhamster.com', 'brazzers.com', 'onlyfans.com', + 'chaturbate.com', 'myfreecams.com', 'stripchat.com', 'bongacams.com', + 'cam4.com', 'streamate.com', 'adultfriendfinder.com', 'ashleymadison.com', + 'fling.com', 'adultmatchmaker.com', 'adultdating.com', 'adultchat.com' +]; + +// Carrega o modelo NSFW +let model; +async function loadModel() { + try { + model = await tf.loadLayersModel('file://./model/model.json'); + console.log('Modelo NSFW carregado com sucesso'); + } catch (error) { + console.error('Erro ao carregar modelo NSFW:', error); } +} +loadModel(); - async initNSFWModel() { - try { - // Carrega o modelo NSFW do TensorFlow.js - this.nsfwModel = await tf.loadGraphModel('https://d1zv2aa70wpiur.cloudfront.net/tfjs_models/tfjs_nsfw_mobilenet/model.json'); - console.log('Modelo NSFW carregado com sucesso'); - } catch (error) { - console.error('Erro ao carregar modelo NSFW:', error); - } - } - - setupMiddleware() { - // Configuração do multer para upload de arquivos - const storage = multer.diskStorage({ - destination: (req, file, cb) => { - const uploadDir = path.join(__dirname, '../uploads'); - if (!fs.existsSync(uploadDir)) { - fs.mkdirSync(uploadDir, { recursive: true }); - } - cb(null, uploadDir); - }, - filename: (req, file, cb) => { - cb(null, Date.now() + '-' + file.originalname); +// Função melhorada para verificar conteúdo NSFW +async function checkNSFW(file) { + try { + const image = await tf.node.decodeImage(file.buffer); + const predictions = await model.classify(image); + + // Verifica todas as categorias NSFW + const nsfwScore = predictions.reduce((score, pred) => { + if (NSFW_CATEGORIES.includes(pred.className)) { + return score + pred.probability; } - }); + return score; + }, 0); - this.upload = multer({ storage: storage }); - - // Middleware para análise de conteúdo - this.app.use(bodyParser.json()); - this.app.use(bodyParser.urlencoded({ extended: true })); - } - - setupRoutes() { - // Rota para verificar conteúdo - this.app.post('/check-content', this.upload.single('file'), async (req, res) => { - try { - if (!req.file) { - return res.status(400).json({ error: 'Nenhum arquivo enviado' }); - } - - const result = await this.checkContent(req.file); - res.json(result); - } catch (error) { - console.error('Erro ao verificar conteúdo:', error); - res.status(500).json({ error: 'Erro ao processar arquivo' }); - } - }); - - // Rota para verificar URL - this.app.post('/check-url', async (req, res) => { - try { - const { url } = req.body; - if (!url) { - return res.status(400).json({ error: 'URL não fornecida' }); - } - - const result = await this.checkUrl(url); - res.json(result); - } catch (error) { - console.error('Erro ao verificar URL:', error); - res.status(500).json({ error: 'Erro ao processar URL' }); - } - }); - - // Configuração do proxy - this.app.use('/', createProxyMiddleware({ - target: 'http://localhost:3000', - changeOrigin: true, - onProxyReq: async (proxyReq, req, res) => { - // Verifica URLs suspeitas - if (req.url.includes('http')) { - const isBlocked = await this.checkUrl(req.url); - if (isBlocked) { - res.status(403).json({ - error: 'Conteúdo bloqueado', - reason: 'URL suspeita detectada' - }); - return; - } - } - } - })); - } - - async checkContent(file) { - // Verifica o nome do arquivo - const fileName = file.originalname.toLowerCase(); - const blockedWords = [ - 'porn', 'sex', 'nude', 'nudes', 'onlyfans', 'leaks', 'hentai', - '🔞', '🍆', '🍑', '🥒', '🥵', 'PORN', 'Pornografia' - ]; - - if (blockedWords.some(word => fileName.includes(word))) { - return { - blocked: true, - reason: 'Nome do arquivo contém termos impróprios' - }; - } - - // Verifica o conteúdo do arquivo - if (file.mimetype.startsWith('image/')) { - return await this.checkImageContent(file.path); - } else if (file.mimetype.startsWith('video/')) { - return await this.checkVideoContent(file.path); - } - - return { blocked: false }; - } - - async checkImageContent(filePath) { - if (!this.nsfwModel) return { blocked: false }; - - try { - const imageBuffer = fs.readFileSync(filePath); - const tfImage = tf.node.decodeImage(imageBuffer); - const resized = tf.image.resizeBilinear(tfImage, [224, 224]); - const expanded = resized.expandDims(0); - const normalized = expanded.div(255.0); - - const predictions = await this.nsfwModel.predict(normalized).data(); - - tfImage.dispose(); - resized.dispose(); - expanded.dispose(); - normalized.dispose(); - - const nsfwScore = predictions[1]; - return { - blocked: nsfwScore > 0.5, - reason: nsfwScore > 0.5 ? 'Conteúdo impróprio detectado' : null, - score: nsfwScore - }; - } catch (error) { - console.error('Erro ao verificar imagem:', error); - return { blocked: false }; - } - } - - async checkVideoContent(filePath) { - if (!this.nsfwModel) return { blocked: false }; - - try { - // Aqui você pode implementar a verificação de frames do vídeo - // Por enquanto, vamos apenas verificar o nome do arquivo - return { blocked: false }; - } catch (error) { - console.error('Erro ao verificar vídeo:', error); - return { blocked: false }; - } - } - - async checkUrl(url) { - const blockedDomains = [ - 'pornhub.com', 'xvideos.com', 'xnxx.com', 'redtube.com', - 'onlyfans.com', 'xhamster.com', 'brazzers.com' - ]; - - const blockedKeywords = [ - 'porn', 'sex', 'nude', 'nudes', 'onlyfans', 'leaks', 'hentai' - ]; - - // Verifica domínios bloqueados - if (blockedDomains.some(domain => url.includes(domain))) { - return { - blocked: true, - reason: 'Domínio bloqueado' - }; - } - - // Verifica palavras-chave bloqueadas - if (blockedKeywords.some(keyword => url.toLowerCase().includes(keyword))) { - return { - blocked: true, - reason: 'URL contém termos impróprios' - }; - } - - return { blocked: false }; - } - - start() { - this.app.listen(this.port, () => { - console.log(`Servidor proxy rodando na porta ${this.port}`); - }); + // Libera a memória + image.dispose(); + + return nsfwScore > NSFW_THRESHOLD; + } catch (error) { + console.error('Erro ao verificar NSFW:', error); + return false; } } -// Inicia o servidor -const proxyServer = new ProxyServer(); -proxyServer.start(); +// Função melhorada para verificar nome do arquivo +function isBlockedFilename(filename) { + const lowerFilename = filename.toLowerCase(); + return BLOCKED_KEYWORDS.some(keyword => lowerFilename.includes(keyword)); +} -module.exports = ProxyServer; +// Função melhorada para verificar URL +function isBlockedUrl(url) { + try { + const urlObj = new URL(url); + return BLOCKED_DOMAINS.some(domain => urlObj.hostname.includes(domain)); + } catch { + return false; + } +} + +// Middleware para verificar conteúdo +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); + +// Rota para upload de arquivos +app.post('/upload', upload.single('file'), async (req, res) => { + try { + if (!req.file) { + return res.status(400).json({ error: '🚫 CONTEÚDO BLOQUEADO' }); + } + + // Verifica o nome do arquivo + if (isBlockedFilename(req.file.originalname)) { + return res.status(403).json({ error: '🚫 CONTEÚDO BLOQUEADO' }); + } + + // Verifica o conteúdo do arquivo + const isNSFW = await checkNSFW(req.file); + if (isNSFW) { + return res.status(403).json({ error: '🚫 CONTEÚDO BLOQUEADO' }); + } + + // Processa o arquivo normalmente + res.json({ message: 'Arquivo processado com sucesso' }); + } catch (error) { + console.error('Erro no upload:', error); + res.status(500).json({ error: '🚫 CONTEÚDO BLOQUEADO' }); + } +}); + +// Configuração do proxy +const proxy = createProxyMiddleware({ + target: 'http://localhost:3000', + changeOrigin: true, + pathRewrite: { + '^/api': '' + }, + onProxyReq: (proxyReq, req, res) => { + // Verifica URLs bloqueadas + if (isBlockedUrl(req.url)) { + res.status(403).json({ error: '🚫 CONTEÚDO BLOQUEADO' }); + return; + } + } +}); + +app.use('/api', proxy); + +const PORT = process.env.PORT || 3001; +app.listen(PORT, () => { + console.log(`Servidor proxy rodando na porta ${PORT}`); +});