socket.io and node.js not working properly - javascript

I am trying to practice creating apps with socket.io and node.js. This is a simple "log in" app, but it doesn't seem to be working, whenever I start the app a 404 not found message pops up on the chrome developer console with this adress: http://localhost:3000/socket.io/?EIO=3&transport=polling&t=1469215104245-2
in my index.hjs file
<div class="input-group">
<span class="input-group-addon" id="basic-addon1"></span>
<input type="text" class="form-control username" placeholder="Username" aria-describedby="basic-addon1">
</div>
<div class="input-group">
<span class="input-group-addon" id="basic-addon1"></span>
<input type="text" class="form-control password" placeholder="Password" aria-describedby="basic-addon1">
</div>
<button type="button" class="btn btn-primary">Primary</button>
<h2></h2>
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
<script type="text/javascript">
var socket = io();
$('.btn-primary').click(function(){
var data = {username: $('.username').val(), password: $('.password').val()};
socket.emit('log-in',data);
socket.on('log-in success', function(){
$('h2').append('success')
});
socket.on('log-in fail', function(){
$('h2').append('fail')
});
});
</script>
on my node js server (there is more code there but these are the rlevant bits):
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/userDB');
var userSchema = mongoose.Schema({
name: String,
password: String
});
var User = mongoose.model('User', userSchema);
io.on('log-in',function(data){
User.findOne({ 'username': data.username, 'password': data.password}, function (err, person) {
if (err) {io.emit('log-in fail')
return handleError(err)};
if (!person) io.emit('log-in success');
})
});
Whenever I try to log in as a premade user just don't get any response back.
Any help would be much appreciated.

You don't listen to messages from a given connection on the server with io.on(). Instead, you do this where you listen for a given socket connecting and then you add event handlers to that specific socket and when you want to send back to that socket, you also use that socket object to send back to. This allows you to send back to the same socket that just sent you a message:
io.on('connection', function (socket) {
socket.on('log-in', function (data) {
User.findOne({'username': data.username, 'password': data.password}, function (err, person) {
if (err) {
socket.emit('log-in fail')
return handleError(err)
};
if (!person) socket.emit('log-in success');
})
});
});
But, you may also want to know that there's a framework for socket.io connection authentication that makes it a little more of a built-in part of accepting a connection. You can do your own like this if you want, but it will likely have some issues you haven't thought of.
P.S. This logic looks a bit flawed to me. If you find the person in your database, you emit no response on the socket.

Related

GET request in Node and React to check login information

I'm making a MERN application. I'm fairly new to it, so I'm trying to make everything based on what I know without looking much stuff up, because if I follow tutorials too much I don't remember stuff. Anyway, I've got a component that sends the registration information to the database and everything there is okay. Now I'm trying to check the login.
When I make the "GET" request to a route that I named "/check", nothing happens. If I change it to a "POST" request, things work. Shouldn't it be a "GET" request though since I'm trying to get information from the database?
The Node file:
const express = require('express');
const mongoose = require('mongoose');
const path = require('path');
const bcrypt = require('bcrypt');
const application = express();
application.use(express.json());
application.use(express.urlencoded({ extended: true }));
const port = process.env.PORT || 8080;
mongoose.connect(process.env.PASSWORD)
.then(console.log('Database connected'))
.catch(error => console.log(error));
const db = mongoose.connection;
application.get('/', (request, response) => {
response.send('Hello World');
});
application.post('/post', (request, response) => {
db.collection('data').insertOne({
name: request.body.username,
password: bcrypt.hashSync(request.body.password, 10),
}).then(console.log('Submission done'));
console.log('POST made');
response.redirect('/');
});
application.get('/check', (request, response) => {
db.collection('data').findOne({
name: request.body.username,
password: bcrypt.compareSync(
request.body.password,
bcrypt.hashSync(request.body.password, 10)
),
});
console.log('The request went through');
response.redirect('/');
});
application.listen(port, () => {
console.log('Listening here...');
});
The React file:
import React from 'react';
export const Login = () => {
return (
<>
<h1 className="text-center">Login</h1>
<div className="row">
<div className="col"></div>
<div className="col text-center">
<form action="/check" method="GET">
<label for="username" name="username">Username: </label>
<input name="username" className="h4" />
<label for="password" name="password">Password: </label>
<input type="password" name="password" className="h4" />
<button>Submit</button>
</form>
</div>
<div className="col"></div>
</div>
</>
);
};
There is difference between the "GET" and "POST" of HTML form element and "GET" and "POST" of node.js .
From Node.js perspective, you can save/send data to database with both POST and GET. However, the situtation is different for form element.
If you use "GET" on the form element, then form will submit all input data to the URL. And on the node.js side, you will need to use req.query to get data on the url, not req.body
So, in your code, you are using "GET" for the Form element but on the node.js file, you are using req.body. This shouldn't work.
Even if you make it work with req.query, the situation will still be totally unsafe, as you openly showing the passwords on the URL.
For more info, on html form attributes, this link can be useful. https://www.w3schools.com/html/html_forms_attributes.asp
you are sending username and password to the server so you should to use POST method

