Merge pull request #15 from RedDuckss/dev

Starting bringing over a better comment scheme for methods (see helpers/api.js), addedemail confirmation sending, proper logging, fixed registration
This commit is contained in:
RedDucks 2018-11-30 22:18:39 -05:00 committed by GitHub
commit aa1f5e5157
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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 = {

31
helpers/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

@ -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;

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('../helpers/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>