Facebook Bot and Node: Empty req.query - javascript

this is my first post on StackOverflow!
I have a problem with a new bot I'm creating.
First of all, this is my code in app.js
import express from 'express';
import bodyParser from 'body-parser';
import mongoose from "mongoose";
import { VERIFY_TOKEN, PORT, MONGODB_URI } from './config';
import { botLogic } from './logic';
mongoose.Promise = global.Promise;
mongoose.connect(MONGODB_URI, { useMongoClient: true });
const app = express();
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
app.get('/', (req, res) => {
res.send('Correcly deployed!');
});
app.get('/webhook', (req, res) => {
if(req.query['hub.verify_token'] === VERIFY_TOKEN) {
res.send(req.query['hub.challenge']);
}
res.send('Invalid credentials');
});
app.post('/webhook/', async (req, res) => {
try {
await res.sendStatus(200);
await Promise.all(req.body.entry.map(async entry => {
await Promise.all(entry.messaging.map(async update => {
console.log(`Received update from ${update.sender.id}`);
await botLogic(update);
}));
}));
} catch (e) {
console.error(e);
}
});
app.get('*', (req, res) => {
res.status('404').send('Nothing interesting here');
});
app.listen(PORT, function() {
console.log('running on port', PORT);
});
I created the app on the Facebook Developer page and the webhook is linked:
Facebook developer page: webhook
If you go on https://my-personal-bot.herokuapp.com/ it should say
correctly deployed
but If you go here
https://my-personal-bot.herokuapp.com/webhook
is gonna say:
Invalid credentials
and if I log req.query the result is an empty object.
Logs screenshot
I built a couple of bots before and this initial setup was quite straightforward, however, I this particular case, I can't figure out where is the problem. The API version that I'm using is v2.11, it's the only difference with my previous bots.
Thank you in advance for any advice!

the body of the webhooks from Facebook is only json encoded, so get rid of the line that adds url encoding:
app.use(bodyParser.urlencoded({extended: false}));
Also the request is encrypted using your app secret, so you'd need to decode that before using bodyParser.json()
app.use(xhub({algorithm: 'sha1', secret: process.env.APP_SECRET }));
of course you wanna set your env variable APP_SECRET in the heroku console
For a complete example usage of webhooks, look at https://github.com/mduppes/webhooks_test/blob/master/index.js

Related

Cannot reach localhost

I'm trying to build a demo application and having "Cannot GET /" error when I try to reach out http://localhost:8800/
On the other hand, the output as expected:
Connected to backend.
mongoDB connected!
Connected to mongoDB.
So I couldn't understand where exactly I have the problem, do you have any suggestions?
import mongoose from "mongoose";
import express from "express";
import authRoute from "./routes/auth.js";
import usersRoute from "./routes/users.js";
import hotelsRoute from "./routes/hotels.js";
import roomsRoute from "./routes/rooms.js";
const app = express();
// dotenv.config()
const connect = async ()=>{
try {
await mongoose.connect('mongodb+srv://********#******.mongodb.net/?retryWrites=true&w=majority');
// Check how we can use .env file
console.log("Connected to mongoDB.")
} catch (error) {
throw error
}
};
mongoose.connection.on("disconnected", ()=>{
console.log("mongoDB disconnected!")
})
mongoose.connection.on("connected", ()=>{
console.log("mongoDB connected!")
})
app.use(express.json())
app.use("api/auth", authRoute);
app.use("api/users", usersRoute);
app.use("api/hotels", hotelsRoute);
app.use("api/rooms", roomsRoute);
app.listen(8800, ()=>{
connect()
console.log("Connected to backend.")
});
auth.js
import express from "express";
const router = express.Router();
router.get("/auth", (req,res)=>{
res.send("Hello, this is auth endpoint");
})
router.get("/register", (req,res)=>{
res.send("Hello, this is auth register endpoint");
})
export default router
You don't need a root route. However, if you still want something to display, you can just add in your code :
app.get('/', (_, res) => res.send({message: 'Hello from Express'}))
Your code is running, it just doesn't have a route at '/', which is your path when you go to any website. if you want to render something on the page, just add
app.get('/', (req, res)=>{
res.send('this text will now appear at localhost:8800');
/*
you could also import path and do
path.join(__dirname+'yourfilename.html') to render an html file
*/
})
you can make '/' root
app.get('/', (req, res) => {
res.send('Hello World!')
})

