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
Binary file added .DS_Store
Binary file not shown.
Binary file added modulo07/.DS_Store
Binary file not shown.
4 changes: 4 additions & 0 deletions modulo07/introducao-autentificacao/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/
build/
.env
.DS_Store
5,785 changes: 5,785 additions & 0 deletions modulo07/introducao-autentificacao/package-lock.json

Large diffs are not rendered by default.

30 changes: 30 additions & 0 deletions modulo07/introducao-autentificacao/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "to-do-list",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"start": "tsc && node --inspect ./build/index.js",
"dev": "tsnd --transpile-only --ignore-watch node_modules ./src/index.ts",
"test": "ts-node-dev ./src/services/authenticator.ts"
},
"author": "Labenu",
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"knex": "^0.21.5",
"mysql": "^2.18.1",
"uuidv4": "^6.2.13"
},
"devDependencies": {
"@types/cors": "^2.8.8",
"@types/express": "^4.17.8",
"@types/jsonwebtoken": "^8.5.8",
"@types/knex": "^0.16.1",
"@types/node": "^14.11.2",
"ts-node-dev": "^1.0.0-pre.63",
"typescript": "4.6.4"
}
}
57 changes: 57 additions & 0 deletions modulo07/introducao-autentificacao/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
## Exercício 1

Na autenticação de usuários o elemento mais fundamental talvez seja o id. É muito importante encontrar um que seja fácil de guardar e que garanta unicidade. Para isso usaremos a versão v4 do UUID, uma das mais recomendadas para isso.

O uso dele é simples, veja abaixo:

```tsx
import { v4 } from "uuid"

const id = v4();

console.log("Generated Id: ", id);
```

a) Qual a sua opinião em relação a usar strings para representar os ids? Você concorda que seja melhor do que usar números?

resposta: Usar strings é mais seguro, é melhor que usar número porque cria mais variedades de id.

b) A partir de hoje vamos tentar isolar, ao máximo, as nossas lógicas dentro de funções. Isso vai deixar nosso código mais organizado e aumentar a facilidade da manutenção e refatoração. Dado isso, crie uma função para gerar um id.

- Dicas

b. _Na pasta: `services/`_

import { v4 } from "uuid";

export function generateId(): string {
return v4();
}

## Exercício 2

Antes de poder fazer o endpoint de cadastro, precisamos de uma forma para gerar o token de autenticação do usuário. Para isso, vamos usar o JWT. Ele possui uma função que permite gerar o token do usuário, que recebe três informações:

- os dados que serão salvos no token (no nosso caso, o id);
- a chave secreta usada pra criptografar o token;
- algumas configurações, como o tempo de expiração

Abaixo, há uma função que faz isso, com o tempo de expiração de 1 minuto:

import * as jwt from "jsonwebtoken";

const expiresIn = "1min"

const generateToken = (id: string): string => {
const token = jwt.sign(
{
id
},
process.env.JWT_KEY as string,
{
expiresIn
}
);
return token;

}
31 changes: 31 additions & 0 deletions modulo07/introducao-autentificacao/requests.rest
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# @name signup

POST http://localhost:3003/user/signup
Content-Type: application/json

{
"name": "Norman Osbourne",
"nickname": "Green Goblin",
"email": "osbourne@oscorp.com" ,
"password": "ihatepeter"
}

###
POST http://localhost:3003/user/login
Content-Type: application/json

{
"email": "osbourne@oscorp.com" ,
"password": "ihatepeter"
}

###

PUT http://localhost:3003/user/edit
Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjE2NjA5MDg3MTM3NjkiLCJpYXQiOjE2NjA5MTg4MDgsImV4cCI6MTY2MDkxODg2OH0.2n86aHlZtejS_JnTCLzrFkuU4irxy0yNctgYLb0adf8
Content-Type: application/json

{
"name": "Harry Osbourne",
"nickname": "maluco beleza"
}
112 changes: 112 additions & 0 deletions modulo07/introducao-autentificacao/src/business/UserBusiness.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { UserDatabase } from "../data/UserDatabase";
import {
CustomError,
InvalidEmail,
InvalidName,
InvalidPassword,
UserNotFound,
} from "../error/customError";
import {
UserInputDTO,
user,
EditUserInputDTO,
EditUserInput,
} from "../model/user";
import { Authenticator } from "../services/Authenticator";
const authenticator = new Authenticator();