Login POST request using AJAX via Node.js

I'm trying to send an AJAX POST request for a login page using javascript via Node.js however I don't really know how to do it. Sorry that I'm really new to this. Here's my code:
In HTML:
<form>
<label for="email"><b>Email Address</b></label><br>
<input type="text" name="email"><br>
<label for="password"><b>Password</b></label><br>
<input type="text" name="password"><br><br>
<input type="submit" class = "button" value="Login" onclick= "submitlogin()">
</form>
In JS:
function submitlogin(){
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function(){
if(this.readyState ==4 && this.status == 200){
console.log("success");
} else if (this.readyState == 4 && this.status == 401) {
console.log("Failed");
}
};
xhttp.open("POST","/login",true);
xhttp.setRequestHeader("Content-type", "application/json");
xhttp.send(JSON.stringify({ email: this.email, password: this.password }));
}
Route:
var user = [{
EmailAddress: 'anne#gmail.com',
Password: 'first'
}]
router.post('/login', function(req, res, next) {
if((req.body.email === user[0].EmailAddress) && user[0].Password === req.body.password){
res.status(200).send();
} else {
res.status(401).send();
}
});
What should go into xhttp.send()? What am I doing wrongly? Can anyone help me with this? (preferably just javascript not jQuery) Thank you!
This is a typical issue about how to deal with the info passed to server using a way that you didn't expected.
There's a lot of things to improve in your code, but i won't focus on this right now. So, first of all, if you pay attention to what happens in your browser right after the submit button is clicked, on the URL you can see the typed inputs in querystring format. And it isn't referencing the /login route descripted.
Something like:
http://localhost:3000/?email=marcelobraga%40hotmail.com&password=agoodpassword
It happened because the Form element, by default, uses the parameters to communicate with your server. Not the object "Body" that you're expecting to receive through the HTTP Request object.
If you really want to access the login data passed as URL parameters, you will need just to fix your code in your front and backend to pass correctly object and prepare your server to read it on the right place.
I strongly advise you not to use the form html element this way. Either use the XMLHttpRequest. I suggest to use the Axios to do deal with the HTTP requests and send Body informations to avoid explicit such a sensitive information like logins could be. Other reason to use Axios is for easy syntax and clean code.
See how i made it with axios:
In HTML (I will insert all the HTML to you see the importation the Axios Lib tag):
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://unpkg.com/axios/dist/axios.min.js"></script> <!-- importing axios to this document -->
<title>Document</title>
</head>
<body>
<label for="email"><b>Email Address</b></label><br>
<input type="text" id="email" name="email"><br>
<label for="password"><b>Password</b></label><br>
<input type="text" id="password" name="password"><br><br>
<input type="submit" class="button" value="Login" onclick="submitlogin()">
</body>
</html>
In JS file:
const emailInput = document.getElementById("email").value //getting the value from input typed
const passwordInput = document.getElementById("password").value //getting the value from input typed
axios.post('/login',
{
email: emailInput,
password: passwordInput
}
)};
In expressjs:
const express = require("express")
const app = express();
const path = require('path');
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.post('/login', (req, res) => {
console.log(req.body); //console to verify the body data received on this endpoint request
const user = [{
EmailAddress: 'anne#gmail.com',
Password: 'first'
}];
if((req.body.email === user[0].EmailAddress) && user[0].Password === req.body.password){
res.status(200).send("Success");
console.log("Success");
} else {
res.status(401).send("Wrong email or password");
console.log("Wrong email or password");
}
});
app.get('/', function (req, res) {
res.sendFile(path.join(__dirname + '/index.html'));
});
app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});
Conclusion
The way that you was doing this made the data unreachable on the backend. The backend was expecting to receive the information to proceed with the verifications on the Body data of the Request. And you was passing it as a query parameter.
You can pass information using params or query params to the backend, but the login information must be more protected. Sending it in your body avoid people to find this data lookin in your history, for example. It's not the most secure way, because someone can catch this data on the middle. But, anyway, is something you should know.
I hope i could help you.