Passport-Local and Express Router Issue with Imports

I have an Express.js app with a Passport-local Auth, I'm tying to implement express router to my app since it's getting really hard to debug
This is an example of my main file (app.js)
const express = require('express')
const app = express()
const passport = require('passport')
const testing = require('./routes/file')
app.use(passport.initialize())
app.use(passport.session())
app.use('/router', testing)
const initializePassport = require('./passport-config');
initializePassport.initialize(passport);
app.get('/', checkAuthenticated, (req, res) => {
let user = data.key
res.send(`Hi ${user}`)
})
app.post('/login', checkNotAuthenticated, passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/login',
failureFlash: true
}))
function checkAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next()
}
res.redirect('/login')
}
function checkNotAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return res.redirect('/')
}
next()
}
app.listen(3000)
This is what my main file is like, this works perfectly fine
and just to make things clear, The function are to check if a user is authenticated or not, also my passport-config returns something called data.key which is basically the username of the user.
Now I've created a router here app.use('/router', testing) with the route as /router for testing purposes
Now this is my file.js that is being used by express
const express = require('express'), router = express.Router();
var bodyParser = require('body-parser');
// Handle POST requests
router.use(bodyParser.urlencoded({ extended: false }));
router.use(bodyParser.json());
router.get('/test', checkAuthenticated, (req, res) => {
let user = data.key;
res.send(`Hello ${user}, this is coming from the router`)
})
module.exports = router;
Now as expected when I open the site at localhost:3000/router/test it returns a undefined error for data.key since it's not imported and then when I comment that out the line causing the error then checkAuthenticated doesn't work, even when I'm not logged in I can get access to the page, now this is the problem, how do I fix it, I've gone through the entire express router docs I couldn't find luck there.
Thanks
Your function is not in the global scope you need to set it to global to be able to see it like:
GLOBAL.authFunction = function(){
}
Suggestion:
1- make a module for auth name it authModule.
2- import the module auth check middleware where ever you want.

how to read a cookie from browser in nextjs api

I am setting my cookie in the layout.js component and can see it in the browser.
I have my api and I want to be able to read the cookie when a post is made and then do something with the value.
I have tried a few different packages to do this and I am getting 'undefined' for the cookie value
How can I read the value of the cookie in my api.js file?
Layout.js
useEffect(() => {
document.cookie = 'tagrid=322323932; path=/'
})
pages/api.js
// import cookies from 'next-cookies'
import cookieCutter from 'cookie-cutter'
import Cookies from 'cookies'
// const cook = Object.keys(cookies).map((name) => cookies[name].toString())
export default async (req, res) => {
const { method, body } = req
if (method === 'POST') {
res.statusCode = 200
res.setHeader('Content-Type', 'application/json')
res.end(
JSON.stringify({
msg: body,
}),
)
try {
const cook = cookies.get('tagrid')
// read cookie value
console.log('cook', cook)
} catch (error) {
console.error(error)
}
} else {
res.status(200)
}
}
express.js
const bodyParser = require("body-parser");
var cookieParser = require("cookie-parser");
var express = require('express');
const app = express();
app.use(cookieParser());
app.get('/', function(req, res){
console.log('Cookies: ', req.cookies)
});
//Here we are configuring express to use body-parser as middle-ware.
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.listen(4000,() => {
console.log("Started on PORT 4000");
})
https://www.npmjs.com/package/cookie-parser
cookie-parser is meant to be used as an express middleware, but most middlewares can be used directly as a function as well.
normally you'd use it in express like this:
app.use(cookieParser());
But if you think about it, app.use takes a function and it passes that function the parameters req, res, next. You can also pass it req, res, and a callback function (the callback function receives no parameters).
To use cookie-parser in your server-side script:
import { cookieParser } from 'cookie-parser'
export default async (req, res) => {
const callback = () => {
const cook = req.cookies['tagrid'];
console.log(cook);
};
cookieParser()(req, res, callback);
};

Node server response is HTML after adding catch-all to allow react-router to work

