Просмотр исходного кода

adicionado controller de usuarios

leonardo 3 месяцев назад
Родитель
Сommit
fc88e0f94c

+ 8 - 34
src/config/db.config.js

@@ -1,36 +1,10 @@
-require('dotenv').config()
+import { db } from "../db/knex.js";
 
-const mysql = require('mysql');
-const connection = mysql.createConnection({
-    host: process.env.DB_HOST,
-    port: process.env.DB_PORT,
-    user: process.env.DB_USER,
-    password: process.env.DB_PASS,
-    database: process.env.DB_SCHEMA,
-    charset: "utf8mb4",
-    collation: "utf8mb4_bin",
-});
+// Compat layer for legacy imports that still expect a db.config module.
+export const knex = db;
+export const connection = null;
 
-var knex = require('knex')({
-    client: 'mysql',
-    connection: {
-        host: process.env.DB_HOST,
-        port: process.env.DB_PORT,
-        user: process.env.DB_USER,
-        password: process.env.DB_PASS,
-        database: process.env.DB_SCHEMA,
-        charset: "utf8mb4",
-        collation: "utf8mb4_bin",
-    },
-    migrations: {
-        tableName: 'knex_seeds',
-        directory: './db/migrations'
-    },
-    seeds: {
-        tableName: 'knex_seeds',
-        directory: './db/seeds'
-    }
-});
-
-module.exports.connection = connection;
-module.exports.knex = knex;
+export default {
+  knex,
+  connection
+};

+ 3 - 0
src/config/index.js

