chore(ops): restore all source files in newwhats.clube67.com
continuous-integration/webhook Falha no deploy de clube67_newwhats.local (VPS 4)
continuous-integration/webhook Falha no deploy de clube67_newwhats.local (VPS 4)
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
"use strict";
|
||||
// ============================================================
|
||||
// Plugin: core-auth — Routes
|
||||
// ============================================================
|
||||
// Migrated from: backend/src/routes/auth.routes.ts
|
||||
// backend/src/controllers/auth.controller.ts
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.createAuthRoutes = createAuthRoutes;
|
||||
const express_1 = require("express");
|
||||
const bcryptjs_1 = __importDefault(require("bcryptjs"));
|
||||
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
||||
function createAuthRoutes(ctx) {
|
||||
const router = (0, express_1.Router)();
|
||||
const { db, hooks } = ctx;
|
||||
// ── POST /login ───────────────────────────────────────
|
||||
router.post('/login', async (req, res) => {
|
||||
try {
|
||||
const { email, password } = req.body;
|
||||
if (!email || !password) {
|
||||
return res.status(400).json({ error: 'Email e senha são obrigatórios' });
|
||||
}
|
||||
const user = await db('users').where({ email }).first();
|
||||
if (!user) {
|
||||
return res.status(401).json({ error: 'Credenciais inválidas' });
|
||||
}
|
||||
const isValid = await bcryptjs_1.default.compare(password, user.password_hash);
|
||||
if (!isValid) {
|
||||
return res.status(401).json({ error: 'Credenciais inválidas' });
|
||||
}
|
||||
const accessToken = jsonwebtoken_1.default.sign({ id: user.id, email: user.email, role: user.role }, process.env.JWT_SECRET, { expiresIn: (process.env.JWT_EXPIRES_IN || '15m') });
|
||||
const refreshToken = jsonwebtoken_1.default.sign({ id: user.id, type: 'refresh' }, process.env.JWT_REFRESH_SECRET, { expiresIn: (process.env.JWT_REFRESH_EXPIRES_IN || '7d') });
|
||||
// Emit hook event
|
||||
await hooks.emit('user:login', { userId: user.id, ip: req.ip });
|
||||
// Audit log
|
||||
await db('audit_log').insert({
|
||||
user_id: user.id,
|
||||
action: 'LOGIN',
|
||||
entity_type: 'user',
|
||||
entity_id: user.id,
|
||||
details: 'Usuário logou no sistema',
|
||||
ip_address: req.ip,
|
||||
}).catch(() => { }); // non-critical
|
||||
const { password_hash, ...safeUser } = user;
|
||||
res.json({ user: safeUser, accessToken, refreshToken });
|
||||
}
|
||||
catch (err) {
|
||||
ctx.logger.error(`Login error: ${err.message}`);
|
||||
res.status(500).json({ error: 'Erro interno no servidor' });
|
||||
}
|
||||
});
|
||||
// ── POST /register ────────────────────────────────────
|
||||
router.post('/register', async (req, res) => {
|
||||
try {
|
||||
const { name, email, password, cpf, whatsapp, city, neighborhood, state } = req.body;
|
||||
if (!name || !email || !password) {
|
||||
return res.status(400).json({ error: 'Nome, email e senha são obrigatórios' });
|
||||
}
|
||||
const existing = await db('users').where({ email }).first();
|
||||
if (existing) {
|
||||
return res.status(409).json({ error: 'Email já cadastrado' });
|
||||
}
|
||||
const password_hash = await bcryptjs_1.default.hash(password, 12);
|
||||
const [id] = await db('users').insert({
|
||||
name,
|
||||
email,
|
||||
password_hash,
|
||||
cpf: cpf || null,
|
||||
whatsapp: whatsapp || null,
|
||||
city: city || null,
|
||||
neighborhood: neighborhood || null,
|
||||
state: state || null,
|
||||
role: 'user',
|
||||
status: 'active',
|
||||
});
|
||||
await hooks.emit('user:register', { userId: id, email });
|
||||
res.status(201).json({ id, name, email, role: 'user' });
|
||||
}
|
||||
catch (err) {
|
||||
ctx.logger.error(`Register error: ${err.message}`);
|
||||
res.status(500).json({ error: 'Erro interno no servidor' });
|
||||
}
|
||||
});
|
||||
// ── GET /me ───────────────────────────────────────────
|
||||
router.get('/me', async (req, res) => {
|
||||
try {
|
||||
const authHeader = req.headers.authorization;
|
||||
if (!authHeader?.startsWith('Bearer ')) {
|
||||
return res.status(401).json({ error: 'Token não fornecido' });
|
||||
}
|
||||
const token = authHeader.split(' ')[1];
|
||||
const payload = jsonwebtoken_1.default.verify(token, process.env.JWT_SECRET);
|
||||
const user = await db('users')
|
||||
.where({ id: payload.id })
|
||||
.select('id', 'name', 'email', 'role', 'status', 'whatsapp', 'cpf', 'city', 'neighborhood', 'state', 'partner_id', 'created_at')
|
||||
.first();
|
||||
if (!user) {
|
||||
return res.status(404).json({ error: 'Usuário não encontrado' });
|
||||
}
|
||||
let partnerConsent = false;
|
||||
let partnerConsentAt = null;
|
||||
let partnerConsentIp = null;
|
||||
if (user?.partner_id) {
|
||||
const partner = await db('partners')
|
||||
.where({ id: user.partner_id })
|
||||
.select('data_consent', 'consent_at', 'consent_ip')
|
||||
.first();
|
||||
partnerConsent = Boolean(partner?.data_consent);
|
||||
partnerConsentAt = partner?.consent_at || null;
|
||||
partnerConsentIp = partner?.consent_ip || null;
|
||||
}
|
||||
res.json({ ...user, partnerConsent, partnerConsentAt, partnerConsentIp });
|
||||
}
|
||||
catch (err) {
|
||||
if (err.name === 'TokenExpiredError') {
|
||||
return res.status(401).json({ error: 'Token expirado' });
|
||||
}
|
||||
res.status(401).json({ error: 'Token inválido' });
|
||||
}
|
||||
});
|
||||
// ── POST /refresh ─────────────────────────────────────
|
||||
router.post('/refresh', async (req, res) => {
|
||||
try {
|
||||
const { refreshToken } = req.body;
|
||||
if (!refreshToken) {
|
||||
return res.status(400).json({ error: 'Refresh token obrigatório' });
|
||||
}
|
||||
const payload = jsonwebtoken_1.default.verify(refreshToken, process.env.JWT_REFRESH_SECRET);
|
||||
if (payload.type !== 'refresh') {
|
||||
return res.status(401).json({ error: 'Token inválido' });
|
||||
}
|
||||
const user = await db('users').where({ id: payload.id }).first();
|
||||
if (!user) {
|
||||
return res.status(404).json({ error: 'Usuário não encontrado' });
|
||||
}
|
||||
const newAccessToken = jsonwebtoken_1.default.sign({ id: user.id, email: user.email, role: user.role }, process.env.JWT_SECRET, { expiresIn: (process.env.JWT_EXPIRES_IN || '15m') });
|
||||
await hooks.emit('token:refresh', { userId: user.id });
|
||||
res.json({ accessToken: newAccessToken });
|
||||
}
|
||||
catch (err) {
|
||||
res.status(401).json({ error: 'Refresh token inválido ou expirado' });
|
||||
}
|
||||
});
|
||||
return router;
|
||||
}
|
||||
//# sourceMappingURL=routes.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,180 @@
|
||||
// ============================================================
|
||||
// Plugin: core-auth — Routes
|
||||
// ============================================================
|
||||
// Migrated from: backend/src/routes/auth.routes.ts
|
||||
// backend/src/controllers/auth.controller.ts
|
||||
|
||||
import { Router, Request, Response } from 'express';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { PluginContext } from '../../../backend/src/core/types';
|
||||
|
||||
export function createAuthRoutes(ctx: PluginContext): Router {
|
||||
const router = Router();
|
||||
const { db, hooks } = ctx;
|
||||
|
||||
// ── POST /login ───────────────────────────────────────
|
||||
router.post('/login', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { email, password } = req.body;
|
||||
|
||||
if (!email || !password) {
|
||||
return res.status(400).json({ error: 'Email e senha são obrigatórios' });
|
||||
}
|
||||
|
||||
const user = await db('users').where({ email }).first();
|
||||
if (!user) {
|
||||
return res.status(401).json({ error: 'Credenciais inválidas' });
|
||||
}
|
||||
|
||||
const isValid = await bcrypt.compare(password, user.password_hash);
|
||||
if (!isValid) {
|
||||
return res.status(401).json({ error: 'Credenciais inválidas' });
|
||||
}
|
||||
|
||||
const accessToken = jwt.sign(
|
||||
{ id: user.id, email: user.email, role: user.role },
|
||||
process.env.JWT_SECRET!,
|
||||
{ expiresIn: (process.env.JWT_EXPIRES_IN || '15m') as any }
|
||||
);
|
||||
|
||||
const refreshToken = jwt.sign(
|
||||
{ id: user.id, type: 'refresh' },
|
||||
process.env.JWT_REFRESH_SECRET!,
|
||||
{ expiresIn: (process.env.JWT_REFRESH_EXPIRES_IN || '7d') as any }
|
||||
);
|
||||
|
||||
// Emit hook event
|
||||
await hooks.emit('user:login', { userId: user.id, ip: req.ip });
|
||||
|
||||
// Audit log
|
||||
await db('audit_log').insert({
|
||||
user_id: user.id,
|
||||
action: 'LOGIN',
|
||||
entity_type: 'user',
|
||||
entity_id: user.id,
|
||||
details: 'Usuário logou no sistema',
|
||||
ip_address: req.ip,
|
||||
}).catch(() => { }); // non-critical
|
||||
|
||||
const { password_hash, ...safeUser } = user;
|
||||
res.json({ user: safeUser, accessToken, refreshToken });
|
||||
} catch (err: any) {
|
||||
ctx.logger.error(`Login error: ${err.message}`);
|
||||
res.status(500).json({ error: 'Erro interno no servidor' });
|
||||
}
|
||||
});
|
||||
|
||||
// ── POST /register ────────────────────────────────────
|
||||
router.post('/register', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { name, email, password, cpf, whatsapp, city, neighborhood, state } = req.body;
|
||||
|
||||
if (!name || !email || !password) {
|
||||
return res.status(400).json({ error: 'Nome, email e senha são obrigatórios' });
|
||||
}
|
||||
|
||||
const existing = await db('users').where({ email }).first();
|
||||
if (existing) {
|
||||
return res.status(409).json({ error: 'Email já cadastrado' });
|
||||
}
|
||||
|
||||
const password_hash = await bcrypt.hash(password, 12);
|
||||
|
||||
const [id] = await db('users').insert({
|
||||
name,
|
||||
email,
|
||||
password_hash,
|
||||
cpf: cpf || null,
|
||||
whatsapp: whatsapp || null,
|
||||
city: city || null,
|
||||
neighborhood: neighborhood || null,
|
||||
state: state || null,
|
||||
role: 'user',
|
||||
status: 'active',
|
||||
});
|
||||
|
||||
await hooks.emit('user:register', { userId: id, email });
|
||||
|
||||
res.status(201).json({ id, name, email, role: 'user' });
|
||||
} catch (err: any) {
|
||||
ctx.logger.error(`Register error: ${err.message}`);
|
||||
res.status(500).json({ error: 'Erro interno no servidor' });
|
||||
}
|
||||
});
|
||||
|
||||
// ── GET /me ───────────────────────────────────────────
|
||||
router.get('/me', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const authHeader = req.headers.authorization;
|
||||
if (!authHeader?.startsWith('Bearer ')) {
|
||||
return res.status(401).json({ error: 'Token não fornecido' });
|
||||
}
|
||||
|
||||
const token = authHeader.split(' ')[1];
|
||||
const payload = jwt.verify(token, process.env.JWT_SECRET!) as any;
|
||||
|
||||
const user = await db('users')
|
||||
.where({ id: payload.id })
|
||||
.select('id', 'name', 'email', 'role', 'status', 'whatsapp', 'cpf', 'city', 'neighborhood', 'state', 'partner_id', 'created_at')
|
||||
.first();
|
||||
|
||||
if (!user) {
|
||||
return res.status(404).json({ error: 'Usuário não encontrado' });
|
||||
}
|
||||
|
||||
let partnerConsent = false;
|
||||
let partnerConsentAt = null;
|
||||
let partnerConsentIp = null;
|
||||
if (user?.partner_id) {
|
||||
const partner = await db('partners')
|
||||
.where({ id: user.partner_id })
|
||||
.select('data_consent', 'consent_at', 'consent_ip')
|
||||
.first();
|
||||
partnerConsent = Boolean(partner?.data_consent);
|
||||
partnerConsentAt = partner?.consent_at || null;
|
||||
partnerConsentIp = partner?.consent_ip || null;
|
||||
}
|
||||
res.json({ ...user, partnerConsent, partnerConsentAt, partnerConsentIp });
|
||||
} catch (err: any) {
|
||||
if (err.name === 'TokenExpiredError') {
|
||||
return res.status(401).json({ error: 'Token expirado' });
|
||||
}
|
||||
res.status(401).json({ error: 'Token inválido' });
|
||||
}
|
||||
});
|
||||
|
||||
// ── POST /refresh ─────────────────────────────────────
|
||||
router.post('/refresh', async (req: Request, res: Response) => {
|
||||
try {
|
||||
const { refreshToken } = req.body;
|
||||
if (!refreshToken) {
|
||||
return res.status(400).json({ error: 'Refresh token obrigatório' });
|
||||
}
|
||||
|
||||
const payload = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET!) as any;
|
||||
if (payload.type !== 'refresh') {
|
||||
return res.status(401).json({ error: 'Token inválido' });
|
||||
}
|
||||
|
||||
const user = await db('users').where({ id: payload.id }).first();
|
||||
if (!user) {
|
||||
return res.status(404).json({ error: 'Usuário não encontrado' });
|
||||
}
|
||||
|
||||
const newAccessToken = jwt.sign(
|
||||
{ id: user.id, email: user.email, role: user.role },
|
||||
process.env.JWT_SECRET!,
|
||||
{ expiresIn: (process.env.JWT_EXPIRES_IN || '15m') as any }
|
||||
);
|
||||
|
||||
await hooks.emit('token:refresh', { userId: user.id });
|
||||
|
||||
res.json({ accessToken: newAccessToken });
|
||||
} catch (err: any) {
|
||||
res.status(401).json({ error: 'Refresh token inválido ou expirado' });
|
||||
}
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
"use strict";
|
||||
// ============================================================
|
||||
// Plugin: core-auth — Entry Point
|
||||
// ============================================================
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const routes_1 = require("./backend/routes");
|
||||
const manifest_json_1 = __importDefault(require("./manifest.json"));
|
||||
const plugin = {
|
||||
manifest: manifest_json_1.default,
|
||||
async activate(ctx) {
|
||||
const router = (0, routes_1.createAuthRoutes)(ctx);
|
||||
ctx.app.use('/api/auth', router);
|
||||
ctx.logger.info('Auth routes registered at /api/auth');
|
||||
},
|
||||
async deactivate(ctx) {
|
||||
ctx.logger.info('Auth plugin deactivated');
|
||||
},
|
||||
};
|
||||
exports.default = plugin;
|
||||
//# sourceMappingURL=index.js.map
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA,+DAA+D;AAC/D,kCAAkC;AAClC,+DAA+D;;;;;AAG/D,6CAAoD;AACpD,oEAAuC;AAEvC,MAAM,MAAM,GAAmB;IAC3B,QAAQ,EAAE,uBAAe;IAEzB,KAAK,CAAC,QAAQ,CAAC,GAAkB;QAC7B,MAAM,MAAM,GAAG,IAAA,yBAAgB,EAAC,GAAG,CAAC,CAAC;QACrC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QACjC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,GAAkB;QAC/B,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAC/C,CAAC;CACJ,CAAC;AAEF,kBAAe,MAAM,CAAC"}
|
||||
@@ -0,0 +1,23 @@
|
||||
// ============================================================
|
||||
// Plugin: core-auth — Entry Point
|
||||
// ============================================================
|
||||
|
||||
import { PluginInstance, PluginContext } from '../../backend/src/core/types';
|
||||
import { createAuthRoutes } from './backend/routes';
|
||||
import manifest from './manifest.json';
|
||||
|
||||
const plugin: PluginInstance = {
|
||||
manifest: manifest as any,
|
||||
|
||||
async activate(ctx: PluginContext): Promise<void> {
|
||||
const router = createAuthRoutes(ctx);
|
||||
ctx.app.use('/api/auth', router);
|
||||
ctx.logger.info('Auth routes registered at /api/auth');
|
||||
},
|
||||
|
||||
async deactivate(ctx: PluginContext): Promise<void> {
|
||||
ctx.logger.info('Auth plugin deactivated');
|
||||
},
|
||||
};
|
||||
|
||||
export default plugin;
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "core-auth",
|
||||
"displayName": "Autenticação",
|
||||
"version": "1.0.0",
|
||||
"description": "Login, JWT, refresh tokens, sessões, Google OAuth e RBAC.",
|
||||
"author": "Clube67",
|
||||
"category": "core",
|
||||
"enabled": true,
|
||||
"canDisable": false,
|
||||
"dependencies": [],
|
||||
"backend": {
|
||||
"routePrefix": "/api/auth",
|
||||
"hasMigrations": true,
|
||||
"globalMiddleware": [
|
||||
"authenticate"
|
||||
]
|
||||
},
|
||||
"frontend": {
|
||||
"menuItems": [],
|
||||
"pages": [
|
||||
{
|
||||
"path": "/login",
|
||||
"component": "LoginPage",
|
||||
"roles": [
|
||||
"*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/register",
|
||||
"component": "RegisterPage",
|
||||
"roles": [
|
||||
"*"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"hooks": {
|
||||
"subscribes": [],
|
||||
"emits": [
|
||||
"user:login",
|
||||
"user:logout",
|
||||
"user:register",
|
||||
"token:refresh"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user