diff --git a/server/proxy-server.js b/server/proxy-server.js index 5a3da28..0ae6d09 100644 --- a/server/proxy-server.js +++ b/server/proxy-server.js @@ -10,25 +10,41 @@ 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']; +const NSFW_THRESHOLD = 0.2; // Limiar para detecção de conteúdo explícito +const NSFW_CATEGORIES = ['porn', 'sexy', 'hentai', 'drawings', 'neutral', 'violence', 'gore']; -// Lista expandida de palavras-chave bloqueadas +// Lista de palavras-chave bloqueadas (baseada em filtros do Google, Instagram e Facebook) const BLOCKED_KEYWORDS = [ + // Palavras em português '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' + 'peito', 'bunda', 'pernas', 'lingerie', 'biquini', 'calcinha', 'cueca', + // Palavras relacionadas a golpes + 'golpe', 'scam', 'fraude', 'phishing', 'hack', 'crack', 'pirata', + 'pirataria', 'ilegal', 'contrabando', 'drogas', 'drogas ilícitas', + // Palavras de violência + 'violência', 'violencia', 'sangue', 'morte', 'assassinato', 'crime', + // Emojis e símbolos + '🔞', '🍆', '🍑', '🥒', '🥵', '💦', '👙', '👄', '💋', '💘', + // Termos do Instagram/Facebook + 'onlyfans', 'leaks', 'vazados', 'vazado', 'privado', 'privada', + 'conteúdo adulto', 'conteudo adulto', 'conteúdo +18', 'conteudo +18' ]; -// Lista expandida de domínios bloqueados +// Lista de domínios bloqueados const BLOCKED_DOMAINS = [ + // Sites adultos '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' + 'fling.com', 'adultmatchmaker.com', 'adultdating.com', 'adultchat.com', + // Sites de golpes + 'hack.com', 'crack.com', 'pirate.com', 'torrent.com', 'warez.com', + // Sites de conteúdo ilegal + 'illegal.com', 'drugs.com', 'weapons.com', 'hacking.com' ]; // Carrega o modelo NSFW @@ -43,41 +59,73 @@ async function loadModel() { } loadModel(); -// Função melhorada para verificar conteúdo NSFW +// Função 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); + const fileExt = path.extname(file.originalname).toLowerCase(); + const isImage = ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp'].includes(fileExt); + const isVideo = ['.mp4', '.avi', '.mov', '.wmv', '.flv', '.mkv', '.webm'].includes(fileExt); - // Libera a memória - image.dispose(); - - return nsfwScore > NSFW_THRESHOLD; + if (isImage) { + const image = await tf.node.decodeImage(file.buffer); + const predictions = await model.classify(image); + + const nsfwScore = predictions.reduce((score, pred) => { + if (NSFW_CATEGORIES.includes(pred.className)) { + return score + pred.probability; + } + return score; + }, 0); + + image.dispose(); + + return { + isNSFW: nsfwScore > NSFW_THRESHOLD, + score: nsfwScore, + type: 'image' + }; + } else if (isVideo) { + return { + isNSFW: isBlockedFilename(file.originalname), + score: 1.0, + type: 'video' + }; + } + + return { + isNSFW: false, + score: 0, + type: 'other' + }; } catch (error) { console.error('Erro ao verificar NSFW:', error); - return false; + return { + isNSFW: false, + score: 0, + type: 'error' + }; } } -// Função melhorada para verificar nome do arquivo +// Função para verificar nome do arquivo function isBlockedFilename(filename) { const lowerFilename = filename.toLowerCase(); return BLOCKED_KEYWORDS.some(keyword => lowerFilename.includes(keyword)); } -// Função melhorada para verificar URL +// Função para verificar URL function isBlockedUrl(url) { try { const urlObj = new URL(url); - return BLOCKED_DOMAINS.some(domain => urlObj.hostname.includes(domain)); + const lowerUrl = url.toLowerCase(); + + // Verifica domínios bloqueados + if (BLOCKED_DOMAINS.some(domain => urlObj.hostname.includes(domain))) { + return true; + } + + // Verifica palavras-chave na URL + return BLOCKED_KEYWORDS.some(keyword => lowerUrl.includes(keyword)); } catch { return false; } @@ -91,25 +139,52 @@ app.use(bodyParser.urlencoded({ extended: true })); app.post('/upload', upload.single('file'), async (req, res) => { try { if (!req.file) { - return res.status(400).json({ error: '🚫 CONTEÚDO BLOQUEADO' }); + return res.status(400).json({ + error: '🚫 CONTEÚDO BLOQUEADO', + message: 'Nenhum arquivo enviado' + }); } // Verifica o nome do arquivo if (isBlockedFilename(req.file.originalname)) { - return res.status(403).json({ error: '🚫 CONTEÚDO BLOQUEADO' }); + return res.status(403).json({ + error: '🚫 CONTEÚDO BLOQUEADO', + message: 'Este conteúdo pode ser sensível', + warning: true, + options: { + view: 'Ver conteúdo', + reject: 'Recusar' + } + }); } // Verifica o conteúdo do arquivo - const isNSFW = await checkNSFW(req.file); - if (isNSFW) { - return res.status(403).json({ error: '🚫 CONTEÚDO BLOQUEADO' }); + const nsfwCheck = await checkNSFW(req.file); + if (nsfwCheck.isNSFW) { + return res.status(403).json({ + error: '🚫 CONTEÚDO BLOQUEADO', + message: 'Este conteúdo pode ser sensível', + warning: true, + options: { + view: 'Ver conteúdo', + reject: 'Recusar' + }, + type: nsfwCheck.type, + score: nsfwCheck.score + }); } // Processa o arquivo normalmente - res.json({ message: 'Arquivo processado com sucesso' }); + res.json({ + message: 'Arquivo processado com sucesso', + type: nsfwCheck.type + }); } catch (error) { console.error('Erro no upload:', error); - res.status(500).json({ error: '🚫 CONTEÚDO BLOQUEADO' }); + res.status(500).json({ + error: '🚫 CONTEÚDO BLOQUEADO', + message: 'Erro ao processar arquivo' + }); } }); @@ -123,7 +198,15 @@ const proxy = createProxyMiddleware({ onProxyReq: (proxyReq, req, res) => { // Verifica URLs bloqueadas if (isBlockedUrl(req.url)) { - res.status(403).json({ error: '🚫 CONTEÚDO BLOQUEADO' }); + res.status(403).json({ + error: '🚫 CONTEÚDO BLOQUEADO', + message: 'Este conteúdo pode ser sensível', + warning: true, + options: { + view: 'Ver conteúdo', + reject: 'Recusar' + } + }); return; } }