diff --git a/.editorconfig b/.editorconfig index 61617beec8..636ceea4c0 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,9 +14,7 @@ insert_final_newline = true # Standard at: https://github.com/felixge/node-style-guide [**.js, **.json] trim_trailing_whitespace = true -indent_style = space -indent_size = 2 -max_line_length = 80 +indent_style = tab quote_type = single curly_bracket_next_line = false spaces_around_operators = true @@ -24,26 +22,15 @@ space_after_control_statements = true space_after_anonymous_functions = false spaces_in_brackets = false -# https://github.com/jedmao/codepainter -[node_modules/**.js] -codepaint = false - # No Standard. Please document a standard if different from .js [**.yml, **.html, **.css] trim_trailing_whitespace = true -indent_style = space -indent_size = 2 +indent_style = tab # No standard. Please document a standard if different from .js [**.md] -indent_style = space - -# Standard at: -[**.py] -indent_style = space -indent_size = 4 +indent_style = tab # Standard at: [Makefile] -indent_style = tab -indent_size = 8 +indent_style = tab \ No newline at end of file diff --git a/README.md b/README.md index 68ab3dafe9..bf0b133e0f 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,14 @@ $ $ docker run -p 3000:3000 -p 35729:35729 -v /Users/mdl/workspace/mean-stack/mean/public:/home/mean/public -v /Users/mdl/workspace/mean-stack/mean/app:/home/mean/app --link db:db_1 mean ``` +## Running in a secure environment +To run your application in a secure manner you'll need to use OpenSSL and generate a set of self-signed certificates. Unix-based users can use the following commnad: +``` +$ sh generate-ssl-certs.sh +``` +Windows users can follow instructions found [here](http://www.websense.com/support/article/kbarticle/How-to-use-OpenSSL-and-Microsoft-Certification-Authority) +To generate the key and certificate and place them in the [config/sslcerts](config/sslcerts) folder. + ## Getting Started With MEAN.JS You have your application running but there are a lot of stuff to understand, we recommend you'll go over the [Official Documentation](http://meanjs.org/docs.html). In the docs we'll try to explain both general concepts of MEAN components and give you some guidelines to help you improve your development process. We tried covering as many aspects as possible, and will keep update it by your request, you can also help us develop the documentation better by checking out the *gh-pages* branch of this repository. diff --git a/app/controllers/errors.server.controller.js b/app/controllers/errors.server.controller.js index 935a9299d4..41078b4d3a 100644 --- a/app/controllers/errors.server.controller.js +++ b/app/controllers/errors.server.controller.js @@ -10,7 +10,7 @@ var getUniqueErrorMessage = function(err) { var fieldName = err.err.substring(err.err.lastIndexOf('.$') + 2, err.err.lastIndexOf('_1')); output = fieldName.charAt(0).toUpperCase() + fieldName.slice(1) + ' already exists'; - } catch(ex) { + } catch (ex) { output = 'Unique field already exists'; } @@ -22,7 +22,7 @@ var getUniqueErrorMessage = function(err) { */ exports.getErrorMessage = function(err) { var message = ''; - + if (err.code) { switch (err.code) { case 11000: @@ -39,4 +39,4 @@ exports.getErrorMessage = function(err) { } return message; -}; +}; \ No newline at end of file diff --git a/app/controllers/users/users.password.server.controller.js b/app/controllers/users/users.password.server.controller.js index d857cd13f6..1d4ae65e8a 100644 --- a/app/controllers/users/users.password.server.controller.js +++ b/app/controllers/users/users.password.server.controller.js @@ -174,7 +174,7 @@ exports.reset = function(req, res, next) { subject: 'Your password has been changed', html: emailHTML }; - + smtpTransport.sendMail(mailOptions, function(err) { done(err, 'done'); }); @@ -242,4 +242,4 @@ exports.changePassword = function(req, res) { message: 'User is not signed in' }); } -}; +}; \ No newline at end of file diff --git a/app/models/user.server.model.js b/app/models/user.server.model.js index 76ff071ba2..9370da01c6 100755 --- a/app/models/user.server.model.js +++ b/app/models/user.server.model.js @@ -86,9 +86,9 @@ var UserSchema = new Schema({ resetPasswordToken: { type: String }, - resetPasswordExpires: { - type: Date - } + resetPasswordExpires: { + type: Date + } }); /** diff --git a/app/routes/users.server.routes.js b/app/routes/users.server.routes.js index bd0a361fed..3120e9abb6 100644 --- a/app/routes/users.server.routes.js +++ b/app/routes/users.server.routes.js @@ -47,11 +47,11 @@ module.exports = function(app) { // Setting the linkedin oauth routes app.route('/auth/linkedin').get(passport.authenticate('linkedin')); app.route('/auth/linkedin/callback').get(users.oauthCallback('linkedin')); - + // Setting the github oauth routes app.route('/auth/github').get(passport.authenticate('github')); app.route('/auth/github/callback').get(users.oauthCallback('github')); // Finish by binding the user middleware app.param('userId', users.userByID); -}; +}; \ No newline at end of file diff --git a/app/tests/article.server.routes.test.js b/app/tests/article.server.routes.test.js index 160f19e0ed..2576095ae1 100644 --- a/app/tests/article.server.routes.test.js +++ b/app/tests/article.server.routes.test.js @@ -1,219 +1,269 @@ 'use strict'; var should = require('should'), - request = require('supertest'), - app = require('../../server'), - mongoose = require('mongoose'), - User = mongoose.model('User'), - Article = mongoose.model('Article'), - // note: the agent allows us to preserve a session and cookies for the logged in user - agent = request.agent(app); - + request = require('supertest'), + app = require('../../server'), + mongoose = require('mongoose'), + User = mongoose.model('User'), + Article = mongoose.model('Article'), + agent = request.agent(app); /** * Globals */ -var user, article; - -describe('Article CRUD tests', function () { - - beforeEach(function(done) { - // saves a user to the test db. - user = new User({ - firstName: 'Full', - lastName: 'Name', - displayName: 'Full Name', - email: 'test@test.com', - username: 'username', - password: 'password', - provider: 'local' - }); - user.save(); - - article = new Article({ - title: 'Article Title', - content: 'Article Content', - user: user - }); - - done(); - }); - - // ------------ CREATE (SAVE) operations ------------ - it('should be able to save an article if logged in', function (done) { - agent - .post('/auth/signin') - .send(user) - .end(function (err, res){ - var userId = res.body._id; - agent - .post('/articles') - .send(article) - .expect(200) - .end(function (err, res) { - agent - .get('/articles') - .end(function(error, res) { - (res.body[0].user._id).should.equal(userId); - (res.body[0].title).should.match('Article Title'); - done(); - }); - }); - }); - }); - - - it('should not be able to save an article if not logged in', function (done) { - agent - .post('/articles') - .send(article) - .expect(200) - .end(function (err, res) { - should.exist(err); - (res.status).should.equal(401); - (res.unauthorized).should.equal(true); - done(); - }); - }); - - it('should not be able to save an article if no title is provided', function (done) { - article.title = ''; - agent - .post('/auth/signin') - .send(user) - .end(function (err, res){ - agent - .post('/articles') - .send(article) - .expect(200) - .end(function (err, res) { - should.exist(err); - (res.body.message).should.match('Title cannot be blank'); - done(); - }); - }); - }); - - - // ------------ PUT (UPDATE) operations ------------ - it('should be able to update an article if signed in', function(done){ - agent - .post('/auth/signin') - .send(user) - .end(function (err, res){ - var userId = res.body._id; - agent - .post('/articles') - .send(article) - .expect(200) - .end(function (err, res) { - agent - .get('/articles') - .end(function(error, res) { - (res.body[0].user._id).should.equal(userId); - (res.body[0].title).should.match('Article Title'); - var article_Id = res.body[0]._id; - article.title = 'WHY YOU GOTTA BE SO MEAN?'; - agent - .put('/articles/' + article_Id) - .send(article) - .end(function (err, res) { - (res.body._id).should.equal(article_Id); - (res.body.title).should.match('WHY YOU GOTTA BE SO MEAN?'); - done(); - }); - }); - }); - }); - }); - - // ------------ READ operations ------------ - it('should be able to get a list of articles if not signed in', function (done) { - // Adding 10 articles to the db - var numArticles = 10; - while (numArticles--) { - var article = new Article({ - title: numArticles + ' Another Article Title', - content: numArticles + ' Another Article Content', - user: user - }); - article.save(); - } - - // note there is no need to use the supertest agent here as we do not need to be signed in - request(app) - .get('/articles') - .end(function (req, res) { - (res.body[0].title).should.match('0 Another Article Title'); - done(); - }); - - }); - - - it('should be able to get a single article if not signed in', function (done) { - var article = new Article({ - title: 'Another Article Title', - content: 'Another Article Content', - user: user - }); - article.save(); - - request(app) - .get('/articles/' + article._id) - .end(function (req, res) { - (res.body.title).should.match('Another Article Title'); - done(); - }); - - }); - - // ------------ DELETE operations ------------ - it('should be able to delete an article if signed in', function (done) { - var article = new Article({ - title: 'Another Article Title', - content: 'Another Article Content', - user: user - }); - article.save(); - - agent - .post('/auth/signin') - .send(user) - .end(function (err, res) { - (err === null).should.equal(true); - agent - .delete('/articles/' + article._id) - .end(function (err, res) { - (res.req.method).should.match('DELETE'); - (res.body.title).should.match('Another Article Title'); - done(); - }); - }); - }); - - it('should not be able to delete an article if not signed in', function (done) { - var article = new Article({ - title: 'Another Article Title', - content: 'Another Article Content', - user: user - }); - article.save(); - - request(app) - .delete('/articles/' + article._id) - .end(function (err, res) { - (res.req.method).should.match('DELETE'); - (res.status).should.equal(401); - (res.unauthorized).should.equal(true); - done(); - }); - }); - - afterEach(function(done) { - User.remove().exec(); - Article.remove().exec(); - done(); - }); +var credentials, user, article; + +/** + * Article routes tests + */ +describe('Article CRUD tests', function() { + beforeEach(function(done) { + // Create user credentials + credentials = { + username: 'username', + password: 'password' + }; + + // Create a new user + user = new User({ + firstName: 'Full', + lastName: 'Name', + displayName: 'Full Name', + email: 'test@test.com', + username: credentials.username, + password: credentials.password, + provider: 'local' + }); + + // Save a user to the test db and create new article + user.save(function() { + article = { + title: 'Article Title', + content: 'Article Content' + }; + + done(); + }); + }); + + it('should be able to save an article if logged in', function(done) { + agent.post('/auth/signin') + .send(credentials) + .expect(200) + .end(function(signinErr, signinRes) { + // Handle signin error + if (signinErr) done(signinErr); + + // Get the userId + var userId = user.id; + + // Save a new article + agent.post('/articles') + .send(article) + .expect(200) + .end(function(articleSaveErr, articleSaveRes) { + // Handle article save error + if (articleSaveErr) done(articleSaveErr); + + // Get a list of articles + agent.get('/articles') + .end(function(articlesGetErr, articlesGetRes) { + // Handle article save error + if (articlesGetErr) done(articlesGetErr); + + // Get articles list + var articles = articlesGetRes.body; + + // Set assertions + (articles[0].user._id).should.equal(userId); + (articles[0].title).should.match('Article Title'); + + // Call the assertion callback + done(); + }); + }); + }); + }); + + it('should not be able to save an article if not logged in', function(done) { + agent.post('/articles') + .send(article) + .expect(401) + .end(function(articleSaveErr, articleSaveRes) { + // Call the assertion callback + done(articleSaveErr); + }); + }); + + it('should not be able to save an article if no title is provided', function(done) { + // Invalidate title field + article.title = ''; + + agent.post('/auth/signin') + .send(credentials) + .expect(200) + .end(function(signinErr, signinRes) { + // Handle signin error + if (signinErr) done(signinErr); + + // Get the userId + var userId = user.id; + + // Save a new article + agent.post('/articles') + .send(article) + .expect(400) + .end(function(articleSaveErr, articleSaveRes) { + // Set message assertion + (articleSaveRes.body.message).should.match('Title cannot be blank'); + + // Handle article save error + done(articleSaveErr); + }); + }); + }); + + it('should be able to update an article if signed in', function(done) { + agent.post('/auth/signin') + .send(credentials) + .expect(200) + .end(function(signinErr, signinRes) { + // Handle signin error + if (signinErr) done(signinErr); + + // Get the userId + var userId = user.id; + + // Save a new article + agent.post('/articles') + .send(article) + .expect(200) + .end(function(articleSaveErr, articleSaveRes) { + // Handle article save error + if (articleSaveErr) done(articleSaveErr); + + // Update article title + article.title = 'WHY YOU GOTTA BE SO MEAN?'; + + // Update an existing article + agent.put('/articles/' + articleSaveRes.body._id) + .send(article) + .expect(200) + .end(function(articleUpdateErr, articleUpdateRes) { + // Handle article update error + if (articleUpdateErr) done(articleUpdateErr); + + // Set assertions + (articleUpdateRes.body._id).should.equal(articleSaveRes.body._id); + (articleUpdateRes.body.title).should.match('WHY YOU GOTTA BE SO MEAN?'); + + // Call the assertion callback + done(); + }); + }); + }); + }); + + it('should be able to get a list of articles if not signed in', function(done) { + // Create new article model instance + var articleObj = new Article(article); + + // Save the article + articleObj.save(function() { + // Request articles + request(app).get('/articles') + .end(function(req, res) { + // Set assertion + res.body.should.be.an.Array.with.lengthOf(1); + + // Call the assertion callback + done(); + }); + + }); + }); + + + it('should be able to get a single article if not signed in', function(done) { + // Create new article model instance + var articleObj = new Article(article); + + // Save the article + articleObj.save(function() { + request(app).get('/articles/' + articleObj._id) + .end(function(req, res) { + // Set assertion + res.body.should.be.an.Object.with.property('title', article.title); + + // Call the assertion callback + done(); + }); + }); + }); + + it('should be able to delete an article if signed in', function(done) { + agent.post('/auth/signin') + .send(credentials) + .expect(200) + .end(function(signinErr, signinRes) { + // Handle signin error + if (signinErr) done(signinErr); + + // Get the userId + var userId = user.id; + + // Save a new article + agent.post('/articles') + .send(article) + .expect(200) + .end(function(articleSaveErr, articleSaveRes) { + // Handle article save error + if (articleSaveErr) done(articleSaveErr); + + // Delete an existing article + agent.delete('/articles/' + articleSaveRes.body._id) + .send(article) + .expect(200) + .end(function(articleDeleteErr, articleDeleteRes) { + // Handle article error error + if (articleDeleteErr) done(articleDeleteErr); + + // Set assertions + (articleDeleteRes.body._id).should.equal(articleSaveRes.body._id); + + // Call the assertion callback + done(); + }); + }); + }); + }); + + it('should not be able to delete an article if not signed in', function(done) { + // Set article user + article.user = user; + + // Create new article model instance + var articleObj = new Article(article); + + // Save the article + articleObj.save(function() { + // Try deleting article + request(app).delete('/articles/' + articleObj._id) + .expect(401) + .end(function(articleDeleteErr, articleDeleteRes) { + // Set message assertion + (articleDeleteRes.body.message).should.match('User is not logged in'); + + // Handle article error error + done(articleDeleteErr); + }); + + }); + }); + afterEach(function(done) { + User.remove().exec(); + Article.remove().exec(); + done(); + }); }); \ No newline at end of file diff --git a/app/views/layout.server.view.html b/app/views/layout.server.view.html index b831bf2853..9f47509e80 100644 --- a/app/views/layout.server.view.html +++ b/app/views/layout.server.view.html @@ -35,8 +35,7 @@ - {% for cssFile in cssFiles %} - {% endfor %} + {% for cssFile in cssFiles %}{% endfor %} - {% for jsFile in jsFiles %} - {% endfor %} + {% for jsFile in jsFiles %}{% endfor %} {% if process.env.NODE_ENV === 'development' %} - {% endif %}
Dear {{name}},
@@ -12,5 +10,4 @@The {{appName}} Support Team
diff --git a/app/views/templates/reset-password-confirm-email.server.view.html b/app/views/templates/reset-password-confirm-email.server.view.html index eec61a672c..626ddc3fa4 100644 --- a/app/views/templates/reset-password-confirm-email.server.view.html +++ b/app/views/templates/reset-password-confirm-email.server.view.html @@ -1,9 +1,7 @@ -
-
-