Feathersjs: Switching to sockets instead of REST, using Express Middleware with Sockets - reactjs

So I'm following Feathersjs docs regarding authentication,
and I have a middleware /signup,
from User Management docs:
module.exports = function(app) {
return function(req, res, next) {
const body = req.body;
app.service('users').create({
email: body.email,
password: body.password
})
// Then redirect to the login page
.then(user => res.redirect('/login.html'))//this will be a redirect in my client not in the server
.catch(next);
};
};
Now in src/middleware/index.js: I have :
module.exports = function() {
const app = this;
app.post('/signup', signup(app));// how can I reimplement this with sockets
app.use(notFound());
app.use(logger(app));
app.use(handler());
};
Using REST was easy :
request.post(`${SERVER}/signup`)
.send({ email: username, password: password })
.then(data=>{console.log(`data comming from response`,data)})
.catch(error=>{console.log(`ERROR comming from response`,error)})
so the problem is that now that I'm using sockets (feathers-client) I don't know how to tell feathers client to "post" the email/pass to that /signup middleware. Is there any way to achieve this?
this is my client conf:
import feathers from 'feathers-client';
const io = require('socket.io-client');
var socket = io(SERVER);
let feathersClient =
feathers()
.configure(feathers.socketio(socket))
.configure(feathers.hooks())
.configure(feathers.authentication({
storage: window.localStorage
}));

You don't need the signup middleware. Just create a new user through the /users service on your client like this:
import feathers from 'feathers-client';
const io = require('socket.io-client');
var socket = io(SERVER);
let feathersClient =
feathers()
.configure(feathers.socketio(socket))
.configure(feathers.hooks())
.configure(feathers.authentication({
storage: window.localStorage
}));
feathersClient.service('users').create({
email: 'test#example.com',
password: 'testing'
});
Then you will be able to authenticate the user like this:
feathersClient.authenticate({
type: 'local',
email: 'test#example.com',
password: 'testing'
});

Related

React-facebook-login work only for one account

Hello I have implemented react facebook login package in my app. However it works only for one account. I can't get login info data with another account. Here is my code:
const registerFb = async (req, res) => {
console.log(req.body);
const newUser = new UsersSchema({
email: req.body.email,
});
try {
const existEmail = await UsersSchema.findOne({ email: req.body.email });
if (existEmail) {
const token = jwt.sign({ email: req.body.email }, "privKey");
res.send(token);
} else {
const savedUser = await newUser.save();
res.send(savedUser);
}
} catch (err) {
res.json({ message: err });
}
};
Is your app still in development mode? If so, you can only test with specified users -- and the person who set-up the app is one of the specified users by default.
You can add more testing users under Roles in the App Dashboard.

React, connect-mongoose & Express session/user login

I'm trying to get sessions to work with a React front-end and an express + connect-mongo using MongoStore back-end.
Handle Register Function
async function handleRegister(evt){
//Prevent default form redirect.
evt.preventDefault();
//Create a new user objec to pass into axios
const user = {
username: username,
password: password
}
//Send axios post request to nodeJS API.
await axios.post("http://localhost:5000/users/register",user)
.then((res) => {
history.push({
pathname: '/',
state: res.data
});
})
.catch((err) => {
console.log(err);
});
//Push react history back to index page.
}
Handle Login function
const handleLogin = async (evt) => {
//Prevent default form submission
evt.preventDefault();
const loginDetails = {
username: username,
password: password,
}
//send login request to api
await axios.post('http://localhost:5000/users/login', loginDetails)
.then((res) => {
})
.catch((err) => {
})
}
I'm stuck on trying to figure out how to make the data be sent back to react after either of the above functions. In the register function I've sent back the res.data which contains the session. See blow route for express
router.post('/register', async (req, res) => {
//Destructure req.body.
const {username,password} = req.body;
//hash password.
const hashedPassword = await hashPassword(password);
//Create new user to store in mongodb.
const newUser = {
username: username,
password: hashedPassword
}
//Create new user document
await User.create(newUser, (err, newlyAddedUser) => {
if(err){
console.log(err);
}else{
req.session.username = newlyAddedUser.username;
console.log(req.session);
res.send(req.session);
}
})
});
With the console.log(req.session) it outputs the cookie and the username I added in the session itself.
Should I make a user object on the react side and store the username and password inside?
Should I be passing back the session itself to the route with history.push({ pathname: '/',state: res.data});
How can I verify that the session is valid for the user using connect-mongo?
I spent 10 minutes trying to understand what is your goal. Didn't find.
But whatever you need to use a jsonwebtoken if you want to verify that the session is valid like you said
Enjoy https://jwt.io/
https://www.npmjs.com/package/jsonwebtoken
I wouldn't store the session in the History state API like you do.
history.push({
pathname: '/',
state: res.data
});
You better use a sessionStorage and/or localStorage. The name just talks by itself.
Give me one point please

