index.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. const express = require('express');
  2. const app = express();
  3. require('dotenv').config(); // add dotnv for config
  4. const server = require('http').createServer(app);
  5. const mongoose = require('mongoose');
  6. const bcrypt = require('bcrypt');
  7. const User = require('./db/models/User');
  8. const Message = require('./db/models/Message');
  9. const jwt = require('jsonwebtoken');
  10. const PORT = process.env.PORT || 4000;
  11. const TOKEN_KEY = process.env.TOKEN_KEY || 'rGH452fdfhdfg06hgj7';
  12. const socket = require('socket.io');
  13. const cors = require('cors');
  14. app.get('/', (req, res) => {
  15. res.send('Hello from express server!')
  16. })
  17. app.use(cors());
  18. app.use(express.json());
  19. const io = socket(server, {
  20. cors: {
  21. origin: "http://localhost:3000" //client endpoint and port
  22. }
  23. });
  24. const generateToken = (id, userName, isAdmin) => {
  25. const payload = {
  26. id,
  27. userName,
  28. isAdmin
  29. }
  30. return jwt.sign(payload, TOKEN_KEY);
  31. }
  32. const getOneUser = async (userName) => {
  33. const userInDb = await User.findOne({userName});
  34. return userInDb;
  35. }
  36. const isValidUserName = (userName) => {
  37. const nameRegex = /[^A-Za-z0-9]/ ;
  38. return (!nameRegex.test(userName) && userName.trim().length > 2);
  39. }
  40. const getAllDbUsers = async (socket) => {
  41. const usersDb = await User.find({})
  42. socket.emit('allDbUsers', usersDb)
  43. }
  44. app.post('/login', async (req, res) => {
  45. try {
  46. const {userName,password} = req.body;
  47. if (!isValidUserName(userName)){
  48. return res.status(400).json({message: 'Invalid username'})
  49. }
  50. const dbUser = await getOneUser(userName)
  51. if (dbUser?.isBanned){
  52. return res.status(401).json({message: 'Your account has been banned!!!'})
  53. }
  54. const salt =await bcrypt.genSalt(2);
  55. const hashPassword = await bcrypt.hash(password, salt);
  56. if (!dbUser) {
  57. const user = new User({
  58. userName,
  59. hashPassword,
  60. isAdmin: !await User.count().exec(),
  61. isBanned: false,
  62. isMutted: false
  63. });
  64. await user.save()
  65. return res.json({
  66. token: generateToken(user.id, user.userName, user.isAdmin)
  67. });
  68. }
  69. if (dbUser && !bcrypt.compareSync(password, dbUser.hashPassword)){
  70. return res.status(400).json({message: 'Invalid credantials'})
  71. }
  72. res.json({
  73. token: generateToken(dbUser.id, dbUser.userName, dbUser.isAdmin)
  74. })
  75. } catch (e) {
  76. console.log(e);
  77. res.status(500).json({message: `Error ${e}`});
  78. }
  79. })
  80. io.use(async (socket, next) => {
  81. const token = socket.handshake.auth.token;
  82. const sockets = await io.fetchSockets();
  83. if(!token) {
  84. socket.disconnect();
  85. return;
  86. }
  87. const usersOnline = [];
  88. sockets.map((sock) => {
  89. usersOnline.push(sock.user);
  90. })
  91. try {
  92. const user = jwt.verify(token, TOKEN_KEY);
  93. const userName = user.userName;
  94. const dbUser = await getOneUser(userName);
  95. if(dbUser.isBanned){
  96. socket.disconnect();
  97. return;
  98. }
  99. socket.user = user;
  100. const exist = sockets.find((current) => current.user.userName == socket.user.userName)
  101. if(exist) { //&& !user.isAdmin - add for two or more admins
  102. console.log(exist.userName, 'exist twice entering...')
  103. exist.disconnect();
  104. }
  105. } catch(e) {
  106. console.log(e);
  107. socket.disconnect();
  108. }
  109. next();
  110. });
  111. io.on("connection", async (socket) => {
  112. const userName = socket.user.userName;
  113. const sockets = await io.fetchSockets();
  114. const dbUser = await getOneUser(userName);
  115. io.emit('usersOnline', sockets.map((sock) => sock.user)); // send array online users
  116. socket.emit('connected', dbUser); //socket.user
  117. if(socket.user.isAdmin){
  118. getAllDbUsers(socket);
  119. }//sent all users from db to admin
  120. const messagesToShow = await Message.find({}).sort({ 'createDate': -1 }).limit(20);
  121. socket.emit('allmessages', messagesToShow.reverse());
  122. socket.on("message", async (data) => {
  123. const dateNow = Date.now(); // for correct working latest post
  124. const post = await Message.findOne({userName}).sort({ 'createDate': -1 })
  125. const oneUser = await getOneUser(userName);
  126. if(oneUser.isMutted){
  127. return;
  128. }
  129. if(post && ((Date.now() - Date.parse(post?.createDate)) < 5000)){
  130. return;
  131. }
  132. if(!oneUser.isMutted && data){
  133. const message = new Message({
  134. text: data.message,
  135. userName: userName,
  136. createDate: Date.now()
  137. });
  138. try {
  139. await message.save();
  140. console.log('saved to db')
  141. } catch (error) {
  142. console.log('Message save to db error', error);
  143. }
  144. io.emit('message', message);
  145. // }
  146. }
  147. });
  148. try {
  149. socket.on("disconnect", async () => {
  150. const sockets = await io.fetchSockets();
  151. io.emit('usersOnline', sockets.map((sock) => sock.user));
  152. console.log(`user :${socket.user.userName} , disconnected to socket`);
  153. });
  154. console.log(`user :${socket.user.userName} , connected to socket`);
  155. socket.on("muteUser",async (data) => {
  156. if(!socket.user.isAdmin){
  157. return;
  158. }
  159. // if(socket.user.isAdmin){
  160. const {user, prevStatus} = data;
  161. const sockets = await io.fetchSockets();
  162. const mute = await User.updateOne({userName : user}, {$set: {isMutted :!prevStatus}});
  163. getAllDbUsers(socket);
  164. const exist = sockets.find( current => current.user.userName == user)
  165. const dbUser = await getOneUser(user);
  166. if(exist){
  167. exist.emit('connected', dbUser);
  168. }
  169. // }
  170. });
  171. socket.on("banUser",async (data) => {
  172. if(!socket.user.isAdmin){
  173. return;
  174. }
  175. // if(socket.user.isAdmin) {
  176. const {user, prevStatus} = data;
  177. const sockets = await io.fetchSockets();
  178. const ban = await User.updateOne({userName : user}, {$set: {isBanned:!prevStatus}});
  179. getAllDbUsers(socket)
  180. const exist = sockets.find( current => current.user.userName == user)
  181. if(exist){
  182. exist.disconnect();
  183. }
  184. // }
  185. });
  186. } catch (e) {
  187. console.log(e);
  188. }
  189. });
  190. const start = async () => {
  191. try {
  192. await mongoose.connect('mongodb://localhost:27017/chat')
  193. .then(() => console.log(`DB started`))
  194. server.listen(PORT, () => {
  195. console.log(`Server started. Port: ${PORT}`);
  196. })
  197. } catch (e) {
  198. console.log(e);
  199. }
  200. }
  201. start();