sending email with nodemailer

I'm trying to create a simple node server that sends emails with nodemailer
let app = require('express')();
app.use(require('body-parser').urlencoded());
const CONTACT_ADDRESS = 'email#email.com';
var mailer = require('nodemailer').createTransport({
service: 'mail.ee',
auth: {
user: 'test#test.com',
pass: 'password',
}
});
app.post('/contact', function(req, res) {
mailer.sendMail({
from: req.body.from,
to: '[CONTACT_ADDRESS]',
subject: req.body.subject || '[No subject]',
html: req.body.message || '[No message]',
}, function(err, info) {
if (err) return res.status(500).send(err);
res.json({success: true});
})
});
//Service is listening to port 3000
app.listen(3000, function(){
console.log("Service is running on port 3000...");
});
and the contact form is as follows:
<form method="post" action="http://localhost:3000/contact">
<label>Your e-mail</label>
<input type="text" name="from">
<label>Subject</label>
<input type="text" name="subject">
<label>Message</label>
<textarea name="body"></textarea>
<input type="submit" value="Submit">
</form>
When ever I press on submit button I get:
JSON.stringify(value); TypeError: Converting circular structure to
JSON
What does it mean? How can I overcome it?
res.send method trying to stringify your err object, but your err object cant be stringified, because not a standard error object. Try to output this err object to see and decide how to handle it.
For example you can use
if (err) return res.status(500).send(err.reason);
istead
if (err) return res.status(500).send(err);

Twilio JavaScript - SMS from client to server

