Blog - 0x00

Creating a pet adoption platform


In september of last year I decided to start a new project, an adoption platform for pets. This was an idea I had for a while but just didn’t have time to start working on it, but now that I had enough time and I also wanted to learn more about developing web applications, in the sense of how they are implemented I started working on it.

I chose Flask to start developing the web application because I felt comfortable using Python and because Flask was a popular and simple framework. Because of its simplicity it doesn’t have any user management feature or database orm, but it does allow extensions to be written to extend its features. Because my web application is going to have users I’ll need a database to store them, so instead of writing raw queries and having to deal with SQL injection attacks, complex and not optimized queries I chose to use an ORM (Object relational mapper), SQLAlchemy, which is the most popular ORM for Python. The benefits of an ORM like SQLAlchemy aside from the previous mentioned is that it supports multiple databases, so by only changing the URL in the configuration you can change the database you use without having to deal with possible syntax problems in your query.

Simple design #

One of the things I believe is important is to avoid bloat in software and try to care about those details when writing code, specially when some languages and tools provide dependencies management makes it easy to add code to your software, which in itself is not bad, dependencies allow us to avoid reinventing the wheel and focus on writing your solution. The problem is when it makes it unnecessarily complex. For that reason is why I decided to use the template feature of Flask using Jinja2 to create the HTML instead of using Flask as a backend and the frontend ran using something like react, vue, angular, etc.

The design in itself is really simple and doesn’t use any Javascript at all. I’ve tried to use some websites which heavily depend on Javascript on my phone and they are practically unusable, they become slow and unresponsive, you could argue that it could be simply bad developers/design but is there really a need for Javascript? By not using Javascript low-end devices shouldn’t have problem loading the website, specially browsers (clients) that might not support javascript. Sure it won’t have any fancy burger menu that fades in when you click it and fades out when clicking elsewhere but again in this case, is it really needed?

Things I learned #

While developing the web application I learned quite a few things, which some I already knew but only from theory by either reading or watching explanations.

Sessions #

Flask has a sessions utility that allows to store information to a user using cookies. So when a user authenticates you store their user ID using cookies and those cookies are cryptographically signed. Meaning that, they can see the content of the cookie but if they modify it (without knowing your SECRET_KEY) then it will be invalid. The problem with client side session approach is that you don’t much control over that cookie, for example if you want to clear all sessions after a user changed their password then you won’t be able to know if that session is before or after the password update because it only contains the user ID, as a workaround you could store the user ID AND a timestamp when the password was changed so every time you receive a request you’ll have to check that the timestamp is the same as the one stored in your database.

I implemented a server side session, so its easier to keep track of the active sessions and to control them.

Authentication #

With authentication I always read and saw videos about hashing password and salting them, I knew how it worked in theory but couldn’t wrap my head around how the server could authenticate a session if the salt was supposedly random and could be put anywhere in the password, how could it be better than hashing if they had to store the salt in the database anyway.

Flask provides an utility through werkzeug that allows you to generate a password hash+salt and also one that checks a password hash.

For example if we generate a password with generate_password_hash("pass") it generates an output like this:


It looks long and complicated because it is but you can see that the output uses $ to separate fields.

>>> import hashlib
>>> hashlib.scrypt(b"pass", salt=b"klNz0yomOYCC3MU6", n=32768, r=8, p=1, maxmem=132*32768*8*1).hex()

Every time you call generate_password_hash() it will generate a random salt for the given password generating a completely different hash for the same password.

Configuring and sending emails #

Sending emails using python is simple they have several examples in their documentation. The part that was hard for me to understand was configuring the email server to be able to send properly configured emails.

Configuring postfix to send emails was simple, there are many guides you can find on the internet, that was the easy part. The problem is that only configuring postfix is not enough if you don’t want your emails to either be rejected or sent directly to peoples spam folder, many phishing emails abuse the fact that they can send email on behalf of another domain, which is why some emails might appear coming from but in fact they are phishing sending it from another domain, for that reason now a days mail servers require setting up DKIM and SPF as authentication methods when sending emails, otherwise your email is going to get rejected or sent to spam folder.

Setting DKIM and SPF took me a while to configure them properly and a lot of emails sent, because once you have configured it, you need to check if they are being received properly.

Conclusion #

I learned quite a few things from this project, although I knew some things just from theory, I believe applying that knowledge made me learn more about them and how they work. It was also fun developing the platform and seeing it slowly coming together.

For future developments I’d probably like to approach something like this with scalability in mind, for example designing it with microservices so it can easily scale horizontally, as a form of challenge.