A RESTful API to share notes and snippets of code.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
Marco Cetica dc06aba733
Added logo
2 weeks ago
db Added documentation and database schema 3 weeks ago
models Fixed a bug 3 weeks ago
routes Added '/gist/delete/:id' route 3 weeks ago
types '/gist/add' no longer ask for user id in request body. It now fetch it from the authorization token(JWT) 3 weeks ago
.dockerignore Added docker support 3 weeks ago
.gitignore First commit 4 weeks ago
.logo.png Added logo 2 weeks ago
Dockerfile Added docker support 3 weeks ago
LICENSE Added License file 2 weeks ago
README.md Added logo 2 weeks ago
checkJwt.ts Added '/gist/update/:id' route 3 weeks ago
docker-compose.yml Added docker support 3 weeks ago
nodemon.json First commit 4 weeks ago
package-lock.json '/gist/add' no longer ask for user id in request body. It now fetch it from the authorization token(JWT) 3 weeks ago
package.json Added docker support 3 weeks ago
process.json Added docker support 3 weeks ago
server.ts Added '/gist/add' route 3 weeks ago
tsconfig.json First commit 4 weeks ago

README.md

GISTBin

logo

A RESTful API to share notes and snippets of code.

Installation

The official and supported way to deploy this webapp is by using Docker. Open docker-compose.yml with an editor of your choice and trim the following parameters on the db service:

POSTGRES_USER: postgres # Postgres username
POSTGRES_PASSWORD: password # Postgres password

Be sure to copy the exact same parameters to the gistbin service:

DB_USER: postgres # Postgres username
DB_PW: password # Postgres password

You also have to generate a random and secure string for the JWT secret key:

JWT_SECRET: donotusethisstring

Finally, to enable user registration, add the following parameter to the gistbin service:

GB_ENABLE_SIGNUP: 1 # 1 = enabled  0 = disabled

by default user registration is enabled.

After that, you can spin up the containers using the following command:

$> docker-compose up -d

On the first deploy, the init script will make sure to create the database schema. The PostgreSQL data will be stored in a local folder called gistbin_db.

The server will listen on http://127.0.0.1:9000, if you want to use a different port, replace all entries of 9000 from process.json, Dockerfile and docker-compose.yml.

API endpoints

This REST service provides two different API endpoints:

  1. /user:
    • /*: GET all users;
    • /:id*: GET an user;
    • /signin: Create a session for existing user(POST);
    • /signup: Add a new user(POST);
    • /update/:id: Update existing user(PUT);
    • /delete/:id: DELETE existing user.
  2. /gist:
    • /: GET all gists;
    • /:id: GET a gist;
    • /add" Add a new gist(POST);
    • /update/:id: Update an existing gist(PUT);
    • /delete/:id: DELETE existing gist.

Endpoints marked with a "*" require authentication.

Authentication

Some API endpoints require user authentication in order to serve the requests. In GISTBin, user authentication is dealt with JSON Web Tokens(JWTs), a valid user can obtain a JWT by logging in using the /user/signin route.

To access restricted areas of the web app, a request must supply a valid JWT by storing it in the header. The correct format for the authorization header is the following:

Bearer <JWT>

When joining in, the user must provide a valid, unique email address and a password. Before adding the user record to the database, an hashing algorithm is applied to the plaintext password. The user record stores the digest of the password, thus the plaintext password is discarded after the hashing process. No further user information is being collected by this system.

A JWT becomes invalid after 5 hours. Expired tokens can not be refreshed.

Restricted areas

The restricted routes have a different behavior from the rest of the system. The edge cases are described below:

  • Querying the /gist/ endpoint without a session token will fetch public gists only;
  • Querying the /gist/ endpoint with a session token and the role of user will fetch public gists and private gists of the prior mentioned user;
  • Querying the /gists/ endpoint with a session token and the role of admin will fetch both public and private gists of any user;
  • Querying the /gist/:id endpoint without a session token will fetch the earlier mentioned gist if and only if it is being marked as public;
  • Querying the /gist/:id endpoint with a session token and the role of user will fetch the prior mentioned gist if and only if it is public or if it belongs to the prior mentioned user;
  • Querying the /gist/:id endpoint with a session token and the role of admin will fetch the prior mentioned gist despite any access constraint;
  • Querying the /gist/update/:id endpoint without a session will result in an error;
  • Querying the /gist/update/:id endpoint with a session and the role of user will update the prior mentioned gist if and only if it belongs to the prior mentioned user;
  • Querying the /gist/update/:id endpoint with a session and the role of admin will update the prior mentioned gist without any further constraint;
  • Querying the /gist/delete/:id endpoint without a session will result in an error;
  • Querying the /gist/delete/:id endpoint with a session and the role of user will delete the prior mentioned gist if and only if it belongs to the prior mentioned user;
  • Querying the /gist/delete/:id endpoint with a session and the role of admin will delete the prior mentioned gist without any further constraint;
  • Querying the /user/ endpoint without a session or with a session and the role of user will result in an error;
  • Querying the /user/:id endpoint without a session or with a session and the role of user will result in an error;
  • Querying the /user/update/:id endpoint without a session or with a session and the role of user will result in an error;
  • Querying the /user/delete/:id endpoint without a session or with a session and the role of user will result in an error;

Database schema

GISTBin relies on a relational(PostgreSQL) database made by two tables:

CREATE TYPE role AS ENUM ('admin', 'user');
CREATE TYPE ALevel AS ENUM ('public', 'private');

CREATE TABLE GB_user (
	UserId INT GENERATED ALWAYS AS IDENTITY,
	UserEmail TEXT NOT NULL,
	UserPassword TEXT NOT NULL,
	UserSignupDate TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
	UserRole role NOT NULL,
	PRIMARY KEY(UserId)
);

CREATE TABLE GB_gist (
	GistId BIGINT GENERATED ALWAYS AS IDENTITY,
	GistTitle TEXT NOT NULL,
	GistContent TEXT NOT NULL,
	GistDate TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
	GistOwner INT NOT NULL,
	GistAccess ALevel NOT NULL,
	PRIMARY KEY(GistId),
	CONSTRAINT fk_user
	FOREIGN KEY (GistOwner) REFERENCES GB_user(UserId) ON DELETE CASCADE
);

GB_user and GB_gist tables have a referential constraint which bounds each gist to one and only one user(one to many relationship). This means that each user amy creates zero, one or more gists but each gist must be created by one and only one user.

You can find a more complete schema on the db/ folder of this repository.

License

Copyright (c) Marco Cetica 2022 under GPLv3 license. You can read the terms of the GPLv3 license here.