This commit is contained in:
leca 2024-06-21 16:26:34 +03:00
parent 0527193add
commit 488db81517
7 changed files with 62 additions and 36 deletions

View File

@ -1,14 +1,21 @@
FROM node:latest FROM node:latest
WORKDIR /usr/src/app ARG UID=987
ARG GID=987
RUN groupadd -g ${GID} chat && useradd -d /usr/src/app -g ${GID} -u ${UID} chat
RUN mkdir -p /usr/src/app
RUN chmod 750 -R /usr/src/app
COPY package*.json ./ COPY package*.json ./
#RUN apk update && apk upgrade # && apk add --update alpine-sdk && apk add --update python WORKDIR /usr/src/app
RUN chown -R chat:chat /usr/src/app
RUN npm install RUN npm install
# If you are building your code for production
# RUN npm ci --omit=dev
COPY . . COPY . .
EXPOSE 8080 EXPOSE 8080
USER chat
CMD [ "node", "src/index.js" ] CMD [ "node", "src/index.js" ]

9
config.json Normal file
View File

@ -0,0 +1,9 @@
{
"sessionSecret": "PLEASE!!CHANGE!!TO!!A!!STRONG!!ONE!!",
"dbUser": "smk",
"dbName": "chat",
"dbPort": 5432,
"dbPassword": "CHANGEME",
"dbHost": "db",
"listenPort": 8080
}

View File

@ -22,9 +22,9 @@ services:
volumes: volumes:
- ./postgres:/var/lib/postgresql/data - ./postgres:/var/lib/postgresql/data
environment: environment:
POSTGRES_USER: smk # The PostgreSQL user (useful to connect to the database) POSTGRES_USER: smk # do not forget to change these in config.json!
POSTGRES_PASSWORD: CHANGEME # The PostgreSQL password (useful to connect to the database) POSTGRES_PASSWORD: CHANGEME
POSTGRES_DB: chat # The PostgreSQL default database (automatically created at first launch) POSTGRES_DB: chat
networks: networks:
ne_nuzhen: ne_nuzhen:

20
docs.md
View File

@ -118,3 +118,23 @@ Otherwise, compares passwords
If passwords match, creating session and redirects to __/__ If passwords match, creating session and redirects to __/__
Requires client to be not logged in. Requires client to be not logged in.
## Deployment
### Traditional
To deploy an application in traditional way, follow these steps:
1. edit ``config.json`` to your needs.
2. Install dependencies: ``npm i``
3. Run __src/index.js__. Use ``npm run prod`` if you want to run it as a production and ``npm run dev`` if you want to run it with nodemon.
### Docker
To deploy an application with Docker, you need to:
1. edit ``config.json`` to your needs ( do not forget that backend must be able to connect to db container.)
2. edit ``docker-compose.yml`` as with the data you've wrote to ``config.json``
3. Build and launch: ``docker-compose up --build``

View File