Firebase not responding to cloud function

I am adding data to the realtime database with React JS, a contact form and the firebase initialized. That all works.
However, I'm trying to implement an email to be sent to me when a new contact form has been submitted. CURRENT PROBLEM: The cloud function is deployed yet when I submit the form (and realtime db is added to), nothing happens. Not even an error message in the firebase console.
Please can you take a look at my code and offer some advice as to how I can get the automatic emails sent.
const functions = require('firebase-functions')
const admin = require('firebase-admin');
const nodemailer = require('nodemailer');
admin.initializeApp()
require('dotenv').config()
const email = process.env.REACT_APP_SENDER_EMAIL;
const pass = process.env.REACT_APP_SENDER_PASS;
exports.sendEmailNotification = functions.firestore.document('messages/{id}')
.onCreate((snap, ctx) => {
const data = snap.data();
let authData = nodemailer.createTransport({
host: 'smtp.gmail.com',
port: 465,
secure: true,
auth: {
user: email,
pass: pass
}
});
authData.sendMail({
from: data.email,
to: data.to,
subject: data.name + ' sent a message',
text: data.text,
}).then(res => console.log('email sent')).catch(err => console.log(err));
});
Your function needs to return a promise that resolves when all the asynchronous work is complete.
return authData.sendMail({
from: data.email,
to: data.to,
subject: data.name + ' sent a message',
text: data.text,
})
Returning this promise lets Cloud Functions know when it's safe to clean up and move on.
I first attempted creating this as a firebase cloud function as well, but I shifted towards building nodemailer on the server. Working in firebase cloud functions I was using the loophole of downgrading to node: 8 in package.json (which is deprecated) and I was being forced into making a Google firebase paid plan. Both items were driving me into a corner that I didn't want to be in.
This is the result of nodemailer in node.js thanks to https://www.youtube.com/watch?v=nF9g1825mwk
const express = require('express')
require('dotenv').config()
const bodyParser = require('body-parser')
const exphbs = require('express-handlebars')
const path = require('path')
const nodemailer = require('nodemailer')
const app = express()
const email_from = process.env.EMAIL_FROM;
const sender_pass = process.env.SENDER_PASS;
const email_to = process.env.EMAIL_TO;
// View engine setup
app.engine('handlebars', exphbs())
app.set('view engine', 'handlebars')
//body parser
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
//static folder
app.use('/public', express.static(path.join(__dirname, 'public')))
app.get('/', (req, res) => {
res.render('contact', { layout: false })
})
app.post('/send', (req, res) => {
const output = `
<p>You have a new submission</p>
<h3>Contact Details</h3>
<ul>
<li>Name: ${req.body.name}</li>
<li>Company: ${req.body.company}</li>
<li>Email: ${req.body.email}</li>
<li>Phone: ${req.body.phone}</li>
</ul>
<h3>Message</h3>
<p> ${req.body.message} </p> `;
async function main() {
// Generate test SMTP service account from ethereal.email
// Only needed if you don't have a real mail account for testing
// let testAccount = await nodemailer.createTestAccount();
// create reusable transporter object using the default SMTP transport
let transporter = nodemailer.createTransport({
host: "smtp.ethereal.email",
port: 587,
secure: false, // true for 465, false for other ports
auth: {
user: email_from,
pass: sender_pass
},
});
// send mail with defined transport object
let info = await transporter.sendMail({
from: email_from,
to: email_to,
subject: 'New Submission from Dean Productions!',
text: 'new submission',
html: output,
});
console.log("Message sent: %s", info.messageId);
// Message sent: <b658f8ca-6296-ccf4-8306-87d57a0b4321#example.com>
// Preview only available when sending through an Ethereal account
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
// Preview URL: https://ethereal.email/message/WaQKMgKddxQDoou...
res.render('contact', { layout: false, msg: 'Message has been sent!' })
}
main().catch(console.error);
})
app.listen(3000, () => console.log('Server started...'))

PassportJs get details of logged in user on page refresh in react app

