Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions semana19/semana19-revisao/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
package-lock.json
build
.env
34 changes: 34 additions & 0 deletions semana19/semana19-revisao/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "semana19-revisao",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"dev": "ts-node-dev . /src/index.ts",
"start": "tsc && node . /build/index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/bcryptjs": "^2.4.2",
"@types/cors": "^2.8.12",
"@types/express": "^4.17.13",
"@types/knex": "^0.16.1",
"@types/uuid": "^8.3.3",
"ts-node-dev": "^1.1.8",
"typescript": "^4.5.4"
},
"dependencies": {
"@types/jsonwebtoken": "^8.5.6",
"bcryptjs": "^2.4.3",
"cors": "^2.8.5",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"knex": "^0.95.14",
"mysql": "^2.18.1",
"uuid": "^8.3.2"
}
}
19 changes: 19 additions & 0 deletions semana19/semana19-revisao/src/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import express, { Express } from "express";
import cors from "cors";
import { AddressInfo } from "net";
import dotenv from "dotenv";

dotenv.config();

export const app: Express = express();
app.use(express.json());
app.use(cors());

const server = app.listen(process.env.PORT || 3003, () => {
if (server) {
const address = server.address() as AddressInfo;
console.log(`Server is running in http://localhost: ${address.port}`);
} else {
console.error(`Failure upon starting server.`);
}
});
15 changes: 15 additions & 0 deletions semana19/semana19-revisao/src/data/BaseDatabase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import knex from "knex";

export class BaseDatabase {
protected static connection = knex({
client: "mysql",
connection: {
host: process.env.DB_HOST,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
database: process.env.DB_SCHEMA,
port: 3306,
multipleStatements: true,
},
});
}
45 changes: 45 additions & 0 deletions semana19/semana19-revisao/src/data/UserDatabase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { BaseDatabase } from "./BaseDatabase";
import { User } from "../types/User";

export class UserDatabase extends BaseDatabase {
async createUser(user: User) {
try {
await BaseDatabase.connection("lbn_user").insert({
id: user.getId(),
name: user.getName(),
email: user.getEmail(),
password: user.getPassword(),
role: user.getRole(),
});
} catch (error) {
throw new Error((error as any).sqlMessage || (error as any).message);
}
}

async findUserByEmail(email: string): Promise<User> {
try {
const user = await BaseDatabase.connection("lbn_user")
.select("*")
.where({ email });
return user[0] && User.toUserModel(user[0]);
//A função toUserModel recebe um usuário e cria uma nova instância do usuário através das informações que vêm do banco de dados
} catch (error) {
throw new Error((error as any).sqlMessage || (error as any).message);
}
}

async getAllUsers(): Promise<User[]> {
try {
const users = await BaseDatabase.connection("lbn_user").select(
"id",
"name",
"email",
"role"
);
return users.map((user) => User.toUserModel(user));
//Dou um map e para cada usuário que estiver dentro do meu array, eu quero retornar um User.ToUserModel
} catch (error) {
throw new Error((error as any).sqlMessage || (error as any).message);
}
}
}
31 changes: 31 additions & 0 deletions semana19/semana19-revisao/src/endpoints/getAllCharacters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Request, Response } from "express";
import { Authenticator } from "../services/Authenticator";
import { UserDatabase } from "../data/UserDatabase";

export async function getAllCharacters(req: Request, res: Response) {
try {
const token = req.headers.authorization;

if (!token) {
res
.status(422)
.send("Esse endpoint exige uma autorização a ser passada nos headers");
}

const authenticator = new Authenticator();
const tokenData = authenticator.getTokenData(token as string);

if (tokenData.role !== "ADMIN") {
res
.status(401)
.send("Somente administradores podem acessar essa funcionalidade");
}

const userDatabase = new UserDatabase();
const users = await userDatabase.getAllUsers();

res.status(200).send(users);
} catch (error) {
res.status(400).send((error as any).message);
}
}
43 changes: 43 additions & 0 deletions semana19/semana19-revisao/src/endpoints/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Request, Response } from "express";
import { UserDatabase } from "../data/UserDatabase";
import { HashManager } from "../services/HashManager";
import { Authenticator } from "../services/Authenticator";

