Cannot remote access to MongoDB Atlas from anywhere except my house - node.js

I am working on a full stack MERN app.
When I am working on the project from my home, everything works fine.
However, as soon as I change my location to somewhere else(different IP adress) like a cafe, the connection to mongoDB fails..
This is what I have tried:
1,Add the IP address of the new location to the network access of my DB => doesn’t work
2, Add “allow access from anywhere” to the network access => doesn’t work
3, disabled firewall on my MacBookAir => doesn’t work
4, create a new user in the DB and try to use the new user login => doesn’t work
5, I am not using any proxy.
I am using macOS BigSur(version 11.5.2)
this is my index.js file
const express = require("express");
const app = express();
const mongoose = require("mongoose");
const dotenv = require("dotenv");
const helmet = require("helmet");
const morgan = require("morgan");
const userRoute = require("./routes/users");
const auth = require("./routes/auth");
const postRoute = require("./routes/posts");
const motorRoute = require("./routes/motors");
const multer = require("multer");
const path = require("path");
var cors = require("cors");
dotenv.config();
//connect to the DB here
mongoose.connect(
process.env.MONGO_URL,
{ useNewUrlParser: true, useUnifiedTopology: true },
() => {
console.log("connected to MongoDB");
}
);
app.use("/images", express.static(path.join(__dirname, "public/images/")));
app.use(express.json());
// app.use(helmet());
app.use(morgan("common"));
// app.use(cors({ origin: true, credentials: true }));
const storage = multer.diskStorage({
destination: (req, file, cb) => {
if (req.path == "/api/upload") {
console.log("yes the path is /api/upload");
cb(null, "public/images/posts/");
}
if (req.path == "/api/upload/profile") {
console.log("yes the path is /api/upload/profile");
cb(null, "public/images/person/");
}
// cb(null, "public/images");
},
filename: (req, file, cb) => {
cb(null, file.originalname);
},
});
//upload post from share
const upload = multer({ storage });
app.post("/api/upload", upload.single("file"), (req, res) => {
try {
return res.status(200).json("File uploaded successfully");
} catch (error) {
console.log(error);
}
});
///upload profile picture
const upload2 = multer({ storage });
app.post("/api/upload/profile", upload2.single("file"), (req, res) => {
try {
return res.status(200).json("File uploaded successfully");
} catch (error) {
console.log(error);
}
});
//get all the users
app.get("/api/allusers", (req, res) => {
try {
console.log("debug: I will try to get all the users");
return res.status(200).json(" will return users here");
} catch (error) {
console.log(error);
}
});
//set some routes in here
app.use("/api/users", userRoute);
app.use("/api/auth", auth);
app.use("/api/posts", postRoute);
app.use("/api/motors", motorRoute);
app.listen(8800, () => {
console.log("Backend server is running");
});
Please let me know if you need more information about it.
Thank you

You are only allowed to connect from whitelisted IPs.
https://www.mongodb.com/docs/atlas/security/ip-access-list/

Related

Not being able to connect to mongoDB

