Added sessions

pull/1/head
Trivernis 5 years ago
parent 4179aac231
commit 69e535276b

64
package-lock.json generated

@ -55,6 +55,15 @@
"@types/node": "*"
}
},
"@types/compression": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.0.1.tgz",
"integrity": "sha512-GuoIYzD70h+4JUqUabsm31FGqvpCYHGKcLtor7nQ/YvUyNX0o9SJZ9boFI5HjFfbOda5Oe/XOvNK6FES8Y/79w==",
"dev": true,
"requires": {
"@types/express": "*"
}
},
"@types/connect": {
"version": "3.4.32",
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz",
@ -153,7 +162,8 @@
"@types/js-yaml": {
"version": "3.12.1",
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-3.12.1.tgz",
"integrity": "sha512-SGGAhXLHDx+PK4YLNcNGa6goPf9XRWQNAUUbffkwVGGXIxmDKWyGGL4inzq2sPmExu431Ekb9aEMn9BkPqEYFA=="
"integrity": "sha512-SGGAhXLHDx+PK4YLNcNGa6goPf9XRWQNAUUbffkwVGGXIxmDKWyGGL4inzq2sPmExu431Ekb9aEMn9BkPqEYFA==",
"dev": true
},
"@types/mime": {
"version": "2.0.1",
@ -215,6 +225,7 @@
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/@types/winston/-/winston-2.4.4.tgz",
"integrity": "sha512-BVGCztsypW8EYwJ+Hq+QNYiT/MUyCif0ouBH+flrY66O5W+KIXAMML6E/0fJpm7VjIzgangahl5S03bJJQGrZw==",
"dev": true,
"requires": {
"winston": "*"
}
@ -1310,6 +1321,40 @@
"resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
"integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM="
},
"compressible": {
"version": "2.0.17",
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz",
"integrity": "sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==",
"requires": {
"mime-db": ">= 1.40.0 < 2"
}
},
"compression": {
"version": "1.7.4",
"resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",
"integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",
"requires": {
"accepts": "~1.3.5",
"bytes": "3.0.0",
"compressible": "~2.0.16",
"debug": "2.6.9",
"on-headers": "~1.0.2",
"safe-buffer": "5.1.2",
"vary": "~1.1.2"
},
"dependencies": {
"bytes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
"integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
}
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@ -1361,9 +1406,9 @@
}
},
"connect-pg-simple": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/connect-pg-simple/-/connect-pg-simple-6.0.0.tgz",
"integrity": "sha512-6pQnRSGFyswyHMdKQp5C+g78fjU/1/6eY05VeixXwMixw5KYhAcoOCXyf8TdPE1IzRLNDBMQi64vojXK/HMXVw==",
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/connect-pg-simple/-/connect-pg-simple-6.0.1.tgz",
"integrity": "sha512-zW5AOtRNOLcXxphSmQ+oYj0snlLs1Je3u5K2NWyF7WhMVoPvnQXraK2wzS8f7qLwhMcmYukah2ymu0Gdxf7Qsg==",
"requires": {
"pg": "^7.4.3"
}
@ -2691,12 +2736,14 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@ -2715,6 +2762,7 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -2894,7 +2942,8 @@
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
@ -3000,7 +3049,8 @@
"yallist": {
"version": "3.0.3",
"bundled": true,
"dev": true
"dev": true,
"optional": true
}
}
},

