--- author: foo-dogsquared categories: "side-projects" date: 2019-02-17 10:03:23 +0800 layout: post tags: ["projects", "node", "express"] title: "My first app with user accounts: 'bookmarkhub'" --- Here we go! Another project! I've been trying to implement the concepts I've been learning about for the past month or so. This time, it's about sessions, cookies, and user management. What could be a better way to actually implement than programming a social media-esque site about bookmarks! ## Overview It's a website that saves your bookmark associated with your account. It can save [Netscape bookmarks](https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa753582(v=vs.85)https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa753582(v=vs.85)) and [Pocket exports](https://help.getpocket.com/article/1015-exporting-your-pocket-list). In the upcoming future, it'll have the ability to add a name-URL key to add into the bookmark lists and import JSON file with specific formats. Also, it'll have the export bookmark feature. Until now, I wasn't able to deploy it mostly because I'm a noob on app deployment and free quality database services are rare as fully reaching the delivery time quota for the free pizza. This is my biggest project, so far, on my one year (and ongoing) worth of programming. This is my implementation of server-related concepts: [user and session management](https://stackoverflow.com/questions/10960131/authentication-authorization-and-session-management-in-traditional-web-apps-and), [sessions and cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies), [web token](https://auth0.com/blog/ten-things-you-should-know-about-tokens-and-cookies/), [HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP), and the [MVC pattern](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller). It's almost like a capstone project for those concepts that I really had a hard time grasping on the whole concept of servers and its related stuff. If you want to see the app yourself, go to the [README on the repo](https://github.com/foo-dogsquared/bookmarkhub/blob/master/README.md) and follow the instructions I listed there, then deploy it locally. ## How does it work First, let's discuss the foundational libraries that are used for this app. - [Express](https://expressjs.com/) — Well, if I want to quickly create a server-sided app, I need a framework for it. - [Pug](https://pugjs.org/) — The views in the [model-view-controller]() part of the app. - [SCSS](http://sass-lang.com/) — Simply the styling language used for the app. - [MongoDB](https://mongodb.com/) — The data layer for this app. Though, it uses [Mongoose](https://mongoosejs.com/) to consistently validate and keep the data intact through schemas. There is also [a session store library using MongoDB](https://www.npmjs.com/package/connect-mongodb-session?activeTab=readme), [JSDom](https://github.com/jsdom/jsdom) for easily parsing HTML bookmarks, [JWT](https://jwt.io/) for token validations, and [Helmet](https://www.npmjs.com/package/helmet) for security (through HTTP headers). The frontend isn't entirely managed (aside from basic user interaction such as toggles and forms) since the core functions are located in the server. I also use a testing library (which is [Mocha]()) for testing out the core features of the app (which is the bookmark import function). I admit that the testing implementation is crappy as I wasn't able to make the testing scope beyond just the one feature of the app. Well, I tried. If you have any feedback on this, you can contact [me through any of the contact list](http://foo-dogsquared.github.io/) or shoot me an [email](mailto://foo.dogsquared@gmail.com), whatever your poison. The app, more or less, functions almost like a social media site since it focuses on sharing bookmarks. Let's break the features down into a list: - user account management — registration, verification, logging in, logging out, and resetting the password with verification - email sending — when the user registration is successful, when the user confirmation is successful, when the user asks for the password reset and when the reset has been successful - session management — tracking of logged in users and their maximum age so the session database won't have much problem in case the user logged out irregularly (or didn't visit the website for a long time) - web tokens — this is specifically for account confirmation and creating a token for password reset - importing of bookmarks — you can import bookmarks from [Netscape](https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/platform-apis/aa753582(v=vs.85)) and [Pocket](https://help.getpocket.com/article/1015-exporting-your-pocket-list) - seeing other users — well, it almost functions as a social media site, remember? Hold on to your seat. It's going to be a somewhat serious and long discussion (whichever I ended up in my writing). ### User management Of course, being a website that focuses on sharing bookmarks among people, there has to be a way of managing your users. Also, it means you'll implement a user management system. My implementation of a user management system is completely generic: user registration, user login, and user logout. There are only a few restrictions such as access on `/account/profile` is completely restricted until you are visiting the page as a user. Another example could be the user couldn't get to `/signup` and `/login`. With the user management system in place, there has to be a session management system to track which of the users are logged in. So I did that with a session store with MongoDB which [someone already implemented it](https://github.com/mongodb-js/connect-mongodb-session). I didn't mind on how to implement it most of the stuff myself since I'm more focused on the concept of sessions and user management, overall. Aside from the usual signup, login, and logout, I also implemented account verification and resetting passwords. Oh, and they also feature email sendings. In other words, if you want to reset your password, you have to go through how most websites handle it: an email will be sent, click through the link, type the new password, submit the new password, and then you're done! If you're a newly registered user, you'll have to go through the verification process which is simple as visiting your email for the verification link and clicking on it.
I have thought of a way on how to implement the verification: - Generate a link that corresponds to the account. - Send to the user via email. - The user visits the link. - Check if the account is valid (in other words, if it exists on the database). - Then KLABLAMO! You're done! For resetting of passwords, it's mostly the same but a few extra steps. - Generate a link that corresponds to the account. - Send to the user via email. - The user visits the link. - If the token has expired, reject the process. Otherwise, continue. - If the account is invalid, reject the process. Otherwise, continue. - Prompt the user for the new password and submit it to the server. - Change the password in the database. For these, I need a couple of components: an email client and a web token generator. I used [Nodemailer](https://nodemailer.com/) for the email client and I registered a new email address for the app (with Gmail, of course since I'm a cheapskate) and I've used [JSON web tokens (or JWT)](https://jwt.io/) for... the tokens. I could've used a more secure token generator option since there are a couple of things I did. Since [JWT are made so that the server does not have to hold the data](https://en.wikipedia.org/wiki/JSON_Web_Token#Vulnerabilities_and_criticism), it could mean it could easily be exploited if implemented improperly. ~~Now that I think about it, I have thought a few implementations without the JWT thing.~~ The solution I have in mind just includes an additional security layer for resetting the password by allowing one user to make one reset password token at any given time. It is yet to be implemented at the time of writing, though. ~~Or I could implement without the JWT.~~ ### Bookmark import The core function of the app is to share bookmarks. Since there are common bookmark formats such as [Netscape/digital bookmarks](https://en.wikipedia.org/wiki/Bookmark_(digital)) and [Pocket exports](https://help.getpocket.com/article/1015-exporting-your-pocket-list), I focused on that. I've already had the schema for the bookmarks so I'm planning from the start to implement it on my own. I looked for similar solutions for converting Netscape bookmarks and based my upcoming code around those solutions. Then, I started to create the algorithm. The algorithm is quite simple: - have the file as input - scan the file - convert the file accordingly - output the object Anyway, this feature is kinda large (at least for me at the time) so I simply break the whole thing down into simple components: - a validator — checks whether the file is a valid bookmark file - a converter — check Each of them to be associated with Netscape bookmarks and Pocket exports so I have at least 4 smaller function components to complete. There's also an upcoming validator and converter for JSON bookmark files but there are not much use cases for it (I think...) so I don't know if it stays or not. #### Validators Let's start with the first component: validators or as I want to call it, checkers (not that [checkers](https://www.pexels.com/photo/red-black-and-blue-tattersall-textile-827056/)). For the bookmark file validators, the program just checks for the file extension. However, since both Netscape bookmarks and Pocket exports are both in HTML format, I have to implement additional checkings. For the Netscape bookmarks, I just have to check the doctype (``). For the Pocket exports which has the common HTML as the doctype (``), I have to check for the title since it is specifically assigned for it (exploitable but eh, at least its body is easy to parse through). #### Converters Next up is the converters. They are functions that convert specific files into a JSON object, to put it simply. The returned object should follow a specific format for it to be stored properly on the database: ```JSON { "type": "STRING", "title": "STRING", "root_name": "STRING", "children": {} } ``` - `type` — What type of bookmark is being imported (Netscape or Pocket) - `title` — The title of the bookmark which is extracted from the ``) only serves as line separators - folders are represented through `