I am building a simple blogging app with the server handling auth with passport js. Here is my server code:
import express from 'express';
import passport from 'passport';
import cookieSession from 'cookie-session'; // encrypt cookie
import router from './routes/routes';
import authRouter from './routes/authRoutes';
import middleware from './middleware';
import keys from './keys';
const app = express();
// use cookies for login/logout session, send cookie to browser
// happens only when user logs in.
app.use(cookieSession({
maxAge: 24 * 60 * 60 * 1000, // 1 day
keys: [keys.session.cookieKey], // encrypt cookie
}));
app.use(passport.initialize());
app.use(passport.session());
// auth routes
app.use('/auth', authRouter);
My authRoutes.js
import Router from 'express';
import passport from 'passport';
import GoogleStrategy from 'passport-google-oauth20';
import popupTools from 'popup-tools';
import { User } from '../database/model';
import keys from '../keys';
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser(async (id, done) => {
const usr = await User.findById(id);
done(null, usr);
});
passport.use(new GoogleStrategy({
clientID: keys.google.clientID,
clientSecret: keys.google.clientSecret,
callbackURL: '/auth/google/redirect',
}, async (accessToken, refreshToken, profile, people, done) => {
let usr = await User.findOne({ googleID: people.id });
if (!usr) {
const user = new User({
name: people.displayName,
email: people.emails[0].value,
googleID: people.id,
image: people._json.image.url,
});
usr = await user.save();
}
// calls serializeUser
done(null, usr);
}));
const authRouter = Router();
authRouter.get('/google', passport.authenticate('google', {
scope: ['profile', 'email'],
}));
authRouter.get('/logout', (req, res) => {
req.logout();
res.set('Content-Type', 'text/html');
res.end(popupTools.popupResponse({
status: true,
message: 'Logged out!',
}));
});
// callback for google auth
authRouter.get('/google/redirect',
passport.authenticate('google'),
(req, res) => {
// here we have the user as req.user
res.set('Content-Type', 'text/html');
res.end(popupTools.popupResponse({
status: true,
message: {
data: req.user,
},
}));
}
);
// I want this route to get me the current user
authRouter.get('/getActiveUser', (req, res) => {
res.json({
user: req.user,
});
});
export default authRouter;
I am using popupTools to help sign in with popup. On the front end, when the user logs in and the popup closes, I am saving the user information in mobx store. But when I am reloading the page, I can't preserve any of that information.
I want a route on my server like the /getActiveUser from where I can get the user currently logged in. But it doesn't seem to work.
You will need to use either localStorage API or sessionStorage in your React App. I use localStorage, such like:
Save user object in localStorage once the user is authenticated successfully:
localStorage.setItem('user', JSON.stringify(userObject));
Load user from the localStorage, once the React app is mounted in the browser using your mobx, such like:
const user = JSON.parse(localStorage.getItem('user'));
this way you have the user object, in case you want to use in the front again, this way you will be saving the user's session.
in case of logout process, you will be removing the user's Item from localStorage.
localStorage.removeItem('user');

React onSubmit function doesn't hit Express endpoint (Nodemailer)

I have a form, which submits name, email and text.
onSubmit function of the React component:
onSubmit = e => {
const { name, email, text } = this.state;
axios.post('/feedback', { name, email, text })
.then((result) => {
console.log(result)
}).catch(err => console.log(err))
}
feedback.js file (api/feedback.js - this works fine and sends email if requested via Postman):
const express = require("express");
const router = express.Router();
const nodemailer = require("nodemailer");
// #route POST api/feedback
// #desc Tests resource route
// #access Public
router.post("/", function(req, res, next) {
let output = `<p>New feedback</p>
<h3>Feedback details</h3>
<ul>
<li>Name: ${req.body.name}</li>
<li>Email: ${req.body.email}</li>
</ul>
<h3>Feedback message</h3>
<p>${req.body.text}</p>
`;
const transporter = nodemailer.createTransport({
host: "smtp.ethereal.email",
port: 587,
auth: {
user: "t4qj6mgea2kpyep7#ethereal.email",
pass: "PASSWORD"
},
tls: {
rejectUnathorized: false
}
});
let mailOptions = {
from: 'Webtool feedback: <t4qj6mgea2kpyep7#ethereal.email>', // sender address
to: "TO#EMAIL.COM", // list of receivers
subject: 'Feedback from Webtool', // Subject line
text: 'Hello world', // plain text body
html: output // html body
};
// send mail with defined transport object
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
}
console.log("Message sent: %s", info.messageId);
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
});
});
module.exports = router;
I have imported this into App.js, and set up the route for the feedback:
const feedback = require('./routes/api/feedback');
The issue is that the endpoint itself works, if I use Postman, I successfully receive an e-mail, so I don't suspect the feedback.js file. However, onSubmit() doesn't work.
​Did you make sure to include the middleware to protect web servers?
--Try this--
//middleware meant to protect web servers [CORS requests]
//can change '*' to 'http://localhost:3000' for local host testing
app.use((request, response, next) => {
response.header("Access-Control-Allow-Origin", "*");
response.header("Access-Control-Allow-Headers", "Content-Type");
next();
app.use(bodyParser.json())
app.use(bodyParser.urlencoded){
extended: false
}));
You are sending the form to /feedback as a post request but in the server side you you are having a post method with route /.So,The route /feedback is not in the express and so it throwed you 404 not found.Try changing the server route to /feedback.

Resources