Gama Academy em parceria com a ACATE
Tecnologias | Proposta | Requisitos | Como usar | Equipe | API | Licença |
- A ideia
- Funcionalidades
- Segurança
- O banco de dados
- Integração com outros serviços
- Quickstart
- Endpoints
- A equipe
Olá! Somos a SavePet. Nosso objetivo é auxiliar animais em vulnerabilidade (ex. abandonados, machucados, doentes, maus tratos) por resgatar esses animais aonde estiverem, por acionar a instituição/ongs/pessoas para que essa possa fazer o resgate do animal e registre o status da ocorrencia. Se o animal estiver ferido/precisando de ajuda medica passará primeiro por cuidados antes de ser liberado para adoção, senão será encaminhado para a lista de adoção. Também contamos com a opção de cadastrar animais pra adoção ou se voluntariar pra adotar algum deles (da instituição ou cadastrado por outros).
Os usuários conseguem se cadastrar fornecendo um endereço de email válido, um número de telefone para contato e um documento de identificação válido, CPF para usuários regulares e CNPJ para ONGs, clínicas/hospitais veterinários ou outras entidades.
Os dados do usuário, com exceção do endereço de email e do documento de identificação, podem ser alterados, desde que o usuário esteja autenticado (mais detalhes em autenticação via JWT).
O usuário pode, ainda, recuperar a senha e excluir a própria conta. Essas duas ações, no entanto, não podem ser feitas diretamente. Para realizá-las o usuário primeiro precisa solicitar um token especial para o servidor que possui um prazo de validade de 10 minutos. Um request subsequente contendo o token válido confirma a ação.
Os tokens de recuperação de senha e de exclusão de conta precisam necessariamente serem enviados para o usuário através de um canal seguro. É comum a utilização de serviços externos de envio de emails, mensagens SMS ou mesmo mensagens em aplicativos como o WhatsApp.
A sessão integração com outros serviços contém mais informações sobre essas funcionalidades e como integrá-las ao SavePet.
Um usuário autenticado pode criar chamados que sinalizam a ocorrência de um animal em vulnerabilidade. Para isso, um pedido deve ser feito fornecendo um título que resuma a situação sendo sinalizada, o tipo do animal em risco, uma descrição mais detalhada da situação e a localização do animal.
A localização deve ser enviada no formato do padrão internacional World Geodetic System (WGS) com, no mínimo, 5 casas decimais. Esse padrão foi escolhido porque é o formato utilizado pelo Google, o que facilita a integração com suas APIs.
Exemplo de um request de criação do chamado mostrando as coordenadas no padrão WGS.
Um chamado pode ter suas informações alteradas pelo usuário que o criou ou por um usuário especial com o cargo de administrador. Da mesma forma, o criador ou administrador pode sinalizar o chamado como finalizado quando a situação tiver sido resolvida. Um chamado finalizado também pode ser reaberto em até 48 horas após ter sido finalizado.
A API SavePet utuliza JSON Web Tokens via cookie como forma de autenticar os usuários e permitir acesso seletivo a rotas restritas. Essa abordagem está alinhada com a proposta de um servidor stateless.
Os tokens levam a tag HttpOnly com o objetivo de mitigar o risco do cookie ser comprometido no lado do cliente.
Token JWT gerado com propriedades ID do usuário, issued at e timestamp de expiração.
Ao tentar acessar uma rota restrita, o JWT é identificado no request e validado. Após identificar o usuário no banco de dados, a timestamp de emissão do token é comparada com a timestamp da última troca de senha do usuário. No caso de comprometimento da conta e subsequente troca de senha por parte do usuário, todos os tokens emitidos antes da troca se tornam inválidos.
Falha na autenticação por qualquer motivo, como cookie expirado, retorna um erro genérico.
Como medida de segurança, a untrusted data enviadas nos requests passam por processos que têm por objetivo prevenir diversos tipos de ataques.
- O método
express.json()
é usado para limitar o tamanho dos requests a 10kb, diminuindo assim o risco de ataques que visam sobrecarregar a API com payloads excessivamente grandes. - A biblioteca xss ajuda a proteger contra ataques do tipo cross-site scripting.
- A biblioteca hpp protege contra ataques do tipo poluição de parâmetros HTTP. Em adição à filtração de parâmetros repetidos, a estratégia de whitelisting é utilizada para limitar quais os parâmetros são aceitos no request. A criação de uma whitelist, no caso da SavePet, é mais adequada do que uma blacklist devido à quantidade relativamente baixa de parâmetros que a API aceita.
- A biblioteca cpf-cnpj-validator valida os números de CPF ou CNPJ inseridos pelo usuário e a biblioteca validator é utilizada para validações diversas (tipos de caracteres na senha, email...).
A senha dos usuários não é armazenada diretamente. Ao invés disso, a as senhas passam por um processo de hashing e salting através da biblioteca bcrypt. O mesmo método é aplicado para proteger tokens de troca/recuperação de senha e deleção de conta (mais detalhes em segurança).
A SavePet segue o paradigma de manuseio de erros de passar os erros para a função next()
ao invés de throw new Error
.
A função de criação de novo usuário, por exemplo, retorna um erro notificando o usuário que o email inserido já está cadastrado.
Para lidar com erros nesse modelo, primeiro criamos uma classe de erro customizada, à qual foi dado o nome de AppError
, que extends a classe Error
padrão do JavaScript. A diferença dessa nova classe para a original é que ela adiciona um atributo que indica que esse erro é operacional.
Classe AppError. Error.captureStackTrace(this, this.constructor)
explicada logo abaixo.
Em seguida, criamos a função de global error handling que verifica se o erro é operacional.
Global error handler, função com 4 parâmetros.
Se o erro for operacional, é encaminhado para o usuário somente o código de status HTTP e a mensagem personalizada que foi escrita na hora que o objeto AppError
foi criado.
Em caso de erro decorrente de falhas no código, o usuário recebe somente um erro genérico com código HTTP 500 e uma mensagem de que algo deu errado.
Toda essa estratégia garante que, em caso de erro, o usuário receberá uma resposta que descreve exatamente o que aconteceu ou uma resposta genérica quando o erro for um bug. Não vazar na resposta o stack do erro é crucial para que o funcionamento interno da API não seja exposto.
Para facilitar o processo de desenvolvimento da aplicação a função global de erro verifica se a variável ambiental NODE_ENV
está definida como production
ou development
. Caso o ambiente seja de produção, a entrega de erros acontece conforme descrito acima. No entanto, para ajudar no processo de debugging, um outro controlador de erro é invocado caso o ambiente esteja definido como desenvolvimento.
Para definir em qual ambiente a aplicação iniciará, utilize os scripts npm run start:dev
e npm run start:prod
para iniciar em modo de desenvolvimento e produção, respectivamente.
Função de envio de erros em desenvolvimento.
Essa resposta inclui o código HTTP, o erro em si, a mensagem e mais importante a stack do erro. A função Error.captureStackTrace(this, this.constructor)
adiciona ao objeto de erro a stack de funções que foram invocadas até a função onde o erro ocorreu. O que facilita identificar onde o problema ocorreu.
Exemplo de erro em desenvolvimento mostrando o stack de funções.
Por motivos de segurança, caso não seja fornecido um valor válido de NODE_ENV
, a aplicação irá executar por padrão no modo produção.
Imagem dos objetos do banco de dados:
A SavePet foi desenvolvida tendo em mente a integração com serviços que possibilitam a autenticação em duas etapas. Os tokens de recuperação de senha e de exclusão de conta devem ser enviados para o usuário através de um canal que podemos assumir ser seguro.
Acima um exemplo de resposta contendo um token de recuperação de senha. O código neste repositório envia o token diretamente na resposta, o que é uma falha crítica de segurança. Quando for colocar essa API em produção, siga os passos descritos em integrar a API com autenticação em duas etapas.
Essa estratégia de autenticação parte do pressuposto que o email e/ou número de telefone do usuário são confiáveis. Com esse princípio estabelecido, a abordagem mais direta é integrar o sistema com APIs que enviam mensagens, seja por email, SMS ou através de aplicativos como o WhatsApp.
Existem centenas de serviços com os mais variados preços, dependendo do volume de mensagens e por onde elas são enviadas. Uma boa opção gratuita é o SendGrid, que possui planos gratuitos que atendem confortavelmente aplicações pequenas.
- Faça um fork e um clone desse repositório para executar o código localmente. Mais informações sobre esse processo aqui.
- Caso não tenha o Node.js, faça o download aqui e instale.
- Da mesma forma, baixe e instale o MySQL, caso não o tenha.
- Abra o CLI do Node.js e navegue até a pasta do projeto OU abra o terminal integrado do seu editor de código favorito na pasta do projeto.
- Execute o comando
npm install
.
-
Considerações sobre o funcionamento da API
-
Sugerimos que o processo de desenvolvimento da API seja feito com a ajuda do nodemon, por isso ele está na lista das dependências instaladas.
-
A API SavePet pode ser iniciada em dois modos: produção ou desenvolvimento. Isso afeta como as respostas são enviadas para o usuário. Mais informações em error handling em desenvolvimento.
-
Os scripts para iniciar a API em cada um dos modos são:
"scripts": { "start": "node server", "start:prod": "set NODE_ENV=production & nodemon server.js", "start:dev": "set NODE_ENV=development & nodemon server.js" },
-
-
Ainda na pasta do projeto, execute o comando
npm run start:dev
. -
A API estará agora rodando no modo desenvolvimento.
-
Os modelos do banco de dados estão configurados para gerar as tabelas automaticamente.
-
Sugerimos a utilização do Workbench para manipular o banco de dados.
-
Sugerimos o uso do Postman para a testagem das rotas.
-
No Postman, defina um ambiente com duas variáveis:
- URL: o endereço do seu
localhost
; - jwt: em branco (as rotas de autenticação irão editar essa variável dinamicamente).
- URL: o endereço do seu
-
A pasta
postman
possui dois arquivos no formato JSON com requests pré-configurados, basta importá-los dentro do Postman. -
Teste os endpoints.
-
Escolha um serviço que atenda ao seu caso de uso e se familiarize com a documentação. Recomendamos o SendGrid.
-
A integração com o serviço externo será feita no arquivo
./controllers/authController.js
. -
Alteração de senha:
- A função responsável por gerar a solicitação é a
resetPasswordRequest()
(linha 169). - Insira o código referente à conexão com o endpoint do serviço de mensagem abaixo da linha 198, enviando a variável
changeToken
, que é o token de troca. - Encapsule o código de conexão em um bloco
try / catch
e certifique-se que eventuais erros são manipulados corretamente. - Na resposta,
res.status(201)...
(originalmente na linha 199), retire o changeToken do corpo da resposta.
- A função responsável por gerar a solicitação é a
-
Encerramento da conta:
- Da mesma forma que na alteração de senha, identifique a função de geração do token para exclusão de conta:
deleteAccountRequest()
, linha 258. - Insira o código da API externa abaixo da linha 281.
- Encapsule o código e confira o manuseio de erros.
- Na resposta, originalmente na linha 282, remova o
deleteToken
do corpo.
- Da mesma forma que na alteração de senha, identifique a função de geração do token para exclusão de conta:
-
Boas práticas no envio de mensagens:
- Devido à quantidade imensa de spam, emails maliciosos e outros tipo de lixo eletrônico, as ferramentas de comunicação modernas possuem sistemas robustos que tentam diminuir esse problema.
- Por esse motivo é necessário seguir boas práticas para que a sua mensagem chegue no destinatário. Aqui estão algumas sugestões de boas práticas para envio de emails.
- Existem sites que permitem que você teste o quão "spam" o seu email parece. Um deles é o UnSpam.
-
Após testar a aplicação no modo desenvolvimento E no modo produção, é hora de colocá-la na internet.
-
Dos milhares de serviços de hospedagem da internet, pagos ou gratuitos, a plataforma Heroku é uma opção excelente para aplicações pequenas. O modo gratuito tem limitações, como por exemplo suspender a aplicação caso não ocorra nenhum acesso durante um certo período e o tempo de cold start pode chegar a 20 segundos.
-
O Heroku é totalmente compatível com aplicações Node e o deploy pode ser feito via Git. Informações detalhadas aqui.
Kanban é um sistema visual de gestão de trabalho, que busca conduzir cada tarefa por um fluxo predefinido de trabalho. Em geral, o conceito de Kanban pode ser definido pelos seguintes itens: O sistema visual: um processo, definido em um quadro com colunas de separação, que permite dividir o trabalho em segmentos ou pelo seu status, fixando cada item em um cartão e colocando em uma coluna apropriada para indicar onde ele está em todo o fluxo de trabalho. Os cartões: que descrevem o trabalho real que transita por este processo. A limitação do trabalho em andamento: que permite atribuir os limites de quantos itens podem estar em andamento em cada segmento ou estado do fluxo de trabalho. Ou seja, o Kanban é um fluxo de trabalho que busca indicar (e limitar) o trabalho em andamento — ou WIP, Work In Progress. O Kanban pode ser considerado também como uma metodologia ágil exatamente por ter o objetivo de evitar a procrastinação e render mais no dia a dia.
Somos uma entidade sem fins lucrativos que desenvolve papel fundamental na promoção do bem estar e proteção dos animais, além de conscientizar a população sobre a posse responsável de cães e gatos. Precisamos encontrar adotantes para nossos peludos e bichanos. Cumprindo essa missão, poderemos fazer mais e melhor em prol de cães e gatos abandonados. Nosso trabalho mantém-se unicamente por doações e trabalho voluntário. Não recebemos ajuda governamental e nem de empresas privadas. Seja nosso colaborador e faça a diferença na vida de peludos e bichanos! Sua solidariedade salva vidas.
Lucas Lamonier (Back-end | JavaScript | NodeJS | ExpressJS)
Linkedin ou GithubLucas Pampolha (Back-end | JavaScript | NodeJS | ExpressJS)
Linkedin ou GithubVando Rocha (Back-end | JavaScript | NodeJS | ExpressJS)
Linkedin ou GithubGisele Souza (Back-end | JavaScript | NodeJS | ExpressJS)
Linkedin ou Github
Instrutor: