Starting bringing over a better comment scheme for methods (see helpers/api.js), addedemail confirmation sending, proper logging, fixed registration

Server now sends confirmation emails to the provided email address. The values can not yet be validated, but they are stored so validation can be added at any time. Added Winston for event logging. Winston has a log level system that merges certain log types into the same file. Maybe we should use a custom logger solution? Registration now works (was not working for me), with added reCaptcha protection, password validation, and the storing of usernames/email validation values. Also changed the PID to a number, cuz it's a number
This commit is contained in:
RedDucks
2018-11-28 14:49:31 -05:00
parent 5703e42de2
commit 1486511463
14 changed files with 465 additions and 69 deletions

View File

@@ -1,2 +1,2 @@
# web javascript causes a lot of eslint warnings
assets/js/*.js
assets/js

View File

@@ -13,6 +13,13 @@
"secrets": {
"session": "session secret here"
},
"email": {
"service": "gmail",
"auth": {
"user": "example@email.com",
"pass": "password"
}
},
"recaptcha": {
"siteKey": "abcd",
"secretKey": "1234"

View File

@@ -5,10 +5,14 @@ common api returns
*/
// use for any api return. it has basic layout used for every return.
/**
* Send generic API response
* @param {ServerResponse} response An express ServerResponse response
* @param {Object} data Response data
* @param {Array} errors Request errors
*/
function sendReturn(response, data, errors) {
response.status(200).json(
// combine 2 objects
return response.status(data.code || 200).json(
Object.assign({
code: 200,
success: true,
@@ -17,44 +21,45 @@ function sendReturn(response, data, errors) {
);
}
// use if api endpoint doesnt exist
/**
* Send API 404
* @param {ServerResponse} response An express ServerResponse response
*/
function sendApi404(response) {
response.status(404).json({
code: 404,
errors: [
'Endpoint not in use'
]
});
return sendApiError(response, 404, [
'Endpoint not in use'
]);
}
// use if not logged in and is required (handled with middleware)
/**
* Send user not authenticated error
* @param {ServerResponse} response An express ServerResponse response
*/
function sendApiAuthError(response) {
response.status(401).json({
code: 401,
errors: [
'Not authenticated'
]
});
return sendApiError(response, 401, [
'Not authenticated'
]);
}
// use for completely broken requests
/**
* Send a generic API error
* @param {ServerResponse} response An express ServerResponse response
*/
function sendApiGenericError(response) {
response.status(400).json({
code: 400,
success: false,
errors: [
'Bad request'
]
});
return sendApiError(response, 400, [
'Bad request'
]);
}
// use for any api not successfull
/**
* Send an API error
* @param {ServerResponse} response An express ServerResponse response
*/
function sendApiError(response, code, errors) {
response.status(code).json({
return sendReturn(response, {
code,
success: false,
errors
});
success: false
}, errors);
}
module.exports = {

View File

@@ -6,6 +6,7 @@ small commonly used utilities
*/
const fs = require('fs-extra');
const logger = require('winston');
// shows 404 template. takes express response object
function send404(res) {
@@ -46,7 +47,7 @@ function getLocale(region, language) {
return require(path);
}
console.warn(`Could not find locale ${region}_${language}! Loading default`);
logger.log('warn', `Could not find locale ${region}_${language}! Loading default`);
return getDefaultLocale();
}
@@ -56,10 +57,15 @@ function getDefaultLocale(locale='default') {
return require(`${__dirname}/../locales/${locale}.json`);
}
function generateRandomInt(length = 4) {
return Math.floor(Math.pow(10, length-1) + Math.random() * 9 * Math.pow(10, length-1));
}
module.exports = {
send404,
templateReadyUser,
getLocales,
getLocale,
getDefaultLocale
getDefaultLocale,
generateRandomInt
};

41
logger.js Normal file
View File

@@ -0,0 +1,41 @@
const winston = require('winston');
const logger = winston.createLogger({
level: 'verbose',
format: winston.format.combine(
winston.format.timestamp(),
winston.format.printf(log => {
return `${log.timestamp} | ${log.level}: ${log.message}`;
})
),
transports: [
new winston.transports.Console({ colorize: true }),
new winston.transports.File({
colorize: false,
json: false,
filename: `${__dirname}/logs/events.log`
}),
new winston.transports.File({
colorize: false,
json: false,
filename: `${__dirname}/logs/error.log`,
level: 'error'
}),
new winston.transports.File({
colorize: false,
json: false,
filename: `${__dirname}/logs/warn.log`,
level: 'warn'
}),
new winston.transports.File({
colorize: false,
json: false,
filename: `${__dirname}/logs/debug.log`,
level: 'debug'
})
]
});
winston.add(logger);
module.exports = winston;

31
mailer.js Normal file
View File

@@ -0,0 +1,31 @@
const nodemailer = require('nodemailer');
const config = require('./config');
const transporter = nodemailer.createTransport(config.email);
/**
* Sends an email with the specified subject and message to an email address
* @param {String} email the destination email address
* @param {String} subject The Subject of the email
* @param {String} message The body of the email
*/
function send(email, subject = 'No email subject provided', message = 'No email body provided') {
const options = {
from: config.email.address,
to: email,
subject: subject,
html: message
};
transporter.sendMail(options, (error, info) => {
if (error) {
console.warn(error);
} else {
console.log(info);
}
});
}
module.exports = {
send: send
};

View File

@@ -8,7 +8,9 @@ file containing the model for pretendo network id's
// imports
const mongoose = require('mongoose');
const uniqueValidator = require('mongoose-unique-validator');
const randtoken = require('rand-token');
const bcrypt = require('bcrypt');
const utilHelper = require('../helpers/util');
// admin user database layout
const PNIDSchema = new mongoose.Schema({
@@ -23,6 +25,14 @@ const PNIDSchema = new mongoose.Schema({
type: Boolean,
default: false
},
email_validation_code: {
type: Number,
required: [true, 'Email validation code is required.'],
},
email_validation_token: {
type: String,
required: [true, 'Email validation token is required.'],
},
// non hashed, gets hashed at save
password: {
type: String,
@@ -32,10 +42,15 @@ const PNIDSchema = new mongoose.Schema({
trim: true
},
pnid: {
key: {
type: String // not sure what this should be
},
pid: {
type: Number,
unique: true
},
username: {
type: String,
unique: true
},
username_lower: {
type: String,
unique: true
}
@@ -79,7 +94,7 @@ PNIDSchema.statics.hashPasswordPrimary = function(password, pid) {
const buff1 = require('python-struct').pack('<I', pid);
const buff2 = Buffer.from(password).toString('ascii');
const unpacked = new Buffer(bufferToHex(buff1) + '\x02eCF' + buff2, 'ascii');
const unpacked = Buffer.from(bufferToHex(buff1) + '\x02eCF' + buff2, 'ascii');
const hashed = require('crypto').createHash('sha256').update(unpacked).digest().toString('hex');
return hashed;
@@ -96,18 +111,44 @@ function bufferToHex(buff) {
return result;
}
PNIDSchema.statics.generatePID = async function() {
PNIDSchema.statics.generatePID = async function() {
// Quick, dirty fix for PIDs
const pid = Math.floor(Math.random() * (4294967295 - 1000000000) + 1000000000);
const does_pid_inuse = await PNIDModel.findOne({
const pid_inuse = await PNIDModel.findOne({
'pnid.pid': pid
});
if (does_pid_inuse) {
return '' + await PNIDModel.generatePID();
if (pid_inuse) {
return await PNIDModel.generatePID();
}
return '' + pid;
return pid;
};
PNIDSchema.statics.generateEmailValidationCode = async function() {
const code = utilHelper.generateRandomInt(6);
const code_inuse = await PNIDModel.findOne({
'email_validation_code': code
});
if (code_inuse) {
return await PNIDModel.generateEmailValidationCode();
}
return code;
};
PNIDSchema.statics.generateEmailValidationToken = async function() {
const token = randtoken.generate(32);
const token_inuse = await PNIDModel.findOne({
'email_validation_token': token
});
if (token_inuse) {
return await PNIDModel.generateEmailValidationToken();
}
return token;
};
const PNIDModel = mongoose.model('pnid', PNIDSchema);

235
package-lock.json generated
View File

@@ -993,11 +993,19 @@
"object-visit": "^1.0.0"
}
},
"color": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz",
"integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==",
"requires": {
"color-convert": "^1.9.1",
"color-string": "^1.5.2"
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": {
"color-name": "1.1.3"
}
@@ -1005,14 +1013,36 @@
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"color-string": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz",
"integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==",
"requires": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
}
},
"colornames": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz",
"integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y="
},
"colors": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.2.0.tgz",
"integrity": "sha512-lweugcX5nailCqZBttArTojZZpHGWhmFJX78KJHlxwhM8tLAy5QCgRgRxrubrksdvA+2Y3inWG5TToyyjL82BQ=="
},
"colorspace": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.1.tgz",
"integrity": "sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw==",
"requires": {
"color": "3.0.x",
"text-hex": "1.0.x"
}
},
"component-emitter": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
@@ -1240,6 +1270,16 @@
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"diagnostics": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz",
"integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==",
"requires": {
"colorspace": "1.1.x",
"enabled": "1.0.x",
"kuler": "1.0.x"
}
},
"doctrine": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
@@ -1269,11 +1309,24 @@
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"enabled": {
"version": "1.0.2",
"resolved": "http://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz",
"integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=",
"requires": {
"env-variable": "0.0.x"
}
},
"encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
"env-variable": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz",
"integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA=="
},
"es6-promise": {
"version": "3.2.1",
"resolved": "http://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz",
@@ -1739,6 +1792,16 @@
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
"dev": true
},
"fast-safe-stringify": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz",
"integrity": "sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg=="
},
"fecha": {
"version": "2.3.3",
"resolved": "http://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz",
"integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg=="
},
"figures": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz",
@@ -2680,6 +2743,11 @@
"kind-of": "^3.0.2"
}
},
"is-arrayish": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
},
"is-binary-path": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
@@ -2921,6 +2989,14 @@
"is-buffer": "^1.1.5"
}
},
"kuler": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz",
"integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==",
"requires": {
"colornames": "^1.1.1"
}
},
"latest-version": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz",
@@ -2984,6 +3060,30 @@
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
},
"logform": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/logform/-/logform-1.10.0.tgz",
"integrity": "sha512-em5ojIhU18fIMOw/333mD+ZLE2fis0EzXl1ZwHx4iQzmpQi6odNiY/t+ITNr33JZhT9/KEaH+UPIipr6a9EjWg==",
"requires": {
"colors": "^1.2.1",
"fast-safe-stringify": "^2.0.4",
"fecha": "^2.3.3",
"ms": "^2.1.1",
"triple-beam": "^1.2.0"
},
"dependencies": {
"colors": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.3.2.tgz",
"integrity": "sha512-rhP0JSBGYvpcNQj4s5AdShMeE5ahMop96cTeDl/v9qQQm2fYClE2QXZRi8wLzc+GmXSxdIqqbOIAhyObEXDbfQ=="
},
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
}
}
},
"long": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz",
@@ -3370,6 +3470,11 @@
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
"dev": true
},
"nodemailer": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.7.0.tgz",
"integrity": "sha512-IludxDypFpYw4xpzKdMAozBSkzKHmNBvGanUREjJItgJ2NYcK/s8+PggVhj7c2yGFQykKsnnmv1+Aqo0ZfjHmw=="
},
"nodemon": {
"version": "1.18.6",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.18.6.tgz",
@@ -3519,6 +3624,11 @@
"wrappy": "1"
}
},
"one-time": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz",
"integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4="
},
"onetime": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz",
@@ -3786,6 +3896,11 @@
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
"integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
},
"rand-token": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/rand-token/-/rand-token-0.4.0.tgz",
"integrity": "sha512-FLNNsir2R+XY8LKsZ+8u/w0qZ4sGit7cpNdznsI77cAVob6UlVPueDKRyjJ3W1Q6FJLgAVH98JvlqqpSaL7NEQ=="
},
"random-bytes": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
@@ -4178,6 +4293,14 @@
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
},
"simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
"requires": {
"is-arrayish": "^0.3.1"
}
},
"slice-ansi": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz",
@@ -4351,6 +4474,11 @@
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true
},
"stack-trace": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
"integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA="
},
"static-extend": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
@@ -4445,6 +4573,11 @@
"execa": "^0.7.0"
}
},
"text-hex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="
},
"text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -4512,6 +4645,11 @@
"nopt": "~1.0.10"
}
},
"triple-beam": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
"integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw=="
},
"tslib": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
@@ -4775,6 +4913,97 @@
"integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
"optional": true
},
"winston": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/winston/-/winston-3.1.0.tgz",
"integrity": "sha512-FsQfEE+8YIEeuZEYhHDk5cILo1HOcWkGwvoidLrDgPog0r4bser1lEIOco2dN9zpDJ1M88hfDgZvxe5z4xNcwg==",
"requires": {
"async": "^2.6.0",
"diagnostics": "^1.1.1",
"is-stream": "^1.1.0",
"logform": "^1.9.1",
"one-time": "0.0.4",
"readable-stream": "^2.3.6",
"stack-trace": "0.0.x",
"triple-beam": "^1.3.0",
"winston-transport": "^4.2.0"
},
"dependencies": {
"async": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz",
"integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==",
"requires": {
"lodash": "^4.17.10"
}
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"string_decoder": {
"version": "1.1.1",
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
}
}
},
"winston-transport": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.2.0.tgz",
"integrity": "sha512-0R1bvFqxSlK/ZKTH86nymOuKv/cT1PQBMuDdA7k7f0S9fM44dNH6bXnuxwXPrN8lefJgtZq08BKdyZ0DZIy/rg==",
"requires": {
"readable-stream": "^2.3.6",
"triple-beam": "^1.2.0"
},
"dependencies": {
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"string_decoder": {
"version": "1.1.1",
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
}
}
},
"wordwrap": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",