@@ -6,6 +6,9 @@ export const config = {
   port: Number(process.env.PORT ?? 3001),
   corsOrigin: process.env.CORS_ORIGIN ?? "http://localhost:5173",
   apiKey: process.env.API_KEY ?? "",
+  auth: {
+    mode: process.env.AUTH_MODE ?? "none"
+  },
   jwt: {
     secret: process.env.JWT_SECRET ?? "",
     issuer: process.env.JWT_ISSUER ?? "oraculo-api",

+ 7 - 2
src/config/server.js

@@ -1,2 +1,7 @@
-require('dotenv').config();
-module.exports.port = process.env.SERVER_PORT ?? 4000;
+import "dotenv/config";
+
+export const port = process.env.SERVER_PORT ?? 4000;
+
+export default {
+  port
+};

+ 76 - 0
src/controllers/Usuario.Controller.js

@@ -0,0 +1,76 @@
+import bcrypt from "bcryptjs";
+import { db } from "../db/knex.js";
+
+async function recordFailedAttempt(_login) {}
+
+function formatarUsuario(usuario) {
+    return {
+        Id: usuario.Id,
+        Nome: usuario.Nome,
+        Login: usuario.Login,
+        Email: usuario.Email,
+        Status: usuario.Status,
+        Nivel: usuario.Nivel,
+        Setor: usuario.Setor
+    };
+}
+
+export const UsuarioController = {
+    Login: async function (req, res, next) {
+        try {
+            const { Login, login, Senha, senha, RemenberMe = false } = req.body ?? {};
+            const userAgent = req.headers["user-agent"] || "unknown";
+            void RemenberMe;
+            void userAgent;
+
+            const loginBody = Login ?? login;
+            const senhaBody = Senha ?? senha;
+
+            if (!loginBody || !senhaBody) {
+                return res.status(401).send({ status: false, msg: "Informacoes faltando para Login!" });
+            }
+
+            const loginInformado = String(loginBody).trim();
+            const senhaInformada = String(senhaBody);
+
+            const usuario = await db("usuarios")
+                .where(loginInformado.includes("@") ? { Email: loginInformado } : { Login: loginInformado })
+                .first();
+
+            if (!usuario) {
+                await recordFailedAttempt(loginInformado);
+                return res.status(401).send({ status: false, msg: "Usuario não localizado!" });
+            }
+
+            if (String(usuario.Status) === "0") {
+                return res.status(401).send({ status: false, msg: "Usuario inativo!" });
+            }
+
+            const passwordIsValid = bcrypt.compareSync(senhaInformada, String(usuario.Senha ?? ""));
+            if (!passwordIsValid) {
+                await recordFailedAttempt(loginInformado);
+                return res.status(401).send({ status: false, msg: "Combinacao de usuario e senho invalida!" });
+            }
+
+            return res.status(200).send({
+                status: true,
+                msg: "Login realizado com sucesso!",
+                usuario: formatarUsuario(usuario)
+            });
+        } catch (error) {
+            return next(error);
+        }
+    },
+
+    Logout: async function (_req, res, next) {
+        try {
+            return res.status(200).send({ status: true, msg: "Logout realizado com sucesso!" });
+        } catch (error) {
+            return next(error);
+        }
+    }
+
+     
+};
+
+export default UsuarioController;

+ 6 - 1
src/middleware/auth.js

@@ -2,10 +2,15 @@ import { config } from "../config/index.js";
 import { verifyAccessToken } from "../services/authTokens.js";
 
 export function authMiddleware(req, res, next) {
+  if (config.auth.mode === "none") {
+    next();
+    return;
+  }
+
   const header = req.header("authorization") ?? "";
   const token = header.startsWith("Bearer ") ? header.slice("Bearer ".length).trim() : "";
 
-  const isPublic = req.path === "/auth/login" || req.path === "/auth/refresh" || req.path === "/auth/logout";
+  const isPublic = req.path === "/auth/login" || req.path === "/auth/logout";
 
   const hasAuthConfigured = Boolean(config.apiKey || config.jwt.secret);
   if (!hasAuthConfigured) return next();

+ 33 - 44
src/models/Usuario.model.js

@@ -1,46 +1,35 @@
-const { knex } = require("../config/db.config");
-const { Model } = require("objection");
-
-Model.knex(knex);
-const unique = require("objection-unique")({
-    fields: ["Id"],
-    identifiers: ["Id"]
-});
-
-class Usuario extends unique(Model) {
-    static get tableName() {
-        return "usuarios";
-    }
-
-    static get idColumn() {
-        return "Id";
-    }
-
-    $formatJson(json) {
-        const formatted = super.$formatJson(json);
-
-        try{
-            formatted.Perfil = JSON.parse(formatted.Perfil);
-        } catch (e) {
-            formatted.Perfil = [];
-        }
-
-        return formatted;
-    }
-
-    static get relationMappings() {
-        const { Setor } = require("./Setor");
-        return {
-            setor: {
-                relation: Model.HasOneRelation,
-                modelClass: Setor,
-                join: {
-                    to: "usuarios.Setor",
-                    from: "setores.Id"
-                }
-            }
-        };
-    }
+import { knex } from "../config/db.config.js";
+
+function formatUsuario(usuario) {
+  if (!usuario) return usuario;
+
+  const formatted = { ...usuario };
+
+  try {
+    formatted.Perfil = JSON.parse(formatted.Perfil);
+  } catch (_error) {
+    formatted.Perfil = [];
+  }
+
+  return formatted;
+}
+
+export class Usuario {
+  static get tableName() {
+    return "usuarios";
+  }
+
+  static get idColumn() {
+    return "Id";
+  }
+
+  static query() {
+    const queryBuilder = knex(this.tableName);
+    const originalFirst = queryBuilder.first.bind(queryBuilder);
+
+    queryBuilder.first = async (...args) => formatUsuario(await originalFirst(...args));
+    return queryBuilder;
+  }
 }
 
-module.exports.Usuario = Usuario;
+export default Usuario;

+ 3 - 175
src/routes/auth.js

@@ -1,179 +1,7 @@
 import { Router } from "express";
-import { z } from "zod";
-import bcrypt from "bcryptjs";
-import { db } from "../db/knex.js";
-import { config } from "../config/index.js";
-import { generateRefreshToken, hashRefreshToken, signAccessToken } from "../services/authTokens.js";
+import { UsuarioController } from "../controllers/Usuario.Controller.js";
 
 export const authRouter = Router();
 
-const loginBodySchema = z.object({
-  login: z.string().min(1),
-  senha: z.string().min(1)
-});
-
-const refreshBodySchema = z.object({
-  refreshToken: z.string().min(1)
-});
-
-const logoutBodySchema = z.object({
-  refreshToken: z.string().min(1).optional()
-});
-
-function toPublicUser(u) {
-  return {
-    id: u.Id,
-    nome: u.Nome,
-    login: u.Login,
-    email: u.Email,
-    status: u.Status,
-    nivel: u.Nivel,
-    setor: u.Setor
-  };
-}
-
-function isUserBlocked(u) {
-  const status = String(u?.Status ?? "").trim();
-  return status === "0";
-}
-
-async function issueTokensForUser(trx, user) {
-  const now = Date.now();
-  const refreshToken = generateRefreshToken();
-  const refreshTokenHash = hashRefreshToken(refreshToken);
-  const expiresAt = new Date(now + config.jwt.refreshTtlSeconds * 1000);
-
-  await trx("refresh_tokens").insert({
-    UsuarioId: user.Id,
-    TokenHash: refreshTokenHash,
-    ExpiresAt: expiresAt
-  });
-
-  const accessToken = signAccessToken({
-    sub: String(user.Id),
-    login: user.Login,
-    nivel: user.Nivel,
-    setor: user.Setor
-  });
-
-  return { accessToken, refreshToken };
-}
-
-authRouter.post("/login", async (req, res, next) => {
-  try {
-    const body = loginBodySchema.parse(req.body);
-
-    const login = body.login.trim();
-    const isEmail = login.includes("@");
-
-    const user = await db("usuarios")
-      .where(isEmail ? { Email: login } : { Login: login })
-      .first();
-
-    if (!user) {
-      res.status(401).json({ error: "invalid_credentials" });
-      return;
-    }
-
-    if (isUserBlocked(user)) {
-      res.status(403).json({ error: "user_inactive" });
-      return;
-    }
-
-    const ok = await bcrypt.compare(body.senha, String(user.Senha ?? ""));
-    if (!ok) {
-      res.status(401).json({ error: "invalid_credentials" });
-      return;
-    }
-
-    const tokens = await db.transaction(async (trx) => issueTokensForUser(trx, user));
-    res.json({ ...tokens, user: toPublicUser(user) });
-  } catch (err) {
-    next(err);
-  }
-});
-
-authRouter.post("/refresh", async (req, res, next) => {
-  try {
-    const body = refreshBodySchema.parse(req.body);
-    const tokenHash = hashRefreshToken(body.refreshToken);
-
-    const now = new Date();
-
-    const result = await db.transaction(async (trx) => {
-      const tokenRow = await trx("refresh_tokens").where({ TokenHash: tokenHash }).first();
-
-      if (!tokenRow) return null;
-      if (tokenRow.RevokedAt) return null;
-      if (new Date(tokenRow.ExpiresAt) <= now) return null;
-
-      const user = await trx("usuarios").where({ Id: tokenRow.UsuarioId }).first();
-      if (!user) return null;
-      if (isUserBlocked(user)) return null;
-
-      await trx("refresh_tokens").where({ Id: tokenRow.Id }).update({ RevokedAt: now });
-
-      const tokens = await issueTokensForUser(trx, user);
-      return { tokens, user };
-    });
-
-    if (!result) {
-      res.status(401).json({ error: "invalid_refresh_token" });
-      return;
-    }
-
-    res.json({ ...result.tokens, user: toPublicUser(result.user) });
-  } catch (err) {
-    next(err);
-  }
-});
-
-authRouter.post("/logout", async (req, res, next) => {
-  try {
-    const body = logoutBodySchema.safeParse(req.body);
-    const refreshToken = body.success ? body.data.refreshToken : undefined;
-
-    const now = new Date();
-    const userId = req.user?.sub ? Number(req.user.sub) : null;
-
-    if (userId) {
-      await db("refresh_tokens")
-        .where({ UsuarioId: userId })
-        .whereNull("RevokedAt")
-        .update({ RevokedAt: now });
-      res.json({ ok: true });
-      return;
-    }
-
-    if (typeof refreshToken !== "string" || !refreshToken.trim()) {
-      res.status(400).json({ error: "refresh_token_required" });
-      return;
-    }
-
-    const tokenHash = hashRefreshToken(refreshToken.trim());
-    await db("refresh_tokens").where({ TokenHash: tokenHash }).update({ RevokedAt: now });
-    res.json({ ok: true });
-  } catch (err) {
-    next(err);
-  }
-});
-
-authRouter.get("/me", async (req, res, next) => {
-  try {
-    const userId = req.user?.sub ? Number(req.user.sub) : null;
-    if (!userId) {
-      res.status(401).json({ error: "unauthorized" });
-      return;
-    }
-
-    const user = await db("usuarios").where({ Id: userId }).first();
-    if (!user) {
-      res.status(404).json({ error: "user_not_found" });
-      return;
-    }
-
-    res.json({ user: toPublicUser(user) });
-  } catch (err) {
-    next(err);
-  }
-});
+authRouter.post("/login", UsuarioController.Login);
+authRouter.post("/logout", UsuarioController.Logout);