├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── Procfile ├── README.md ├── SETUP.md ├── database ├── conn.js ├── registers.js └── signupschema.js ├── index.js ├── middleware └── auth.js ├── package.json ├── public ├── css │ ├── login.css │ ├── old.main.css │ └── style.css ├── img │ ├── chatApplogo.png │ ├── favicon.ico │ └── signUp.png └── js │ └── client.js ├── tmp └── old.index.html └── views ├── fpassword.html ├── index.html ├── login.html └── signup.html /.gitignore: -------------------------------------------------------------------------------- 1 | #ENV 2 | .env 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | yarn-debug.log* 8 | yarn-error.log* 9 | lerna-debug.log* 10 | 11 | # Diagnostic reports (https://nodejs.org/api/report.html) 12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | *.lcov 26 | 27 | # nyc test coverage 28 | .nyc_output 29 | 30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 31 | .grunt 32 | 33 | # Bower dependency directory (https://bower.io/) 34 | bower_components 35 | 36 | # node-waf configuration 37 | .lock-wscript 38 | 39 | # Compiled binary addons (https://nodejs.org/api/addons.html) 40 | build/Release 41 | 42 | # Dependency directories 43 | node_modules/ 44 | jspm_packages/ 45 | package-lock.json 46 | 47 | # TypeScript v1 declaration files 48 | typings/ 49 | 50 | # TypeScript cache 51 | *.tsbuildinfo 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Microbundle cache 60 | .rpt2_cache/ 61 | .rts2_cache_cjs/ 62 | .rts2_cache_es/ 63 | .rts2_cache_umd/ 64 | 65 | # Optional REPL history 66 | .node_repl_history 67 | 68 | # Output of 'npm pack' 69 | *.tgz 70 | 71 | # Yarn Integrity file 72 | .yarn-integrity 73 | 74 | # dotenv environment variables file 75 | .env 76 | .env.test 77 | 78 | # parcel-bundler cache (https://parceljs.org/) 79 | .cache 80 | 81 | # Next.js build output 82 | .next 83 | 84 | # Nuxt.js build / generate output 85 | .nuxt 86 | dist 87 | 88 | # Gatsby files 89 | .cache/ 90 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 91 | # https://nextjs.org/blog/next-9-1#public-directory-support 92 | # public 93 | 94 | # vuepress build output 95 | .vuepress/dist 96 | 97 | # Serverless directories 98 | .serverless/ 99 | 100 | # FuseBox cache 101 | .fusebox/ 102 | 103 | # DynamoDB Local files 104 | .dynamodb/ 105 | 106 | # TernJS port file 107 | .tern-port 108 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | ## Choosing an Issue 4 | - Go through the list of issues on the repository for chatApp and feel free to choose an issue that has not been assigned to anyone. 5 | - Preferably call dibs on the issue by commenting and letting the maintainers know you want to contribute to the code. 6 | 7 | ## Creating a Pull Request 8 | - It's recommended that you create a new branch to work on. 9 | - Write a fitting title and give appropriate details in the description while creating a Pull Request. 10 | - Also try to attach relevant screenshots, if any. 11 | - Please do not create PRs which are not resolving an already created issue. In order to streamline workflow, create an issue and get it assigned before submitting a pull request for it. 12 | 13 | ## Creating an Issue 14 | - Feel free to report bugs/new features/enhancements/documentation errors in the repository's 'Issues' section. 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 osBins 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: node index.js -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # chatApp 2 | 3 | ChatApp is a project that we started to get familiar with Websockets and their implementation with Socket.IO. 4 | 5 | 6 | ![Issues](https://img.shields.io/github/issues/osBins/chatApp?&color=brightgreen&style=flat-square) 7 | ![Pull Requests](https://img.shields.io/github/issues-pr/osBins/chatApp?color=brightgreen&style=flat-square) 8 | ![Forks](https://img.shields.io/github/forks/osBins/chatApp?&style=flat-square) 9 | ![Stars](https://img.shields.io/github/stars/osBins/chatApp?&style=flat-square) 10 | 11 | The [chatApp](https://chatapp-420.herokuapp.com) is hosted using Heroku. 12 | 13 | --- 14 | ## Tech Stack 15 | 1. HTML and CSS 16 | 2. Javascript 17 | 3. Express.js 18 | 4. Socket.IO 19 | 20 | #### For guidelines on how to contribute, check out [CONTRIBUTING.md](https://github.com/osBins/chatApp/blob/main/CONTRIBUTING.md) 21 | 22 | ## Setting Up The Project For Development 23 | Check out [**SETUP.md**](./SETUP.md) 24 | 25 | ## Contributors 26 |
27 | 28 | 29 | 30 |
31 | -------------------------------------------------------------------------------- /SETUP.md: -------------------------------------------------------------------------------- 1 | ## How to set up to contribute to the project 2 | It is recommended that you install and use [Git Bash](https://git-scm.com/downloads) for commands in the following instructions. 3 | In order to succesfully run the project on your local system, you will need to set up MongoDB on your system too. Instructions are given below. 4 | 5 | #### Downloading the Project 6 | 7 | 1. **Fork** the GitHub repository. 8 | ![image](https://user-images.githubusercontent.com/70942982/143769515-719cdb62-3b85-4d55-8577-ca6a5cdbc4bb.png) 9 | 10 | 2. Copy and **clone *your fork's*** URL using the `git clone [URL]` command.
11 | Copy -
12 | ![image](https://user-images.githubusercontent.com/70942982/143769547-9c69be81-e449-4c95-b3ac-2adea2ea7ea1.png)
13 | Clone -
14 | ![image](https://user-images.githubusercontent.com/70942982/143769592-3bdf78ab-aa1a-4f78-91e7-8e0e728d85c9.png) 15 | 16 | 3. Change your directory to reach **chatApp** folder using `cd chatApp` 17 | 18 | 4. Install the required Node.js modules by running `npm install` 19 | (make sure you have [Node.js](https://nodejs.org/en/download/) installed on your system) 20 | ![image](https://user-images.githubusercontent.com/70942982/143769635-a7dc31c9-6681-4032-b181-1045330d149e.png) 21 | 22 | #### Downloading and Installing MongoDB on Windows 23 | 24 | 1. Download MongoDB Community server from [their site](https://www.mongodb.com/try/download/community). 25 | ![image](https://user-images.githubusercontent.com/70942982/145673558-3ed3f457-0c89-43ab-b64e-fed285ecb076.png) 26 | 27 | 2. Select 'Complete' in their 'choose setup type' section of the installer. 28 | ![image](https://user-images.githubusercontent.com/70942982/145673581-8977bf8e-8564-4e81-9e62-5bc7a6064623.png) 29 | 30 | 3. On the next section, select *Install MongoDB as a service* -> *Run service as Network Service user* 31 | ![image](https://user-images.githubusercontent.com/70942982/145673593-a7aff4fd-7420-4aef-9b69-3212ffb0dbc9.png) 32 | 33 | 4. Install MongoDB compass (GUI Interface for MongoDB) 34 | 5. *Install* 35 | 6. Create a file named `.env` in the project directory and write the following line in it - 36 | ``` 37 | MONGO_URL="mongodb://127.0.0.1:27017" 38 | ``` 39 | ![image](https://user-images.githubusercontent.com/70942982/145827232-f1b0c5b8-fd70-4913-add7-f205ec9ff3ef.png) 40 | 7. Make sure the `MongoDB Database Server` background process is running (in Task Manager). In case it isn't open `services.msc` from Windows search/Run and right-click and start the process `MongoDB Server`. 41 | ![image](https://user-images.githubusercontent.com/70942982/145827387-315e3db6-aba7-4282-bde0-bcf14adffaf6.png) 42 | 43 | 8. Finally, run `node index.js` in your terminal/Git bash. Visit `localhost:8080`to see the chatApp working. 44 |
45 | 46 | You are required to sign up with an Email ID/Password (can be anything, a valid Email ID is not required so far). Login with the credentials and you'll land at the ChatApp's main page. 47 | 48 | 49 | --- 50 | Open the folder in your choice of editor to edit to make changes to the project. 51 | 52 | 53 | -------------------------------------------------------------------------------- /database/conn.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | mongoose.connect(process.env.MONGO_URL, { 4 | useNewUrlParser: true 5 | }).then(() => { 6 | console.log("MongoDB connected"); 7 | }).catch((e) => { 8 | console.log("MongoDB not connected"); 9 | console.log(e); 10 | }) 11 | -------------------------------------------------------------------------------- /database/registers.js: -------------------------------------------------------------------------------- 1 | 2 | const mongoose = require("mongoose"); 3 | const chatSchema = new mongoose.Schema({ 4 | name: { 5 | type: String, 6 | 7 | }, 8 | message: { 9 | type: String, 10 | required: true 11 | }, 12 | email: { 13 | type: String, 14 | required: true 15 | }, 16 | time: { 17 | type: String 18 | } 19 | }); 20 | const Message = new mongoose.model("message", chatSchema); 21 | module.exports = Message; 22 | 23 | -------------------------------------------------------------------------------- /database/signupschema.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const { isEmail } = require("validator"); 3 | const bcrypt = require("bcrypt"); 4 | const userSchema = new mongoose.Schema({ 5 | username: { 6 | type: String, 7 | required: [true, "Please enter a username"], 8 | }, 9 | email: { 10 | type: String, 11 | lowercase: true, 12 | required: [true, "Please enter an email"], 13 | 14 | unique: true, 15 | validate: [isEmail, "Please enter a valid email"], 16 | }, 17 | password: { 18 | type: String, 19 | required: [true, "Please enter the password"], 20 | minlength: [6, "Minimum length should be 6 character"], 21 | }, 22 | }); 23 | userSchema.pre("save", async function (next) { 24 | const salt = await bcrypt.genSalt(); 25 | this.password = await bcrypt.hash(this.password, salt); 26 | next(); 27 | }) 28 | const User = new mongoose.model("user", userSchema); 29 | module.exports = User; 30 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // Usual Express and Socket.IO stuff 2 | require("dotenv").config(); 3 | require("./database/conn"); 4 | const bcrypt = require("bcrypt"); 5 | const express = require("express"); 6 | let favicon = require("serve-favicon"); 7 | const app = express(); 8 | const http = require("http"); 9 | const cookieParser = require("cookie-parser"); 10 | const server = http.createServer(app); 11 | const { Server } = require("socket.io"); 12 | const io = new Server(server); 13 | const { requireauth } = require("./middleware/auth"); 14 | const jwt = require("jsonwebtoken"); 15 | const Message = require("./database/registers"); 16 | const User = require("./database/signupschema"); 17 | 18 | const { timeEnd } = require("console"); 19 | const nodemailer = require("nodemailer"); 20 | // Load external styles and scripts from folder 'public' 21 | app.use(express.static("public")); 22 | app.use(express.json()); 23 | app.use(cookieParser()); 24 | /******************************************************************************************/ 25 | const port = process.env.PORT || 8080; 26 | let users = []; 27 | let err1 = { email: "", password: "" }; 28 | let userentered; 29 | let useremail; 30 | let user1; 31 | 32 | /****************************************************************************************/ 33 | const getmessages = async (socket) => { 34 | const result = await Message.find().sort({ _id: 1 }); 35 | socket.emit("output", { result: result, useremail: useremail }); 36 | }; 37 | const storemessage = async (user_name, msg, mail, time) => { 38 | const message = new Message({ 39 | name: user_name, 40 | message: msg, 41 | email: mail, 42 | time: time, 43 | }); 44 | await message.save(); 45 | }; 46 | 47 | const handlerror = (err) => { 48 | let errors = { email: "", password: "" }; 49 | 50 | if (err.code === 11000) { 51 | errors.email = "email already exist"; 52 | return errors; 53 | } 54 | if (err.message.includes("user validation failed")) { 55 | Object.values(err.errors).forEach(({ properties }) => { 56 | errors[properties.path] = properties.message; 57 | }); 58 | } 59 | return errors; 60 | }; 61 | const maxAge = 3 * 24 * 60 * 60; 62 | const createtoken = (id) => { 63 | return jwt.sign({ id }, "ankitgarg", { 64 | expiresIn: maxAge, 65 | }); 66 | }; 67 | 68 | const checkuser = (req, res, next) => { 69 | const token = req.cookies.login; 70 | if (token) { 71 | jwt.verify(token, "ankitgarg", async (err, decodedToken) => { 72 | if (err) { 73 | user1 = null; 74 | next(); 75 | } else { 76 | console.log(decodedToken); 77 | let user = await User.findById(decodedToken.id); 78 | console.log(user); 79 | user1 = user; 80 | next(); 81 | } 82 | }); 83 | } else { 84 | user1 = null; 85 | next(); 86 | } 87 | }; 88 | /*******************************************************************************************/ 89 | 90 | //to serve favicon 91 | app.use(favicon(__dirname + "/public/img/favicon.ico")); 92 | 93 | // Serve the main file 94 | app.get("*", checkuser); 95 | app.get("/", requireauth, (req, res) => { 96 | userentered = user1.username; 97 | useremail = user1.email; 98 | res.sendFile(__dirname + "/views/index.html"); 99 | }); 100 | 101 | app.get("/ui", requireauth, (req, res) => { 102 | userentered = user1.username; 103 | useremail = user1.email; 104 | res.sendFile(__dirname + "/tmp/old.index.html"); 105 | }); 106 | 107 | //handling signup 108 | app.get("/signup", (req, res) => { 109 | res.sendFile(__dirname + "/views/signup.html"); 110 | }); 111 | 112 | //handling sign post request 113 | app.post("/signup", async (req, res) => { 114 | try { 115 | console.log(req.body); 116 | if (req.body.password === req.body.conpassword) { 117 | const user = new User({ 118 | username: req.body.username, 119 | email: req.body.email, 120 | password: req.body.password, 121 | }); 122 | await user.save(); 123 | 124 | res.status(201).json({ user: user._id }); 125 | } else { 126 | throw "Password does not matches"; 127 | } 128 | } catch (err) { 129 | if (err != "Password does not matches") { 130 | err1 = handlerror(err); 131 | } 132 | if (err == "Password does not matches" && err1.password == "") { 133 | if (err1.email != "email already exist") { 134 | err1.password = "Password does not matches"; 135 | } 136 | } 137 | 138 | console.log(err1); 139 | let error = { ...err1 }; 140 | err1.password = ""; 141 | err1.email = ""; 142 | res.status(400).json({ error }); 143 | } 144 | }); 145 | 146 | //handling login 147 | 148 | app.get("/login", (req, res) => { 149 | res.sendFile(__dirname + "/views/login.html"); 150 | }); 151 | 152 | app.post("/login", async (req, res) => { 153 | try { 154 | const user = await User.findOne({ email: req.body.email }); 155 | if (!user) { 156 | console.log("inside error block"); 157 | throw "Invalid Email"; 158 | } 159 | 160 | if (user) { 161 | const auth = await bcrypt.compare(req.body.password, user.password); 162 | 163 | if (auth) { 164 | const token = createtoken(user._id); 165 | res.cookie("login", token, { httpOnly: true, maxAge: maxAge * 1000 }); 166 | 167 | res.status(200).json({ user: user._id }); 168 | } else { 169 | throw Error("Incorrect Password"); 170 | } 171 | } 172 | } catch (err) { 173 | if (err == "Invalid Email") { 174 | err1.email = "Email not registered"; 175 | } else { 176 | err1.password = "Incorrect Password"; 177 | } 178 | 179 | let error = { ...err1 }; 180 | err1.password = ""; 181 | err1.email = ""; 182 | console.log(error); 183 | res.status(400).json({ error }); 184 | } 185 | }); 186 | 187 | app.post("/otp", async (req, res) => { 188 | try { 189 | const user = await User.findOne({ email: req.body.email }); 190 | if (!user) { 191 | throw "Invalid Email"; 192 | } else { 193 | var email; 194 | 195 | let transporter = nodemailer.createTransport({ 196 | host: "smtp.gmail.com", 197 | port: 465, 198 | secure: true, 199 | service: "Gmail", 200 | 201 | auth: { 202 | user: process.env.EMAIL, 203 | pass: process.env.PASSWORD, 204 | }, 205 | }); 206 | let otp = Math.random(); 207 | otp = otp * 1000000; 208 | otp = parseInt(otp); 209 | console.log(otp); 210 | 211 | // send mail with defined transport object 212 | var mailOptions = { 213 | from: process.env.EMAIL, 214 | to: req.body.email, 215 | subject: "Reset Password OTP | ChatApp", 216 | text: `Hello user,\nYour OTP is : ${otp}\nEnter this code within 1 hour to login to your account if you have forgotten your password or go to the login page to resend it. If you do not recognize or expect this mail, please do not share the above OTP with anyone.\n\nchatApp`, 217 | }; 218 | 219 | transporter.sendMail(mailOptions, (error, info) => { 220 | if (error) { 221 | return console.log(error); 222 | } else { 223 | console.log("done"); 224 | } 225 | }); 226 | 227 | res.json({ otp }); 228 | } 229 | } catch (err) { 230 | let error = { email: "" }; 231 | if (err === "Invalid Email") { 232 | error.email = "Invalid Email"; 233 | } 234 | 235 | res.status(400).json({ error }); 236 | } 237 | }); 238 | app.get("/forgotpassword", (req, res) => { 239 | res.sendFile(__dirname + "/views/fpassword.html"); 240 | }); 241 | 242 | app.post("/forgotpassword", async (req, res) => { 243 | try { 244 | console.log(req.body.otp, parseInt(req.body.userotp)); 245 | if (req.body.otp != parseInt(req.body.userotp)) { 246 | throw "Invalid Otp"; 247 | } else { 248 | console.log("noerror"); 249 | if (req.body.password === req.body.conpassword) { 250 | if (req.body.password.length >= 6) { 251 | const salt = await bcrypt.genSalt(); 252 | let password = await bcrypt.hash(req.body.password, salt); 253 | const user = await User.updateOne( 254 | { email: req.body.email }, 255 | { $set: { password: password } } 256 | ); 257 | res.status(201).json({ user: user._id }); 258 | } else { 259 | throw "Minimum length should be 6 character"; 260 | } 261 | } else { 262 | throw "Password does not matches"; 263 | } 264 | } 265 | } catch (err) { 266 | let error = { password: "", otpmessage: "" }; 267 | if (err === "Invalid Otp") { 268 | error.otpmessage = "Invalid Otp"; 269 | } else if (err === "Password does not matches") { 270 | error.password = "Password does not matches"; 271 | } else if (err === "Minimum length should be 6 character") { 272 | error.password = "Minimum length should be 6 character"; 273 | } 274 | res.status(400).json({ error }); 275 | } 276 | }); 277 | // Serve list of users 278 | app.get("/users", (req, res) => { 279 | res.send(users); 280 | }); 281 | 282 | app.get("/me", (req, res) => { 283 | res.send(user1); 284 | }); 285 | 286 | app.get("/messages", async (req, res) => { 287 | const result = await Message.find(); 288 | res.send(result); 289 | }); 290 | 291 | app.get("/logout", (req, res) => { 292 | res.cookie("login", "", { maxAge: 1 }); 293 | res.redirect("/login"); 294 | }); 295 | 296 | /***************************************************************************************************** */ 297 | 298 | // When a connection is received 299 | io.on("connection", (socket) => { 300 | if (user1) { 301 | console.log("A user has connected"); 302 | io.emit("connected", { 303 | id: socket.id, 304 | name: userentered, 305 | email: useremail, 306 | }); 307 | getmessages(socket); 308 | 309 | socket.name = ""; 310 | let filtered_users = users.filter((user) => user.id == socket.id); 311 | if (filtered_users != []) { 312 | users.push({ 313 | name: userentered, 314 | id: socket.id, 315 | email: useremail, 316 | }); 317 | } 318 | 319 | // Receiving a chat message from client 320 | socket.on("mychat message", (msg, time) => { 321 | console.log("Received a chat message"); 322 | let current_user = users.filter((user) => user.id === socket.id); 323 | const mail = current_user[0].email; 324 | const name = current_user[0].name; 325 | socket.name = name; 326 | 327 | let userList = []; 328 | if (msg.substr(0, 3) == "/w ") { 329 | msg = msg.substr(3); 330 | const idx = msg.indexOf(" "); 331 | 332 | if (idx != -1) { 333 | const toUsername = msg.substr(0, idx); 334 | msg = msg.substr(idx + 1); 335 | userList = users.filter((_user_) => _user_.name === toUsername); 336 | } 337 | } 338 | 339 | if (userList.length) 340 | userList.forEach((user) => 341 | io 342 | .to(socket.id) 343 | .to(user.id) 344 | .emit( 345 | "chat message", 346 | { name: socket.name, id: socket.id }, 347 | msg, 348 | time, 349 | user 350 | ) 351 | ); 352 | else 353 | io.emit( 354 | "chat message", 355 | { name: socket.name, id: socket.id }, 356 | msg, 357 | time, 358 | "null" 359 | ); 360 | 361 | storemessage(name, msg, mail, time); 362 | }); 363 | 364 | // Received when some client is typing 365 | socket.on("typing", (user) => { 366 | socket.broadcast.emit("typing", user); 367 | }); 368 | // Receiving an image file from client 369 | socket.on("base64_file", function (msg, time) { 370 | let current_user = users.filter((user) => user.id === socket.id); 371 | const name = current_user[0].name; 372 | socket.name = name; 373 | console.log(`received base64 file from ${socket.name}`); 374 | var data = {}; 375 | data.fileName = msg.fileName; 376 | data.file = msg.file; 377 | data.id = socket.id; 378 | data.username = socket.name == "" ? "Anonymous" : socket.name; 379 | io.sockets.emit("base64_file", data, time); 380 | }); 381 | // Sent to all clients when a socket is disconnected 382 | socket.on("disconnect", () => { 383 | console.log("A user has disconnected"); 384 | users = users.filter((user) => user.id !== socket.id); 385 | io.emit("disconnected", socket.id); 386 | }); 387 | } 388 | }); 389 | 390 | server.listen(port, () => { 391 | console.log("Listening on:", port); 392 | }); 393 | -------------------------------------------------------------------------------- /middleware/auth.js: -------------------------------------------------------------------------------- 1 | const jwt = require("jsonwebtoken"); 2 | 3 | const requireauth = (req, res, next) => { 4 | const token = req.cookies.login; 5 | if (token) { 6 | jwt.verify(token, "ankitgarg", (err, decodedToken) => { 7 | if (err) { 8 | console.log(err.message); 9 | res.redirect("/login"); 10 | } 11 | else { 12 | console.log(decodedToken); 13 | next(); 14 | } 15 | } 16 | ) 17 | } 18 | else { 19 | res.redirect("/login"); 20 | } 21 | }; 22 | 23 | 24 | 25 | module.exports = { requireauth }; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chatapp", 3 | "version": "1.0.0", 4 | "description": "my first socket.io app", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "dev": "nodemon index.js", 9 | "start": "node index.js" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/osBins/chatApp.git" 14 | }, 15 | "keywords": [], 16 | "author": "", 17 | "license": "ISC", 18 | "bugs": { 19 | "url": "https://github.com/osBins/chatApp/issues" 20 | }, 21 | "homepage": "https://github.com/osBins/chatApp#readme", 22 | "dependencies": { 23 | "bcrypt": "^5.0.1", 24 | "cookie-parser": "^1.4.6", 25 | "dotenv": "^10.0.0", 26 | "express": "^4.17.1", 27 | "jsonwebtoken": "^8.5.1", 28 | "mongoose": "^6.0.14", 29 | "nodemailer": "^6.7.2", 30 | "nodemon": "^2.0.15", 31 | "serve-favicon": "^2.5.0", 32 | "socket.io": "^4.2.0", 33 | "validator": "^13.7.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /public/css/login.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | font-family: "Roboto", sans-serif; 6 | } 7 | .container { 8 | width: 100vw; 9 | display: flex; 10 | } 11 | 12 | .design { 13 | width: 30%; 14 | background-image: url(../img/signUp.png); 15 | background-position: cover; 16 | background-repeat: no-repeat; 17 | padding: 4rem; 18 | display: flex; 19 | height: 100vh; 20 | } 21 | .design img { 22 | width: 50px; 23 | height: 50px; 24 | } 25 | 26 | .design h1 { 27 | color: #1374f2; 28 | font-size: 3rem; 29 | padding-left: 12px; 30 | font-weight: bold; 31 | margin-bottom: 1rem; 32 | letter-spacing: 0.055em; 33 | } 34 | .content { 35 | width: 70%; 36 | height: 100vh; 37 | background-color: rgb(255, 255, 255); 38 | position: relative; 39 | } 40 | .go-back { 41 | position: absolute; 42 | right: 20px; 43 | top: 20px; 44 | } 45 | .form { 46 | height: 500px; 47 | padding: 5.2rem 4rem; 48 | } 49 | 50 | form { 51 | padding-top: 2rem; 52 | } 53 | .name-input, 54 | .email-input, 55 | .pass-input, 56 | .pass-reinput, 57 | .otp-input { 58 | display: flex; 59 | flex-direction: column; 60 | margin-bottom: 1rem; 61 | } 62 | 63 | input[type="text"], 64 | input[type="password"], 65 | input[type="email"], 66 | input[type="number"] { 67 | width: 50%; 68 | height: 45px; 69 | border: 2px solid #1d8ff2; 70 | box-sizing: border-box; 71 | border-radius: 14px; 72 | margin-bottom: 1rem; 73 | padding: 1rem; 74 | outline: none; 75 | font-size: 18px; 76 | } 77 | 78 | .form-label { 79 | font-family: Roboto; 80 | font-style: normal; 81 | font-weight: normal; 82 | font-size: 20px; 83 | line-height: 23px; 84 | letter-spacing: 0.045em; 85 | color: #475d75; 86 | padding-bottom: 0.4rem; 87 | } 88 | .fontsize { 89 | font-size: 14px; 90 | } 91 | .account, 92 | .naccount { 93 | font-size: 18px; 94 | display: inline-block; 95 | padding-top: 1rem; 96 | letter-spacing: 0.6px; 97 | } 98 | .login, 99 | .signup { 100 | text-decoration: none; 101 | display: inline-block; 102 | color: #1374f2; 103 | text-decoration: none; 104 | border: 2px solid #1374f2; 105 | padding: 0.4rem 0.8rem; 106 | border-radius: 20px; 107 | transition: 0.4s; 108 | } 109 | .signup:hover, 110 | .login:hover { 111 | background-color: #1374f2; 112 | color: white; 113 | } 114 | .heading { 115 | font-size: 4rem; 116 | letter-spacing: 0.055em; 117 | color: #475d75; 118 | font-weight: 500; 119 | } 120 | .secondary-heading { 121 | padding-top: 0.4rem; 122 | font-weight: 500; 123 | font-size: 2.4rem; 124 | letter-spacing: 0.04em; 125 | color: #1374f2; 126 | } 127 | 128 | .btn-submit { 129 | height: 58px; 130 | padding: 0 3rem; 131 | filter: drop-shadow(4px 4px 9px rgba(0, 0, 0, 0.25)); 132 | background-color: #1374f2; 133 | border: none; 134 | color: white; 135 | font-size: 24px; 136 | border-radius: 49px; 137 | cursor: pointer; 138 | transition: 0.4s; 139 | } 140 | .btn-submit:hover { 141 | color: #1374f2; 142 | background-color: white; 143 | border: 2px solid #1374f2; 144 | } 145 | #email-error, 146 | #password-error { 147 | color: rgb(220, 53, 69); 148 | font-size: 14px; 149 | } 150 | .forgetpassword { 151 | margin-top: 10px; 152 | font-size: 18px; 153 | } 154 | .fpassword { 155 | text-decoration: none; 156 | color: black; 157 | } 158 | -------------------------------------------------------------------------------- /public/css/old.main.css: -------------------------------------------------------------------------------- 1 | /* ################################### STYLING INDEX.HTML ########################################### */ 2 | body { 3 | margin: 0; 4 | padding-bottom: 3rem; 5 | font-family: BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; 6 | background-color: cyan; 7 | } 8 | 9 | /* ################################### STYLING HEADER ############################################## */ 10 | #header img { 11 | height: 100px; 12 | left: 32%; 13 | position: absolute; 14 | } 15 | 16 | #header h2 { 17 | color: #ed1c24; 18 | font-size: 79px; 19 | font-family: Copperplate; 20 | position: absolute; 21 | left: 40%; 22 | top: 4px; 23 | } 24 | 25 | .logout { 26 | display: inline-block; 27 | position: absolute; 28 | right: calc(13rem + 4%); 29 | text-align: center; 30 | text-decoration: none; 31 | background-color: rgb(237, 28, 36); 32 | margin-top: 1.6rem; 33 | color: white; 34 | padding: 0.8rem 1.8rem; 35 | border-radius: 40px; 36 | } 37 | 38 | .logout:hover { 39 | background-color: rgb(255, 0, 8); 40 | color: white; 41 | } 42 | 43 | #header nav { 44 | right: 3rem; 45 | margin-top: 1.4rem; 46 | position: absolute; 47 | } 48 | 49 | #online { 50 | margin: 0; 51 | padding: 0; 52 | } 53 | 54 | #online li { 55 | padding: 10px 14px; 56 | text-align: left; 57 | cursor: pointer; 58 | display: flex; 59 | align-items: center; 60 | } 61 | 62 | #online li:hover { 63 | background-color: #bdbdbd; 64 | } 65 | 66 | .dot { 67 | height: 8px; 68 | width: 8px; 69 | background-color: green; 70 | border-radius: 50%; 71 | display: inline-block; 72 | margin-right: 11px; 73 | } 74 | 75 | .search-messages { 76 | display: inline-block; 77 | margin-left: 100px; 78 | margin-top: 20px; 79 | } 80 | 81 | .search-messages input { 82 | display: inline-block; 83 | text-align: center; 84 | margin-left: 100px; 85 | margin-top: 20px; 86 | border-radius: 15px; 87 | font-size: 18px; 88 | border: 2px solid rgb(255, 0, 8); 89 | outline: none; 90 | } 91 | .search-messages input :focus { 92 | outline: none; 93 | } 94 | .collapsible { 95 | background-color: #1a4d5e; 96 | color: white; 97 | cursor: pointer; 98 | padding: 15px; 99 | width: 13rem; 100 | border: none; 101 | text-align: center; 102 | outline: none; 103 | font-size: 18px; 104 | text-align: center; 105 | border-radius: 20px; 106 | } 107 | 108 | .active, 109 | .collapsible:hover { 110 | background-color: #05465c; 111 | } 112 | 113 | .content { 114 | padding: 0 18px; 115 | display: none; 116 | overflow: hidden; 117 | background-color: #f1f1f1; 118 | width: 13rem; 119 | border-radius: 10px; 120 | overflow-wrap: break-word; 121 | } 122 | .uname { 123 | width: 89%; 124 | overflow-wrap: break-word; 125 | display: inline-block; 126 | } 127 | 128 | div.content { 129 | margin-top: 0.3rem; 130 | padding: 0; 131 | } 132 | 133 | /* ############################################ STYLING MAIN ################################## */ 134 | #main { 135 | width: 95%; 136 | position: absolute; 137 | top: 11%; 138 | left: 2.5%; 139 | height: 80%; 140 | border-radius: 20px; 141 | background-color: #1a4d5e; 142 | padding: 10px; 143 | overflow: auto; 144 | border: 8px solid #ed1c24; 145 | z-index: -1; 146 | } 147 | 148 | #main::-webkit-scrollbar { 149 | width: 0.8em; 150 | margin: 1em; 151 | } 152 | 153 | #main::-webkit-scrollbar-track { 154 | box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); 155 | } 156 | 157 | #main::-webkit-scrollbar-thumb { 158 | background-color: rgb(6, 168, 168); 159 | outline: 1px solid rgb(13, 115, 218); 160 | margin: 0.3em; 161 | border-radius: 20px; 162 | } 163 | 164 | #messages { 165 | word-wrap: break-word; 166 | list-style-type: none; 167 | margin: 0; 168 | padding: 0; 169 | } 170 | 171 | #messages > li { 172 | padding: 0.5rem 1rem; 173 | padding-bottom: 0.7rem; 174 | border-radius: 20px; 175 | margin-bottom: 0.8rem; 176 | clear: both; 177 | border: 0.1px solid rgb(213 213 213); 178 | font-weight: 500; 179 | } 180 | 181 | .connection { 182 | text-align: center; 183 | width: 50%; 184 | left: 25%; 185 | position: relative; 186 | } 187 | 188 | .messages { 189 | width: 50%; 190 | float: left; 191 | background-color: white; 192 | } 193 | .useridentified { 194 | float: right; 195 | background-color: gold; 196 | } 197 | .self { 198 | color: rgb(0, 0, 255); 199 | background-color: gold; 200 | float: right; 201 | } 202 | 203 | #feedback { 204 | padding: 0.5rem 1rem; 205 | color: rgb(255 255 255); 206 | text-align: center; 207 | clear: both; 208 | } 209 | 210 | /* ##################################### STYLING FORM ################################# */ 211 | #form { 212 | /* background: rgba(0, 0, 0, 0.15); */ 213 | padding: 0.25rem; 214 | position: fixed; 215 | height: 60px; 216 | bottom: 0; 217 | left: 0; 218 | right: 0; 219 | display: flex; 220 | box-sizing: border-box; 221 | backdrop-filter: blur(10px); 222 | background-color: #1a4d5e; 223 | } 224 | 225 | #username { 226 | outline: none; 227 | border: none; 228 | padding: auto auto; 229 | /* margin: 650px 20px 20px; */ 230 | height: 40px; 231 | margin: auto 10px; 232 | width: 200px; 233 | border-radius: 20px; 234 | font-family: FontAwesome, Arial; 235 | } 236 | 237 | #input { 238 | border: none; 239 | padding: 0 1rem; 240 | flex-grow: 1; 241 | border-radius: 20px; 242 | margin: auto 10px; 243 | height: 40px; 244 | width: 900px; 245 | font-family: FontAwesome, Arial; 246 | } 247 | 248 | #input:focus { 249 | outline: none; 250 | } 251 | 252 | #form > button { 253 | background: #333; 254 | border: none; 255 | padding: 0 1rem; 256 | margin: 0.25rem; 257 | border-radius: 3px; 258 | outline: none; 259 | color: #fff; 260 | } 261 | 262 | input { 263 | text-align: center; 264 | } 265 | 266 | ::-webkit-input-placeholder { 267 | text-align: center; 268 | } 269 | 270 | .btn--send { 271 | background-color: #ed1c24; 272 | color: white; 273 | border: none; 274 | padding: 0.4rem 1.5rem; 275 | border-radius: 20px; 276 | margin-top: 0.3rem; 277 | outline: none; 278 | color: #fff; 279 | font-size: 1.2rem; 280 | } 281 | .time { 282 | font-size: 0.8rem; 283 | color: #333; 284 | } 285 | 286 | #Not_uploaded { 287 | background-color: red; 288 | color: white; 289 | padding: 0.5rem 0.5rem 0.5rem 1rem; 290 | font-family: sans-serif; 291 | border-radius: 20px; 292 | cursor: pointer; 293 | width: 130px; 294 | margin: 0.3rem; 295 | } 296 | 297 | #Uploaded { 298 | background-color: #38b000; 299 | color: white; 300 | padding: 0.5rem 0.5rem 0.5rem 1rem; 301 | font-family: sans-serif; 302 | border-radius: 20px; 303 | cursor: pointer; 304 | width: 170px; 305 | margin: 0.3rem; 306 | } 307 | -------------------------------------------------------------------------------- /public/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #f4f7f6; 3 | margin-top: 20px; 4 | min-height: 100vh; 5 | overflow: hidden; 6 | } 7 | 8 | .mh-100 { 9 | min-height: 100vh; 10 | } 11 | 12 | .mh-175px { 13 | min-height: 175px; 14 | } 15 | 16 | .details-bg { 17 | background-color: #1d8ff229; 18 | } 19 | 20 | .h-250px { 21 | height: 250px; 22 | } 23 | 24 | .border-custom { 25 | border: 2px solid #1d8ff2; 26 | outline: none; 27 | } 28 | 29 | .text-custom { 30 | color: #1374f2; 31 | } 32 | 33 | .bg-custom { 34 | background-color: #1d8ff2 !important; 35 | } 36 | 37 | .mh-75 { 38 | min-height: 75vh; 39 | } 40 | 41 | .end-10 { 42 | right: 10px; 43 | } 44 | 45 | .bottom--10 { 46 | bottom: -25px; 47 | } 48 | 49 | .stat-circle { 50 | height: 15px; 51 | width: 15px; 52 | border-radius: 50%; 53 | display: inline-block; 54 | } 55 | 56 | .btn-custom { 57 | filter: drop-shadow(4px 4px 9px rgba(0, 0, 0, 0.25)); 58 | border: none; 59 | color: white; 60 | font-size: 20px; 61 | border-radius: 49px; 62 | cursor: pointer; 63 | } 64 | 65 | .card { 66 | background: #fff; 67 | transition: 0.5s; 68 | border: 0; 69 | margin-bottom: 30px; 70 | border-radius: 0.55rem; 71 | position: relative; 72 | width: 100%; 73 | min-width: 80vw; 74 | box-shadow: 0 1px 2px 0 rgb(0 0 0 / 10%); 75 | } 76 | .chat-app .people-list { 77 | width: 280px; 78 | position: absolute; 79 | left: 0; 80 | top: 0; 81 | padding: 20px; 82 | z-index: 7; 83 | } 84 | 85 | .chat-app .chat { 86 | margin-left: 280px; 87 | border-left: 1px solid #eaeaea; 88 | } 89 | 90 | .outline-none:focus { 91 | outline: none !important; 92 | box-shadow: none !important; 93 | } 94 | 95 | .people-list { 96 | -moz-transition: 0.5s; 97 | -o-transition: 0.5s; 98 | -webkit-transition: 0.5s; 99 | transition: 0.5s; 100 | } 101 | 102 | .people-list .chat-list li { 103 | padding: 10px 15px; 104 | list-style: none; 105 | border-radius: 3px; 106 | } 107 | 108 | .people-list .chat-list li:hover { 109 | background: #efefef; 110 | cursor: pointer; 111 | } 112 | 113 | .people-list .chat-list li.active { 114 | background: #efefef; 115 | } 116 | 117 | .people-list .chat-list li .name { 118 | font-size: 15px; 119 | } 120 | 121 | .people-list .chat-list img { 122 | width: 45px; 123 | border-radius: 50%; 124 | } 125 | 126 | .people-list img { 127 | float: left; 128 | border-radius: 50%; 129 | } 130 | 131 | .people-list .about { 132 | float: left; 133 | padding-left: 8px; 134 | } 135 | 136 | .people-list .status { 137 | color: #999; 138 | font-size: 13px; 139 | } 140 | 141 | .chat .chat-header { 142 | padding: 15px 20px; 143 | border-bottom: 2px solid #f4f7f6; 144 | } 145 | 146 | .chat .chat-header img { 147 | float: left; 148 | border-radius: 40px; 149 | width: 40px; 150 | } 151 | 152 | .chat .chat-header .chat-about { 153 | float: left; 154 | padding-left: 10px; 155 | } 156 | 157 | .chat .chat-history { 158 | padding: 20px; 159 | border-bottom: 2px solid #fff; 160 | } 161 | 162 | .chat .chat-history ul { 163 | padding: 0; 164 | } 165 | 166 | .chat .chat-history ul li { 167 | list-style: none; 168 | margin-bottom: 30px; 169 | margin-top: 50px; 170 | } 171 | 172 | .chat .chat-history ul li:last-child { 173 | margin-bottom: 0px; 174 | } 175 | 176 | .chat .chat-history .message-data { 177 | margin-bottom: 15px; 178 | } 179 | 180 | .chat .chat-history .message-data img { 181 | border-radius: 40px; 182 | width: 40px; 183 | } 184 | 185 | .chat .chat-history .message-data-time { 186 | color: #434651; 187 | padding-left: 6px; 188 | } 189 | 190 | .chat .chat-history .message { 191 | color: #444; 192 | padding: 18px 20px; 193 | line-height: 26px; 194 | font-size: 16px; 195 | border-radius: 7px; 196 | display: inline-block; 197 | position: relative; 198 | } 199 | 200 | .chat .chat-history .message:after { 201 | bottom: 100%; 202 | /* left: 7%; */ 203 | border: solid transparent; 204 | content: " "; 205 | height: 0; 206 | width: 0; 207 | position: absolute; 208 | pointer-events: none; 209 | border-bottom-color: #fff; 210 | border-width: 10px; 211 | margin-left: -10px; 212 | } 213 | 214 | .chat .chat-history .my-message { 215 | background: #efefef; 216 | } 217 | 218 | .chat .chat-history .my-message:after { 219 | bottom: 5px; 220 | left: -10px; 221 | border: solid transparent; 222 | content: " "; 223 | height: 0; 224 | width: 0; 225 | position: absolute; 226 | pointer-events: none; 227 | border-right-color: #efefef; 228 | border-width: 10px; 229 | margin-left: -10px; 230 | } 231 | 232 | .chat .chat-history .other-message { 233 | background: #e8f1f3; 234 | text-align: right; 235 | } 236 | 237 | .chat .chat-history .other-message:after { 238 | border-left-color: #1d8ff2; 239 | /* left: 93% */ 240 | /* right: 20%; */ 241 | bottom: 5px; 242 | right: -20px; 243 | } 244 | 245 | .chat .chat-message { 246 | padding: 20px; 247 | } 248 | 249 | .online, 250 | .offline, 251 | .me { 252 | margin-right: 2px; 253 | font-size: 8px; 254 | vertical-align: middle; 255 | } 256 | 257 | .online { 258 | color: #86c541; 259 | } 260 | 261 | .offline { 262 | color: #e47297; 263 | } 264 | 265 | .me { 266 | color: #1d8ecd; 267 | } 268 | 269 | .float-right { 270 | float: right; 271 | } 272 | 273 | .clearfix:after { 274 | visibility: hidden; 275 | display: block; 276 | font-size: 0; 277 | content: " "; 278 | clear: both; 279 | height: 0; 280 | } 281 | 282 | @media only screen and (max-width: 767px) { 283 | .chat-app .people-list { 284 | height: 465px; 285 | width: 100%; 286 | overflow-x: auto; 287 | background: #fff; 288 | left: -400px; 289 | display: none; 290 | } 291 | .chat-app .people-list.open { 292 | left: 0; 293 | } 294 | .chat-app .chat { 295 | margin: 0; 296 | } 297 | .chat-app .chat .chat-header { 298 | border-radius: 0.55rem 0.55rem 0 0; 299 | } 300 | .chat-app .chat-history { 301 | height: 300px; 302 | overflow-x: auto; 303 | } 304 | } 305 | 306 | @media only screen and (min-width: 768px) { 307 | .chat-app { 308 | height: 650px; 309 | min-width: 80vw; 310 | overflow-x: auto; 311 | } 312 | .chat-app .chat-history { 313 | height: calc(100vh - 170px); 314 | min-height: 480px; 315 | /* height: 600px; */ 316 | overflow-x: auto; 317 | } 318 | #online { 319 | height: 200px; 320 | } 321 | } 322 | @media (max-height: 611px){ 323 | body{ 324 | overflow: auto; 325 | } 326 | .chat-app { 327 | margin-top: 20px; 328 | } 329 | } 330 | /* This will work on Firefox */ 331 | * { 332 | scrollbar-width: thin; 333 | scrollbar-color: blue rgb(250, 248, 244); 334 | } 335 | 336 | /* Targtes on Chrome, Edge, and Safari */ 337 | *::-webkit-scrollbar { 338 | width: 12px; 339 | } 340 | 341 | *::-webkit-scrollbar-track { 342 | background: rgb(239, 238, 235); 343 | } 344 | 345 | *::-webkit-scrollbar-thumb { 346 | background-color: rgb(33, 100, 243); 347 | border-radius: 20px; 348 | border: 3px solid rgb(33, 100, 243); 349 | } 350 | 351 | @media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: landscape) and (-webkit-min-device-pixel-ratio: 1) { 352 | /* .chat-app .chat-list { 353 | height: 480px; 354 | overflow-x: auto 355 | } 356 | .chat-app .chat-history { 357 | /* height: calc(100vh - 350px); 358 | overflow-x: auto 359 | } */ 360 | } 361 | -------------------------------------------------------------------------------- /public/img/chatApplogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osPrims/chatApp/4aad4d05c7a910941dae6cfd6a371c5483290c77/public/img/chatApplogo.png -------------------------------------------------------------------------------- /public/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osPrims/chatApp/4aad4d05c7a910941dae6cfd6a371c5483290c77/public/img/favicon.ico -------------------------------------------------------------------------------- /public/img/signUp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/osPrims/chatApp/4aad4d05c7a910941dae6cfd6a371c5483290c77/public/img/signUp.png -------------------------------------------------------------------------------- /public/js/client.js: -------------------------------------------------------------------------------- 1 | let socket = io(); 2 | let form = document.getElementById("form"); 3 | let input = document.getElementById("input"); 4 | let feedback = document.getElementById("feedback"); 5 | let username = document.getElementById("username"); 6 | let messages = document.getElementById("messages"); 7 | let online = document.getElementById("online"); 8 | let sendBtn = document.querySelector(".btn--send"); 9 | let list = document.querySelector("#messages"); 10 | let forms = document.forms; 11 | let users = []; 12 | let selfId, selfMail; 13 | let md; 14 | let myId; 15 | 16 | let input_file = document.getElementById("input_file"); 17 | let label = document.getElementsByClassName("file"); 18 | 19 | md = window.markdownit({ 20 | html: false, 21 | xhtmlOut: false, 22 | linkify: true, 23 | typographer: true, 24 | breaks: true, 25 | }); 26 | 27 | fetch("/me") 28 | .then((user) => user.json()) 29 | .then((data) => { 30 | console.log(data); 31 | document.getElementById("username_holder").innerText = data.username; 32 | document.getElementById("email_holder").innerText = `<${data.email}>`; 33 | myId = data; 34 | }); 35 | 36 | // Color for the messages 37 | let colors = [ 38 | "#0080FF", 39 | "#8000FF", 40 | "#FF00FF", 41 | "#FF0080", 42 | "#FF0000", 43 | "#FF8000", 44 | "#80FF00", 45 | "#00FF00", 46 | "#00FF80", 47 | ]; 48 | 49 | // let coll = document.getElementsByClassName("collapsible"); 50 | 51 | // coll[0].addEventListener("click", function () { 52 | // this.classList.toggle("active"); 53 | // var content = this.nextElementSibling; 54 | // if (content.style.display === "block") { 55 | // content.style.display = "none"; 56 | // } else { 57 | // content.style.display = "block"; 58 | // } 59 | // }) 60 | 61 | // Add user to collapsible 62 | let addusertolist = (user) => { 63 | let item = document.createElement("li"); 64 | // item.style.color = (selfId) ? user.color : 'blue'; 65 | item.className = "clearfix"; 66 | item.innerHTML = 67 | '
' + user.name + "
"; 68 | item.id = user.id; 69 | item.onclick = handleOnlineClick.bind(null, user.id); 70 | online.appendChild(item); 71 | }; 72 | 73 | // Fetch users online as soon as you connect 74 | fetch("/users") 75 | .then((user) => user.json()) 76 | .then((data) => { 77 | console.log("asdasd"); 78 | console.log(data); 79 | data.forEach((user) => { 80 | user.color = colors[0]; 81 | colors = colors.splice(1); 82 | addusertolist(user); 83 | }); 84 | users = users.concat(data); 85 | }); 86 | 87 | // Fetch messages as soon as you connect 88 | // fetch("/messages") 89 | // .then((user) => user.json()) 90 | // .then((data) => { 91 | // if (data.length>0) { 92 | // data.map(msg => { 93 | // let item = document.createElement("li"); 94 | // item.className = "clearfix position-relative" 95 | 96 | // if (msg.email == myId.email) { 97 | // item.innerHTML = `
${msg.message}
${msg.name}, ${msg.time} `; 98 | // } 99 | // else { 100 | // item.innerHTML = `
${msg.message}
${msg.name}, ${msg.time} `; 101 | 102 | // } 103 | // messages.appendChild(item); 104 | // }) 105 | // }} 106 | // ) 107 | // Sent a chat message to server when submit a form 108 | form.addEventListener("submit", (e) => { 109 | e.preventDefault(); 110 | if (input.value) { 111 | socket.emit("mychat message", input.value, getTime()); 112 | // console.log("send", input.value); 113 | input.value = ""; 114 | } 115 | // if (username.readOnly === false) { 116 | // username.readOnly = true; 117 | // username.style.backgroundColor = "gold" 118 | // } 119 | }); 120 | 121 | // Received from server when someone gets connected 122 | socket.on("connected", ({ id, name, email }) => { 123 | // update user's (socket) id when reconnected 124 | if (selfMail === email) { 125 | const userIdx = users.findIndex((u) => u.email === email); 126 | users[userIdx].id = id; 127 | selfId = id; 128 | return; 129 | } 130 | 131 | if (selfId) { 132 | let item = document.createElement("li"); 133 | item.className = "connection p-2 rounded"; 134 | item.style.color = "black"; 135 | item.textContent = ` ${name} has connected`; 136 | item.style.backgroundColor = "LightGray"; 137 | messages.appendChild(item); 138 | } else { 139 | // Set user id and email when connected for first time 140 | selfId = id; 141 | selfMail = email; 142 | feedback.innerHTML = "Welcome to Chat App - Instant Messaging App"; 143 | } 144 | 145 | users.push({ name, id, email, color: colors[0] }); 146 | addusertolist({ name, id, email, color: colors[0] }); 147 | colors = colors.splice(1); 148 | 149 | scrollSmoothToBottom("main"); 150 | }); 151 | 152 | // Received from server when someone gets disconnected 153 | socket.on("disconnected", (id) => { 154 | let current_user = users.filter((user) => user.id === id); 155 | colors.push(current_user[0].color); 156 | users = users.filter((user) => user.id != id); 157 | 158 | let item = document.createElement("li"); 159 | item.style.color = "black"; 160 | item.className = "connection p-2"; 161 | item.style.backgroundColor = "LightGray"; 162 | item.textContent = current_user[0].name + " has disconnected"; 163 | messages.appendChild(item); 164 | 165 | scrollSmoothToBottom("main"); 166 | removeuserfromlist(id); 167 | feedback.innerHTML = ""; 168 | }); 169 | 170 | // Recieved from a server when a chat message is received 171 | socket.on("chat message", (user, msg, time, toUser) => { 172 | console.log(user, msg, time, toUser); 173 | let item = document.createElement("li"); 174 | item.className = user.id + " clearfix position-relative"; 175 | 176 | let current_user = users.filter((_user_) => _user_.id === user.id); 177 | if (selfId === user.id) { 178 | item.innerHTML = `
${ 179 | user.name 180 | }
${md.render( 181 | msg 182 | )}
${time} `; 183 | // item.classList.add('self') 184 | } else { 185 | // item.style.color = current_user[0].color 186 | item.innerHTML = `
${ 187 | user.name 188 | }
${md.render( 189 | msg 190 | )}
${time} `; 191 | } 192 | 193 | // if (toUser !== "null") item.innerHTML = `${user.name} toUser: ${toUser.name}  ${time} ` + `
${md.render(msg)}
`; 194 | // else item.innerHTML = `${user.name}  ${time} ` + `
${md.render(msg)}
`; 195 | // item.innerHTML = `${ user.name }: ` + `
${msg}
`; 196 | // item.classList.add('messages') 197 | messages.appendChild(item); 198 | 199 | scrollSmoothToBottom("main"); 200 | if (user.id !== selfId) feedback.innerHTML = ""; 201 | 202 | // check if someone has set their name 203 | users.forEach((saved_user) => { 204 | if (saved_user.id === user.id) { 205 | saved_user.name = user.name; 206 | let item = document.getElementById(user.id); 207 | item.innerHTML = `
${user.name}
`; 208 | } 209 | }); 210 | }); 211 | socket.on("output", ({ result, useremail }) => { 212 | console.log(result); 213 | if (result.length) { 214 | for (var x = 0; x < result.length; x++) { 215 | let item = document.createElement("li"); 216 | item.className = "clearfix position-relative"; 217 | 218 | // item.innerHTML = `${result[x].name}  ${result[x].time} ` + `
${md.render(result[x].message)}
`; 219 | 220 | if (result[x].email == useremail) { 221 | // item.classList.add("useridentified"); 222 | item.innerHTML = `
${ 223 | result[x].name 224 | }
${md.render( 225 | result[x].message 226 | )}
${ 227 | result[x].time 228 | } `; 229 | } else { 230 | // item.classList.add('messages'); 231 | item.innerHTML = `
${ 232 | result[x].name 233 | }
${md.render( 234 | result[x].message 235 | )}
${ 236 | result[x].time 237 | } `; 238 | } 239 | messages.appendChild(item); 240 | } 241 | } 242 | scroll("main"); 243 | }); 244 | function scroll(id) { 245 | var div = document.getElementById(id); 246 | var scrollHeight = div.scrollHeight; 247 | div.scroll({ 248 | top: scrollHeight + 10, 249 | }); 250 | } 251 | 252 | // Sent to server when you type 253 | input.addEventListener("keypress", () => { 254 | socket.emit("typing", myId.username); 255 | }); 256 | 257 | //Received from server when someone else is typing 258 | let fbTimer; 259 | socket.on("typing", (user) => { 260 | clearTimeout(fbTimer); 261 | feedback.innerHTML = user + " is typing..."; 262 | fbTimer = setTimeout(() => { 263 | feedback.innerHTML = ""; 264 | }, 2000); 265 | }); 266 | // Recieved from a server when an image file is received 267 | socket.on("base64_file", (data, time) => { 268 | var listitem = document.createElement("li"); 269 | listitem.className = "clearfix position-relative"; 270 | var curr_user_img = users.filter((_user_) => _user_.id === data.id); 271 | if (selfId === data.id) { 272 | listitem.innerHTML = `
${data.username} 
${time} `; 273 | input_file.value = ""; 274 | } else { 275 | listitem.innerHTML = `
${data.username} 
${time} `; 276 | } 277 | 278 | //listitem.classList.add('messages') 279 | messages.appendChild(listitem); 280 | if (data.id !== selfId) feedback.innerHTML = ""; 281 | 282 | scrollSmoothToBottom("main"); 283 | }); 284 | 285 | // Remove use from collapsible 286 | let removeuserfromlist = (userid) => { 287 | let item = document.getElementById(userid); 288 | if (item != null) item.remove(); 289 | }; 290 | 291 | // Auto scroll to bottom when messages come 292 | function scrollSmoothToBottom(id) { 293 | var div = document.getElementById(id); 294 | var scrollHeight = div.scrollHeight; 295 | div.scroll({ 296 | top: scrollHeight + 10, 297 | behavior: "smooth", 298 | }); 299 | } 300 | 301 | function handleOnlineClick(id) { 302 | let current_user = users.filter((user) => user.id === id); 303 | input.value = `@${current_user[0].name}`; 304 | } 305 | 306 | // search box JS 307 | const searchBar = forms["search-messages"].querySelector("input"); 308 | 309 | document 310 | .getElementById("search-messages") 311 | .addEventListener("submit", function (event) { 312 | event.preventDefault(); 313 | }); 314 | 315 | searchBar.addEventListener("keyup", (e) => { 316 | e.preventDefault(); 317 | const term = e.target.value.toLowerCase(); 318 | const messageList = list.getElementsByClassName("ls-msg"); 319 | Array.from(messageList).forEach((msgList) => { 320 | const title = msgList.textContent; 321 | if (title.toLowerCase().indexOf(e.target.value) !== -1) { 322 | msgList.parentNode.style.display = "block"; 323 | } else { 324 | msgList.parentNode.style.display = "none"; 325 | } 326 | }); 327 | }); 328 | sendBtn.addEventListener("mousedown", () => { 329 | if (input.value || input_file.value) { 330 | sendBtn.innerHTML = 331 | 'Sent  '; 332 | sendBtn.style.backgroundColor = "#38b000"; 333 | } 334 | }); 335 | 336 | sendBtn.addEventListener("mouseup", () => { 337 | setTimeout(() => { 338 | sendBtn.innerHTML = 'Send '; 339 | sendBtn.style.backgroundColor = "#ed1c24"; 340 | }, 400); 341 | }); 342 | 343 | input.addEventListener("keyup", function (event) { 344 | if (event.key === "Enter") { 345 | sendBtn.click(); 346 | sendBtn.style.backgroundColor = "#38b000"; 347 | setTimeout(() => { 348 | sendBtn.style.backgroundColor = "#ed1c24"; 349 | }, 400); 350 | } 351 | }); 352 | 353 | function readThensend() { 354 | const data = document.querySelector("input[type=file]").files[0]; 355 | const reader = new FileReader(); 356 | reader.onload = function (evt) { 357 | var msg = {}; 358 | msg.username = socket.name; 359 | msg.file = evt.target.result; 360 | msg.fileName = data.fileName; 361 | socket.emit("base64_file", msg, getTime()); 362 | }; 363 | reader.readAsDataURL(data); 364 | } 365 | function sendposition(position) { 366 | var centerCoordinates = new google.maps.LatLng(37.6, -95.665); 367 | var defaultOptions = { center: centerCoordinates, zoom: 4 }; 368 | var mapLayer = document.createElement("div"); 369 | 370 | var map = new google.maps.Map(mapLayer, defaultOptions); 371 | var currentLatitude = position.coords.latitude; 372 | var currentLongitude = position.coords.longitude; 373 | 374 | var infoWindowHTML = 375 | "Latitude: " + currentLatitude + "
Longitude: " + currentLongitude; 376 | var infoWindow = new google.maps.InfoWindow({ 377 | map: map, 378 | content: infoWindowHTML, 379 | }); 380 | var currentLocation = { lat: currentLatitude, lng: currentLongitude }; 381 | infoWindow.setPosition(currentLocation); 382 | socket.emit("location_Send", infoWindow); 383 | } 384 | function send_location() { 385 | if (navigator.geolocation) { 386 | navigator.geolocation.getCurrentPosition(sendposition); 387 | } 388 | } 389 | 390 | function getTime() { 391 | let date = new Date(); 392 | let hours = date.getHours(); 393 | let minutes = date.getMinutes(); 394 | let meridian = hours >= 12 ? "PM" : "AM"; 395 | hours = hours % 12; 396 | hours = hours ? hours : 12; 397 | minutes = minutes < 10 ? "0" + minutes : minutes; 398 | let strTime = hours + ":" + minutes + " " + meridian; 399 | return strTime; 400 | } 401 | -------------------------------------------------------------------------------- /tmp/old.index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ChatApp 9 | 11 | 13 | 16 | 17 | 20 | 21 | 25 | 26 | 27 | 28 | 29 | 30 | 42 |
43 | 44 |
45 |
46 | 47 | 48 | 51 |
52 | 57 |
58 |
59 |
60 | 61 |
62 | 63 |
64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /views/fpassword.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Reset Password 12 | 13 | 14 |
15 |
16 | 17 |

CHATAPP

18 |
19 |
20 |
21 |
22 |

Welcome To ChatApp!

23 |

Forgot Your Password?

24 |
25 | 37 |
38 |
39 | 40 | 48 |
49 |
50 |
51 | 52 | 61 |
62 |
63 | 64 | 73 |
74 |
75 | 76 |
77 |
78 |
79 |
80 |
81 |
82 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /views/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | ChatApp 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | chatapp-logo 32 |

CHAT APP

33 |
34 |

,

35 |
36 |
37 |
38 |
39 | 40 |
41 | 42 |
43 |
44 |
45 |
Online
46 |
    47 |
48 |
49 |
50 | LOG OUT 51 |
52 |
53 |
54 |
    55 |
56 |
57 |
58 |
59 |
60 | 61 |
62 | 66 | 67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /views/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Login 12 | 13 | 14 |
15 |
16 | 17 |

CHATAPP

18 |
19 |
20 |
21 |
22 |

Welcome To ChatApp!

23 |

Login

24 |
25 | 37 |
38 |
39 | 40 | 48 |
49 |
50 | 51 |
52 | Forgot password? 53 |
54 |
55 | Do not have an account? 56 | 57 | 58 |
59 |
60 |
61 |
62 |
63 |
64 | 69 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /views/signup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Signup 12 | 13 | 14 |
15 |
16 | 17 |

CHATAPP

18 |
19 |
20 |
21 |
22 |

Welcome To ChatApp!

23 |

Register

24 |
25 |
26 | 27 | 36 |
37 | 49 |
50 |
51 | 52 | 60 |
61 |
62 |
63 | 64 | 73 |
74 | 75 |
76 |
77 | 78 | 79 |
80 |
81 |
82 |
83 |
84 |
85 | 120 | 121 | 122 | --------------------------------------------------------------------------------