export class UserBusiness {
public signup = async (input: UserInputDTO): Promise<string> => {
try {
const { name, nickname, email, password } = input;

if (!name || !nickname || !email || !password) {
throw new CustomError(
400,
'Preencha os campos "name","nickname", "email" e "password"'
);
}

if (name.length < 4) {
throw new InvalidName();
}

if (!email.includes("@")) {
throw new InvalidEmail();
}

const id: string = Date.now().toString();

const user: user = {
id,
name,
nickname,
email,
password,
};
const userDatabase = new UserDatabase();
await userDatabase.insertUser(user);
const token = authenticator.generateToken({ id });
return token;
} catch (error: any) {
throw new CustomError(400, error.message);
}
};

public login = async (input: any): Promise<string> => {
try {
const { email, password } = input;

if (!email || !password) {
throw new CustomError(400, 'Preencha os campos "email" e "password"');
}

if (!email.includes("@")) {
throw new InvalidEmail();
}

const userDatabase = new UserDatabase();
const user = await userDatabase.findUserByEmail(email);
if (!user) {
throw new UserNotFound();
}
if (user.password !== password) {
throw new InvalidPassword();
}

const token = authenticator.generateToken({ id: user.id });
return token;
} catch (error: any) {
throw new CustomError(400, error.message);
}
};

public editUser = async (input: EditUserInputDTO) => {
try {
const { name, nickname, token } = input;

if (!name || !nickname) {
throw new CustomError(
400,
'Preencha os campos "id", "name" e "nickname"'
);
}
const { id } = authenticator.getTokenData(token);

if (name.length < 4) {
throw new InvalidName();
}

const editUserInput: EditUserInput = {
id,
name,
nickname,
};

const userDatabase = new UserDatabase();
await userDatabase.editUser(editUserInput);
} catch (error: any) {
throw new CustomError(400, error.message);
}
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Request, Response } from "express";
import { UserBusiness } from "../business/UserBusiness";
import { EditUserInputDTO, LoginInputDTO, UserInputDTO } from "../model/user";

export class UserController {
public signup = async (req: Request, res: Response) => {
try {
const { name, nickname, email, password } = req.body;

const input: UserInputDTO = {
name,
nickname,
email,
password,
};
const userBusiness = new UserBusiness();
const token = await userBusiness.signup(input);

res.status(201).send({ message: "Usuário criado!", token });
} catch (error: any) {
res.status(400).send(error.message);
}
};

public login = async (req: Request, res: Response) => {
try {
const { name, nickname, email, password } = req.body;

const input: LoginInputDTO = {
email,
password,
};
const userBusiness = new UserBusiness();
const token = await userBusiness.login(input);

res.status(200).send({ token });
} catch (error: any) {
res.status(400).send(error.message);
}
};

public editUser = async (req: Request, res: Response) => {
try {
const input: EditUserInputDTO = {
name: req.body.name,
nickname: req.body.nickname,
token: req.headers.authorization as string,
};

const userBusiness = new UserBusiness();
userBusiness.editUser(input);

res.status(201).send({ message: "Usuário alterado!" });
} catch (error: any) {
res.status(400).send(error.message);
}
};
}
13 changes: 13 additions & 0 deletions modulo07/introducao-autentificacao/src/controller/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import express from 'express'
import cors from 'cors'

const app = express()

app.use(express.json())
app.use(cors())

app.listen(3003, ()=>{
console.log('Servidor rodando na porta 3003')
})

export default app
11 changes: 11 additions & 0 deletions modulo07/introducao-autentificacao/src/controller/userRouter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import express from "express";

import { UserController } from "../controller/UserController";

export const userRouter = express.Router();

const userController = new UserController();

userRouter.post("/signup", userController.signup);
userRouter.post("/login", userController.login);
userRouter.put("/edit", userController.editUser);
21 changes: 21 additions & 0 deletions modulo07/introducao-autentificacao/src/data/BaseDatabase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import knex from 'knex'
import dotenv from 'dotenv'

dotenv.config()

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
}
})

}

43 changes: 43 additions & 0 deletions modulo07/introducao-autentificacao/src/data/UserDatabase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { CustomError } from "../error/customError";
import { EditUserInput, user } from "../model/user";
import { BaseDatabase } from "./BaseDatabase";

export class UserDatabase extends BaseDatabase {
public insertUser = async (user: user) => {
try {
await UserDatabase.connection
.insert({
id: user.id,
name: user.name,
nickname: user.nickname,
email: user.email,
password: user.password,
})
.into("Auth_users");
} catch (error: any) {
throw new CustomError(400, error.message);
}
};

public editUser = async (user: EditUserInput) => {
try {
await UserDatabase.connection
.update({ name: user.name, nickname: user.nickname })
.where({ id: user.id })
.into("Auth_users");
} catch (error: any) {
throw new CustomError(400, error.message);
}
};

public findUserByEmail = async (email: string): Promise<user> => {
try {
const result = await UserDatabase.connection("Auth_users")
.select()
.where({ email });
return result[0];
} catch (error: any) {
throw new CustomError(400, error.message);
}
};
}
Loading