export async function login(req: Request, res: Response) {
try {
const { email, password } = req.body;

if (!email || !password) {
res
.status(422)
.send(
"Insira corretamente as informações de 'name', 'email', 'password' e 'role'"
);
}

const userDatabase = new UserDatabase();
const user = await userDatabase.findUserByEmail(email);

if (!user) {
res.status(404).send("Esse email não está cadastrado!");
}

const hashManager = new HashManager();
const passwordIsCorrect = hashManager.compare(password, user.getPassword());
//A função irá comparar a senha que o usuário enviou com a senha "hasheada"

if (!passwordIsCorrect) {
res.status(401).send("Email ou senha incorretos.");
}

const authenticator = new Authenticator();
const token = authenticator.generate({
id: user.getId(),
role: user.getRole(),
});

res.status(200).send({ message: "Usuário logado com sucesso", token });
} catch (error) {
res.status(400).send((error as Error).message);
}
}
43 changes: 43 additions & 0 deletions semana19/semana19-revisao/src/endpoints/signup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { Request, Response } from "express";
import { IdGenerator } from "../services/IdGenerator";
import { UserDatabase } from "../data/UserDatabase";
import { HashManager } from "../services/HashManager";
import { User } from "../types/User";
import { Authenticator } from "../services/Authenticator";

export async function signup(req: Request, res: Response) {
try {
const { name, email, password, role } = req.body;

if (!name || !email || !password || !role) {
res
.status(422)
.send(
"Insira corretamente as informações de 'name', 'email', 'password' e 'role'"
);
}

const userDatabase = new UserDatabase();
const user = await userDatabase.findUserByEmail(email);

if (user as any) {
res.status(409).send("Esse email já está cadastrado!");
}

const idGenerator = new IdGenerator();
const id = idGenerator.generate();

const hashManager = new HashManager();
const hashPassword = await hashManager.hash(password);

const newUser = new User(id, name, email, hashPassword, role);
await userDatabase.createUser(newUser);

const authenticator = new Authenticator();
const token = authenticator.generate({ id, role });

res.status(200).send({ message: "Usuário criado com sucesso", token });
} catch (error) {
res.status(400).send((error as Error).message);
}
}
8 changes: 8 additions & 0 deletions semana19/semana19-revisao/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { app } from "./app";
import { signup } from "./endpoints/signup";
import { login } from "./endpoints/login";
import { getAllCharacters } from "./endpoints/getAllCharacters";

app.get("/user", getAllCharacters);
app.post("/user", signup);
app.post("/user/login", login);
22 changes: 22 additions & 0 deletions semana19/semana19-revisao/src/services/Authenticator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import * as jwt from "jsonwebtoken";
import { USER_ROLES } from "../types/User";

export interface AuthenticationData {
id: string;
role: USER_ROLES;
}

export class Authenticator {
generate(input: AuthenticationData): string {
const token = jwt.sign(input, process.env.JWT_KEY as any, {
expiresIn: process.env.ACCESS_TOKEN_EXPIRES_IN,
});

return token;
}

getTokenData(token: string): AuthenticationData {
const data = jwt.verify(token, process.env.JWT_KEY as any);
return data as AuthenticationData;
}
}
15 changes: 15 additions & 0 deletions semana19/semana19-revisao/src/services/HashManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import * as bcrypt from "bcryptjs";

export class HashManager {
async hash(text: string): Promise<string> {
const rounds = Number(process.env.BCRYPT_COST);
const salt = await bcrypt.genSalt(rounds);
return bcrypt.hash(text, salt);
}

async compare(text: string, hash: string): Promise<boolean> {
return bcrypt.compare(text, hash);
}
}

//OBS: O que veio antes do async é o método ex: async hash e async compare
5 changes: 5 additions & 0 deletions semana19/semana19-revisao/src/services/IdGenerator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { v4 } from "uuid";

export class IdGenerator {
generate = (): string => v4();
}
33 changes: 33 additions & 0 deletions semana19/semana19-revisao/src/types/User.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export enum USER_ROLES {
NORMAL = "NORMAL",
ADMIN = "ADMIN",
}

export class User {
constructor(
private id: string,
private name: string,
private email: string,
private password: string,
private role: USER_ROLES
) {}
public getId() {
return this.id;
}
public getName() {
return this.name;
}
public getEmail() {
return this.email;
}
public getPassword() {
return this.password;
}
public getRole() {
return this.role;
}

static toUserModel(data: any): User {
return new User(data.id, data.name, data.email, data.password, data.role);
}
}
Loading