Desafio Técnico para a vaga de Desenvolvedor Pleno AppSec do LuizaLabs
O Magalu está expandindo seus negócios e uma das novas missões do time de tecnologia é criar uma funcionalidade de Produtos Favoritos de nossos Clientes, em que os nossos aplicativos irão enviar requisições HTTP para um novo backend que deverá gerenciar nossos clientes e seus produtos favoritos.
- Desenho da Aplicação
- Tecnologias Utilizadas
- Segurança
- Instalações Necessárias
- Preparando o ambiente
- Iniciando a Aplicação
- Acesso à aplicação
- Documentação das Rotas
- Módulo de Login
- Módulo de Usuários
- Módulo de Produtos
- Módulo de Itens Favoritos
- Testes unitários
- Docker
- Docker-Compose
- Nestjs + Typescript
- Swagger
- JWT
- Mongoose
- MongoDB
A aplicação foi pensada levando em conta pontos importantes da segurança como:
- Implementação de senha criptografada e validação de rotas através do token JWT.
- Tratamento correto dos parâmetros de entrada nas requisições e funcionalidades de acesso ao banco de dados evitando SQL Injection.
- Utilização da biblioteca Helmet() que é uma coleção de middelwares para Express. Ajuda a proteger uma aplicação NodeJs de várias vulnerabilidades conhecidas na web configurando cabeçalhos HTTP de forma segura
- XSS (Cross-Site-Scripting)
- Ataques de Injeção de Conteúdo
- Ataques de Injeção de Dados
- Clickjacking
- Cache
- Controle de requisições com Throttler que atua na prevenção de ataques de força bruta ou negação de serviço (DoS)
- A aplicação utiliza o CORS (Cross-Origin Resource Sharing) para controlar o acesso de recursos entre diferentes origens.
Abra o terminal e navegue até onde deseja armazenar o repositório
Clone o repositório (Exemplo SSH)
git clone [email protected]:EddyeBoy27/luizalabs-challenge.git
É necessário que você possua o Postman para testar a aplicação, Docker e o Docker-Compose instalado na sua máquina pois todo o ecossistema terá seus containers orquestrados pelo Docker-Compose.
Este guia de instalação e utilização da API será realizado considerando sistemas operacionais Linux.
Tutorial de instalação Postman (Github)
Tutorial de instalação Docker (Dev.to)
Tutorial de instalação Docker-Compose (Dev.to)
Tutorial de instalação Postman (Alura)
Tutorial de instalação Docker (Em inglês)
Tutorial de instalação Docker-Compose (Em inglês)
Para que possamos subir a aplicação, é necessário criar no diretório do projeto um arquivo de environments (.env). Junto do repositório há um arquivo de environments de exemplo pronto para o uso (.env.example), apenas renomeio-o para .env
Abra o postman e importe o arquivo LuizaLabs-Magalu.postman_collection.json pois ele já possui todas as rotas configuradas para testar a aplicação.
Com o terminal aberto no diretório onde você clonou o repositório execute o seguinte comando:
docker-compose up
Caso não deseje ver os logs da aplicação (Não-recomendado) a flag (-d) roda os logs em segundo plano, não necessitando manter o terminal aberto:
docker-compose up -d
Você ainda poderá ver os logs da aplicação:
docker-compose logs
Com isso será instalado a imagem do banco de dados MongoDB e a imagem da aplicação construída com NestJS
O Banco de dados está configurado previamente para utilizar a porta 27017 enquanto a API utilizará a porta 3000. Certifique-se de ter essas portas livres na sua máquina para que não haja conflito.
Na primeira vez que subir o contâiner, será criada uma pasta mongo_data no diretório local do projeto que será responsável pela persistência dos dados no MongoDB.
Há um arquivo no diretório (init-mongo.js) que inicializará o banco de dados com um usuário possuindo uma role do tipo ROLE_ADMIN. Não é necessário realizar nenhuma instrução, pois o docker-compose já está configurado para a leitura do arquivo.
Você pode utilizar este usuário para logar na aplicação através do Postman no fluxo de Login ou poderá criar um novo usuário.
email: [email protected]
password: xzxgptcW1!
A aplicação estará disponível no seguinte endpoint
http://localhost:3000
Para acessar as rotas no Postman e usufruir da aplicação você deve se atentar à algumas estruturas específicas na hora de realizar a requisição de algumas rotas.
Acesse através do seu navegador a documentação detalhada da API através do Swagger da aplicação
http://localhost:3000/docs
/login - POST
Rota utilizada para realizar o login na aplicação e obter um Token JWT.
Payload no body da requisição (JSON):
{
"email": string
"password": string
}
/users - GET
Rota utilizada para visualizar todos os usuários da aplicação.
Necessário usuário com permissão ROLE_ADMIN.
Payload da requisição:
{
headers: {
"Authorization": "Bearer <TOKENJWT>"
"Content-type": "application/json"
}
}
/users/:id - GET
Rota utilizada para listar os detalhes de um usuário.
Inserir no path da requisição o ID do usuário a ser realizado a busca.
Caso o usuário logado seja ROLE_USER, visualizará apenas os dados do próprio usuário independente do id no path da requisição.
Caso o usuário logado seja ROLE_ADMIN, poderá obter os detalhes de qualquer usuário procurado pelo id no path da requisição
Payload da requisição:
{
headers: {
"Authorization": "Bearer <TOKENJWT>"
"Content-type": "application/json"
}
params: {
id: string,
}
/users - POST
Rota utilizada para criar um novo usuário.
Por padrão o usuário é criado com nível de acesso ROLE_USER
Payload da requisição:
{
headers: {
"Authorization": "Bearer <TOKENJWT>"
"Content-type": "application/json"
},
body: {
"name": string,
"email": string,
"password": string,
}
}
/users - PATCH
Rota utilizada para atualizar os dados do usuário logado.
Payload da requisição:
{
headers: {
"Authorization": "Bearer <TOKENJWT>"
"Content-type": "application/json"
},
body: {
"name": string,
"password": string,
}
}
/users - DELETE
Rota utilizada para remover um usuário.
Caso o usuário tenha nível de acesso ROLE_USER, removerá o próprio usuário independente do id enviado no body da requisição.
Caso o usuário tenha nível de acesso ROLE_ADMIN, poderá remover qualquer usuário cadastrado.
Payload da requisição:
{
headers: {
"Authorization": "Bearer <TOKENJWT>"
"Content-type": "application/json"
},
body: {
"id": string,
}
}
/products?page=number - GET
Rota utilizada para listar todos os produtos disponíveis
Inserir a página de busca no Path da requisição
{
headers: {
"Content-type": "application/json"
},
query: {
"page": number,
}
}
/products/:id/ - GET
Rota utilizada para realizar uma busca detalhada de um único produto.
{
headers: {
"Content-type": "application/json"
},
params: {
"id": string,
}
}
/wishlist - POST
Rota utilizada para inserir um novo produto na lista de favoritos do usuário logado.
Payload da requisição:
{
headers: {
"Authorization": "Bearer <TOKENJWT>"
"Content-type": "application/json"
},
body: {
"productId": string,
}
}
/wishlist - DELETE
Rota utiizada para remover um produto da lista de favoritos do usuário logado.
{
headers: {
"Authorization": "Bearer <TOKENJWT>"
"Content-type": "application/json"
},
body: {
"productId": string,
}
}
Para visualizar os testes unitários realizados no projeto, rode o seguinte comando no terminal:
npm run test
- Testes Totais:
Para visualizar o coverage, rode o seguinte comando no terminal:
npm run test:cov
- Coverage