@ -18,6 +18,7 @@
"author": "SoftEngI",
"license": "ISC",
"devDependencies": {
"@types/compression": "^1.0.1",
"@types/connect-pg-simple": "^4.2.0",
"@types/cookie-parser": "^1.4.2",
"@types/express": "^4.17.1",
@ -26,9 +27,11 @@
"@types/express-socket.io-session": "^1.3.2",
"@types/fs-extra": "^8.0.0",
"@types/graphql": "^14.2.3",
"@types/js-yaml": "^3.12.1",
"@types/node": "^12.7.2",
"@types/pg": "^7.11.0",
"@types/socket.io": "^2.1.2",
"@types/winston": "^2.4.4",
"delete": "^1.1.0",
"gulp": "^4.0.2",
"gulp-minify": "^3.1.0",
@ -40,9 +43,8 @@
"typescript": "^3.5.3"
},
"dependencies": {
"@types/js-yaml": "^3.12.1",
"@types/winston": "^2.4.4",
"connect-pg-simple": "^6.0.0",
"compression": "^1.7.4",
"connect-pg-simple": "^6.0.1",
"cookie-parser": "^1.4.4",
"express": "^4.17.1",
"express-graphql": "^0.9.0",

@ -1,4 +1,12 @@
import * as compression from "compression";
import connectPgSimple = require("connect-pg-simple");
import * as cookieParser from "cookie-parser";
import * as express from "express";
import * as graphqlHTTP from "express-graphql";
import * as session from "express-session";
import sharedsession = require("express-socket.io-session");
import {buildSchema} from "graphql";
import {importSchema} from "graphql-import";
import * as http from "http";
import * as path from "path";
import * as socketIo from "socket.io";
@ -6,6 +14,8 @@ import dataaccess from "./lib/dataaccess";
import globals from "./lib/globals";
import routes from "./routes";
const PgSession = connectPgSimple(session);
class App {
public app: express.Application;
public io: socketIo.Server;
@ -23,10 +33,43 @@ class App {
public async init() {
await dataaccess.init();
await routes.ioListeners(this.io);
const appSession = session({
cookie: {
maxAge: Number(globals.config.session.cookieMaxAge),
secure: "auto",
},
resave: false,
saveUninitialized: true, // TODO: Set to false and only save when accepted by user.
secret: globals.config.session.secret,
store: new PgSession({
pool: dataaccess.pool,
tableName: "user_sessions",
}),
});
this.io.use(sharedsession(appSession, {autoSave: true}));
this.app.set("views", path.join(__dirname, "views"));
this.app.set("view engine", "pug");
this.app.set("trust proxy", 1);
this.app.use(compression());
this.app.use(express.json());
this.app.use(express.urlencoded({extended: false}));
this.app.use(express.static(path.join(__dirname, "public")));
this.app.use(cookieParser());
this.app.use(appSession);
this.app.use(routes.router);
this.app.use("/graphql", graphqlHTTP(async (request, response) => {
return {
// @ts-ignore all
context: {session: request.session},
graphiql: true,
rootValue: await routes.resolvers(request, response),
schema: buildSchema(importSchema("./public/graphql/schema.graphql")),
};
}));
}
/**

@ -9,3 +9,7 @@ database:
# http server configuration
server:
port: 8080
session:
secret: REPLACE WITH SAFE RANDOM GENERATED SECRET
cookieMaxAge: 604800000 # 7 days

@ -0,0 +1,51 @@
import {queryHelper} from "./index";
import {User} from "./User";
export class Profile extends User {
/**
* Sets the greenpoints of a user.
* @param points
*/
public async setGreenpoints(points: number): Promise<number> {
const result = await queryHelper.first({
text: "UPDATE users SET greenpoints = $1 WHERE id = $2 RETURNING greenpoints",
values: [points, this.id],
});
return result.greenpoints;
}
/**
* Sets the email of the user
* @param email
*/
public async setEmail(email: string): Promise<string> {
const result = await queryHelper.first({
text: "UPDATE TABLE users SET email = $1 WHERE users.id = $2 RETURNING email",
values: [email, this.id],
});
return result.email;
}
/**
* Updates the handle of the user
*/
public async setHandle(handle: string): Promise<string> {
const result = await queryHelper.first({
text: "UPDATE TABLE users SET handle = $1 WHERE id = $2",
values: [handle, this.id],
});
return result.handle;
}
/**
* Sets the username of the user
* @param name
*/
public async setName(name: string): Promise<string> {
const result = await queryHelper.first({
text: "UPDATE TABLE users SET name = $1 WHERE id = $2",
values: [name, this.id],
});
return result.name;
}
}

@ -17,18 +17,6 @@ export class User extends DataObject {
return this.$name;
}
/**
* Sets the username of the user
* @param name
*/
public async setName(name: string): Promise<string> {
const result = await queryHelper.first({
text: "UPDATE TABLE users SET name = $1 WHERE id = $2",
values: [name, this.id],
});
return result.name;
}
/**
* The unique handle of the user.
*/
@ -37,17 +25,6 @@ export class User extends DataObject {
return this.$handle;
}
/**
* Updates the handle of the user
*/
public async setHandle(handle: string): Promise<string> {
const result = await queryHelper.first({
text: "UPDATE TABLE users SET handle = $1 WHERE id = $2",
values: [handle, this.id],
});
return result.handle;
}
/**
* The email of the user
*/
@ -56,18 +33,6 @@ export class User extends DataObject {
return this.$email;
}
/**
* Sets the email of the user
* @param email
*/
public async setEmail(email: string): Promise<string> {
const result = await queryHelper.first({
text: "UPDATE TABLE users SET email = $1 WHERE users.id = $2 RETURNING email",
values: [email, this.id],
});
return result.email;
}
/**
* The number of greenpoints of the user
*/
@ -76,18 +41,6 @@ export class User extends DataObject {
return this.$greenpoints;
}
/**
* Sets the greenpoints of a user.
* @param points
*/
public async setGreenpoints(points: number): Promise<number> {
const result = await queryHelper.first({
text: "UPDATE users SET greenpoints = $1 WHERE id = $2 RETURNING greenpoints",
values: [points, this.id],
});
return result.greenpoints;
}
/**
* The date the user joined the platform
*/

@ -1,6 +1,7 @@
import {Pool} from "pg";
import globals from "../globals";
import {QueryHelper} from "../QueryHelper";
import {Profile} from "./Profile";
import {User} from "./User";
const config = globals.config;
@ -16,7 +17,18 @@ const dbClient: Pool = new Pool({
});
export const queryHelper = new QueryHelper(dbClient, tableCreationFile, tableUpdateFile);
/**
* Generates a new handle from the username and a base64 string of the current time.
* @param username
*/
function generateHandle(username: string) {
return `${username}.${Buffer.from(Date.now().toString()).toString("base64")}`;
}
namespace dataaccess {
export const pool: Pool = dbClient;
/**
* Initializes everything that needs to be initialized asynchronous.
*/
@ -45,6 +57,33 @@ namespace dataaccess {
return new User(result.id, result);
}
/**
* Returns the user by email and password
* @param email
* @param password
*/
export async function getUserByLogin(email: string, password: string) {
const result = await this.queryHelper.first({
text: "SELECT * FROM users WHERE email = $1 AND password = $2",
values: [email, password],
});
return new Profile(result.id, result);
}
/**
* Registers a user with a username and password returning a user
* @param username
* @param email
* @param password
*/
export async function registerUser(username: string, email: string, password: string) {
const result = await this.queryHelper.first({
text: "INSERT INTO users (name, handle, password, email) VALUES ($1, $2, $3, $4) RETURNING *",
values: [username, generateHandle(username), password, email],
});
return new Profile(result.id, result);
}
/**
* Enum representing the types of votes that can be performed on a post.
*/

@ -28,9 +28,9 @@ namespace routes {
* @param request
* @param response
*/
export const resolvers = async (request: any, response: any): Promise<object> => {
export async function resolvers(request: any, response: any): Promise<object> {
return homeRoute.resolver(request, response);
};
}
/**
* Assigns the io listeners or namespaces to the routes

@ -1,3 +1,10 @@
CREATE TABLE IF NOT EXISTS "user_sessions" (
"sid" varchar NOT NULL COLLATE "default",
"sess" json NOT NULL,
"expire" timestamp(6) NOT NULL,
PRIMARY KEY ("sid") NOT DEFERRABLE INITIALLY IMMEDIATE
) WITH (OIDS=FALSE);
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name varchar(128) NOT NULL,

Loading…
Cancel
Save