I am trying to connect my app to MongoDB but i get the following error as i run my app:
DepracationWarning: current URL string parser is deprecated, and will be removed in a future version. To use the new parser, pass option { useNewUrlParser: true } to MongoClient.connect.
[MONGODB DRIVER] Warning: Current Server Discover and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to MongoClient constructor
I know both above are just warnings but they are stopping my app and no letting me run it.
This is how i am setting the connection to mongodb in app.js:
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const session = require('express-session');
const MongoDBStore = require('connect-mongodb-session')(session);
const csrf = require('csurf');
const flash = require('connect-flash');
const multer = require('multer');
const errorController = require('./controllers/error');
const User = require('./models/user');
const MONGODB_URI =
'mongodb+srv://mateoghidini:<PASSWORD>#cluster0.9dernor.mongodb.net/test';
const app = express();
const store = new MongoDBStore({
uri: MONGODB_URI,
collection: 'sessions'
});
const csrfProtection = csrf();
const fileStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'images');
},
filename: (req, file, cb) => {
cb(null, new Date().toISOString() + '-' + file.originalname);
}
});
const fileFilter = (req, file, cb) => {
if (
file.mimetype === 'image/png' ||
file.mimetype === 'image/jpg' ||
file.mimetype === 'image/jpeg'
) {
cb(null, true);
} else {
cb(null, false);
}
};
app.set('view engine', 'ejs');
app.set('views', 'views');
const adminRoutes = require('./routes/admin');
const shopRoutes = require('./routes/shop');
const authRoutes = require('./routes/auth');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(
multer({ storage: fileStorage, fileFilter: fileFilter }).single('image')
);
app.use(express.static(path.join(__dirname, 'public')));
app.use('/images', express.static(path.join(__dirname, 'images')));
app.use(
session({
secret: 'my secret',
resave: false,
saveUninitialized: false,
store: store
})
);
app.use(csrfProtection);
app.use(flash());
app.use((req, res, next) => {
res.locals.isAuthenticated = req.session.isLoggedIn;
res.locals.csrfToken = req.csrfToken();
next();
});
app.use((req, res, next) => {
// throw new Error('Sync Dummy');
if (!req.session.user) {
return next();
}
User.findById(req.session.user._id)
.then(user => {
if (!user) {
return next();
}
req.user = user;
next();
})
.catch(err => {
next(new Error(err));
});
});
app.use('/admin', adminRoutes);
app.use(shopRoutes);
app.use(authRoutes);
app.get('/500', errorController.get500);
app.use(errorController.get404);
app.use((error, req, res, next) => {
// res.status(error.httpStatusCode).render(...);
// res.redirect('/500');
res.status(500).render('500', {
pageTitle: 'Error!',
path: '/500',
isAuthenticated: req.session.isLoggedIn
});
});
mongoose
.connect(MONGODB_URI)
.then(result => {
app.listen(3000);
})
.catch(err => {
console.log(err);
});
Is any of the packages that i am requiring above deprecated? Or should i include new lines of code that i am missing?
I remember having similar issue, so first of all make sure your mongoose version is above 5.7.1, if it is you can pass the options objects suggested from your warning message to your connect function like so:
mongoose
.connect(MONGODB_URI, {useNewUrlParser: true, useUnifiedTopology: true})
.then(result => {
app.listen(3000);
})
.catch(err => {
console.log(err);
});

MERN Heroku returns index.html instead of actual JSON data from server

this was working perfectly fine with localhost but after I deployed from Heroku it doesn't work.
please help.
Index.js
const express = require("express");
const app = express();
const mongoose = require("mongoose");
const dotenv = require("dotenv");
const helmet = require("helmet");
const morgan = require("morgan");
const userRoute = require("./routes/users");
const authRoute = require("./routes/auth");
const postRoute = require("./routes/posts");
const multer = require("multer");
const path = require("path");
dotenv.config();
mongoose.connect(
process.env.MONGO_URL,
() => {
console.log("Connected to MongoDB");
}
);
app.use("/img", express.static(path.join(__dirname, "public/images")))
//middleware
app.use(express.json());
app.use(helmet());
app.use(morgan("common"));
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "public/images");
},
filename: (req, file, cb) => {
cb(null, req.body.name);
}
});
const upload = multer({storage});
app.post("/api/upload", upload.single("file"), (req,res)=>{
try {
return res.status(200).json("file uploaded successfully");
} catch(err){
console.log(err);
}
})
if (process.env.NODE_ENV === 'production') {
app.use(express.static(path.join(__dirname, 'frontend/build')));
app.get('/*', (req, res) => {
res.sendFile(path.join(__dirname, 'frontend/build', 'index.html'));
});
}
app.use("/api/auth", authRoute);
app.use("/api/users", userRoute);
app.use("/api/posts", postRoute);
//const port = parseInt(process.env.PORT) || 8800;
app.listen(process.env.PORT || 8800, () => {
console.log("backend server is running");
});
Feed.jsx
import "./feed.css";
import Share from "../share/Share";
import Post from "../post/Post";
import { useEffect, useState, useContext } from "react";
//import {Posts} from "../../dummyData";
import {axiosInstance} from "../../config";
import { AuthContext } from "../../context/AuthContext";
export default function Feed({username}) {
const [posts, setPosts] = useState([]);
const { user } = useContext(AuthContext);
//this helps you to render once when the page open. and only re-render whatever you put in[] changes, which is the dependency
useEffect(() => {
const fetchPosts = async () => {
const res = username
? await axiosInstance.get("/posts/profile/" + username)
: await axiosInstance.get("/posts/timeline/" + user._id);
console.log(user._id);
console.log(username);
console.log(res.data);
setPosts(
res.data.sort((p1,p2)=>{
return new Date(p2.createdAt) - new Date(p1.createdAt);
})
);
};
fetchPosts();
},[username, user._id])
return (
<div className="feed">
<div className="feedWrapper">
{(!username || username === user.username) && <Share/>}
{posts.map((p) => (
<Post key={p._id} post={p}/>
))}
</div>
</div>
);
}
if I do Console.log(res.data) from Feed.js, I see index.html data instead of JSON data I should be getting from "api/posts/timeline/"...
this was working perfectly fine with localhost but after I deployed from Heroku it doesn't work.
please help.

