basic registration/login/session
This commit is contained in:
parent
44510096d1
commit
f3cae4b90f
|
@ -0,0 +1,14 @@
|
||||||
|
FROM node:latest
|
||||||
|
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
#RUN apk update && apk upgrade # && apk add --update alpine-sdk && apk add --update python
|
||||||
|
RUN npm install
|
||||||
|
# If you are building your code for production
|
||||||
|
# RUN npm ci --omit=dev
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
CMD [ "node", "src/index.js" ]
|
|
@ -0,0 +1,23 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS Users (
|
||||||
|
ID SERIAL,
|
||||||
|
lastname VARCHAR(32),
|
||||||
|
firstname VARCHAR(32),
|
||||||
|
middlename VARCHAR(32),
|
||||||
|
password_hash CHAR(60), --nodejs bcrypt.
|
||||||
|
salt CHAR(29), -- nodejs bcrypt.
|
||||||
|
chats INT[] -- to table Chats, column ID.
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS Chats (
|
||||||
|
ID SERIAL,
|
||||||
|
name VARCHAR(32), --chat name
|
||||||
|
admins INT[], -- to table Users, column ID.
|
||||||
|
messages INT[] -- ref to table Messages, column ID.
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS Messages (
|
||||||
|
ID SERIAL,
|
||||||
|
author_id INT, -- ref to table Users, column ID.
|
||||||
|
time_sent TIMESTAMP,
|
||||||
|
content TEXT
|
||||||
|
);
|
|
@ -0,0 +1,33 @@
|
||||||
|
version: "3.3"
|
||||||
|
|
||||||
|
services:
|
||||||
|
chat:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- 8080:8080
|
||||||
|
networks:
|
||||||
|
ne_nuzhen:
|
||||||
|
ipv4_address: 10.5.0.5
|
||||||
|
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
db:
|
||||||
|
image: 'postgres:15'
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
|
networks:
|
||||||
|
ne_nuzhen:
|
||||||
|
ipv4_address: 10.5.0.6
|
||||||
|
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: smk # The PostgreSQL user (useful to connect to the database)
|
||||||
|
POSTGRES_PASSWORD: CHANGEME # The PostgreSQL password (useful to connect to the database)
|
||||||
|
POSTGRES_DB: chat # The PostgreSQL default database (automatically created at first launch)
|
||||||
|
|
||||||
|
networks:
|
||||||
|
ne_nuzhen:
|
||||||
|
driver: bridge
|
||||||
|
ipam:
|
||||||
|
config:
|
||||||
|
- subnet: 10.5.0.0/16
|
||||||
|
gateway: 10.5.0.1
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
"name": "chat",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "test.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "nodemon test.js",
|
||||||
|
"dev": "nodemon src/index.js"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.foxarmy.org/leca/smk-chat"
|
||||||
|
},
|
||||||
|
"author": "leca",
|
||||||
|
"license": "WTFPL",
|
||||||
|
"dependencies": {
|
||||||
|
"bcrypt": "^5.1.1",
|
||||||
|
"cookie-session": "^2.1.0",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"express": "^4.19.2",
|
||||||
|
"express-session": "^1.18.0",
|
||||||
|
"nodemon": "^3.1.3",
|
||||||
|
"pg": "^8.12.0"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
<mxfile host="app.diagrams.net" modified="2024-06-11T11:00:11.476Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36" etag="D0Ei79GTjtOxs9i7zUn2" version="24.5.2" type="device">
|
||||||
|
<diagram id="C5RBs43oDa-KdzZeNtuy" name="Page-1">
|
||||||
|
<mxGraphModel dx="1279" dy="748" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||||
|
<root>
|
||||||
|
<mxCell id="WIyWlLk6GJQsqaUBKTNV-0" />
|
||||||
|
<mxCell id="WIyWlLk6GJQsqaUBKTNV-1" parent="WIyWlLk6GJQsqaUBKTNV-0" />
|
||||||
|
<mxCell id="GfNOIcLhO2e9G-0w8RP9-0" value="Users" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" parent="WIyWlLk6GJQsqaUBKTNV-1" vertex="1">
|
||||||
|
<mxGeometry y="80" width="240" height="240" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="GfNOIcLhO2e9G-0w8RP9-1" value="ID SERIAL" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="GfNOIcLhO2e9G-0w8RP9-0" vertex="1">
|
||||||
|
<mxGeometry y="30" width="240" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="GfNOIcLhO2e9G-0w8RP9-2" value="lastname VARCHAR(32)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="GfNOIcLhO2e9G-0w8RP9-0" vertex="1">
|
||||||
|
<mxGeometry y="60" width="240" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="5QsmdMTZOQ-KcOoPIG_9-1" value="firstname VARCHAR(32)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="GfNOIcLhO2e9G-0w8RP9-0">
|
||||||
|
<mxGeometry y="90" width="240" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="5QsmdMTZOQ-KcOoPIG_9-2" value="middlename VARCHAR(32)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="GfNOIcLhO2e9G-0w8RP9-0">
|
||||||
|
<mxGeometry y="120" width="240" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="GfNOIcLhO2e9G-0w8RP9-3" value="password_hash CHAR(60)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" parent="GfNOIcLhO2e9G-0w8RP9-0" vertex="1">
|
||||||
|
<mxGeometry y="150" width="240" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="5QsmdMTZOQ-KcOoPIG_9-0" value="salt CHAR(29)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="GfNOIcLhO2e9G-0w8RP9-0">
|
||||||
|
<mxGeometry y="180" width="240" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="5QsmdMTZOQ-KcOoPIG_9-4" value="chats INT[]" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="GfNOIcLhO2e9G-0w8RP9-0">
|
||||||
|
<mxGeometry y="210" width="240" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="5QsmdMTZOQ-KcOoPIG_9-5" value="Chats" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
|
||||||
|
<mxGeometry x="687" y="110" width="140" height="150" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="5QsmdMTZOQ-KcOoPIG_9-6" value="ID SERIAL" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="5QsmdMTZOQ-KcOoPIG_9-5">
|
||||||
|
<mxGeometry y="30" width="140" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="5QsmdMTZOQ-KcOoPIG_9-7" value="name VARCHAR(32)" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="5QsmdMTZOQ-KcOoPIG_9-5">
|
||||||
|
<mxGeometry y="60" width="140" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="5QsmdMTZOQ-KcOoPIG_9-21" value="admins<span style="background-color: initial;">&nbsp;INT[]</span>" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="5QsmdMTZOQ-KcOoPIG_9-5">
|
||||||
|
<mxGeometry y="90" width="140" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="5QsmdMTZOQ-KcOoPIG_9-8" value="messages INT[]" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="5QsmdMTZOQ-KcOoPIG_9-5">
|
||||||
|
<mxGeometry y="120" width="140" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="5QsmdMTZOQ-KcOoPIG_9-9" value="Messages" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;" vertex="1" parent="WIyWlLk6GJQsqaUBKTNV-1">
|
||||||
|
<mxGeometry x="360" y="360" width="240" height="150" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="5QsmdMTZOQ-KcOoPIG_9-10" value="ID SERIAL" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="5QsmdMTZOQ-KcOoPIG_9-9">
|
||||||
|
<mxGeometry y="30" width="240" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="5QsmdMTZOQ-KcOoPIG_9-11" value="author_id INT" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="5QsmdMTZOQ-KcOoPIG_9-9">
|
||||||
|
<mxGeometry y="60" width="240" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="5QsmdMTZOQ-KcOoPIG_9-12" value="time_sent TIMESTAMP" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="5QsmdMTZOQ-KcOoPIG_9-9">
|
||||||
|
<mxGeometry y="90" width="240" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="5QsmdMTZOQ-KcOoPIG_9-23" value="content TEXT" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="5QsmdMTZOQ-KcOoPIG_9-9">
|
||||||
|
<mxGeometry y="120" width="240" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="5QsmdMTZOQ-KcOoPIG_9-17" value="" style="edgeStyle=entityRelationEdgeStyle;fontSize=12;html=1;endArrow=ERzeroToMany;startArrow=ERmandOne;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="5QsmdMTZOQ-KcOoPIG_9-4" target="5QsmdMTZOQ-KcOoPIG_9-6">
|
||||||
|
<mxGeometry width="100" height="100" relative="1" as="geometry">
|
||||||
|
<mxPoint x="400" y="370" as="sourcePoint" />
|
||||||
|
<mxPoint x="500" y="270" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="5QsmdMTZOQ-KcOoPIG_9-20" value="" style="edgeStyle=entityRelationEdgeStyle;fontSize=12;html=1;endArrow=ERzeroToOne;startArrow=ERmandOne;rounded=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="5QsmdMTZOQ-KcOoPIG_9-8" target="5QsmdMTZOQ-KcOoPIG_9-10">
|
||||||
|
<mxGeometry width="100" height="100" relative="1" as="geometry">
|
||||||
|
<mxPoint x="160" y="500" as="sourcePoint" />
|
||||||
|
<mxPoint x="260" y="400" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="5QsmdMTZOQ-KcOoPIG_9-22" value="" style="edgeStyle=entityRelationEdgeStyle;fontSize=12;html=1;endArrow=ERzeroToMany;startArrow=ERmandOne;rounded=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="5QsmdMTZOQ-KcOoPIG_9-21" target="GfNOIcLhO2e9G-0w8RP9-1">
|
||||||
|
<mxGeometry width="100" height="100" relative="1" as="geometry">
|
||||||
|
<mxPoint x="505" y="550" as="sourcePoint" />
|
||||||
|
<mxPoint x="815" y="440" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="5QsmdMTZOQ-KcOoPIG_9-24" value="" style="edgeStyle=entityRelationEdgeStyle;fontSize=12;html=1;endArrow=ERzeroToOne;startArrow=ERmandOne;rounded=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="WIyWlLk6GJQsqaUBKTNV-1" source="5QsmdMTZOQ-KcOoPIG_9-11" target="GfNOIcLhO2e9G-0w8RP9-1">
|
||||||
|
<mxGeometry width="100" height="100" relative="1" as="geometry">
|
||||||
|
<mxPoint x="150" y="480" as="sourcePoint" />
|
||||||
|
<mxPoint x="250" y="380" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
</root>
|
||||||
|
</mxGraphModel>
|
||||||
|
</diagram>
|
||||||
|
</mxfile>
|
|
@ -0,0 +1,131 @@
|
||||||
|
const express = require('express');
|
||||||
|
const pg = require('pg');
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
const bcrypt = require('bcrypt');
|
||||||
|
const cors = require("cors");
|
||||||
|
const cookieSession = require("cookie-session");
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
const { Client } = pg;
|
||||||
|
const client = new Client({
|
||||||
|
user: "smk",
|
||||||
|
password: "CHANGEME", // do not forget to change it in docker-compose.yml in db section.
|
||||||
|
host: "10.5.0.6", //defined in docker-compose.yml.
|
||||||
|
port: 5432,
|
||||||
|
database: "chat"
|
||||||
|
})
|
||||||
|
app.use(cors());
|
||||||
|
app.use(express.json());
|
||||||
|
app.use(express.urlencoded({ extended: false }));
|
||||||
|
app.use(require('express-session')({
|
||||||
|
|
||||||
|
name: 'smk_chat',
|
||||||
|
secret: 'PLEASE!!GENERATE!!A!!STRONG!!ONE',
|
||||||
|
resave: false,
|
||||||
|
saveUninitialized: false
|
||||||
|
|
||||||
|
}));
|
||||||
|
|
||||||
|
let sessions = {}
|
||||||
|
|
||||||
|
app.get('/', (req, res) => {
|
||||||
|
if (sessions[req.session.token] == undefined) return res.redirect('/login');
|
||||||
|
res.sendFile('views/index.html', { root: __dirname });
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/registration', (req, res) => {
|
||||||
|
if (req.session.token != undefined) return res.redirect('/');
|
||||||
|
|
||||||
|
res.sendFile('views/registration.html', { root: __dirname });
|
||||||
|
});
|
||||||
|
|
||||||
|
app.get('/login', (req, res) => {
|
||||||
|
if (sessions[req.session.token] != undefined) return res.redirect('/');
|
||||||
|
res.sendFile('views/login.html', { root: __dirname });
|
||||||
|
});
|
||||||
|
|
||||||
|
const generateRandomString = () => {
|
||||||
|
return Math.floor(Math.random() * Date.now()).toString(36);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const getIdByCredentials = async (lastname, firstname, middlename) => {
|
||||||
|
let query_res = await client.query("SELECT ID FROM Users WHERE lastname = $1::text AND firstname = $2::text AND middlename = $3::text;", [lastname, firstname, middlename]);
|
||||||
|
if (query_res.rowCount == 0) return -1; // no such user
|
||||||
|
if (query_res.rowCount == 1) return query_res.rows[0].id;
|
||||||
|
}
|
||||||
|
|
||||||
|
app.get('/api/logout', (req, res) => {
|
||||||
|
if (req.session.token == undefined) return res.redirect('/login');
|
||||||
|
sessions[req.session.token] = undefined;
|
||||||
|
res.redirect('/login');
|
||||||
|
})
|
||||||
|
|
||||||
|
app.post('/api/register', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { lastname, firstname, middlename, password } = req.body;
|
||||||
|
|
||||||
|
const salt = bcrypt.genSaltSync(10);
|
||||||
|
const hash = bcrypt.hashSync(password, salt);
|
||||||
|
|
||||||
|
if (await getIdByCredentials(lastname, firstname, middlename) > -1) {
|
||||||
|
return res.status(400).send("Such user exists.").end();
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = (await client.query(
|
||||||
|
"INSERT INTO Users (lastname, firstname, middlename, password_hash, salt) VALUES ($1, $2, $3, $4, $5) RETURNING ID;",
|
||||||
|
[lastname, firstname, middlename, hash, salt]
|
||||||
|
)).rows[0].id;
|
||||||
|
req.session.token = generateRandomString();
|
||||||
|
sessions[req.session.token] = id;
|
||||||
|
res.redirect('/');
|
||||||
|
} catch (err) {
|
||||||
|
console.log("[ERROR] in /api/register: " + err)
|
||||||
|
res.status(500).send();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.post('/api/login', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { lastname, firstname, middlename, password } = req.body;
|
||||||
|
|
||||||
|
const ID = await getIdByCredentials(lastname, firstname, middlename)
|
||||||
|
if (ID == -1) {
|
||||||
|
return res.status(400).send("No such user.").end();
|
||||||
|
}
|
||||||
|
|
||||||
|
let stored_password = (await client.query("SELECT password_hash FROM Users WHERE ID = $1;", [ID])).rows[0].password_hash;
|
||||||
|
|
||||||
|
if (bcrypt.compareSync(password, stored_password)) {
|
||||||
|
req.session.token = generateRandomString()
|
||||||
|
sessions[req.session.token] = ID;
|
||||||
|
return res.redirect('/');
|
||||||
|
} else {
|
||||||
|
return res.status(400).send("Wrong password").end();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("[ERROR] in /api/login: " + err)
|
||||||
|
res.status(500).send();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
const initDb = async () => {
|
||||||
|
await client.connect()
|
||||||
|
|
||||||
|
let db_schema = fs.readFileSync('./db.psql').toString();
|
||||||
|
try {
|
||||||
|
const res = await client.query(db_schema);
|
||||||
|
console.log("Database initialized.")
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Cannot initialize database. Error: " + err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
initDb().then(() => {
|
||||||
|
app.listen(8080, "0.0.0.0", () => {
|
||||||
|
console.log("Ready to use.");
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,10 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>index</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<a href="/api/logout">Выйти</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,23 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>login</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<body>
|
||||||
|
<form method="post" action="/api/login">
|
||||||
|
<label for="lastname">Фамилия:</label><br/>
|
||||||
|
<input type="text" id="lastname" name="lastname"><br/>
|
||||||
|
<label for="firstname">Имя:</label><br/>
|
||||||
|
<input type="text" id="firstname" name="firstname"><br/>
|
||||||
|
<label for="middlename">Отчество:</label><br/>
|
||||||
|
<input type="text" id="middlename" name="middlename"><br/>
|
||||||
|
<label for="password">Пароль:</label><br/>
|
||||||
|
<input type="text" id="password" name="password"><br/>
|
||||||
|
<input type="submit" value="Войти">
|
||||||
|
</form>
|
||||||
|
Нет аккаунта? <a href="/register">Зарегистрируйте.</a>
|
||||||
|
</body>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,36 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>registration</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<form onSubmit="return checkPassword(this)" method="post" action="/api/register">
|
||||||
|
<label for="lastname">Фамилия:</label><br/>
|
||||||
|
<input type="text" id="lastname" name="lastname"><br/>
|
||||||
|
<label for="firstname">Имя:</label><br/>
|
||||||
|
<input type="text" id="firstname" name="firstname"><br/>
|
||||||
|
<label for="middlename">Отчество:</label><br/>
|
||||||
|
<input type="text" id="middlename" name="middlename"><br/>
|
||||||
|
<label for="password">Пароль:</label><br/>
|
||||||
|
<input type="text" id="password" name="password"><br/>
|
||||||
|
<label for="confirmPassword">Повтор пароля:</label><br/>
|
||||||
|
<input type="text" id="confirmPassword" name="confirmPassword"><br/>
|
||||||
|
<input type="submit" value="Зарегистрироваться">
|
||||||
|
</form>
|
||||||
|
Уже есть аккаунт? <a href="/login">Войдите.</a>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
function checkPassword(form) {
|
||||||
|
const password = form.password.value;
|
||||||
|
const confirmPassword = form.confirmPassword.value;
|
||||||
|
|
||||||
|
if (password != confirmPassword) {
|
||||||
|
alert("Error! Password did not match.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</html>
|
Loading…
Reference in New Issue