node.js serving up HTML documents in server directory - javascript

So I have a pretty simple question, at the moment my server file and HTML documents all live in the same directory. However, I've realised this has lead to quite an annoying problem. If I user were to type:
http://localhost:3000/HTML/homepage.html
The server serves them the HTML document, where usually they'd have to go through sign in, and have their session ID verified before they could access the homepage.
Is there any way to deny access to files held in the server directory?
Example of how my code currently runs:
var http = require('http'),
fs = require('fs');
var path = require("path");
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser')
var session = require('express-session')
var sqlite3 = require('sqlite3').verbose();
var express = require('express');
var app = express();
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
app.use(bodyParser());
app.use(express.static(__dirname));
app.get('/signin', function (req, res) {
res.sendFile(path.join(__dirname + '/HTML/signin'));
});
app.post('/signin', function (req, res) {
var email = req.body.email;
var password = req.body.password;
if (email!="" || password != ""){
req.session.sessID = email //using email for example purposes
res.setHeader('Content-Type', 'application/json' );
res.send(JSON.stringify({
success: true //the client then catches the JSON, and will redirect to http://localhost:3000/homepage
}));
}
}
app.get('/homepage', function(req, res){
if (req.session.sessID == undefined){
res.send("You must login first!")
}else{
res.sendFile(path.join(__dirname + '/HTML/homepage.html'));
}
}

The source of your problem is this:
app.use(express.static(__dirname));
This tells express to serve ANY file it can find on your hard drive from the app directory on down. This is not advisable. This will even serve up your private server source code files if the right path is entered into the browser.
You should distinguish between your static files and your dynamically handled routes and you should make sure there is no possibility of conflict between them.
A common design is to designate a separate directory on your hard drive for static HTML files (not your app directory) and then set up express static routing to there. And, make sure that none of your dynamic routes will ever be satisfied with the static routing.
For example, if your static HTML files are in a sub-directory HTML which is below your __dirname directory, then you can do this:
app.use(express.static(path.join(__dirname, "HTML")));
And, then make sure none of your dynamic HTML files such as homepage.html are in that directory (put them somewhere else that express.static() will not ever see).
If you don't actually want the user to be able to see anything except your custom routes, then get rid of the app.use(express.static(__dirname)); line entirely and just create custom routes for each page you are serving.

Related

Prerender Angular app on an already existing Node.js server

My goal is to have dynamic og: tags, that can be seen by the facebook crawler. By doing some research I figured the best (and probably the only) approach is to prerender my app on the server. However I'm having problems with doing that.
I already have an existing Node.js server which looks a little different from the servers in most online guides.
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const http = require('http');
const app = express();
// Api for retrieving data from DB
const api = require('./server/api');
// Parsers
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// Angular DIST folder
app.use(express.static(path.join(__dirname, 'dist')));
// Api location
app.use('/api', api);
// Send all other requests to the Angular app
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.html'))
})
// Set Port
const port = process.env.PORT || '3040';
app.set('port', port);
const server = http.createServer(app)
server.listen(port, () => console.log('Magic happens on localhost:' + port));
I've tried using prerender.io. I got an API key, installed prerender-node and put this right before redirecting the request to index.html:
app.use(require('prerender-node').set('prerenderToken', 'my-token'));
// Send all other requests to the Angular app
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.html'))
})
I also added this to my index.html:
<meta name="fragment" content="!">
Nothing changed. Perhaps there's something else I need to do to get it working? Again, my goal is to have dynamic og: tags, that can be seen by the facebook crawler.
Additional info: For now, I'm setting the meta tags using the Meta serivce that comes with Angular 4, if it matters.
EDIT:
Demo link if someone wants to test: http://aramet.demo.cdots.bg/news-preview/1
Can you try moving the:
app.use(require('prerender-node').set('prerenderToken', 'my-token'));
above the static file line like:
app.use(require('prerender-node').set('prerenderToken', 'my-token'));
// Angular DIST folder
app.use(express.static(path.join(__dirname, 'dist')));
Since your index.html file is in your dist folder and you're serving static files from the dist folder, I'm wondering if the static call is serving your index.html file somehow.

express-subdomain handling any subdomain