I have been developing a node backend, react front end web app for a couple months. It has working just fine when I started the server via nodemon and the front end with npm start. But now that I am getting ready to host an alpha version and ran 'npm run build' I've been running into issues.
It seems to be stemming from the interaction of accessing the app from the server's port and react-router. I added a catch-all endpoint app.get('/*'...) to my server to allow the react-router to work. So now when the front requests data, the response is HTML not the array I want.
I feel like there is a simple solution to this, but I just don't see it yet. I looked into using HashRouter instead of BrowserRouter, but unfortunately I can't use that because I am using MSAL Active Directory for login.
server/index.js
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors')
require('dotenv').config();
const massive = require('massive');
const session = require("express-session");
const morgan = require('morgan');
const path = require('path');
const ctrl = require(`./controllers/controller.js`);
//Middleware
const app = express();
app.use(bodyParser.json());
app.use(cors());
app.use(express.static(__dirname + './../build'));
app.use(morgan('dev'));
//Connection to Azure DB
massive(process.env.CONNECTION_STRING)
.then(db => {
console.log('Connected to Azure PostgreSQL Database')
app.set('db', db)
}).catch(err=>console.log(err))
app.use(session({
secret: process.env.SESSION_SECRET,
cookie: { maxAge: 60000 },
resave: false,
saveUninitialized: true
}));
//Endpoints
app.get('/*', function(req, res) {
res.sendFile(path.join(__dirname, './../build/index.html'), function(err) {
if (err) {
res.status(500).send(err)
}
})
})
app.get('/getallemployees/', ctrl.getAllEmployees)
app.listen(8080, () => console.log(`Listening on ${8080}`));
Put that catch-all endpoint after all the others that return data.
//Endpoints
app.get('/getallemployees/', ctrl.getAllEmployees)
app.get('/*', function(req, res) {
res.sendFile(path.join(__dirname, './../build/index.html'), function(err) {
if (err) {
res.status(500).send(err)
}
})
})

Why do I get the PUT request with POSTMAN not done?

Before embarking on the routes of my application, I have created some requests with POSTMAN of which PUT is not made to me in full.
This is my configuration of my server in ExpressJS:
const express = require('express');
const morgan = require('morgan');
const helmet = require('helmet');
const mongoose = require('mongoose');
const app = express();
// Settings
app.set('port', process.env.PORT || 3000);
mongoose.connect('mongodb://localhost/mevn-curso', {
useNewUrlParser: true,
useFindAndModify: false,
useCreateIndex: true
})
.then(db => console.log('DB is connected'))
.catch(err => console.log(err));
mongoose.set('useNewUrlParser', true);
mongoose.set('useFindAndModify', false);
mongoose.set('useCreateIndex', true);
// Middlewares
app.use(morgan('dev'));
app.use(express.json());
app.use(helmet());
// Routes
app.use('/tasks/', require('./routes/tasks'));
// Static files
app.use(express.static(__dirname + '/public'))
app.listen(app.get('port'), ()=> {
console.log('Server on port', app.get('port'));
});
It works for me normally and this is the router I am using, which is inside the tasks.js file in the routes folder:
const express = require('express');
const router = express.Router();
const Task = require('../models/Task');
router.get('/', async (req,res)=> {
const tasks = await Task.find();
res.json(tasks);
})
router.post('/', async (req,res) => {
const task = new Task(req.body);
await task.save();
res.json({
status: "Task Saved"
})
})
router.put('/:id', async (req,res)=> {
console.log(req.params._id);
console.log(req.body);
await Task.findByIdAndUpdate(req.params._id, req.body)
res.json('recivied');
console.log('Listo')
})
module.exports = router;
In console does not seem to give me any error. I make the request with normal POSTMAN, and it returns the logs of the console. Even the server answers the json and everything. But the data in the database is not changed. This does not happen with GET or POST, on the contrary, everything is going well.
Here I leave you how I make the request with POSTMAN. First of all I am going to show you the data that I already have in the database, with the get request that is normally done with the browser:
ready, when I'm making the PUT request this is my configuration in POSTMAN:
It's a json type content type because that's what I'm going to process, then comes the body:
and this is the answer in the console:
What do you think it could be?
as I see the console.log of req.params._id is undefined: change the
Task.findByIdAndUpdate(req.params.id, req.body) changed _id to id
router.put('/:id', async (req,res)=> {
console.log(req.params.id);
console.log(req.body);
await Task.findByIdAndUpdate(req.params.id, req.body)
res.json('recieved');
})

Categories