I've found docs teaching on how to implement Twilio on server-side using Node, however, I couldn't find an end-end example where I can send a SMS coming from my client app.
Can anyone tell me what the implementation would look like to send a post custom SMS from client to server?
Disclaimer my server file is named as app.js and my client file is named as index.js
**1- This is what I have currently setup on my app.js
const express = require('express');
const app = express();
const path = require('path');
const twilio = require('twilio');
const bodyParser = require('body-parser');
//JSON DATA
const guests= require('./public/data/Guests');
app.use(bodyParser.urlencoded({extended: false}));
app.use(express.static('public'));
//SET PORT
app.set("port", process.env.PORT || 3000);
//GET JSON DATA
app.get('/data', function(req, res) {
Promise.all([guests])//combine requests into one object
.then(([guests]) => {
res.send({guests});
});
});
//CATCHALL
app.get("/*", function(req,res){
let file = req.params[0] || "/views/index.html";
res.sendFile(path.join(__dirname, "/public/", file));
});
//LISTEN ON PORT
app.listen(app.get("port"), function(){
console.log("Listening on port: " , app.get("port"));
});
let client = new twilio('xxxxxxxxxx', 'xxxxxxxxxxxxx');
app.post('/sms', (request, result) => {
const message = request.body.message;
client.messages.create({
to: +1847820802492359,
from: +8475302725792530 ,
body: message
}).then(() => {
// message sent successfully, redirect to the home page.
res.redirect('/');
}).catch((err) => {
console.error(err);
res.sendStatus(400);
});
});
-2 am trying to process a dynamic message in my index.js. The code works on the DOM properly, it is just the SMS with Twilio that isn't posting the message to the server
$(function() {
$.ajax({
type: "GET",
url: "/data",
success: res => {
//console.log(res);
handleMessage(res);
},
error: err => console.log(err)
});
//message method
let handleMessage = (res) => {
const getFirstName = res.guests.map(name => name.firstName);
//populate drop-down select
let handleSelect = () => {
//adds first names to select dropDown
$.each(getFirstName, function(i, value) {
$('#selectName').append($('<option>').text(value).attr('value', value));
});
};
handleSelect();
let handleSubmit = () => {
$("#form").submit(function(e) {
e.preventDefault();
let name = $('#selectName').val();
let greetGuest = `Welcome ${name}!`;
console.log(greetGuest);
//append to Dom
$('.showMessage').append(`<div class="newMessage"><span>${greetGuest}</span></div>`);
});
};
handleSubmit()
};
});
-3 HTML form
<form id="form" action="/sms" method="POST">
<label>
<label for=selectName>Guest
<select id="selectName" class="select " name="sms">
</select>
</label>
</label>
<input type="submit" value="send" class="btn btn-success" />
</form>
Am I having an asynchronicity issue here?
Twilio developer evangelist here.
I can give you a basic example here, which should give you a good idea of how to achieve this. I'll start with the server side, which you already have the basics of.
Firstly, I would recommend you use a POST request rather than a GET, simply because GETs can be easily repeated by users or cached by proxies. I assume you are using Express as the web application server. You will also need the body-parser module to read the data that we send from the client side.
const Twilio = require('twilio');
const express = require('express');
const bodyParser = require('body-parser');
const app = new express();
app.use(bodyParser.urlencoded({extended: false}));
app.use(express.static('public'));
const twilio = new Twilio(YOUR_ACCOUNT_SID, YOUR_AUTH_TOKEN);
app.post('/messages', (request, result) => {
const message = request.body.message;
twilio.messages.create({
to: TO_NUMBER,
from: FROM_NUMBER,
body: message
}).then(() => {
// message sent successfully, redirect to the home page.
res.redirect('/');
}).catch((err) => {
console.error(err);
res.sendStatus(400);
});
});
app.listen(3000);
This sets up a server which is serving static files from a public directory and then has one endpoint, POST to /messages, that sends a message.
We now need to create the client side. I shall do this in HTML only for simplicity. You need a form that will POST to the /messages endpoint with, in this case, a single field for the message. I've included a textarea to write the message in and a button to submit the form. If you save this as index.html in the public directory where you run the application from then it should work.
<!DOCTYPE html>
<html lang="en">
<head>
<title>Send a message!</title>
</head>
<body>
<h1>Send a message!</h1>
<form action="/messages" method="POST">
<label for="message">What would you like to send?</label>
<textarea name="message" id="message"></textarea>
<button type="submit">Send!</button>
</form>
</body>
</html>
Let me know if that helps at all.
Update
So you're looking to make the request to the server using Ajax so your page doesn't reload and you can display a different message. Your current form seems to have removed the message textarea that I added, I'll put it back in again. I assume you also want to send the message to whichever guest you are welcoming at the time, but I don't know how that works in your system, so I'm going to avoid that for now and hopefully you can sort it out.
So, if you update your form to something like this:
<form id="form" action="/sms" method="POST">
<label>
<label for=selectName>Guest
<select id="selectName" class="select " name="sms">
</select>
</label>
</label>
<label for="message">Message</label>
<textarea id="message" name="message"></textarea>
<input type="submit" value="send" class="btn btn-success" />
</form>
Then you need to add to your JavaScript a way to actually submit the form (since you are preventing the submission with e.preventDefault().
const $form = $('#form');
$form.submit(function(e) {
e.preventDefault();
let name = $('#selectName').val();
let greetGuest = `Welcome ${name}!`;
console.log(greetGuest);
$.ajax({
url: $form.attr('action'),
type: $form.attr('method'),
data: $form.serialize(),
success: function(data) {
console.log("The message has been sent");
},
error: function() {
console.error("The message couldn't be sent");
console.error(...arguments);
}
})
//append to Dom
$('.showMessage').append(
`<div class="newMessage"><span>${greetGuest}</span></div>`
);
});
In this case we are hooking into the callback for the submit event to make a new $.ajax request to the form's action, using the method (POST), and including the form data (which we get from $form.serialize()). We then setup success and error callbacks as you've done at the top of the function.
Let me know if this helps.

Sending Email with Node Mailer and Sendgrid in Angular MEAN stack using angular-fullstack from Yeoman

I am trying to understand where to locate the logic to send an email via a contact form in my Angular App (using angular-fullstack MEAN stack from Yeoman).
I can add the logic to send an email in the app.js file on the server side using nodemailer and sendgrid and everything works and an email is sent every time I refresh the server, however I am a little fuzzy on where to place the logic so that it only gets sent once the form is submitted and it hits the server side.
This is what the create action looks like on the Express JS side...
exports.create = function(req, res) {
Contact.create(req.body, function(err, contact) {
if(err) { return handleError(res, err); }
return res.json(201, contact);
});
};
Here is the code in app.js that is working, but obviously not in the right place...
var nodemailer = require('nodemailer');
var sgTransport = require('nodemailer-sendgrid-transport');
var options = {
auth: {
api_user: 'username', // 'SENDGRID_USERNAME' - Recommended to store as evn variables
api_key: 'password', // 'SENDGRID_PASSWORD'
}
};
var mailer = nodemailer.createTransport(sgTransport(options));
var email = {
to: 'sendto#email.com',
from: 'sendfrom#email.com',
subject: 'Test Email',
text: 'Awesome Email',
html: '<b>Bold and Awesome Email</b>'
};
mailer.sendMail(email, function(err, res) {
if (err) {
console.log(err)
}
console.log(res);
});
Coming from a rails background my initial thought is to stick the logic in the create action so that if the object is created successfully the email gets sent. Is this a correct way of thinking about it in this scenario...I am new to the MEAN stack.
Thanks for any help...
You need to create a route on the server that you can post form values to from Angular using $http.post.
The following lets you enter details in an Angular form. The form is then posted to Node where the req.body values are extracted and added email object. The email is then send by SendGrid.
SERVER.JS
var express = require('express');
var http = require('http');
var bodyParser = require('body-parser');
var dotenv = require('dotenv');
dotenv.load(); //load environment variables from .env into ENV (process.env).
var sendgrid_username = process.env.SENDGRID_USERNAME;
var sendgrid_password = process.env.SENDGRID_PASSWORD;
var sendgrid = require('sendgrid')(sendgrid_username, sendgrid_password);
var email = new sendgrid.Email();
var app = express();
app.use(bodyParser.json()); //needed for req.body
app.set('port', process.env.PORT || 3000);
app.use(express.static(__dirname + '/public'));
app.post('/email', function(req, res) {
email.addTo(req.body.to);
email.setFrom(req.body.from);
email.setSubject(req.body.subject);
email.setText(req.body.text);
email.addHeader('X-Sent-Using', 'SendGrid-API');
email.addHeader('X-Transport', 'web');
sendgrid.send(email, function(err, json) {
if (err) {
return res.send("Problem Sending Email!!!!");
}
console.log(json);
res.send("Email Sent OK!!!!");
});
});
var server = http.createServer(app);
server.listen(app.get('port'), function() {
console.log('Express server listening on port ' + app.get('port') ) ;
});
INDEX.HTML
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="utf-8">
<title></title>
<!-- CSS -->
</head>
<body ng-controller="MainCtrl">
<form name="emailForm">
<div class="group">
<input type="email" name="to" ng-model="email.to" ng-required="true">
<label>To</label>
</div>
<div>
<input type="email" name="from" ng-model="email.from" ng-required="true">
<label>From</label>
</div>
<div>
<input type="text" name="subject" ng-model="email.subject" ng-required="true">
<label>Subject</label>
</div>
<div>
<textarea ng-model="email.text" name="text" placeholder="Enter Text Here.."></textarea>
</div>
<button id="emailSubmitBn" type="submit" ng-click="submitEmail()">
Submit
</button>
</form>
<!-- JS -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.11/angular.min.js"></script>
<script type="text/javascript" src="js/app.js"></script>
</body>
</html>
CLIENT SIDE APP.JS
angular.module('myApp', [])
.controller('MainCtrl', function($scope, $http) {
$scope.submitEmail = function() {
console.log("TEST");
//Request
$http.post('/email', $scope.email)
.success(function(data, status) {
console.log("Sent ok");
})
.error(function(data, status) {
console.log("Error");
})
};
});

Categories

Resources