Skip to content

Commit

Permalink
creating and managing sessions
Browse files Browse the repository at this point in the history
  • Loading branch information
k1r0s committed Sep 1, 2018
1 parent b376b90 commit 038234f
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 8 deletions.
14 changes: 13 additions & 1 deletion src/config/lowdb.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
{
"sessions": [],
"sessions": [
{
"uid": "SY09e587g",
"expiration": 1535663517217,
"userUid": "1ywRUmDWy"
}
],
"users": [
{
"uid": "_gXUVVF6z",
Expand All @@ -14,6 +20,12 @@
"mail": "gt@test.net",
"name": "Genoveva Thillet",
"pass": "92fca2fc53414b3f12c765d22c51873e285f43c19a8596505c3251c1308214be2709dbf4906c2068632575fb1f28dc2dwLGIJ1YbTMVYwUq6u/+8hA=="
},
{
"uid": "xqR16Gi7w",
"name": "Norman Tuner",
"mail": "nt@foo.b",
"pass": "3e12a12b6e76895eb23542e6eec2bc60df2ad8d4b771de465ef5b62073ebafd739ca2358bc2d2b7a017e9f74b4389417SdDADGTbEVRAdKnUD7EatQ=="
}
]
}
88 changes: 88 additions & 0 deletions src/models/session.model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import DatabaseService from "../services/database.service";
import EncryptService from "../services/encrypt.service";
import { Provider, Dependency } from "@ritley/decorators";

@Provider.factory
@Dependency("database", DatabaseService)
@Dependency("encrypt", EncryptService)
export default class SessionModel {

static SESSION_MS_EXPIRATION = 1800000;

static newExpirationDate() {
return Date.now() + this.SESSION_MS_EXPIRATION;
}

static buildSession({ uid, name, ...user }) {
return {
expiration: this.newExpirationDate(),
userUid: uid
}
}

static updateSession({ expiration, ...session }) {
return {
expiration: this.newExpirationDate(),
...session
}
}

static hasSessionExpired = session => session.expiration < Date.now();

validateCredentials({ mail, pass }) {
return new Promise((resolve, reject) => {
this.database
.one("users", { mail })
.then(user => {
if(user && this.encrypt.decode(user.pass) === pass) resolve(user);
else reject(new SessionInvalidCredentialsError);
})
});
}

upsertSession(user) {
return new Promise(resolve => this.database.exists("sessions", { userUid: user.uid })
.then(session => this.updateSession(session).then(resolve),
() => this.createSession(user)).then(resolve));
}

createSession(user) {
return this.database.create("sessions", SessionModel.buildSession(user));
}

updateSession(session) {
return this.database.update("sessions", { uid: session.uid }, SessionModel.updateSession(session))
}

revalidate(session) {
if(SessionModel.hasSessionExpired(session)) {
this.database.remove("sessions", session.uid);
return Promise.reject(new SessionExpiredError);
} else {
return this.updateSession(session);
}
}

sessionExists(criteria) {
return new Promise((resolve, reject) =>
this.database.exists("sessions", criteria).then(resolve, () => reject(new SessionNotCreatedError)));
}
}

export class SessionNotCreatedError extends Error {
constructor() {
super("you need to create a session to perform this action")
}
}

export class SessionInvalidCredentialsError extends Error {
constructor() {
super("your credentials are invalid")
}
}

export class SessionExpiredError extends Error {
constructor() {
super("your session has expired")
}
}
34 changes: 30 additions & 4 deletions src/resources/session.resource.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,38 @@
import { AbstractResource } from "@ritley/core";
import SessionModel, { SessionInvalidCredentialsError } from "../models/session.model";

import {
Default,
MethodNotAllowed,
Created,
Throws,
Unauthorized,
BadRequest,
Dependency,
ReqTransformBodyAsync
} from "@ritley/decorators";


@Dependency("sessionModel", SessionModel)
export default class SessionResource extends AbstractResource {
@Default(MethodNotAllowed) get() {}
@Default(MethodNotAllowed) put() {}
@Default(MethodNotAllowed) delete() {}

static URI = "/sessions";

constructor() {
super("/sessions");
super(SessionResource.URI);
}

get(req, res) {
res.statusCode = 200;
res.end("Hello from sessions!");
@Throws(SyntaxError, BadRequest)
@Throws(SessionInvalidCredentialsError, Unauthorized)
@Default(Created)
@ReqTransformBodyAsync
async post(req) {
const body = await req.body;
const payload = body.toJSON();
const user = await this.sessionModel.validateCredentials(payload);
return this.sessionModel.upsertSession(user);
}
}
19 changes: 16 additions & 3 deletions src/resources/user.resource.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { AbstractResource } from "@ritley/core";
import UserModel, { UserValidationError, UserMailInUseError } from "../models/user.model";
import SessionModel, { SessionNotCreatedError, SessionExpiredError } from "../models/session.model";

import {
Dependency,
ReqTransformBodyAsync,
Default,
Throws,
InternalServerError,
BadRequest,
Conflict,
Created
Created,
Ok,
Unauthorized
} from "@ritley/decorators";

@Dependency("userModel", UserModel)
@Dependency("sessionModel", SessionModel)
export default class UserResource extends AbstractResource {
constructor() {
super("/users");
Expand All @@ -23,11 +26,21 @@ export default class UserResource extends AbstractResource {
@Throws(UserMailInUseError, Conflict)
@Default(Created)
@ReqTransformBodyAsync
async post(req, res) {
async post(req) {
const body = await req.body;
const payload = body.toJSON();
await this.userModel.validate(payload);
await this.userModel.isUnique(payload);
return this.userModel.create(payload);
}

@Throws(SessionNotCreatedError, Unauthorized)
@Throws(SessionExpiredError, Unauthorized)
@Default(Ok)
async get(req) {
const uid = req.headers["x-session"];
const session = await this.sessionModel.sessionExists({ uid });
await this.sessionModel.revalidate(session);
return this.userModel.searchBy();
}
}

0 comments on commit 038234f

Please sign in to comment.