Răsfoiți Sursa

add: Message encryption

gugdun 9 luni în urmă
părinte
comite
a5a3484ace
8 a modificat fișierele cu 51 adăugiri și 11 ștergeri
  1. 1 1
      Dockerfile.development
  2. 1 1
      Dockerfile.production
  3. 12 3
      compose.yaml
  4. 1 1
      src/db.js
  5. 1 1
      src/index.js
  6. 4 3
      src/routes/chat.js
  7. 2 1
      src/routes/longpoll.js
  8. 29 0
      src/util/crypto.js

+ 1 - 1
Dockerfile.development

@@ -4,5 +4,5 @@ RUN mkdir -p /home/node/app && chown node:node /home/node/app
 WORKDIR /home/node/app
 USER node
 
-EXPOSE 8080
+EXPOSE 3000
 CMD ["npm", "run", "dev"]

+ 1 - 1
Dockerfile.production

@@ -8,5 +8,5 @@ USER node
 RUN npm install
 COPY --chown=node:node . .
 
-EXPOSE 8080
+EXPOSE 3000
 CMD ["npm", "run", "start"]

+ 12 - 3
compose.yaml

@@ -4,7 +4,10 @@ services:
       dockerfile: Dockerfile.production
     restart: always
     ports:
-      - 8080:5000
+      - 3000:3000
+    depends_on:
+      postgres:
+        condition: service_started
     profiles: [prod]
 
   dev:
@@ -12,16 +15,22 @@ services:
       dockerfile: Dockerfile.development
     restart: always
     ports:
-      - 8080:5000
+      - 3000:3000
     volumes:
       - .:/home/node/app
+    depends_on:
+      postgres:
+        condition: service_started
     profiles: [dev]
 
   adminer:
     image: adminer
     restart: always
     ports:
-      - 8081:8080
+      - 5000:8080
+    depends_on:
+      postgres:
+        condition: service_started
 
   postgres:
     image: "postgres:alpine"

+ 1 - 1
src/db.js

@@ -7,6 +7,6 @@ const db = pgp(process.env.POSTGRES_CONNECTION);
     await db.none("CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, username TEXT UNIQUE, hashed_password BYTEA, salt BYTEA )");
     await db.none("CREATE TABLE IF NOT EXISTS chats ( id SERIAL PRIMARY KEY, user1_id INTEGER, user2_id INTEGER, CONSTRAINT user1_fk FOREIGN KEY (user1_id) REFERENCES users (id), CONSTRAINT user2_fk FOREIGN KEY (user2_id) REFERENCES users (id) )")
     await db.none("CREATE TABLE IF NOT EXISTS attachments ( id SERIAL PRIMARY KEY, type TEXT NOT NULL, data BYTEA ) ")
-    await db.none("CREATE TABLE IF NOT EXISTS messages ( id SERIAL PRIMARY KEY, chat_id INTEGER, user_id INTEGER, attachment_id INTEGER, text TEXT, timestamp TIMESTAMP, CONSTRAINT chat_fk FOREIGN KEY (chat_id) REFERENCES chats (id), CONSTRAINT user_fk FOREIGN KEY (user_id) REFERENCES users (id), CONSTRAINT attachment_fk FOREIGN KEY (attachment_id) REFERENCES attachments (id) )")
+    await db.none("CREATE TABLE IF NOT EXISTS messages ( id SERIAL PRIMARY KEY, chat_id INTEGER, user_id INTEGER, attachment_id INTEGER, text BYTEA, timestamp TIMESTAMP, CONSTRAINT chat_fk FOREIGN KEY (chat_id) REFERENCES chats (id), CONSTRAINT user_fk FOREIGN KEY (user_id) REFERENCES users (id), CONSTRAINT attachment_fk FOREIGN KEY (attachment_id) REFERENCES attachments (id) )")
 })();
 module.exports = db;

+ 1 - 1
src/index.js

@@ -16,7 +16,7 @@ const chatRouter = require("./routes/chat");
 const addRouter = require("./routes/add");
 const longpollRouter = require("./routes/longpoll");
 
-const PORT = process.env.PORT || 5000;
+const PORT = process.env.PORT || 3000;
 
 const app = express();
 app.set("view engine", "ejs");

+ 4 - 3
src/routes/chat.js

@@ -5,6 +5,7 @@ const path = require("path");
 const express = require("express");
 const ejs = require("ejs");
 const db = require("../db");
+const { encrypt, decrypt } = require("../util/crypto");
 
 const views = path.join(__dirname, "..", "views");
 const router = express.Router();
@@ -25,7 +26,7 @@ router.get("/chat/:chat_id", async (req, res) => {
                     messages: messages.map((message) => {
                         return {
                             username: message.username,
-                            text: message.text,
+                            text: decrypt(message.text),
                             datetime: message.timestamp
                         }
                     }),
@@ -59,7 +60,7 @@ router.post("/chat/:chat_id", async (req, res) => {
             await db.none("INSERT INTO messages (chat_id, user_id, text, timestamp) VALUES ($1, $2, $3, $4)", [
                 chat?.id,
                 req.user.id,
-                req.body.text,
+                encrypt(req.body.text),
                 datetime
             ]);
             res.json({ success: true });
@@ -84,7 +85,7 @@ router.post("/chat/:chat_id/messages", async (req, res) => {
                 messages: messages.map((message) => {
                     return {
                         username: message.username,
-                        text: message.text,
+                        text: decrypt(message.text),
                         datetime: message.timestamp
                     }
                 }),

+ 2 - 1
src/routes/longpoll.js

@@ -3,6 +3,7 @@
 
 const express = require("express");
 const db = require("../db");
+const { decrypt } = require("../util/crypto");
 
 const router = express.Router();
 
@@ -20,7 +21,7 @@ router.post("/poll/:id", async (req, res) => {
                         messages: messages.map((message) => {
                             return {
                                 username: message.username,
-                                text: message.text,
+                                text: decrypt(message.text),
                                 datetime: message.timestamp
                             }
                         })

+ 29 - 0
src/util/crypto.js

@@ -0,0 +1,29 @@
+// Copyright (c) 2025 gugdun
+// All rights reserved. Unauthorized use, copying, or distribution is strictly prohibited.
+
+const crypto = require("crypto");
+const key = Buffer.from(process.env.MESSAGE_SECRET);
+
+function encrypt(plaintext) {
+    const iv = crypto.randomBytes(16);
+    const cipher = crypto.createCipheriv(
+        "aes-256-cbc",
+        key,
+        iv
+    );
+    return Buffer.concat([iv, cipher.update(plaintext, "utf8"), cipher.final()]);
+}
+
+function decrypt(ivCiphertext) {
+    const iv = ivCiphertext.subarray(0, 16);
+    const ciphertext = ivCiphertext.subarray(16);
+    const cipher = crypto.createDecipheriv(
+        "aes-256-cbc",
+        key,
+        iv
+    );
+    const decrypted = Buffer.concat([cipher.update(ciphertext), cipher.final()]);
+    return decrypted.toString("utf-8");
+}
+
+module.exports = { encrypt, decrypt };