Encrypted-Chat-Server/server.js

316 lines
8.8 KiB
JavaScript
Raw Normal View History

2024-12-15 14:11:44 +00:00
const express = require("express");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const { PrismaClient } = require("@prisma/client");
const crypto = require("crypto");
const cors = require("cors");
require("dotenv").config();
const prisma = new PrismaClient();
const app = express();
app.use(express.json());
app.use(cors({
origin: "*", // Allow all origins
methods: ["GET", "POST", "PUT", "DELETE"], // Allow all methods
}));
const JWT_SECRET = "your_jwt_secret"; // Replace with a secure secret
// Authentication Middleware
const authenticate = async (req, res, next) => {
const token = req.header("Authorization")?.replace("Bearer ", "");
if (!token) return res.status(401).send("Access denied");
try {
const decoded = jwt.verify(token, JWT_SECRET);
req.user = decoded;
next();
} catch (err) {
return res.status(401).send("Invalid token");
}
};
// Register User
app.post("/register", async (req, res) => {
const { email, username, password, pubKey } = req.body;
const userExists = await prisma.user.findUnique({ where: { username } });
if (userExists) return res.status(400).send("User already exists");
const hashedPassword = await bcrypt.hash(password, 10);
const user = await prisma.user.create({
data: {
email,
username,
password: hashedPassword,
pubKey,
},
});
const token = jwt.sign({ username: user.username }, JWT_SECRET, { expiresIn: "1h" });
res.send({ token });
});
// Update Public Key
app.post("/user/updatePublicKey", authenticate, async (req, res) => {
const { pubKey } = req.body;
const username = req.user.username;
if (!pubKey) return res.status(400).send("Public key is required");
try {
await prisma.user.update({
where: { username },
data: { pubKey },
});
res.send({ message: "Public key updated successfully" });
} catch (error) {
console.error("Error updating public key:", error);
res.status(500).send({ error: "Failed to update public key" });
}
});
// Login User
// Login User
app.post("/login", async (req, res) => {
const { username, password } = req.body;
const user = await prisma.user.findUnique({
where: { username },
select: { password: true, pubKey: true },
});
if (!user) return res.status(400).send("Invalid credentials");
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) return res.status(400).send("Invalid credentials");
const token = jwt.sign({ username }, JWT_SECRET, { expiresIn: "1h" });
res.send({ token, pubKey: user.pubKey });
});
// Fetch pending friend requests sent to the authenticated user
app.get("/friend-requests/pending", authenticate, async (req, res) => {
const username = req.user.username;
try {
const pendingRequests = await prisma.friendRequest.findMany({
where: {
receiverUsername: username,
status: "pending",
},
include: {
sender: {
select: { username: true },
},
},
});
res.send(pendingRequests);
} catch (err) {
res.status(500).send({ error: "Failed to fetch pending friend requests" });
}
});
// Send Friend Request
app.post("/friend-request", authenticate, async (req, res) => {
const { receiverUsername } = req.body;
const senderUsername = req.user.username;
const receiver = await prisma.user.findUnique({ where: { username: receiverUsername } });
if (!receiver) return res.status(404).send("User not found");
const existingRequest = await prisma.friendRequest.findFirst({
where: {
OR: [
{ senderUsername, receiverUsername },
{ senderUsername: receiverUsername, receiverUsername: senderUsername },
],
},
});
if (existingRequest) return res.status(400).send("Friend request already exists");
const request = await prisma.friendRequest.create({
data: {
senderUsername,
receiverUsername,
status: "pending",
},
});
res.send(request);
});
// Respond to Friend Request
app.post("/friend-request/respond", authenticate, async (req, res) => {
const { requestId, response } = req.body;
const username = req.user.username;
const request = await prisma.friendRequest.findUnique({ where: { id: requestId } });
if (!request || request.receiverUsername !== username)
return res.status(403).send("You cannot respond to this request");
const status = response === "accepted" ? "accepted" : "rejected";
await prisma.friendRequest.update({
where: { id: requestId },
data: { status },
});
res.send("Response recorded");
});
// Fetch Friends
app.get("/friends", authenticate, async (req, res) => {
const username = req.user.username;
try {
const friends = await prisma.friendRequest.findMany({
where: {
OR: [
{ senderUsername: username, status: "accepted" },
{ receiverUsername: username, status: "accepted" },
],
},
include: {
sender: { select: { username: true, email: true } },
receiver: { select: { username: true, email: true } },
},
});
const friendList = friends.map((f) => ({
username: f.senderUsername === username ? f.receiver.username : f.sender.username,
email: f.senderUsername === username ? f.receiver.email : f.sender.email,
}));
res.send(friendList);
} catch (err) {
res.status(500).send({ error: "Failed to fetch friends" });
}
});
// Fetch Messages Between Two Users
app.get("/messages", authenticate, async (req, res) => {
const { receiverUsername } = req.query;
const username = req.user.username;
if (!receiverUsername) {
return res.status(400).send("Receiver username is required");
}
const messages = await prisma.message.findMany({
where: {
OR: [
{ senderUsername: username, receiverUsername },
{ senderUsername: receiverUsername, receiverUsername: username },
],
},
orderBy: { createdAt: "asc" },
});
res.send(messages);
});
// Send a Message
app.post("/messages", authenticate, async (req, res) => {
const senderUsername = req.user.username;
const { encrypted, nonce, pubKey, receiverUsername } = req.body;
console.log(encrypted)
if (!encrypted || !nonce || !pubKey || !receiverUsername) {
return res.status(400).send("Missing required fields (encrypted, nonce, pubKey, receiverUsername)");
}
const receiver = await prisma.user.findUnique({ where: { username: receiverUsername } });
if (!receiver) return res.status(404).send("Receiver not found");
const isFriend = await prisma.friendRequest.findFirst({
where: {
OR: [
{ senderUsername, receiverUsername, status: "accepted" },
{ senderUsername: receiverUsername, receiverUsername: senderUsername, status: "accepted" },
],
},
});
if (!isFriend) return res.status(403).send("You can only message friends");
const message = await prisma.message.create({
data: {
content: encrypted,
senderUsername,
receiverUsername,
nonce: nonce,
pubKey: pubKey,
},
});
res.send(message);
});
app.get("/test" , async(req,res) => {
const messages = await prisma.message.findMany()
res.send(messages)
})
// Get User Public Key if they are friends
app.get("/user/pubkey", authenticate, async (req, res) => {
const { username: friendUsername } = req.query; // Username of the requested friend
const username = req.user.username; // Authenticated user's username
try {
// Check if the user exists
const user = await prisma.user.findUnique({
where: { username: friendUsername },
select: { pubKey: true }, // Only select the public key
});
if (!user) {
return res.status(404).send("User not found");
}
// Check if the authenticated user is friends with the requested user
const isFriend = await prisma.friendRequest.findFirst({
where: {
OR: [
{ senderUsername: username, receiverUsername: friendUsername, status: "accepted" },
{ senderUsername: friendUsername, receiverUsername: username, status: "accepted" },
],
},
});
if (!isFriend) {
return res.status(403).send("You can only fetch the public key of your friends");
}
// Return the public key
res.send({ pubKey: user.pubKey });
} catch (err) {
res.status(500).send({ error: "Failed to fetch the public key" });
}
});
// Delete Message
app.delete("/messages/:id", authenticate, async (req, res) => {
const { id } = req.params;
const username = req.user.username;
const message = await prisma.message.findUnique({ where: { id: parseInt(id) } });
if (!message || message.senderUsername !== username)
return res.status(403).send("You can only delete your own messages");
await prisma.message.delete({ where: { id: parseInt(id) } });
res.send("Message deleted successfully");
});
app.listen(4000, () => {
console.log("Server running on http://localhost:4000");
});