I'm trying to use https://github.com/bmullan91/express-subdomain for subdomain routing in express. The following are the contents of my main.js and src/routes/site files.
const express = require('express');
const bodyParser = require('body-parser');
const subdomain = require('express-subdomain');
const siteRouter = require('./src/routes/site');
const app = express()
app.use(express.json() );
app.use(express.urlencoded());
app.use(express.static('public'));
app.use(subdomain('*.www', siteRouter));
app.get('/', function(req, res) {
res.send('Homepage');
});
const server = app.listen(80,'x3.loc', function () {
var host = server.address().address;
var port = server.address().port;
console.log('X3 listening at http://%s:%s', host, port);
});
const express = require('express');
let router = express.Router();
router.get('/', function(req, res) {
res.send('Welcome to site');
});
module.exports = router;
This way of doing app.use(subdomain('*.www', siteRouter)); has been suggested in https://github.com/bmullan91/express-subdomain/issues/33 but does not work.
I have also tried just * as the subdomain aswell, but that caused the homepage w/o a subdomain, to get treated like one aswell. How could I get this to work?
We know that / matches any base path regardless of subdomain. So I made your homepage middleware "subdomain-aware" like so:
app.get('/', function(req, res,next) {
/* If there are any subdomains, skip to next handler, since request is not for the main home page */
if (req.subdomains.length > 0) {
return next();
}
res.send('Homepage');
});
Then I placed the middleware for subdomains below the homepage middleware like so:
app.use(subdomain('*', siteRouter));
This makes homepage middleware to serve requests for x3.loc and the subdomain middleware to serve requests for any subdomain like api.x3.loc or api.v1.x3.loc.
But in my opinion, the real fix should be done in the module. I think it should be changed so that either the case where req.subdomains being empty is handled, or * is matched against an actual string, instead of skipping the iteration.
I am surprised that the fix suggested in bug 33 worked as-is for the reporter. In my testing, it works the opposite way i.e. www.example.com goes to subdomain middleware while stat1.example.com goes to the homepage middleware. Perhaps the reporter saw this and swapped the middleware bodies.

Questions on to use Node.js as local server with Braintree?

I'm not new to JavaScript but I am new to Node.js and back end languages. I have a very simple question.
I've installed and setup Node.js on my computer and I'm attempting to get a server going between my static files & directory(s) and my browser to be able to send and receive requests. I've downloaded Braintree's free Sandbox (found here) for practice to get some faux transactions going just to gain a better understanding of how this can work.
I set up a local server by running npm install -g http-server on my command line and then http-server to set it up.
I then received the following message in my command line:
Starting up http-server, serving ./public
Available on:
http://127.0.0.1:8080
http://10.0.1.4:8080
Hit CTRL-C to stop the server
So, with this setup...if I wanted to do get() and post() methods and see it rendered and communicating between my "server" and my static files. How do I do this? For example, if I were to set up Braintree's sandboxed environment and then create a clientToken using the following code from Braintree's website
const http = require('http'),
url = require('url'),
fs = require('fs'),
express = require('express'),
braintree = require('braintree');
const gateway = braintree.connect({
environment: braintree.Environment.Sandbox,
merchantId: "xxxxx",
publicKey: "xxxxx",
privateKey: "xxxxx" //blocked out real numbers for privacy
});
Here is the remaining code I hae to create a "client Token" for a transaction...and here is the guide I'm following via Braintree's website...
http.createServer((req,res) => {
gateway.clientToken.generate({
},(err, response) => {
if(err){
throw new Error(err);
}
if(response.success){
var clientToken = response.clientToken
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(clientToken);
res.end("<p>This is the end</p>");
} else {
res.writeHead(500, {'Content-Type': 'text/html'});
res.end('Whoops! Something went wrong.');
}
});
}).listen(8080,'127.0.0.1');
So, my question is...if I wanted to generate send a token to a client using the get() method...how would I do that? Would it have to be a separate js file? How would they be linked? If they're in the same directory will they just see each other?
Here is an example on Braintree's website of how a client token may be sent:
app.get("/client_token", function (req, res) {
gateway.clientToken.generate({}, function (err, response) {
res.send(response.clientToken);
});
});
How could this be integrated into my current code and actually work? I apologize if these are elementary questions, but I would like to gain a better understanding of this. Thanks a lot in advance!
I don't know much about braintree, but usually you would use somthing like express.js to handel stuff like this. So I'll give you some quick examples from an app I have.
#!/usr/bin/env node
var http = require('http');
var app = require('../server.js');
var models = require("../models");
models.sync(function () {
var server = http.createServer(app);
server.listen(4242, function(){
console.log(4242);
});
});
So that's the file that gets everything started. Don't worry about models, its just syncing the db.
var express = require('express');
var path = require('path');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var app = express();
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());
// share public folder
app.use(express.static(path.join(__dirname, 'public')));
require('./router.js')(app);
module.exports = app;
next up is the server.js that ties eveything together. app.use() lines are for adding middleware and the app.use(logger('dev')); sets the route logger for what your looking for.
app.use(express.static(path.join(__dirname, 'public'))); shares out all files in the public directory and is what your looking for for static files
var path = require('path');
module.exports = function(app){
//catch
app.get('*', function(req, res){
res.sendFile(path.join(__dirname, '..', 'public', 'index.html'));
});
}
last piece is the router.js. This is were you would put all of you get and post routes. generally I've found that if you see app.get or app.post in examples there talking about express stuff. It's used a lot with node and just makes routing way easier.
Also if your using tokens a route would look like this.
app.get('/print', checkToken, function(req, res){
print.getPrinters(function(err, result){
response(err, result, req, res);
});
});
function checkToken(req, res, next){
models.Tokens.findOne({value: req.headers.token}, function(err, result){
if(err){
res.status(500).send(err);
}else if(result == null){
console.log(req.headers);
res.status(401).send('unauthorized');
}else{
next();
}
});
}
so any route you want to make sure had a token you would just pass that function into it. again models is for db

