Twirl is a web app that shortens URLs. It allows users to sign up (verified with reCAPTCHA) and sign-in on the app and create short links by entering their original links. The app ensures protection of passwords by storing them in the database using salted hashing, by using the standard pbkdf2 function (imported from NodeJs' Crypto library). Each short link is uniquely generated. This is done by combining a pseudo-random string (generated by the randomBytes function of NodeJs' Crypto library) with a counter generated from the PostgreSQL database.
The app provides for two user-roles: admin and ordinary. Ordinary users can view the list of top 50 links shortened by them, the number of times each such short link has been accessed and an option to enable or disable them. Admin users can access the top 50 short links created by the app; however, an admin user is not given the permission to disable or enable links created by other users.
The project is accompanied by complete integration tests using Jest framework. The app has been deployed on Heroku. It can be accessed here: https://oteetwirl.herokuapp.com/login.
This project implements a Model-View-Controller (MVC) architecture. It has two models and two controllers, one each for handling user interactions and for generating short-links. It has a shared view component for displaying shortened links and basic analytics.
As the system uses PostgreSQL deployed on Docker, the relevant Docker container needs to be started:
docker-compose up
The database schema will need to be created:
\c postgres;
DROP DATABASE IF EXISTS twirl;
CREATE DATABASE twirl;
\connect twirl;
CREATE TABLE roles (
id SERIAL PRIMARY KEY,
name TEXT
);
CREATE TABLE users (
id UUID PRIMARY KEY,
username TEXT UNIQUE NOT NULL,
password TEXT NOT NULL,
created_at TIMESTAMP WITH TIME ZONE,
role_id INTEGER REFERENCES roles (id)
);
INSERT INTO roles (name) values ('admin') , ('normal'), ('superAdmin');
CREATE TABLE counters(
id TEXT PRIMARY KEY,
value INTEGER
);
INSERT INTO counters (id, value) values ('link_counter', 0);
UPDATE counters SET value=value+1 WHERE id='link_counter' RETURNING value;
CREATE TABLE links (
user_id UUID REFERENCES users (id),
original_link TEXT NOT NULL,
short_link TEXT NOT NULL,
enabled BOOLEAN NOT NULL DEFAULT 'true',
accessed_count INTEGER DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE,
updated_at TIMESTAMP WITH TIME ZONE,
PRIMARY KEY (user_id, original_link)
);
To run the system (environment variables for cookie secret, PostgreSQL connection string, and reCAPTCHA secret will need to be provided):
COOKIE_SECRET=<secret> PG_CONNECTION_STRING=postgres:https://<username>:<password>@localhost:5432/twirl PORT=4001 RECAPTCHA_SECRET=<secret> node app.js
To by-pass reCAPTCHA validation, use 'EXEMPTED' for the environment variable RECAPTCHA_SECRET
To start the system locally, with sample values for cookie secret:
npm run start_local app.js
To run the tests:
npm test