'Cannot GET /api/items'

Working on a MERN application as a way to learn how it all works, but I am stuck trying to get my routes to display. I don't get any other errors, and if I use a simple app.get('/'), I am able to see that just fine; it seems that the routes I have defined are not being recognized for some reason.
require('dotenv').config();
const express = require('express');
const cors = require('cors');
const app = express();
const port = process.env.PORT;
const options = {
origin: 'http://localhost:8081'
}
app.use(cors(options));
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
const db = require('./models');
db.mongoose
.connect(db.url, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => {
console.log('Successfully connected.');
})
.catch((error) =>{
console.log(`Connection failed. Error: ${error}`);
process.exit();
}
);
require('./routes/items.routes')(app)
app.listen(port, () => {
console.log(`Listening at localhost:${port}`);
});
const multer = require('multer');
const dir = './public/';
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, dir);
},
filename: (req, file, cb) => {
const fileName = file.originalname.toLowerCase().split(' ').join('-');
cb(null, fileName + '-' + Date.now());
}
});
var upload = multer({
storage: storage,
fileFilter: (req, file, cb) => {
if (file.mimetype == 'image/png' || file.mimetype == 'image/jpg' || file.mimetype == 'image/jpeg') {
cb(null, true);
} else {
cb(null, false);
return cb(new Error('Invalid file type.'));
}
}
});
module.exports = app => {
const items = require('../controllers/items.controller');
let router = require('express').Router();
router.post('/', upload.single('icon'), items.create);
router.delete('/:id', items.delete);
app.use('/api/items', router);
};
I followed this and this as a start point. Unsure what I am missing or why it is unable to retrieve my POST route.
The error in your title:
Cannot GET /api/items
means it is a GET request to /api/items. But, you don't have a GET handler for that route. You only have a POST handler for that route defined with these two lines of code:
router.post('/', upload.single('icon'), items.create);
app.use('/api/items', router);
So, you apparently need to change your test on that route to a POST, not a GET and the POST will be expecting a body part with the data for an icon in it.
If you want to see exactly what is getting to your router (for debugging/troubleshooting purposes), you can add this right after you declare the router as the first item you register on the router.
router.use((req, res, next) => {
console.log(`In router: ${req.method}:${req.originalUrl}`);
next();
});

Express server not responding route request