View File

@@ -27,10 +27,13 @@
"mongoose": "^5.3.2",
"mongoose-unique-validator": "^2.0.2",
"morgan": "^1.9.1",
"nodemailer": "^4.7.0",
"passport": "^0.4.0",
"passport-local": "^1.0.0",
"python-struct": "^1.0.6",
"showdown": "^1.8.6"
"rand-token": "^0.4.0",
"showdown": "^1.8.6",
"winston": "^3.1.0"
},
"devDependencies": {
"eslint": "^5.6.1",

View File

@@ -6,6 +6,7 @@ file for handling routes regarding blog posts.
*/
// imports
const logger = require('winston');
const router = require('express').Router();
const moment = require('moment');
const apiHelper = require('../helpers/api');
@@ -25,7 +26,7 @@ router.get('/news/:date/:title', (request, response) => {
blogPostModel.getPost(moment(date), title_lower, (error, post) => {
// error exists or no post exists with the date and name
if (error || !post) {
console.warn(`'error: ${error} and post: ${post}`);
logger.log('warn', `error: ${error} and post: ${post}`);
return utilHelper.send404(response);
}

View File

@@ -6,6 +6,7 @@ file for handling routes regarding contact
*/
// imports
const logger = require('winston');
const router = require('express').Router();
const apiHelper = require('../helpers/api');
const utilHelper = require('../helpers/util');
@@ -69,7 +70,7 @@ router.post('/api/v1/sendmessage', (req, response) => {
// error handling
request.on('error', (error) => {
console.warn('request errored' + error);
logger.log('warn', 'request errored' + error);
return apiHelper.sendApiGenericError(response);
});

View File

@@ -6,11 +6,13 @@ file for handling admin api.
*/
// imports
const logger = require('winston');
const router = require('express').Router();
const passport = require('passport');
const userMiddleware = require('../middleware/authentication');
const apiHelper = require('../helpers/api');
const utilHelper = require('../helpers/util');
const mailer = require('../mailer');
const config = require('../config.json');
const Recaptcha = require('express-recaptcha').Recaptcha;
const recaptcha = new Recaptcha(config.recaptcha.siteKey, config.recaptcha.secretKey);
@@ -19,11 +21,11 @@ const recaptcha = new Recaptcha(config.recaptcha.siteKey, config.recaptcha.secre
const PNID = require('../models/pnid');
// renders register page
router.get('/pnid/register', recaptcha.middleware.render, (request, response) => {
router.get('/pnid/register', (request, response) => {
return response.render('register', {
title: 'Pretendo | Register',
captcha: response.recaptcha,
locale: utilHelper.getLocale('US', 'en')
locale: utilHelper.getLocale('US', 'en'),
recaptcha_sitekey: config.recaptcha.siteKey
});
});
// renders login page
@@ -92,36 +94,58 @@ router.post('/api/v1/login', passport.authenticate('PNIDStrategy'), function (re
*/
router.post('/api/v1/register', recaptcha.middleware.verify, async (request, response) => {
if (!request.body) {
// no post body
return apiHelper.sendApiGenericError(response);
}
/*if (request.recaptcha.error) {
apiHelper.sendApiError(response, 500, ['Captcha error']);
return;
}*/
const { email, password } = request.body;
if (request.recaptcha.error) {
logger.log('warn', `[reCaptcha ERROR] ${request.recaptcha.error} | IP: ${request.ip} | Data: ${JSON.stringify(request.body)}`);
return apiHelper.sendApiError(response, 500, ['Captcha error']);
}
const { email, password, confirm_password, username } = request.body;
if (password !== confirm_password) {
return apiHelper.sendApiError(response, 400, ['Passwords do not match']);
}
const email_validation_code = await PNID.PNIDModel.generateEmailValidationCode();
const email_validation_token = await PNID.PNIDModel.generateEmailValidationToken();
const newUser = new PNID.PNIDModel({
email,
email_validation_code,
email_validation_token,
password,
pnid: {
key: 'abcd',
pid: await PNID.PNIDModel.generatePID()
pid: await PNID.PNIDModel.generatePID(),
username,
username_lower: username.toLowerCase()
}
});
// TODO verify password
// saving to database
newUser.save().then((user) => {
mailer.send(
user.get('email'),
'[Pretendo Network] Please confirm your e-mail address',
`Hello,
Your Pretendo Network ID activation is almost complete. Please click the link below to confirm your e-mail address and complete the activation process.
https://account.pretendo.cc/account/email-confirmation?token${user.get('email_validation_token')}
If you are unable to connect to the above URL, please enter the following confirmation code on the device to which your Pretendo Network ID is linked.
&lt;&lt;Confirmation code: ${user.get('email_validation_code')}&gt;&gt;`
);
return apiHelper.sendReturn(response, {
email: user.email,
email_validated: user.email_validated,
pnid: user.pnid.key
pnid: user.pnid.pid
});
}).catch((rejection) => {
// TODO format exception so it doesnt have a huge list of errors
console.warn(rejection);
logger.log('warn', rejection);
return apiHelper.sendApiError(response, 500, [rejection]);
});
});

View File

@@ -6,6 +6,7 @@ the file that contains the startup code
*/
// imports
const logger = require('./logger');
const express = require('express');
const handlebars = require('express-handlebars');
const session = require('express-session');
@@ -98,11 +99,12 @@ app.use((request, response) => {
// TODO remove param decoding errors from logs example: "host/test/%"
// 4 parameters required to read the error, cant help the eslint error
app.use((error, request, response, next) => { // eslint-disable-line no-unused-vars
console.warn(error.stack);
logger.log('warn', error.stack);
return response.status(500).send('Something broke!');
});
// startup
app.listen(config.http.port, () => {
logger.log('debug', `started the server on port: ${config.http.port}`);
console.log(`started the server on port: ${new String(config.http.port).green}`);
});

View File

@@ -4,6 +4,8 @@
{{> head-common }}
<!-- page specific -->
<link rel="stylesheet" href="/assets/css/pretendo-auth.css">
<script src='https://www.google.com/recaptcha/api.js'></script>
<script src="/assets/js/auth.js" defer></script>
</head>
<body class="flex center">
@@ -12,17 +14,20 @@
<div class="content">
<p class="txt-highlight">{{ locale.register.card.caption }}</p>
<h1 class="txt-title small">{{ locale.register.card.title }}</h1>
<form action="/api/v1/sendmessage" method="POST">
<form action="/api/v1/register" method="POST">
<label for="email">{{ locale.register.card.email_text }}</label>
<input type="text" class="hasLabel" id="email_input" name="email">
<label for="email">{{ locale.register.card.username_text }}</label>
<label for="username">{{ locale.register.card.username_text }}</label>
<input type="text" class="hasLabel" id="username_input" name="username">
<label for="email">{{ locale.register.card.password_text }}</label>
<label for="password">{{ locale.register.card.password_text }}</label>
<input type="password" class="hasLabel" id="password_input" name="password">
<label for="email">{{ locale.register.card.password_confirm_text }}</label>
<label for="confirm_password">{{ locale.register.card.password_confirm_text }}</label>
<input type="password" class="hasLabel" id="password_confirm_input" name="confirm_password">
<div class="g-recaptcha" data-sitekey="{{ recaptcha_sitekey }}"></div>
<button type="submit" class="btn btnMargin">ERROR</button>
</form>
<button class="btn btnMargin" onclick="register()">ERROR</button>
<p class="lowText">ERROR <a href="#">ERROR</a></p>
</div>
</div>