Nodejs on single page

I'm new on Nodejs.
I have to do a web app with node js, express, socket.io on an existing website.
I use JXcore on Parallels Plesk panel to execute node.
But when I run js file and I visit any page on the website it returns "Cannot GET ".
If I use express get() function:
var app = require('express')();
var http = require('http').Server(app);
var path = require('path');
app.get('/path/to/index.html', function(req, res){
res.sendfile( path.resolve(__dirname + '/index.html') );
});
http.listen(10500, function(){
console.log('listening on *:10500');
});
it works on /path/to/index.html but every other website page is blocked by the same error "Cannot GET ".
Is there a way to run node only on one page?
Thanks
What your code is doing is defining just one route /path/to/index.html and mapping that to your index.html file. If you want to serve files from a directory, static html/css/js/whatever files, you can use the static method express provides:
app.use("/", express.static(__dirname + '/myHtmlDirectory'));
Change the "myHtmlDirectory" to whatever directory you store your files in and make sure to change the includes to define express:
var express = require('express');
var app = express();
However, if you want all GET requests to point to one single file, index.html for example, you can use the following:
app.get('*', function (req, res) {
res.sendfile( path.resolve(__dirname + '/index.html') );
});

NodeJS / Express / Mean Stack

I am new to Express and semi-new to nodejs and I am trying to run a simple app / webserver as a proof of concept. I have been stuck for hours because my server serves every file as index.html (with the content of index.html).
In my index.html I am making calls to JS files and CSS files and they are all coming back but with a 200 in the console but they are all coming back with index.html content instead of the actual content contained in them. I believe the problem is in my server.js file which is below:
// server.js
// modules =================================================
var express = require('express');
var app = express();
var mongoose= require('mongoose');
var path = require('path');
// configuration ===========================================
// config files
var db = require('../config/db');
var port = process.env.PORT || 9999; // set our port
//mongoose.connect(db.url); // connect to our mongoDB database (uncomment after you enter in your own credentials in config/db.js)
app.configure(function() {
app.use(express.static(__dirname + '/public')); // set the static files location /public/img will be /img for users
app.use(express.logger('dev')); // log every request to the console
app.use(express.bodyParser()); // have the ability to pull information from html in POST
app.use(express.methodOverride()); // have the ability to simulate DELETE and PUT
});
// routes ==================================================
require('../../app/routes')(app); // configure our routes
// start app ===============================================
app.listen(port); // startup our app at http://localhost:9999
console.log('Magic happens on port ' + port); // shoutout to the user
exports = module.exports = app; // expose app
// app/routes.js
module.exports = function(app) {
// server routes ===========================================================
// handle things like api calls
// authentication routes
// sample api route
app.get('/api/nerds', function(req, res) {
// use mongoose to get all nerds in the database
Nerd.find(function(err, nerds) {
// if there is an error retrieving, send the error. nothing after res.send(err) will execute
if (err)
res.send(err);
res.json(nerds); // return all nerds in JSON format
});
});
// route to handle creating (app.post)
// route to handle delete (app.delete)
// frontend routes =========================================================
// route to handle all angular requests
app.get('*', function(req, res) {
res.sendfile('/Users/...../app/public/index.html'); // load our public/index.html file
//res.sendfile(path, {'root': '../'});
});
};
I have been following this tutorial verbatum: http://scotch.io/bar-talk/setting-up-a-mean-stack-single-page-application but haven't had much success.
I cannot confirm without looking at your computer but I get the feeling the paths in your application are wrong.
The crucial parts in the express setup are:
app.use(express.static(__dirname + '/public'));
and
app.get('*', function(req, res) {
res.sendfile('/Users/...../app/public/index.html');
The first rule catches and returns any static file in __dirname + '/public'.
The second returns index.html for anything else.
The problem is that your server.js is not in the apps directory (I can see this since you use ../../app/routes.js to get to routes.js) this means __dirname + '/public' is not pointing to the public directory. Which is why your static files are being served by the global rule in routes.js.
In order to fix this change __dirname + '/public' to ../../app/public, or better yet place your server.js file where it should be and update your paths.
I can also see you are using an absolute full path to index.html in routes.js instead of a relative one so it seems as if your applications needs to tidied out.
The tutorial that you are following contains this route
app.get('*', function(req, res) {
res.sendfile('./public/index.html'); // load our public/index.html file
});
which explicitly defines the behaviour you described.
In this tutorial it makes sense because it explains how to build a single page application. This type of the application typically returns the same content for all the request while the actual presentation work happens on the client by the client-side library (angular in this example).
So if you what to serve more pages with different content you need to add more routes for them, just like route for /api/nerds in the example.
Update:
After clarifying that the issue is incorrectly served CSS and JS files, the proposed solution is to check the location of the server.js - it should be in the folder together with the folder "public".

Categories