Angular + Node.js HTTP & HTTPS (SSL) - angularjs

I want to use https for the post requests in my payment view. I stumbled over diff tutorials and now my setup is the following (and I still don't get it running):
Certificates
I generated certificates for my development environment using this tutorial:
http://greengeckodesign.com/blog/2013/06/15/creating-an-ssl-certificate-for-node-dot-js/
Node.js
I followed answer #2 to setup the http and https server in node:
Listen on HTTP and HTTPS for a single express app
It looks like that:
environment = require('./config/config.js')()
express = require('express')
bodyParser = require('body-parser')
app = express()
portHTTP = process.env.PORT || 61361
portHTTPS = 3030
mongoose = require('mongoose')
morgan = require('morgan')
http = require('http')
https = require('https')
socket = require('socket.io')
#SSL Server
fs = require('fs')
sslOptions = {
key: fs.readFileSync(__dirname + '/config/ssl/server.key'),
cert: fs.readFileSync(__dirname + '/config/ssl/server.crt'),
ca: fs.readFileSync(__dirname + '/config/ssl/ca.crt'),
requestCert: true,
rejectUnauthorized: false
}
#Database
configDB = require('./config/database.js')(environment)
mongoose.connect(configDB.url,{auth:{authdb:configDB.authdb}}, (err)->
if (err)
console.log(err)
)
db = mongoose.connection
db.on('error', console.error.bind(console, 'connection error:'))
db.once('open', () ->
console.log "Database established"
)
#Express Application
app.use(morgan('dev'))# log every request to the console
app.use(bodyParser.urlencoded({ extended: true }))
app.use(bodyParser.json())
rootPath = __dirname + '/../../'
app.use('/bower_components', express.static(rootPath + 'bower_components'))
app.use('/partials', express.static(__dirname + '/../partials'))
# Routes
require('./node/routes.js')(app, db) # load our routes and pass in our app and fully configured passport
# Launch the application
https.createServer(sslOptions,app).listen(portHTTPS, () ->
console.log("Secure Express server listening on port #{portHTTPS}")
)
http.createServer(app).listen(portHTTP)
io = socket.listen(https)
#app.listen(portHTTP)
console.log('Unsecure Express server listening on port #{portHTTP} environment: #{environment}')
Angularjs
I installed the angular module:
https://github.com/btford/angular-socket-io
And added it to my index.coffee
angular.module "app", [lots of dependencies, 'btford.socket-io', 'myCodeService']
.config ($stateProvider, $urlRouterProvider) ->
...states...
.factory('mySocket', (socketFactory) ->
return socketFactory({
ioSocket: io.connect('https://localhost:3030/',{secure: true})
#ioSocket: io.connect('https://cdn.socket.io/socket.io-1.3.4.js',{secure: true})
})
)
I added the two script tags into my index.html
<script src="../bower_components/angular-socket-io/socket.js"></script>
<script src="http://localhost:3030/socket.io/socket.io.js"></script>
Gulp Setup
And I serve in gulp with nodemon and browsersync
gulp.task('serve',['watch'], function(cb){
var called = false;
return nodemon({
script: paths.tmp + '/serve/server.js',
watch: [paths.src + '/node', paths.src + '/config'],
ext: 'coffee',
tasks: ['templateCache', 'partials_tmp'],
env: { 'NODE_ENV': 'development' } ,
nodeArgs: ['--debug=9999']
})
....
function browserSyncInit(files, browser) {
browser = browser === undefined ? 'default' : browser;
browserSync.instance = browserSync.init(files, {
startPath: '/#/',
browser: browser,
proxy: "http://localhost:61361"
});
}
I get an empty response from socket.io and I don't see anything in my browser which bugs me to accept the certificate.
There is an https option for browsersync but I don't really know how to split the traffic/ or if this is done automatically in node.js.

io = socket.listen(https) is incorrect. You should be passing the server instance, not the https module:
// ...
var srv = https.createServer(sslOptions,app);
srv.listen(portHTTPS, () ->
console.log("Secure Express server listening on port #{portHTTPS}")
)
io = socket.listen(srv);
// ...
Also your <script> src that points to socket.io.js should be https and not http.

To split the routing in the front end this can be used:
.run ($rootScope, $window, authUserService) ->
#Listens for state changes and redirects User if he is not logged in
$rootScope.$on "$stateChangeStart", (event, toState, toParams, fromState, fromParams) ->
#After login send user to share
if toState.name is "payment" and !authUserService.isSecure()
event.preventDefault()
$window.location.href='https://localhost:3030/#/spenden'
true

Related

Why is my react router not passing my express route to server?

I tried to add social login to my (already working) react/express app, and I got it working in localhost. However, when I deploy it to production, the social login doesn't work. This is how it gets started
Google+
However, in production, it stays at https://sample.com/api/auth/google in my browser. So, it appears the react router is catching it first before express. How?
In localhost, it works because the proxy in package.js
"proxy": {
"/api": {
"target": "http://localhost:4000",
"ws": true
}
Now, how can I do this for production?
By the way, all my server APIs starts with '/api/...'. Also, in my react routes, I don't have a catch-all component.
UPDATE:
Here is my server.js
var express = require('express');
var session = require('express-session');
var bodyParser = require('body-parser');
var flash = require('connect-flash');
var cookieParser = require('cookie-parser');
var path = require('path');
var fs = require('fs');
var app = express();
var isSecured = true;
app.isDevMode = app.get('env') == 'development'
require('./server/config/log')(app)
var port = (process.env.PORT || app.isDevMode) ? 4000 : (isSecured ? 443 : 80);
app.set('port', port);
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json({ limit: '10mb' }));
app.use(flash()); // use connect-flash for flash messages stored in session
var server = require('http').createServer(app);
if (!app.isDevMode && isSecured) {
var options = {
ca: fs.readFileSync('ca_bundle.crt'),
key: fs.readFileSync('private.key'),
cert: fs.readFileSync('certificate.crt')
}
server = require('https').createServer(options, app);
}
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function () {
console.log('Connected to MongoDB');
var routes = require('./server/routes');
routes.init(app);
if (app.isDevMode) {
app.use(express.static(__dirname));
}
else {
app.use(express.static(path.join(__dirname, 'client/build')));
app.get('/*', function (req, res) {
res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
});
if (isSecured) {
require('http').createServer(function (req, res) {
res.writeHead(307, { "Location": "https://" + req.headers['host'] + req.url });
res.end();
}).listen(80);
}
}
server.listen(app.get('port'), function () {
console.log('Server listening on port ' + app.get('port'));
});
});
module.exports = app;
Here is my routes:
app.get('/api/auth/google', passport.authenticate('google', { scope: ['https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/userinfo.email'] }))
app.get('/api/callback/google', passport.authenticate('google', {successRedirect: '/?action=login&provider=google', failureRedirect: '/?action=login'}))
UPDATE:
Here is the morgan log. I added a number for each line for my reference. Line 4 started when I click the link to send '/api/auth/google', and finished at line 6.
1. GET /api/get/list?parm={%22kind%22:%22Prod%22,%22limit%22:5,%22createdOn%22:-1} 304 - - 22.959 ms
2. GET /images/logo.png 200 3432 - 17.410 ms
3. GET /service-worker.js 200 3097 - 3.398 ms
4. GET /static/js/main.cef8cdac.js 304 - - 5.180 ms
5. GET /images/two.png 304 - - 4.908 ms
6. GET /service-worker.js 200 3097 - 3.838 ms
So, basically, the request didn't come to express server. Actually, if I had a catch all route in react, I can see it's hitting there.
Here is the network log:

Express/Angular/Browsersync CORS - No 'Access-Control-Allow-Origin' 403 (forbidden)

I'm as junior as it gets when it comes to web development so please bear with me on this. I'm attempting to access data from the USDA Food Composition Databases NDB API - https://ndb.nal.usda.gov/ndb/doc/index
via an angular $http request from localhost. I'm using an express server and gulp/browsersync and am encountering two errors:
Failed to load resource: http://api.nal.usda.gov/ndb/list?format=json&It=f&max=20&sort=n&offset=15&api_key=API_KEY the server responded with a status of
and
XMLHttpRequest cannot load http://api.nal.usda.gov/ndb/list?format=json&It=f&max=20&sort=n&offset=15&api_key=API_KEY. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. The response had HTTP status code 403.
I've tried setting my CORS headers in browsersync as well as my express server but I simply cannot get around this issue. Here is how I've configured the relevant code for this:
The $http request
(function() {
'use strict';
angular
.module('commonSenseDietApp')
.factory('getFoodNamesOnly', getFoodNamesOnly);
/** #ngInject */
function getFoodNamesOnly($log, $http, devEnvironment) {
var service = {
ndbApiKey: devEnvironment.api_key,
ndbApiUrl: devEnvironment.api_url,
getFoodNamesList: getFoodNamesList
};
return service;
function getFoodNamesList(limit) {
if(!limit) {
limit = 30;
}
// For a list of all request parameters visit - https://ndb.nal.usda.gov/ndb/doc/apilist/API-LIST.md
return $http.get(service.ndbApiUrl + '/ndb/list?format=json&It=f' + '&max=' + limit + '&sort=n&offset=15&api_key=' + service.ndbApiKey)
.then(returnFoodNamesList)
.catch(getFoodNamesFail);
function returnFoodNamesList(response) {
return response.data;
}
function getFoodNamesFail(err) {
// return $log.error(err.data);
return console.log(err);
}
}
}
})();
My Browersync/Express Server
'use strict';
var express = require('express');
var cors = require('cors');
var bodyParser = require('body-parser');
var http = require('http')
// require database data modeling via mongoose
var mongoose = require('mongoose');
var session = require('express-session');
var cookieParser = require('cookie-parser');
var flash = require('connect-flash');
// Use express and set it up
var app = express();
app.use(cors());
app.use(function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', false);
next();
});
app.set('views', __dirname + '/views');
app.use(express.static(__dirname + '/'));
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json())
var path = require('path');
var gulp = require('gulp');
var conf = require('./conf');
var browserSync = require('browser-sync');
var browserSyncSpa = require('browser-sync-spa');
var util = require('util');
var proxyMiddleware = require('http-proxy-middleware');
function browserSyncInit(baseDir, browser) {
browser = browser === undefined ? 'default' : browser;
var routes = null;
if(baseDir === conf.paths.src || (util.isArray(baseDir) && baseDir.indexOf(conf.paths.src) !== -1)) {
routes = {
'/bower_components': 'bower_components'
};
}
var server = {
baseDir: baseDir,
routes: routes,
middleware: function (req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With, content-type');
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', false);
next();
}
};
browserSync.instance = browserSync.init({
startPath: '/',
cors: true,
browser: browser,
notify: true,
port: 8080,
server: server,
});
}
browserSync.use(browserSyncSpa({
selector: '[ng-app]'// Only needed for angular apps
}));
gulp.task('serve', ['setenvconstants','watch'], function () {
browserSyncInit([path.join(conf.paths.tmp, '/serve'), conf.paths.src]);
});
gulp.task('serve:dist', ['setenvconstants','build'], function () {
browserSyncInit(conf.paths.dist);
});
gulp.task('serve:e2e', ['inject'], function () {
browserSyncInit([conf.paths.tmp + '/serve', conf.paths.src], []);
});
gulp.task('serve:e2e-dist', ['build'], function () {
browserSyncInit(conf.paths.dist, []);
});
My Angular .config
(function() {
'use strict';
angular
.module('commonSenseDietApp')
.config(config);
/** #ngInject */
function config($logProvider, $httpProvider) {
// Enable log
$logProvider.debugEnabled(true);
// For Access-Control-Allow-Origin and Set-Cookie header
$httpProvider.defaults.withCredentials = false;
}
})();
I'm using gulp and browsersync to serve locally over localhost:8080 but no matter what I try (setting headers in express, setting headers in browsersync, setting browsersync cors option to 'true', setting browsersync https options to true, switching my 'Access-Control-Allow-Origin' to '*' or to "localhost:8080") none of it seems to work. I suspect the NDB API has forbidden my access but I can't get in contact with them to ask about it. Their suggested contact us link - "https://api.data.gov/contact/" leads to nothing.
Any suggestions or tips on this would be greatly appreciated. I'm a total noob here in terms of web development as well as posting to Stack Overflow so please let me know if my question doesn't make any sense and needs further clarification.
I was fortunate enough to stumble upon a solution although I don't quite understand what's happening and would certainly like to.
Turns out I was attempting to run a local server while using my VPN (https://www.privateinternetaccess.com/) which for some reasons was causing my CORS issue. Once I turned the VPN off and began using my local network I was able to run my server and make my requests without a hitch.
I'm not sure why using my VPN would cause a 403 but my guess would be that the API I was attempting to access simply does not allow request from a remote network like the one I was using. I will look into it more and update my answer shortly.
Try serving from https and not http when making your API calls. Being that you are fetching an https location, but issuing an http request, you will get CORS issue.
Look into: https://nodejs.org/api/https.html

Catch all routes loading blank page Angular NodeJs

I was working on Angular app with routing (NodeJs as backend). Routing through pages works fine but when I try to reload page it gives 'cannot load path /home'. I browsed through and got to few solutions like THIS.
My code is
app.get('*', function (req, res) {
res.sendFile('mypath/index.html');
});
But this loads up blank page. Is there any way I can solve this issue?
This us how my server.js looks like
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var port = process.env.PORT || 8080; // set our port
var staticdir = process.env.NODE_ENV === 'production' ? 'dist.prod' : 'dist.dev'; // get static files dir
// get all data/stuff of the body (POST) parameters
app.use(bodyParser.json()); // parse application/json
//app.use(bodyParser.json({ type: 'application/vnd.api+json' })); // parse application/vnd.api+json as json
//app.use(bodyParser.urlencoded({ extended: true })); // parse application/x-www-form-urlencoded
app.use(methodOverride('X-HTTP-Method-Override')); // override with the X-HTTP-Method-Override header in the request. simulate DELETE/PUT
app.use(express.static(__dirname + '/' + staticdir)); // set the static files location /public/img will be /img for users
// routes ==================================================
app.set('views', __dirname + '/app');
app.set('view engine', 'html');
require('./devServer/routes')(app); // configure our routes
// start app ===============================================
app.listen(port); // startup our app at http://localhost:8080
console.log('Starting sever on port ' + port); // shoutout to the user
exports = module.exports = app; // expose app
app.get('/', function (req, res) {
res.render('index', {
page: 'index'
}
});
then out this into your config,
app.set('views', 'directory where index.html is');

Why Angular says that cross origin request occurs when there's actually no any?

I am trying to serve Angular application using ExpressJS. Here is my index.js:
var express = require('express');
var path = require('path');
var app = express();
app.set('port', (process.env.PORT || 8000));
app.use(express.static(__dirname));
app.use(express.static(path.join(__dirname + 'fake_data')));
// views is directory for all template files
app.set('views', __dirname + '/app/pages');
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.get('/', function(request, response) {
response.render('index');
});
app.listen(app.get('port'), function() {
console.log('Node app is running on port', app.get('port'));
});
In my angular app there is also a constant containing API server address:
(function () {
angular.module('Bankbox')
.constant('webConfig', {
API_SERVER: ''
});
})();
It is been set during run phase:
(function () {
angular.module('Bankbox')
.config(bankboxConfig)
.run(runConfig);
function runConfig($location, webConfig){
var port = ":" + $location.port() + "/";
webConfig.API_SERVER = $location.host();
if (port){
webConfig.API_SERVER += port;
}
}
.....
Finally when i execute node index.js, and trying to load 'localhost:8000' in the browser i get an error:
XMLHttpRequest cannot load localhost:8000/fake_data/my-deals.json. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.
The GET request is in a factory and it looks like:
function getMyDeals() {
return $http.get(webConfig.API_SERVER + 'fake_data/my-deals.json')
.then($http.getDataFromResult);
}
Why this happens? I assumed that localhost:8000 shouldn't think of itself as an another origin.

How to store variable for each user session in MEAN.JS?

I am using MEAN.JS and I want to store some parameter for each user during his session (from the opening of the website until the closing of the browser without login), and I want this parameter to be accessible from the client side by AngularJS and from the server side in the ExpressJS route handlers.
Please forgive my poor English
Use an express session and set up routes for angular to query:
var express = require('express'),
logger = require('morgan'),
bodyParser = require('body-parser'),
cookieParser = require('cookie-parser'),
expressSession = require('express-session');
var app = express();
app.use(logger("tiny"));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(cookieParser('yousecretcode'));
app.use(expressSession({secret: 'yourothersecretcode', saveUninitialized: true, resave: true}));
var router = express.Router();
router.get('/session/set/:value', function(req, res) {
req.session.mySession = req.params.value;
res.send('session write success');
});
app.get('/session/get/', function(req, res) {
if(req.session.mySession)
res.send('the session value is: ' + req.session.mySession);
else
res.send("no session value");
});
app.use('/', router);
var server = app.listen(8097, function() {
console.log('BASIC SESSION server is listening on port %d', server.address().port);
});
Reference: http://blog.arisetyo.com/?p=492
There is an express module called redis that offers a more advanced solution as the aforementioned reference highlights. Refer to meanjs documentation if you require reference to query the routes or use the Yeoman generator(recommended).
I hope this helps you.

Resources