From 75e333c470d136386003cde11239f9caa16963d1 Mon Sep 17 00:00:00 2001 From: Shakaos Date: Wed, 29 Apr 2026 01:14:54 +0000 Subject: [PATCH] Enviar arquivos para "/" --- authMiddleware.js | 79 +++++++++++++ db.js | 48 ++++---- libraryController.js | 258 ++++++++++++++++++++++--------------------- libraryModel.js | 66 +++++------ libraryRoutes.js | 53 ++++----- 5 files changed, 294 insertions(+), 210 deletions(-) create mode 100644 authMiddleware.js diff --git a/authMiddleware.js b/authMiddleware.js new file mode 100644 index 0000000..cfed2ec --- /dev/null +++ b/authMiddleware.js @@ -0,0 +1,79 @@ +// filepath: config/authMiddleware.js +const jwt = require('jsonwebtoken'); +const crypto = require('crypto'); + +// Middleware para validar o token JWT nas requisições +const authenticateToken = (req, res, next) => { + // Pega o token do header Authorization + const authHeader = req.headers['authorization']; + const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN + + if (!token) { + return res.status(401).json({ + error: 'Acesso negado. Token não fornecido.' + }); + } + + // Decodifica o token sem verificar para detectar o algoritmo + const decoded = jwt.decode(token, { complete: true }); + const algorithm = decoded?.header?.alg || 'HS256'; + + // Converte a chave pública PEM de string multilinha para formato de linha única + const publicKeyPEM = process.env.JWT_PUBLIC_KEY_PEM + ? process.env.JWT_PUBLIC_KEY_PEM.replace(/\\n/g, '\n') + : null; + + // Opções de verificação do token + const verifyOptions = { + issuer: process.env.JWT_ISSUER, + audience: process.env.JWT_AUDIENCE, + }; + + // Detecta o algoritmo e usa a chave correta + if (algorithm === 'RS256' || algorithm === 'RS384' || algorithm === 'RS512') { + // Usa chave pública para RS256 + if (!publicKeyPEM) { + return res.status(500).json({ + error: 'Configuração erro: chave pública não configurada.' + }); + } + verifyOptions.algorithms = ['RS256']; + jwt.verify(token, publicKeyPEM, verifyOptions, (err, user) => { + if (err) { + return res.status(403).json({ + error: 'Token inválido ou expirado.', + details: err.message + }); + } + // Define req.auth com id do payload e o token + req.auth = { + id: user.sub || user.id, + token + }; + next(); + }); + } else if (algorithm === 'HS256' || algorithm === 'HS384' || algorithm === 'HS512') { + // Usa JWT_SECRET para HS256 + verifyOptions.algorithms = ['HS256']; + jwt.verify(token, process.env.JWT_SECRET, verifyOptions, (err, user) => { + if (err) { + return res.status(403).json({ + error: 'Token inválido ou expirado.', + details: err.message + }); + } + // Define req.auth com id do payload e o token + req.auth = { + id: user.sub || user.id, + token + }; + next(); + }); + } else { + return res.status(400).json({ + error: 'Algoritmo não suportado: ' + algorithm + }); + } +}; + +module.exports = { authenticateToken }; \ No newline at end of file diff --git a/db.js b/db.js index 53cdb2e..6190161 100644 --- a/db.js +++ b/db.js @@ -1,24 +1,24 @@ -const mysql = require('mysql2'); - -// Aqui está a configuração da nossa conexão com o banco de dados! -// Cada microsserviço tem seu próprio banco, lembra? Isso garante independência. -// Estou usando MySQL porque é confiável e funciona bem com Node.js. -const connection = mysql.createConnection({ - host: 'localhost', // O banco roda na mesma máquina - user: 'root', // Usuário padrão do MySQL - password: '', // Sem senha para desenvolvimento local - database: 'gameverse_library' // Nosso banco exclusivo da biblioteca -}); - -// Esta função tenta conectar ao banco quando o serviço inicia. -// Se der erro, a gente sabe que tem problema na configuração do MySQL. -connection.connect((err) => { - if (err) { - console.error('Erro ao conectar:', err); - return; - } - console.log('Banco conectado!'); -}); - -// Exportamos a conexão para usar em outros arquivos, principalmente no model. -module.exports = connection; +const mysql = require('mysql2'); + +// Aqui está a configuração da nossa conexão com o banco de dados! +// Cada microsserviço tem seu próprio banco, lembra? Isso garante independência. +// Estou usando MySQL porque é confiável e funciona bem com Node.js. +const connection = mysql.createConnection({ + host: 'localhost', // O banco roda na mesma máquina + user: 'root', // Usuário padrão do MySQL + password: '', // Sem senha para desenvolvimento local + database: 'gameverse_library' // Nosso banco exclusivo da biblioteca +}); + +// Esta função tenta conectar ao banco quando o serviço inicia. +// Se der erro, a gente sabe que tem problema na configuração do MySQL. +connection.connect((err) => { + if (err) { + console.error('Erro ao conectar:', err); + return; + } + console.log('Banco conectado!'); +}); + +// Exportamos a conexão para usar em outros arquivos, principalmente no model. +module.exports = connection; diff --git a/libraryController.js b/libraryController.js index dfa3b31..49cd2fd 100644 --- a/libraryController.js +++ b/libraryController.js @@ -1,127 +1,131 @@ -const model = require('../models/libraryModel'); - -// Este é o "cérebro" do nosso microsserviço! -// O controller recebe as requisições HTTP, valida os dados, -// chama as funções do model e retorna respostas apropriadas. -// É como o gerente que coordena tudo. - -// Função para adicionar um item manualmente à biblioteca. -// Pode ser usado para correções ou imports especiais. -exports.addItem = (req, res) => { - // Validação básica dos dados obrigatórios - const { user_id, type, item_id, title } = req.body; - - if (!user_id || !type || !item_id || !title) { - return res.json({ - success: false, - message: 'Dados obrigatórios faltando: user_id, type, item_id, title' - }); - } - - // Só aceitamos tipos válidos para manter consistência - if (!['game', 'gift_card'].includes(type)) { - return res.json({ - success: false, - message: 'Tipo inválido. Use "game" ou "gift_card"' - }); - } - - // Chama o model para adicionar o item - model.addItem(req.body, (err) => { - if (err) { - return res.json({ - success: false, - error: err, - message: 'Erro ao adicionar item à biblioteca' - }); - } - - res.json({ - success: true, - message: 'Item adicionado à biblioteca com sucesso!' - }); - }); -}; - -// Função que retorna toda a biblioteca de um usuário. -// É chamada quando o usuário abre sua página de biblioteca. -exports.getLibrary = (req, res) => { - const user_id = req.params.user_id; - - // Validação do ID do usuário - if (!user_id || isNaN(user_id)) { - return res.json({ - success: false, - message: 'ID do usuário inválido' - }); - } - - // Busca todos os itens do usuário - model.getUserLibrary(user_id, (err, results) => { - if (err) { - return res.json({ - success: false, - error: err, - message: 'Erro ao buscar biblioteca' - }); - } - - res.json({ - success: true, - data: results, - message: `Encontrados ${results.length} itens na biblioteca` - }); - }); -}; - -// Esta é a função mais importante para integração! -// É chamada AUTOMATICAMENTE pelo serviço de pagamentos quando uma compra é aprovada. -// Garante que o usuário receba seu jogo/gift card na biblioteca. -exports.paymentApproved = (req, res) => { - const data = req.body; - - // Validações rigorosas pois isso vem de outro serviço - const { user_id, type, item_id, title } = data; - - if (!user_id || !type || !item_id || !title) { - return res.json({ - success: false, - message: 'Dados de pagamento incompletos' - }); - } - - // Primeiro verifica se o usuário já tem esse item (evita duplicatas) - model.checkItem(user_id, item_id, (err, results) => { - if (err) { - return res.json({ - success: false, - error: err, - message: 'Erro ao verificar item existente' - }); - } - - // Se já tem, informa que não precisa adicionar novamente - if (results.length > 0) { - return res.json({ - success: false, - message: 'Usuário já possui este item em sua biblioteca' - }); - } - - // Se não tem, adiciona o item - model.addItem(data, (err) => { - if (err) { - return res.json({ - success: false, - error: err, - message: 'Erro ao adicionar item após pagamento' - }); - } - - res.json({ - success: true, - message: 'Pagamento aprovado! Item adicionado à biblioteca.' - }); - }); - }); -}; +const model = require('../models/libraryModel'); + +// Este é o "cérebro" do nosso microsserviço! +// O controller recebe as requisições HTTP, valida os dados, +// chama as funções do model e retorna respostas apropriadas. +// É como o gerente que coordena tudo. + +// Função para adicionar um item manualmente à biblioteca. +// Pode ser usado para correções ou imports especiais. +exports.addItem = (req, res) => { + // Usa o user_id do token JWT para segurança (req.auth) + const user_id = req.auth?.id; + + // Validação básica dos dados obrigatórios + const { type, item_id, title } = req.body; + + if (!user_id || !type || !item_id || !title) { + return res.json({ + success: false, + message: 'Dados obrigatórios faltando: user_id, type, item_id, title' + }); + } + + // Só aceitamos tipos válidos para manter consistência + if (!['game', 'gift_card'].includes(type)) { + return res.json({ + success: false, + message: 'Tipo inválido. Use "game" ou "gift_card"' + }); + } + + // Chama o model para adicionar o item + model.addItem({ user_id, type, item_id, title }, (err) => { + if (err) { + return res.json({ + success: false, + error: err, + message: 'Erro ao adicionar item à biblioteca' + }); + } + + res.json({ + success: true, + message: 'Item adicionado à biblioteca com sucesso!' + }); + }); +}; + +// Função que retorna toda a biblioteca de um usuário. +// É chamada quando o usuário abre sua página de biblioteca. +exports.getLibrary = (req, res) => { + // Usa o user_id do token JWT para segurança (req.auth) + const user_id = req.auth?.id; + + // Validação do ID do usuário + if (!user_id || isNaN(user_id)) { + return res.json({ + success: false, + message: 'ID do usuário inválido' + }); + } + + // Busca todos os itens do usuário + model.getUserLibrary(user_id, (err, results) => { + if (err) { + return res.json({ + success: false, + error: err, + message: 'Erro ao buscar biblioteca' + }); + } + + res.json({ + success: true, + data: results, + message: `Encontrados ${results.length} itens na biblioteca` + }); + }); +}; + +// Esta é a função mais importante para integração! +// É chamada AUTOMATICAMENTE pelo serviço de pagamentos quando uma compra é aprovada. +// Garante que o usuário receba seu jogo/gift card na biblioteca. +exports.paymentApproved = (req, res) => { + const data = req.body; + + // Validações rigorosas pois isso vem de outro serviço + const { user_id, type, item_id, title } = data; + + if (!user_id || !type || !item_id || !title) { + return res.json({ + success: false, + message: 'Dados de pagamento incompletos' + }); + } + + // Primeiro verifica se o usuário já tem esse item (evita duplicatas) + model.checkItem(user_id, item_id, (err, results) => { + if (err) { + return res.json({ + success: false, + error: err, + message: 'Erro ao verificar item existente' + }); + } + + // Se já tem, informa que não precisa adicionar novamente + if (results.length > 0) { + return res.json({ + success: false, + message: 'Usuário já possui este item em sua biblioteca' + }); + } + + // Se não tem, adiciona o item + model.addItem(data, (err) => { + if (err) { + return res.json({ + success: false, + error: err, + message: 'Erro ao adicionar item após pagamento' + }); + } + + res.json({ + success: true, + message: 'Pagamento aprovado! Item adicionado à biblioteca.' + }); + }); + }); +}; diff --git a/libraryModel.js b/libraryModel.js index dbad0d7..2a909b1 100644 --- a/libraryModel.js +++ b/libraryModel.js @@ -1,33 +1,33 @@ -const db = require('../config/db'); - -// Este arquivo é o nosso "guarda-roupa" - aqui guardamos todas as funções -// que interagem diretamente com o banco de dados da biblioteca. -// Seguimos o padrão MVC: Model lida com dados, Controller com lógica, View com apresentação. - -// Função para adicionar um item (jogo ou gift card) à biblioteca do usuário. -// É chamada quando um pagamento é aprovado ou quando queremos adicionar manualmente. -exports.addItem = (data, callback) => { - // SQL preparado para evitar injeção de código malicioso - // Campos: user_id (quem comprou), type (jogo ou gift card), item_id (ID do item), - // title (nome do jogo/gift), platform (onde roda ou vale) - const sql = `INSERT INTO users_library (user_id, type, item_id, title, platform) - VALUES (?, ?, ?, ?, ?)`; - - // Executa a query com os dados sanitizados - db.query(sql, [data.user_id, data.type, data.item_id, data.title, data.platform], callback); -}; - -// Função que busca TODOS os itens da biblioteca de um usuário específico. -// É usada quando o usuário quer ver sua coleção completa. -exports.getUserLibrary = (user_id, callback) => { - // Query simples mas eficiente - busca tudo do usuário - db.query('SELECT * FROM users_library WHERE user_id = ?', [user_id], callback); -}; - -// Função importante para evitar duplicatas! -// Antes de adicionar um item, verificamos se o usuário já não o tem. -// Isso evita que alguém compre o mesmo jogo duas vezes por acidente. -exports.checkItem = (user_id, item_id, callback) => { - // Busca se existe algum registro com esse usuário e item - db.query('SELECT * FROM users_library WHERE user_id = ? AND item_id = ?', [user_id, item_id], callback); -}; +const db = require('../config/db'); + +// Este arquivo é o nosso "guarda-roupa" - aqui guardamos todas as funções +// que interagem diretamente com o banco de dados da biblioteca. +// Seguimos o padrão MVC: Model lida com dados, Controller com lógica, View com apresentação. + +// Função para adicionar um item (jogo ou gift card) à biblioteca do usuário. +// É chamada quando um pagamento é aprovado ou quando queremos adicionar manualmente. +exports.addItem = (data, callback) => { + // SQL preparado para evitar injeção de código malicioso + // Campos: user_id (quem comprou), type (jogo ou gift card), item_id (ID do item), + // title (nome do jogo/gift), platform (onde roda ou vale) + const sql = `INSERT INTO users_library (user_id, type, item_id, title, platform) + VALUES (?, ?, ?, ?, ?)`; + + // Executa a query com os dados sanitizados + db.query(sql, [data.user_id, data.type, data.item_id, data.title, data.platform], callback); +}; + +// Função que busca TODOS os itens da biblioteca de um usuário específico. +// É usada quando o usuário quer ver sua coleção completa. +exports.getUserLibrary = (user_id, callback) => { + // Query simples mas eficiente - busca tudo do usuário + db.query('SELECT * FROM users_library WHERE user_id = ?', [user_id], callback); +}; + +// Função importante para evitar duplicatas! +// Antes de adicionar um item, verificamos se o usuário já não o tem. +// Isso evita que alguém compre o mesmo jogo duas vezes por acidente. +exports.checkItem = (user_id, item_id, callback) => { + // Busca se existe algum registro com esse usuário e item + db.query('SELECT * FROM users_library WHERE user_id = ? AND item_id = ?', [user_id, item_id], callback); +}; diff --git a/libraryRoutes.js b/libraryRoutes.js index 239a0ae..13fc9b8 100644 --- a/libraryRoutes.js +++ b/libraryRoutes.js @@ -1,26 +1,27 @@ -const express = require('express'); -const router = express.Router(); -const controller = require('../controllers/libraryController'); - -// Este arquivo define as "portas de entrada" da nossa API! -// Cada rota é como uma porta específica do prédio - cada uma leva a um lugar diferente. -// Seguimos convenções REST: POST para criar, GET para buscar. - -// Rota para adicionar um item manualmente à biblioteca -// Método: POST /library/add -// Uso: Para correções ou imports especiais (não para compras normais) -router.post('/add', controller.addItem); - -// Rota para buscar toda a biblioteca de um usuário -// Método: GET /library/user/:user_id -// Exemplo: GET /library/user/123 retorna todos os jogos e gift cards do usuário 123 -router.get('/user/:user_id', controller.getLibrary); - -// Rota CRUCIAL para integração com o serviço de pagamentos! -// Método: POST /library/integration/payment-approved -// Esta rota é chamada AUTOMATICAMENTE quando um pagamento é aprovado. -// É o elo entre "comprou" e "recebeu na biblioteca". -router.post('/integration/payment-approved', controller.paymentApproved); - -// Exportamos o router para que o app.js possa usar essas rotas -module.exports = router; +const express = require('express'); +const router = express.Router(); +const controller = require('../controllers/libraryController'); +const { authenticateToken } = require('../config/authMiddleware'); + +// Este arquivo define as "portas de entrada" da nossa API! +// Cada rota é como uma porta específica do prédio - cada uma leva a um lugar diferente. +// Seguimos convenções REST: POST para criar, GET para buscar. + +// Rota para adicionar um item manualmente à biblioteca +// Método: POST /library/add +// Uso: Para correções ou imports especiais (não para compras normais) +router.post('/add', authenticateToken, controller.addItem); + +// Rota para buscar toda a biblioteca de um usuário +// Método: GET /library/user/:user_id +// Exemplo: GET /library/user/123 retorna todos os jogos e gift cards do usuário 123 +router.get('/user/:user_id', authenticateToken, controller.getLibrary); + +// Rota CRUCIAL para integração com o serviço de pagamentos! +// Método: POST /library/integration/payment-approved +// Esta rota é chamada AUTOMATICAMENTE quando um pagamento é aprovado. +// É o elo entre "comprou" e "recebeu na biblioteca". +router.post('/integration/payment-approved', controller.paymentApproved); + +// Exportamos o router para que o app.js possa usar essas rotas +module.exports = router;