My express server is not responding to any of the route requests, whatever I do no luck.
following are the routes I am trying to access:
http://localhost:3000/api/files
http://localhost:3000/files/<:uuid>
http://localhost:3000/api/files/send
Terminal output:
Response via insomia:
Following are the files of the project
server.js
const express = require('express');
const app = express();
const path = require('path');
app.use(express.static('public'));
app.use(express.json);
const PORT = process.env.PORT||3000;
const connectDB = require('./config/db');
connectDB();
app.set('views', path.join(__dirname, '/views'));
app.set('view engine', 'ejs');
app.use('/api/files', require('./routes/files'));
app.use('/files', require('./routes/show'));
app.use('/files/download', require('./routes/download'));
console.log("Server");
app.listen(PORT, () =>{
console.log(`Listening on port ${PORT}`);
});
routes/files.js
const router = require('express').Router();
const multer = require('multer');
const path = require('path');
const File = require('../models/file');
const {v4 : uuid4} = require('uuid');
const sendMail = require('../services/email');
require('dotenv').config();
let storage = multer.diskStorage({
destination: (req, file, cb) => cb(null, 'uploads/'),
filename: (req, file, cb) => {
const uniqueName = `${Date.now()}-${Math.round(Math.random() * 1E9)}${path.extname(file.originalname)}`;
cb(null, uniqueName)
},
});
let upload = multer({
storage:storage,
limit: { fileSize: 100000*200},
}).single('myfile');
router.post('/', (req, res) => {
console.log("Reached here");
console.log(req);
// store locally
upload(req, res, async (err) => {
// check for valid req
if(!req.file){
return res.json({
error: "Error processing file!"
});
}
if(err){ return res.status(500).send({error: err.message})}
// store in db
const file = File({
filename: req.file.filename,
uuid: uuid4(),
path: req.file.path,
size: req.file.size,
});
const response = await file.save();
return res.json({file: `${process.env['APP_BASE_URL']}/files/${response.uuid}`})
});
//return link
});
router.post('/send', async (req, res) => {
console.log(req.body);
const {uuid, emailTo, emailFrom} = req.body;
if(!uuid || !emailTo || !emailFrom){ return res.status(422).send({error: 'All files are required.'});}
const file = await File.findOne({uuid: uuid});
if(file.sender){
return res.status(422).send({error: 'Email already sent.'});
}
file.sender = emailFrom;
file.receiver = emailTo;
const response = await file.save();
sendMail({
from: emailFrom,
to: emailTo,
subject: "shareMe File Sharing",
text: `${emailFrom} shared a file with you`,
html: require('../service/template')({
emailFrom: emailFrom,
downloadLink: `${process.env['APP_BASE_URL']}/files/${file.uuid}`,
size: parseInt(file.size/1000)+'KB',
expires: '24 hours'
})
});
return res.send({success: true});
});
module.exports=router;
routes/show.js
const router = require('express').Router();
const File = require('../models/file');
router.get('/:uuid', async (req, res) => {
try{
const file = await File.findOne({
uuid: req.params.uuid
});
if(!file){
return res.render('download', {error: 'File not fetched.'});
}
console.log(`${process.env['APP_BASE_URL']}/files/download/${file.uuid}`);
return res.render('download', {
uuid: file.uuid,
fileName: file.filename,
size: file.size,
downloadLink: `${process.env['APP_BASE_URL']}/files/download/${file.uuid}`,
});
}catch(err){
return res.render('download', {error: 'Something seems to be upset :('});
}
});
module.exports = router;
routes/download.js
const router = require('express').Router();
const File = require('../models/file');
router.get('/:uuid', async (req, res) => {
// Extract link and get file from storage send download stream
const file = await File.findOne({ uuid: req.params.uuid });
// Link expired
if(!file) {
return res.render('download', { error: 'Link has been expired.'});
}
const response = await file.save();
const filePath = `${__dirname}/../${file.path}`;
res.download(filePath);
});
module.exports = router;

increase express post body limit to proxied api