@ -5,7 +5,8 @@
"main": "test.js", "main": "test.js",
"scripts": { "scripts": {
"test": "nodemon test.js", "test": "nodemon test.js",
"dev": "nodemon src/index.js" "dev": "nodemon src/index.js",
"prod": "node src/index.js"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -4,6 +4,9 @@ const cors = require("cors");
const WebSocket = require('ws'); const WebSocket = require('ws');
const http = require('http'); const http = require('http');
const session = require('express-session'); const session = require('express-session');
const fs = require('fs')
const config = JSON.parse(fs.readFileSync('config.json'));
sessions = {}; // logged in clients, there are stored objects like {"token": "some_token_here", "socket": here-is-websocket-object} sessions = {}; // logged in clients, there are stored objects like {"token": "some_token_here", "socket": here-is-websocket-object}
@ -12,7 +15,7 @@ const utils = require("./utils")
const app = express(); const app = express();
const PORT = 8080; const PORT = config.listenPort;
utils.initDb(); utils.initDb();
@ -135,7 +138,7 @@ console.log("[LOG] Socket has been started");
const sessionParser = session({ const sessionParser = session({
name: 'smk_chat', name: 'smk_chat',
secret: 'PLEASE!!GENERATE!!A!!STRONG!!ONE!!', secret: config.sessionSecret,
resave: false, resave: false,
saveUninitialized: false saveUninitialized: false
}); });
@ -282,7 +285,7 @@ app.get('/api/getChatInfo/:chatId', middleware.requireToBeLoggedIn, async (req,
membersRequest.rows.forEach((member, index, membersRequest) => { membersRequest.rows.forEach((member, index, membersRequest) => {
members.push(member.id) members.push(member.id)
}); });
if (!members.includes(sessions[req.session.token].userId)) { if (!members.includes(sessions[req.session.token].userId)) {
return res.send("-2").status(403).end(); return res.send("-2").status(403).end();
} }
@ -300,10 +303,7 @@ app.get('/api/getChatInfo/:chatId', middleware.requireToBeLoggedIn, async (req,
} }
}); });
//IN: UserId, array of UserIDs that are to be invited.
//OUT: "Ok" if successful, "User with id ${MEMBERID} does not exist."
//Return -1 if amout of users to invite is 0.
//Requires to be logged in
app.post('/api/createChat', middleware.requireToBeLoggedIn, async (req, res) => { app.post('/api/createChat', middleware.requireToBeLoggedIn, async (req, res) => {
try { try {
const userId = sessions[req.session.token].userId const userId = sessions[req.session.token].userId
@ -343,10 +343,6 @@ app.post('/api/createChat', middleware.requireToBeLoggedIn, async (req, res) =>
} }
}); });
//IN: none.
//OUT: redirect to /login.
//Removes client's session, thus unlogging a user.
//Requires to be logged in.
app.get('/api/logout', middleware.requireToBeLoggedIn, (req, res) => { app.get('/api/logout', middleware.requireToBeLoggedIn, (req, res) => {
try { try {
sessions[req.session.token] = undefined; sessions[req.session.token] = undefined;
@ -359,11 +355,7 @@ app.get('/api/logout', middleware.requireToBeLoggedIn, (req, res) => {
}); });
//IN: lastname, firstname, middlename, password.
//OUT: redirect to /.
//Checks if user exist. If so, returns 400 with response "Such user exists.".
//Otherwise, registers a user with given data.
//Requires to be not logged in.
app.post('/api/register', middleware.requireToBeNotLoggedIn, async (req, res) => { app.post('/api/register', middleware.requireToBeNotLoggedIn, async (req, res) => {
try { try {
const { lastname, firstname, middlename, password } = req.body; const { lastname, firstname, middlename, password } = req.body;
@ -391,11 +383,7 @@ app.post('/api/register', middleware.requireToBeNotLoggedIn, async (req, res) =>
} }
}); });
//IN: lastname, firstname, middlename, password.
//OUT: redirect to /.
//Checks if user exists. If not, returns 400 with response "No such user.".
//Otherwise, compares passwords using bcrypt
//If passwords match, creating session and redirects to /
app.post('/api/login', middleware.requireToBeNotLoggedIn, async (req, res) => { app.post('/api/login', middleware.requireToBeNotLoggedIn, async (req, res) => {
try { try {
const { lastname, firstname, middlename, password } = req.body; const { lastname, firstname, middlename, password } = req.body;

View File

@ -1,15 +1,16 @@
const pg = require('pg'); const pg = require('pg');
const fs = require('fs'); const fs = require('fs');
const config = JSON.parse(fs.readFileSync('config.json'))
const { Client } = pg; const { Client } = pg;
client = new Client({ client = new Client({
user: "smk", user: config.dbUser,
password: "CHANGEME", // do not forget to change it in docker-compose.yml in db section. password: config.dbPassword,
// host: "10.5.0.6", //defined in docker-compose.yml. host: config.dbHost,
host: 'localhost', port: config.dbPort,
port: 5432, database: config.dbName
database: "chat"
}); });
module.exports = { module.exports = {