I have a seperate frontend and backend, where all requests to http://frontend.com/api are proxied to the backend. However we allow image uploads to be 10mb max, which gets limited by the 1mb internal limit of express on all request bodies.
I have the following config:
const express = require('express');
const consola = require('consola');
const { Nuxt, Builder } = require('nuxt');
const helmet = require('helmet');
// Express
const app = express();
const host = process.env.HOST || '127.0.0.1';
const port = process.env.PORT || 8080;
app.set('port', port);
// Import and Set Nuxt.js options
const config = require('../nuxt.config.js');
config.dev = !(process.env.NODE_ENV === 'production');
async function start() {
// Init Nuxt.js
const nuxt = new Nuxt(config);
if (config.dev) {
const builder = new Builder(nuxt);
await builder.build();
}
// NOTE: Only in production mode
if (!config.dev) {
// Helmet default security + Referrer + Features
app.use(helmet());
}
// Proxy /api to proper backend
app.use('/api', proxy(process.env.API_ENDPOINT || 'http://localhost:3000'));
// Give nuxt middleware to express
app.use(nuxt.render);
// Listen the server
app.listen(port, host);
consola.ready({
message: `Server listening on http://${host}:${port}`,
badge: true,
});
}
start();
I have tried adding body-parser, until I found out this only works for non multipart/form type of requests. Considering that this isn't an express backend, but only used to serve SSR (with nuxt), I have no idea how to get this to work with something like multer or busboy.
Can this be done without having to setup nginx as a reverse proxy?
Express itself doesn't impose any limits on body size, because it doesn't process the request body at all.
However, some middleware do impose a limit, like body-parser and express-http-proxy, which is what you're using.
To increase the limit to 10MB:
app.use('/api', proxy(process.env.API_ENDPOINT || 'http://localhost:3000', {
limit: '10mb'
));
The way mine works is I define my api base url in a config file which I reference in an api/init.js file. This file is added to plugins in nuxt.config.js. This is that file:
import axios from 'axios'
import {baseURL} from '~/config'
import cookies from 'js-cookie'
import {setAuthToken, resetAuthToken} from '~/utils/auth'
import { setUser, setCart } from '../utils/auth'
axios.defaults.baseURL = baseURL
const token = cookies.get('x-access-token')
const currentUser = cookies.get('userDetails')
const currentCart = cookies.get('userCart')
if (token) {
setAuthToken(token)
setUser(currentUser)
setCart(currentCart)
} else {
resetAuthToken()
}
The backend runs on it's own server which I launch with node index.js and it is the base url that my init.js looks for. The backend index.js looks like this:
const mysql = require('mysql')
const express = require('express')
const bodyParser = require('body-parser')
const config = require('./config')
const jwt = require('jsonwebtoken')
const bcrypt = require('bcrypt')
const multer = require('multer')
const auth = require('./auth')
const files = require('./files')
const create = require('./create')
const get = require('./get')
const delet = require('./delet')
const blogFiles = require('./blogFiles')
const db = mysql.createConnection(config.db)
const app = express()
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
extended: true
}))
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS')
res.header('Access-Control-Allow-Headers', 'Content-Type, Content-Length, x-access-token, userDetails, userCart')
if (req.method === 'OPTIONS') {
res.sendStatus(200)
}
else {
next()
}
})
app.use((err, req, res, next) => {
if (err.code === 'LIMIT_FILE_TYPES') {
res.status(422).json({ error: 'Only images are allowed'})
return
}
if (err.code === 'LIMIT_FILE_SIZE') {
res.status(422).json({ error: `Too Large. Max filesize is ${MAX_SIZE/1000}kb` })
return
}
})
app.use('/auth', auth({db, express, bcrypt, jwt, jwtToken: config.jwtToken}))
app.use('/files', files({db, express, multer}))
app.use('/blogFiles', blogFiles({db, express, multer}))
app.use('/create', create({db, express}))
app.use('/get', get({db, express}))
app.use('/delet', delet({db, express}))
app.get('/test', (req, res) => {
db.query('select 1+1', (error, results) => {
if (error) {
return res.status(500).json({type: 'error', error})
}
res.json({type: 'success', message: 'Test OK', results})
})
})
app.listen(config.port)
console.log('App is running on port ' + config.port)
The files.js handles file uploads and as you can see index.js requires that. It is in there that I use multer to handle the upload limit and such. This is file.js
module.exports = ({db, express, multer }) => {
const routes = express.Router()
const fileFilter = function(req, file, cb) {
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif']
if (!allowedTypes.includes(file.mimetype)) {
const error = new Error('Wrong file type')
error.code = 'LIMIT_FILE_TYPES'
return cb(error, false)
}
cb(null, true)
}
const MAX_SIZE = 250000
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '../frontend/assets/images')
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
})
const upload = multer ({
storage: storage,
fileFilter,
limits: {
fileSize: MAX_SIZE
},
})
routes.post('/upload', upload.single('file'), (req, res) => {
res.json({ file: req.file })
})
return routes
}
As you can see I set the MAX_SIZE for my file uploads here so guess you can set any limit and as multer is handling it, it will over ride any limits set by express.

Resources