diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..2d59b87 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,39 @@ +{ + "env": { + "node": true, + "commonjs": true, + "es6": true + }, + "parserOptions": { + "ecmaVersion": 2017 + }, + "extends": "eslint:recommended", + "rules": { + "no-console": "off", + "prefer-const": "error", + "no-var": "error", + "one-var": [ + "error", + "never" + ], + "indent": [ + "error", + "tab", + { + "SwitchCase": 1 + } + ], + "linebreak-style": [ + "error", + "windows" + ], + "quotes": [ + "error", + "single" + ], + "semi": [ + "error", + "always" + ] + } +} \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..ea48110 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: node_js +node_js: + - "7" + - "8" + - "9" + +sudo: false + +script: + - "npm run lint" \ No newline at end of file diff --git a/constants.js b/constants.js index eb5a83c..47eeb2d 100644 --- a/constants.js +++ b/constants.js @@ -1,29 +1,29 @@ module.exports = { - URL_ENDPOINTS: { - mii: 'http://mii-secure.account.riiu.net/' - }, - LATEST_SYSTEM_VERSION: '0230', - MINIMUN_SYSTEM_VERSION: '0209', - PID_SORT_LIST: '0123456789', - VALID_CLIENT_ID_SECRET_PAIRS: { - // 'Key' is the client ID, 'Value' is the client secret - 'a2efa818a34fa16b8afbc8a74eba3eda': 'c91cdb5658bd4954ade78533a339cf9a', // Possibly WiiU exclusive? - 'daf6227853bcbdce3d75baee8332b': '3eff548eac636e2bf45bb7b375e7b6b0', // Possibly 3DS exclusive? - 'ea25c66c26b403376b4c5ed94ab9cdea': 'd137be62cb6a2b831cad8c013b92fb55', // Possibly 3DS exclusive? - }, - REGEX: { - HEADER_FORMATS: { - DEVICE_ID: /^\d{10}$/g, - REGION: /^\d+$/g, - SYSTEM_VERSION: /^\d+$/g, - } - }, - REGION_CODES_NUM: { - '4': 'EUR', - '2': 'US' - }, - REGION_CODES_STR: { - EUR: 4, - US: 2 - }, -} \ No newline at end of file + URL_ENDPOINTS: { + mii: 'http://mii-secure.account.riiu.net/' + }, + LATEST_SYSTEM_VERSION: '0230', + MINIMUN_SYSTEM_VERSION: '0209', + PID_SORT_LIST: '0123456789', + VALID_CLIENT_ID_SECRET_PAIRS: { + // 'Key' is the client ID, 'Value' is the client secret + 'a2efa818a34fa16b8afbc8a74eba3eda': 'c91cdb5658bd4954ade78533a339cf9a', // Possibly WiiU exclusive? + 'daf6227853bcbdce3d75baee8332b': '3eff548eac636e2bf45bb7b375e7b6b0', // Possibly 3DS exclusive? + 'ea25c66c26b403376b4c5ed94ab9cdea': 'd137be62cb6a2b831cad8c013b92fb55', // Possibly 3DS exclusive? + }, + REGEX: { + HEADER_FORMATS: { + DEVICE_ID: /^\d{10}$/g, + REGION: /^\d+$/g, + SYSTEM_VERSION: /^\d+$/g, + } + }, + REGION_CODES_NUM: { + '4': 'EUR', + '2': 'US' + }, + REGION_CODES_STR: { + EUR: 4, + US: 2 + }, +}; \ No newline at end of file diff --git a/db.js b/db.js index 79d57b6..d453315 100644 --- a/db.js +++ b/db.js @@ -1,23 +1,23 @@ const mongoist = require('mongoist'); const config = require('./config.json'); const user_database_collection_name = 'users'; -const database = config.mongo.database -const hostname = config.mongo.hostname -const port = config.mongo.port -const auth = config.mongo.authentication +const database = config.mongo.database; +const hostname = config.mongo.hostname; +const port = config.mongo.port; +const auth = config.mongo.authentication; let connection_string = ''; -if(config.mongo.use_authentication) { - connection_string = `mongodb://${auth.username}:${auth.password}@${hostname}:${port}/${database}?authSource=${auth.authentication_database}` -}else { - connection_string = `mongodb://${hostname}:${port}/${database}` +if (config.mongo.use_authentication) { + connection_string = `mongodb://${auth.username}:${auth.password}@${hostname}:${port}/${database}?authSource=${auth.authentication_database}`; +} else { + connection_string = `mongodb://${hostname}:${port}/${database}`; } -user_database = mongoist(connection_string); -user_collection = user_database.collection(user_database_collection_name); +const user_database = mongoist(connection_string); +const user_collection = user_database.collection(user_database_collection_name); module.exports = { - user_database: user_database, - user_collection: user_collection + user_database: user_database, + user_collection: user_collection }; diff --git a/debugger.js b/debugger.js index 72115db..1c33917 100644 --- a/debugger.js +++ b/debugger.js @@ -1,59 +1,59 @@ -let ms = require('ms'), - colors = require('colors'); +const ms = require('ms'); +require('colors'); class Debugger { - constructor(title) { - this.title = title; - this.previous_time = new Date(); - } + constructor(title) { + this.title = title; + this.previous_time = new Date(); + } - success(input) { - let current_time = new Date(), - time_taken = ms(ms(current_time - this.previous_time)), - suffix = ''; + success(input) { + const current_time = new Date(); + const time_taken = ms(ms(current_time - this.previous_time)); + let suffix = ''; - if (time_taken > 0) { - suffix = '-> '.green + (time_taken + 'ms').magenta; - } + if (time_taken > 0) { + suffix = '-> '.green + (time_taken + 'ms').magenta; + } - let message = (this.title + ':').green.bold + ' ' + input.yellow.bold + ' ' + suffix.bold; + const message = (this.title + ':').green.bold + ' ' + input.yellow.bold + ' ' + suffix.bold; - console.log(message); + console.log(message); - this.previous_time = current_time; - } + this.previous_time = current_time; + } - error(input) { - let current_time = new Date(), - time_taken = ms(ms(current_time - this.previous_time)), - suffix = ''; + error(input) { + const current_time = new Date(); + const time_taken = ms(ms(current_time - this.previous_time)); + let suffix = ''; - if (time_taken > 0) { - suffix = '-> '.green + (time_taken + 'ms').magenta; - } + if (time_taken > 0) { + suffix = '-> '.green + (time_taken + 'ms').magenta; + } - let message = (this.title + ':').red.bold + ' ' + input.yellow.bold + ' ' + suffix.bold; + const message = (this.title + ':').red.bold + ' ' + input.yellow.bold + ' ' + suffix.bold; - console.log(message); + console.log(message); - this.previous_time = current_time; - } + this.previous_time = current_time; + } - log(input) { - let current_time = new Date(), - time_taken = ms(ms(current_time - this.previous_time)), - suffix = ''; + log(input) { + const current_time = new Date(); + const time_taken = ms(ms(current_time - this.previous_time)); + let suffix = ''; - if (time_taken > 0) { - suffix = '-> '.green + (time_taken + 'ms').magenta; - } + if (time_taken > 0) { + suffix = '-> '.green + (time_taken + 'ms').magenta; + } - let message = (this.title + ':').cyan.bold + ' ' + input.yellow.bold + ' ' + suffix.bold; + const message = (this.title + ':').cyan.bold + ' ' + input.yellow.bold + ' ' + suffix.bold; - console.log(message); + console.log(message); - this.previous_time = current_time; - } + this.previous_time = current_time; + } } module.exports = Debugger; \ No newline at end of file diff --git a/helpers.js b/helpers.js index 8868088..9769ec1 100644 --- a/helpers.js +++ b/helpers.js @@ -6,247 +6,245 @@ const constants = require('./constants'); const database = require('./db'); async function generatePID() { - // Quick, dirty fix for PIDs - const pid = Math.floor(Math.random() * (4294967295 - 1000000000) + 1000000000); - let does_pid_inuse = await database.user_collection.findOne({ - pid: pid - }); + // Quick, dirty fix for PIDs + const pid = Math.floor(Math.random() * (4294967295 - 1000000000) + 1000000000); + const does_pid_inuse = await database.user_collection.findOne({ + pid: pid + }); - if (does_pid_inuse) { - return await generatePID(); - } + if (does_pid_inuse) { + return await generatePID(); + } - return pid; + return pid; } function generateRandID(length = 10) { - let id = ''; + let id = ''; - for (var i=0;i { - account = account.account - let attributes = []; + user.accounts.forEach(account => { + account = account.account; + const attributes = []; - account.attributes.forEach(attribute => { - attribute = attribute.attribute; - attributes.push({ - attribute: { - id: attribute.id, - name: attribute.name, - updated_by: attribute.updated_by, - value: attribute.value, - } - }); - }); + account.attributes.forEach(attribute => { + attribute = attribute.attribute; + attributes.push({ + attribute: { + id: attribute.id, + name: attribute.name, + updated_by: attribute.updated_by, + value: attribute.value, + } + }); + }); - accounts.push({ - account: { - attributes: attributes, - domain: account.domain, - type: account.type, - username: account.username - } - }) - }); + accounts.push({ + account: { + attributes: attributes, + domain: account.domain, + type: account.type, + username: account.username + } + }); + }); - user.device_attributes.device_attribute.forEach(device_attribute => { - let attribute = { - name: device_attribute.name, - value: device_attribute.value - }; + user.device_attributes.device_attribute.forEach(device_attribute => { + const attribute = { + name: device_attribute.name, + value: device_attribute.value + }; - if (device_attribute.created_date) { - attribute.created_date = device_attribute.created_date; - } + if (device_attribute.created_date) { + attribute.created_date = device_attribute.created_date; + } - device_attributes.push({ - device_attribute: attribute - }); - }); + device_attributes.push({ + device_attribute: attribute + }); + }); - let person = { - person: { - accounts: accounts, - active_flag: user.active_flag, - birth_date: user.birth_date, - country: user.country, - create_date: user.create_date, - device_attributes: device_attributes, - gender: user.gender, - language: user.language, - updated: user.updated, - marketing_flag: user.marketing_flag, - off_device_flag: user.off_device_flag, - pid: user.pid, - email: { - address: user.email.address.address, - id: user.email.id, - parent: user.email.address.parent, - primary: user.email.address.primary, - reachable: user.email.reachable, - type: user.email.address.type, - updated_by: user.email.updated_by, - validated: user.email.address.validated, - validated_date: user.updated - }, - mii: { - status: user.mii.status, - data: user.mii.data.replace('\r\n', ''), - id: user.mii.id, - mii_hash: user.mii.mii_hash, - mii_images: [ - { - mii_image: { - cached_url: user.mii.mii_images[0].cached_url, - id: user.mii.mii_images[0].id, - url: user.mii.mii_images[0].url, - type: user.mii.mii_images[0].type - } - } - ], - name: user.mii.name, - primary: user.mii.primary - }, - region: user.region, - tz_name: user.tz_name, - user_id: user.user_id, - utc_offset: user.utc_offset - } - } + const person = { + person: { + accounts: accounts, + active_flag: user.active_flag, + birth_date: user.birth_date, + country: user.country, + create_date: user.create_date, + device_attributes: device_attributes, + gender: user.gender, + language: user.language, + updated: user.updated, + marketing_flag: user.marketing_flag, + off_device_flag: user.off_device_flag, + pid: user.pid, + email: { + address: user.email.address.address, + id: user.email.id, + parent: user.email.address.parent, + primary: user.email.address.primary, + reachable: user.email.reachable, + type: user.email.address.type, + updated_by: user.email.updated_by, + validated: user.email.address.validated, + validated_date: user.updated + }, + mii: { + status: user.mii.status, + data: user.mii.data.replace('\r\n', ''), + id: user.mii.id, + mii_hash: user.mii.mii_hash, + mii_images: [ + { + mii_image: { + cached_url: user.mii.mii_images[0].cached_url, + id: user.mii.mii_images[0].id, + url: user.mii.mii_images[0].url, + type: user.mii.mii_images[0].type + } + } + ], + name: user.mii.name, + primary: user.mii.primary + }, + region: user.region, + tz_name: user.tz_name, + user_id: user.user_id, + utc_offset: user.utc_offset + } + }; - return person; + return person; } module.exports = { - generatePID: generatePID, - generateRandID: generateRandID, - generateNintendoHashedPWrd: generateNintendoHashedPWrd, - doesUserExist: doesUserExist, - generateAccessToken: generateAccessToken, - generateRefreshToken: generateRefreshToken, - getUser: getUser, - getUserBasic: getUserBasic, - mapUser: mapUser, - generateEmailToken: generateEmailToken, - generateEmailCode: generateEmailCode, -} \ No newline at end of file + generatePID: generatePID, + generateRandID: generateRandID, + generateNintendoHashedPWrd: generateNintendoHashedPWrd, + doesUserExist: doesUserExist, + generateAccessToken: generateAccessToken, + generateRefreshToken: generateRefreshToken, + getUser: getUser, + getUserBasic: getUserBasic, + mapUser: mapUser, + generateEmailToken: generateEmailToken, + generateEmailCode: generateEmailCode, +}; \ No newline at end of file diff --git a/mailer.js b/mailer.js index 292772b..0dcf10c 100644 --- a/mailer.js +++ b/mailer.js @@ -2,11 +2,11 @@ const nodemailer = require('nodemailer'); const config = require('./config.json'); const transporter = nodemailer.createTransport({ - service: 'gmail', - auth: { - user: config.email.address, - pass: config.email.password - } + service: 'gmail', + auth: { + user: config.email.address, + pass: config.email.password + } }); /** @@ -16,22 +16,22 @@ const transporter = nodemailer.createTransport({ * @param {String} message The body of the email */ function send(email, subject = 'No email subject provided', message = 'No email body provided') { - let options = { - from: config.email.address, - to: email, - subject: subject, - html: message - } + const options = { + from: config.email.address, + to: email, + subject: subject, + html: message + }; - transporter.sendMail(options, (error, info) => { - if (error) { - console.log(error); - } else { - console.log(info); - } - }); + transporter.sendMail(options, (error, info) => { + if (error) { + console.log(error); + } else { + console.log(info); + } + }); } module.exports = { - send: send -} + send: send +}; diff --git a/package-lock.json b/package-lock.json index 61ee83d..02fa6b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,11 +13,125 @@ "negotiator": "0.6.1" } }, + "acorn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.0.tgz", + "integrity": "sha512-arn53F07VXmls4o4pUhSzBa4fvaagPRe7AVZ8l7NHxFWUie2DsuFSBMMNAkgzRlOhEhzAnxeKyaWVzOH4xqp/g==" + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" + } + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=" + }, + "ansi-escapes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz", + "integrity": "sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ==" + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "1.0.3" + } + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "2.1.1" + } + } + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, "basic-auth": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz", @@ -65,6 +179,15 @@ } } }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, "bson": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.4.tgz", @@ -80,6 +203,65 @@ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "requires": { + "callsites": "0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=" + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "1.9.1" + } + }, + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==" + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "requires": { + "restore-cursor": "2.0.0" + } + }, "cli-table": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", @@ -95,16 +277,54 @@ } } }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" + }, "clone": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.3.tgz", "integrity": "sha1-KY1+IjFmD0DAA8LtMUDezz9TCF8=" }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "color-convert": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, "colors": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=" }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.1.tgz", + "integrity": "sha512-gslSSJx03QKa59cIKqeJO9HQ/WZMotvYJCuaUULrLpjj8oG40kV2Z+gz82pVxlTkOADi4PJxQPPfhl1ELYrrXw==", + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.2.7", + "typedarray": "0.0.6" + } + }, "content-disposition": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", @@ -130,6 +350,36 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "requires": { + "lru-cache": "4.1.1", + "shebang-command": "1.2.0", + "which": "1.3.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + }, "defaults": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", @@ -138,6 +388,20 @@ "clone": "1.0.3" } }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.0", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + } + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -148,6 +412,14 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "requires": { + "esutils": "2.0.2" + } + }, "each-series": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/each-series/-/each-series-1.0.0.tgz", @@ -173,6 +445,125 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "eslint": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.18.2.tgz", + "integrity": "sha512-qy4i3wODqKMYfz9LUI8N2qYDkHkoieTbiHpMrYUI/WbjhXJQr7lI4VngixTgaG+yHX+NBCv7nW4hA0ShbvaNKw==", + "requires": { + "ajv": "5.5.2", + "babel-code-frame": "6.26.0", + "chalk": "2.3.2", + "concat-stream": "1.6.1", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.1.0", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "1.0.0", + "espree": "3.5.4", + "esquery": "1.0.0", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "11.3.0", + "ignore": "3.3.7", + "imurmurhash": "0.1.4", + "inquirer": "3.3.0", + "is-resolvable": "1.1.0", + "js-yaml": "3.11.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.5", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "require-uncached": "1.0.3", + "semver": "5.4.1", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.2", + "text-table": "0.2.0" + } + }, + "eslint-plugin-eslint-snake-case": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/eslint-plugin-eslint-snake-case/-/eslint-plugin-eslint-snake-case-0.0.6.tgz", + "integrity": "sha1-K4pMb9Terzy8LgOizXm1DsiULRM=", + "requires": { + "requireindex": "1.1.0" + } + }, + "eslint-plugin-more-naming-conventions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-more-naming-conventions/-/eslint-plugin-more-naming-conventions-1.0.1.tgz", + "integrity": "sha512-K1Lw0dMUOIYeY0qe7SYSjHpHW8aZfxaVpXoFli672ywpRq05R1STmpxfhXyVxrphbsNt/SgBCaJPXl7pqSpUfg==", + "requires": { + "eslint": "4.18.2" + } + }, + "eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "requires": { + "esrecurse": "4.2.1", + "estraverse": "4.2.0" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==" + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "requires": { + "acorn": "5.5.0", + "acorn-jsx": "3.0.1" + } + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==" + }, + "esquery": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", + "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", + "requires": { + "estraverse": "4.2.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "requires": { + "estraverse": "4.2.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" + }, "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", @@ -245,6 +636,48 @@ "resolved": "https://registry.npmjs.org/express-subdomain/-/express-subdomain-1.0.5.tgz", "integrity": "sha1-mQ75eUC39MKCPZWTZIt5voWKY4s=" }, + "external-editor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.1.0.tgz", + "integrity": "sha512-E44iT5QVOUJBKij4IIV3uvxuNlbKS38Tw1HiupxEIHPv9qtC2PrDYohbXV5U+1jnfIXttny8gUhj+oZvflFlzA==", + "requires": { + "chardet": "0.4.2", + "iconv-lite": "0.4.19", + "tmp": "0.0.33" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "requires": { + "flat-cache": "1.3.0", + "object-assign": "4.1.1" + } + }, "finalhandler": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", @@ -276,6 +709,17 @@ } } }, + "flat-cache": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", + "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, "forwarded": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", @@ -296,11 +740,65 @@ "universalify": "0.1.1" } }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globals": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.3.0.tgz", + "integrity": "sha512-kkpcKNlmQan9Z5ZmgqKH/SMbSmjxQ7QjyNqfXVc8VJcoBV2UEg+sxQD15GQofGRh2hfpwUb70VC31DR7Rq5Hdw==" + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, "http-errors": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", @@ -329,21 +827,126 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" }, + "ignore": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz", + "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==" + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "requires": { + "ansi-escapes": "3.0.0", + "chalk": "2.3.2", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.1.0", + "figures": "2.0.0", + "lodash": "4.17.5", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + } + }, "ipaddr.js": { "version": "1.5.2", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=" }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=" + }, + "is-path-in-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "requires": { + "is-path-inside": "1.0.1" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "js-yaml": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.11.0.tgz", + "integrity": "sha512-saJstZWv7oNeOyBh3+Dx1qWzhW0+e6/8eDzo7p5rDFqxntSztloLtuKu+Ejhtq82jsilwOIZYsCz+lIjthg1Hw==", + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + }, "json2xml": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/json2xml/-/json2xml-0.1.3.tgz", @@ -357,11 +960,34 @@ "graceful-fs": "4.1.11" } }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "lodash": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==" + }, "long": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" }, + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -395,6 +1021,32 @@ "mime-db": "1.30.0" } }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, "moment": { "version": "2.20.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz", @@ -484,6 +1136,16 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + }, "negotiator": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", @@ -494,6 +1156,11 @@ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.4.2.tgz", "integrity": "sha512-sstDxbCSPHDXrWRQhH++khr3yVU0CGvH2dCtAHOPQQ0lRR7xwq2txItEXckMpX481B/cN+0akER2bfExh7Gu/Q==" }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -515,6 +1182,32 @@ "wrappy": "1.0.2" } }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "requires": { + "mimic-fn": "1.2.0" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, "parse-mongo-url": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/parse-mongo-url/-/parse-mongo-url-1.1.1.tgz", @@ -525,21 +1218,64 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + }, "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "2.0.4" + } + }, "pixl-xml": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/pixl-xml/-/pixl-xml-1.0.13.tgz", "integrity": "sha1-W6cUCL3zeZTCOd0BJRwQxTwFh+M=" }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==" + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, "process-nextick-args": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" }, + "progress": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", + "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=" + }, "proxy-addr": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", @@ -549,6 +1285,11 @@ "ipaddr.js": "1.5.2" } }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, "puid": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/puid/-/puid-1.0.7.tgz", @@ -611,11 +1352,70 @@ "semver": "5.4.1" } }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + }, + "dependencies": { + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=" + } + } + }, + "requireindex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.1.0.tgz", + "integrity": "sha1-5UBLgVV+91225JxacgBIk/4D4WI=" + }, "resolve-from": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "requires": { + "glob": "7.1.2" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "requires": { + "is-promise": "2.1.0" + } + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=" + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "requires": { + "rx-lite": "4.0.8" + } + }, "safe-buffer": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", @@ -677,6 +1477,37 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "requires": { + "is-fullwidth-code-point": "2.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, "statuses": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", @@ -690,16 +1521,89 @@ "safe-buffer": "5.1.1" } }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + } + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "requires": { + "ajv": "5.5.2", + "ajv-keywords": "2.1.1", + "chalk": "2.3.2", + "lodash": "4.17.5", + "slice-ansi": "1.0.0", + "string-width": "2.1.1" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, "thunky": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.0.2.tgz", "integrity": "sha1-qGLgGOP7HqLsP85dVWBc9X8kc3E=" }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "1.0.2" + } + }, "to-mongodb-core": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-mongodb-core/-/to-mongodb-core-2.0.0.tgz", "integrity": "sha1-NZbsdhOsmtO5ioncua77pWnNJ+s=" }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "1.1.2" + } + }, "type-is": { "version": "1.6.15", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", @@ -709,6 +1613,11 @@ "mime-types": "2.1.17" } }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, "universalify": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", @@ -734,15 +1643,41 @@ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" }, + "which": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "requires": { + "isexe": "2.0.0" + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "requires": { + "mkdirp": "0.5.1" + } + }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" } } } diff --git a/package.json b/package.json index e1a64bd..e69d31d 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "", "main": "server.js", "scripts": { + "lint": "./node_modules/.bin/eslint .", "test": "echo \"Error: no test specified\" && exit 1", "start": "NODE_ENV=production node server.js", "start:dev": "NODE_ENV=development node server.js" @@ -14,6 +15,7 @@ "bcryptjs": "^2.4.3", "cli-table": "^0.3.1", "colors": "^1.1.2", + "eslint": "^4.18.2", "express": "^4.16.2", "express-rate-limit": "^2.11.0", "express-subdomain": "^1.0.5", diff --git a/routes/account/index.js b/routes/account/index.js index 4815a80..de36cbb 100644 --- a/routes/account/index.js +++ b/routes/account/index.js @@ -10,61 +10,43 @@ route_debugger.success('Loading \'account\' API routes'); * Description: Verifies a user email via token */ routes.get('/email-confirmation', async (request, response) => { - let _GET = request.query; + const _GET = request.query; - console.log(_GET) + if (!_GET.token) { + return response.send('ERROR: Invalid token'); + } - if (!_GET.token) { - return response.send('ERROR: Invalid token'); - } + const user = await database.user_collection.findOne({ + 'sensitive.email_confirms.token': _GET.token + }); - console.log(2) + if (!user) { + return response.send('ERROR: Invalid token'); + } - let user = await database.user_collection.findOne({ - 'sensitive.email_confirms.token': _GET.token - }); + user.email.reachable = 'Y'; + user.email.validated = 'Y'; - console.log(3) + await database.user_collection.update({ + pid: user.pid + }, { + $set: { + email: user.email + } + }); - if (!user) { - return response.send('ERROR: Invalid token'); - } + user.sensitive.email_confirms.token = null; + user.sensitive.email_confirms.code = null; - console.log(4) + await database.user_collection.update({ + pid: user.pid + }, { + $set: { + sensitive: user.sensitive + } + }); - user.email.reachable = 'Y'; - user.email.validated = 'Y'; - - console.log(5) - - await database.user_collection.update({ - pid: user.pid - }, { - $set: { - email: user.email - } - }); - - console.log(6) - - user.sensitive.email_confirms.token = null; - user.sensitive.email_confirms.code = null; - - console.log(7) - - await database.user_collection.update({ - pid: user.pid - }, { - $set: { - sensitive: user.sensitive - } - }); - - console.log(8) - - response.send('It has been confirmed that you can receive e-mails from Pretendo. The confirmation process is now complete.'); - - console.log(9) + response.send('It has been confirmed that you can receive e-mails from Pretendo. The confirmation process is now complete.'); }); module.exports = routes; \ No newline at end of file diff --git a/routes/admin/index.js b/routes/admin/index.js index b83220f..caa7d20 100644 --- a/routes/admin/index.js +++ b/routes/admin/index.js @@ -13,97 +13,97 @@ route_debugger.success('Loading \'admin\' API routes'); * Description: Maps given input to expected output */ routes.all('/mapped_ids', async (request, response) => { - response.set('Content-Type', 'text/xml'); - response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('Content-Type', 'text/xml'); + response.set('Server', 'Nintendo 3DS (http)'); + response.set('X-Nintendo-Date', new Date().getTime()); - let headers = request.headers, - _GET = request.query; + const headers = request.headers; + const _GET = request.query; - if ( - !headers['x-nintendo-client-id'] || - !headers['x-nintendo-client-secret'] || - !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || - headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] - ) { - let error = { - errors: { - error: { - cause: 'client_id', - code: '0004', - message: 'API application invalid or incorrect application credentials' - } - } - } + if ( + !headers['x-nintendo-client-id'] || + !headers['x-nintendo-client-secret'] || + !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || + headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] + ) { + const error = { + errors: { + error: { + cause: 'client_id', + code: '0004', + message: 'API application invalid or incorrect application credentials' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - if ( - !_GET.output_type || - !_GET.input_type || - !_GET.input || - _GET.input.trim() == '' - ) { - let error = { - errors: { - error: { - cause: 'Bad Request', - code: '1600', - message: 'Unable to process request' - } - } - } + if ( + !_GET.output_type || + !_GET.input_type || + !_GET.input || + _GET.input.trim() == '' + ) { + const error = { + errors: { + error: { + cause: 'Bad Request', + code: '1600', + message: 'Unable to process request' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - let output = { - mapped_ids: [ - ] - } + const output = { + mapped_ids: [ + ] + }; - _GET.input = _GET.input.split(','); + _GET.input = _GET.input.split(','); - switch (true) { - case (_GET.input_type === 'user_id' && _GET.output_type === 'pid'): - await _GET.input.asyncForEach(async user_id => { - let user = await database.user_collection.findOne({ - user_id_flat: user_id.toLowerCase(), - }), - out_id = null; + switch (true) { + case (_GET.input_type === 'user_id' && _GET.output_type === 'pid'): + await _GET.input.asyncForEach(async user_id => { + const user = await database.user_collection.findOne({ + user_id_flat: user_id.toLowerCase(), + }); + let out_id = null; - if (user) { - out_id = user.pid; - } + if (user) { + out_id = user.pid; + } - output.mapped_ids.push({ - mapped_id: { - in_id: user_id, - out_id: out_id - } - }); - }); - break; - default: - _GET.input.forEach(input => { - output.mapped_ids.push({ - mapped_id: { - in_id: input, - out_id: null - } - }); - }); - } + output.mapped_ids.push({ + mapped_id: { + in_id: user_id, + out_id: out_id + } + }); + }); + break; + default: + _GET.input.forEach(input => { + output.mapped_ids.push({ + mapped_id: { + in_id: input, + out_id: null + } + }); + }); + } - response.send(json2xml(output)); -}) + response.send(json2xml(output)); +}); module.exports = routes; Array.prototype.asyncForEach = async function (cb) { - for (let i=0;i { - response.set('Content-Type', 'text/xml'); - response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('Content-Type', 'text/xml'); + response.set('Server', 'Nintendo 3DS (http)'); + response.set('X-Nintendo-Date', new Date().getTime()); - let headers = request.headers, - region = request.params.region, - language = request.params.language; + const headers = request.headers; + const region = request.params.region; + const language = request.params.language; - if ( - !headers['x-nintendo-client-id'] || - !headers['x-nintendo-client-secret'] || - !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || - headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] - ) { - let error = { - errors: { - error: { - cause: 'client_id', - code: '0004', - message: 'API application invalid or incorrect application credentials' - } - } - } + if ( + !headers['x-nintendo-client-id'] || + !headers['x-nintendo-client-secret'] || + !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || + headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] + ) { + const error = { + errors: { + error: { + cause: 'client_id', + code: '0004', + message: 'API application invalid or incorrect application credentials' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - if (!fs.pathExistsSync(path.join(__dirname, 'storage', 'timezones', region, language + '.xml'))) { - let error = { - errors: { - error: { - code: '0000', - message: 'Unknown error' - } - } - } + if (!fs.pathExistsSync(path.join(__dirname, 'storage', 'timezones', region, language + '.xml'))) { + const error = { + errors: { + error: { + code: '0000', + message: 'Unknown error' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - response.sendFile(path.join(__dirname, 'storage', 'timezones', region, language + '.xml')); + response.sendFile(path.join(__dirname, 'storage', 'timezones', region, language + '.xml')); }); @@ -64,73 +64,72 @@ routes.get('/time_zones/:region/:language', (request, response) => { * Description: Sends the client requested agreement */ routes.get('/agreements/:type/:region/:version', (request, response) => { - response.set('Content-Type', 'text/xml'); - response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('Content-Type', 'text/xml'); + response.set('Server', 'Nintendo 3DS (http)'); + response.set('X-Nintendo-Date', new Date().getTime()); - let headers = request.headers, - type = request.params.type, - region = request.params.region, - version = request.params.version, - _GET = request.query; + const headers = request.headers; + const type = request.params.type; + const region = request.params.region; + const version = request.params.version; - // for some reason, the 3ds won't work if you have this. - // TODO: fix this for the 3ds - if ( - !headers['x-nintendo-client-id'] || - !headers['x-nintendo-client-secret'] || - !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || - headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] - ) { - let error = { - errors: { - error: { - cause: 'client_id', - code: '0004', - message: 'API application invalid or incorrect application credentials' - } - } - } + // for some reason, the 3ds won't work if you have this. + // TODO: fix this for the 3ds + if ( + !headers['x-nintendo-client-id'] || + !headers['x-nintendo-client-secret'] || + !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || + headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] + ) { + const error = { + errors: { + error: { + cause: 'client_id', + code: '0004', + message: 'API application invalid or incorrect application credentials' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - if (!fs.pathExistsSync(path.join(__dirname, 'storage', 'agreements', type, region, version + '.xml'))) { - let error = { - errors: { - error: { - code: '1101', - message: 'No stored agreement found for this country: ' + region + ' type: ' + type + ' and version: ' + version - } - } - } + if (!fs.pathExistsSync(path.join(__dirname, 'storage', 'agreements', type, region, version + '.xml'))) { + const error = { + errors: { + error: { + code: '1101', + message: 'No stored agreement found for this country: ' + region + ' type: ' + type + ' and version: ' + version + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - /* - // ALSO NEED TO FIGURE OUT WHEN TO THROW ERROR 1102: - let error = { - errors: { - error: { - code: '1102', - message: 'No privacy policy found for this country ' + region + ' version ' + version - } - } - } + /* + // ALSO NEED TO FIGURE OUT WHEN TO THROW ERROR 1102: + let error = { + errors: { + error: { + code: '1102', + message: 'No privacy policy found for this country ' + region + ' version ' + version + } + } + } - return response.send(json2xml(error)); + return response.send(json2xml(error)); - // SEEMS TO BE RELATED TO THE `X-Nintendo-Region` HEADER. - // SETTING `X-Nintendo-Region` TO 4 (and `:region` is `US`) WHEN `:type` IS `Nintendo-Network-EULA` THROWS ERROR 1102 - */ + // SEEMS TO BE RELATED TO THE `X-Nintendo-Region` HEADER. + // SETTING `X-Nintendo-Region` TO 4 (and `:region` is `US`) WHEN `:type` IS `Nintendo-Network-EULA` THROWS ERROR 1102 + */ - response.sendFile(path.join(__dirname, 'storage', 'agreements', type, region, version + '.xml')); + response.sendFile(path.join(__dirname, 'storage', 'agreements', type, region, version + '.xml')); }); module.exports = routes; Array.prototype.contains = function(el) { // polyfill custom Array method - return this.indexOf(el) > -1; -} + return this.indexOf(el) > -1; +}; diff --git a/routes/devices/index.js b/routes/devices/index.js index bc29ae7..a83a7ca 100644 --- a/routes/devices/index.js +++ b/routes/devices/index.js @@ -1,6 +1,4 @@ const routes = require('express').Router(); -const path = require('path'); -const fs = require('fs-extra'); const json2xml = require('json2xml'); const debug = require('../../debugger'); const constants = require('../../constants'); @@ -14,32 +12,32 @@ route_debugger.success('Loading \'devices\' API routes'); * Description: Unknown use */ routes.get('/@current/status', (request, response) => { - response.set('Content-Type', 'text/xml'); - response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('Content-Type', 'text/xml'); + response.set('Server', 'Nintendo 3DS (http)'); + response.set('X-Nintendo-Date', new Date().getTime()); - let headers = request.headers; + const headers = request.headers; - if ( - !headers['x-nintendo-client-id'] || - !headers['x-nintendo-client-secret'] || - !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || - headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] - ) { - let error = { - errors: { - error: { - cause: 'client_id', - code: '0004', - message: 'API application invalid or incorrect application credentials' - } - } - } + if ( + !headers['x-nintendo-client-id'] || + !headers['x-nintendo-client-secret'] || + !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || + headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] + ) { + const error = { + errors: { + error: { + cause: 'client_id', + code: '0004', + message: 'API application invalid or incorrect application credentials' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - return response.send(json2xml({device: null})); + return response.send(json2xml({device: null})); }); module.exports = routes; \ No newline at end of file diff --git a/routes/oauth20/index.js b/routes/oauth20/index.js index efab084..c06c0e9 100644 --- a/routes/oauth20/index.js +++ b/routes/oauth20/index.js @@ -11,184 +11,183 @@ route_debugger.log('Loading \'oauth20\' API routes'); /** * [GET] * Replacement for: https://account.nintendo.net/v1/api/oauth20/access_token/generate - * Description: Unknown use + * Description: Generates user access tokens */ routes.all('/access_token/generate', async (request, response) => { - let POST = request.body; - - if ( - !POST || - !POST.grant_type || - !['password', 'refresh_token'].includes(POST.grant_type) - ) { - let error = { - errors: { - error: { - cause: 'grant_type', - code: '0004', - message: 'Invalid Grant Type' - } - } - } + const POST = request.body; - return response.send(json2xml(error)); - } + if ( + !POST || + !POST.grant_type || + !['password', 'refresh_token'].includes(POST.grant_type) + ) { + const error = { + errors: { + error: { + cause: 'grant_type', + code: '0004', + message: 'Invalid Grant Type' + } + } + }; - if (POST.grant_type == 'password') { - if (!POST.user_id || !POST.password) { - let error = { - errors: { - error: { - cause: 'grant_type', - code: '0004', - message: 'Invalid Grant Type' - } - } - } - - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - let user = await database.user_collection.findOne({ - user_id: POST.user_id - }); + if (POST.grant_type == 'password') { + if (!POST.user_id || !POST.password) { + const error = { + errors: { + error: { + cause: 'grant_type', + code: '0004', + message: 'Invalid Grant Type' + } + } + }; + + return response.send(json2xml(error)); + } - if (!user) { - let error = { - errors: { - error: { - code: '0113', - message: 'Unauthorized device' - } - } - } + const user = await database.user_collection.findOne({ + user_id: POST.user_id + }); - return response.send(json2xml(error)); - } + if (!user) { + const error = { + errors: { + error: { + code: '0113', + message: 'Unauthorized device' + } + } + }; - if (!POST.password_type || POST.password_type.toLowerCase() !== 'hash') { - POST.password = helpers.generateNintendoHashedPWrd(POST.password, user.pid); - } + return response.send(json2xml(error)); + } - if (!bcrypt.compareSync(POST.password, user.sensitive.password)) { - let error = { - errors: { - error: { - code: '0106', - message: 'Invalid account ID or password.' - } - } - } + if (!POST.password_type || POST.password_type.toLowerCase() !== 'hash') { + POST.password = helpers.generateNintendoHashedPWrd(POST.password, user.pid); + } - return response.send(json2xml(error)); - } - - let access_token = helpers.generateAccessToken({ - pid: user.pid, - token_salt: helpers.generateRandID(100) - }); - //let access_token = user.pid + if (!bcrypt.compareSync(POST.password, user.sensitive.password)) { + const error = { + errors: { + error: { + code: '0106', + message: 'Invalid account ID or password.' + } + } + }; - let refresh_token = helpers.generateRefreshToken({ - pid: user.pid, - token_salt: helpers.generateRandID(100) - }); + return response.send(json2xml(error)); + } + + const access_token = helpers.generateAccessToken({ + pid: user.pid, + token_salt: helpers.generateRandID(100) + }); - user.sensitive.tokens.refresh = refresh_token; - user.sensitive.tokens.access.token = access_token; - user.sensitive.tokens.access.ttl = Math.floor((Date.now() / 1000) + 3600); + const refresh_token = helpers.generateRefreshToken({ + pid: user.pid, + token_salt: helpers.generateRandID(100) + }); - await database.user_collection.update({ - pid: user.pid - }, { - $set: { - sensitive: user.sensitive - } - }); - - response.send(json2xml({ - OAuth20: { - access_token: { - token: access_token, - refresh_token: refresh_token, - expires_in: 3600, - } - } - })); - } else if (POST.grant_type == 'refresh_token') { - if (!POST.refresh_token) { - let error = { - errors: { - error: { - cause: 'refresh_token', - code: '0106', - message: 'Invalid Refresh Token' - } - } - } + user.sensitive.tokens.refresh = refresh_token; + user.sensitive.tokens.access.token = access_token; + user.sensitive.tokens.access.ttl = Math.floor((Date.now() / 1000) + 3600); - return response.send(json2xml(error)); - } + await database.user_collection.update({ + pid: user.pid + }, { + $set: { + sensitive: user.sensitive + } + }); + + response.send(json2xml({ + OAuth20: { + access_token: { + token: access_token, + refresh_token: refresh_token, + expires_in: 3600, + } + } + })); + } else if (POST.grant_type == 'refresh_token') { + if (!POST.refresh_token) { + const error = { + errors: { + error: { + cause: 'refresh_token', + code: '0106', + message: 'Invalid Refresh Token' + } + } + }; - let user = database.user_collection.findOne({ - sensitive: { - tokens: { - refresh: POST.refresh_token - } - } - }); + return response.send(json2xml(error)); + } - if (!user || user.sensitive.tokens.refresh !== POST.refresh_token) { - let error = { - errors: { - error: { - cause: 'refresh_token', - code: '0106', - message: 'Invalid Refresh Token' - } - } - } + const user = database.user_collection.findOne({ + sensitive: { + tokens: { + refresh: POST.refresh_token + } + } + }); - return response.send(json2xml(error)); - } + if (!user || user.sensitive.tokens.refresh !== POST.refresh_token) { + const error = { + errors: { + error: { + cause: 'refresh_token', + code: '0106', + message: 'Invalid Refresh Token' + } + } + }; - let access_token = helpers.generateAccessToken({ - pid: user.pid, - token_salt: helpers.generateRandID(100) - }); + return response.send(json2xml(error)); + } - let refresh_token = helpers.generateRefreshToken({ - pid: user.pid, - token_salt: helpers.generateRandID(100) - }); + const access_token = helpers.generateAccessToken({ + pid: user.pid, + token_salt: helpers.generateRandID(100) + }); - user.sensitive.tokens.refresh = refresh_token; - user.sensitive.tokens.access.token = access_token; - user.sensitive.tokens.access.ttl = Math.floor((Date.now() / 1000) + 3600); + const refresh_token = helpers.generateRefreshToken({ + pid: user.pid, + token_salt: helpers.generateRandID(100) + }); - await database.user_collection.update({ - sensitive: { - tokens: { - refresh: POST.refresh_token - } - } - }, { - $set: { - sensitive: user.sensitive - } - }); + user.sensitive.tokens.refresh = refresh_token; + user.sensitive.tokens.access.token = access_token; + user.sensitive.tokens.access.ttl = Math.floor((Date.now() / 1000) + 3600); - - response.send(json2xml({ - OAuth20: { - access_token: { - token: access_token, - refresh_token: refresh_token, - expires_in: 3600, - } - } - })); - } + await database.user_collection.update({ + sensitive: { + tokens: { + refresh: POST.refresh_token + } + } + }, { + $set: { + sensitive: user.sensitive + } + }); + + + response.send(json2xml({ + OAuth20: { + access_token: { + token: access_token, + refresh_token: refresh_token, + expires_in: 3600, + } + } + })); + } }); diff --git a/routes/people/index.js b/routes/people/index.js index fde9ef9..4dc53a4 100644 --- a/routes/people/index.js +++ b/routes/people/index.js @@ -3,15 +3,14 @@ const RateLimit = require('express-rate-limit'); const json2xml = require('json2xml'); const bcrypt = require('bcryptjs'); const moment = require('moment'); -const moment_timezone = require('moment-timezone'); const puid = require('puid'); -const fs = require('fs-extra'); const helpers = require('../../helpers'); const constants = require('../../constants'); const database = require('../../db'); const mailer = require('../../mailer'); const debug = require('../../debugger'); const route_debugger = new debug('People Route'.green); +require('moment-timezone'); route_debugger.log('Loading \'people\' API routes'); @@ -21,194 +20,194 @@ route_debugger.log('Loading \'people\' API routes'); * Description: Registers a user */ routes.post('/', new RateLimit({ - // THIS RATELIMIT IS PUT IN TO PLACE AS A TEMP SOLUTION TO BOT SPAM. - // WE CANNOT 1:1 CLONE THE CHECKS AND ERRORS FROM THIS ENDPOINT. - // THIS IS BECAUSE NINTENDO SEEMS TO VALIDATE A CONSOLES IDENTIFICATION HEADERS AGAINST AN - // INTERNAL DATABASE TO VERIFY A CONSOLE IS LEGITIMATE. - // THEY THEN SEEM TO DO FURTHER CHECKS USING THE CONSOLE IDENTIFICATION WHICH I HAVE NOT FIGURED - // OUT YET. BECAUSE OF THIS, ALL CUSTOM SERVERS WILL INHERENTLY BE LESS SECURE. + // THIS RATELIMIT IS PUT IN TO PLACE AS A TEMP SOLUTION TO BOT SPAM. + // WE CANNOT 1:1 CLONE THE CHECKS AND ERRORS FROM THIS ENDPOINT. + // THIS IS BECAUSE NINTENDO SEEMS TO VALIDATE A CONSOLES IDENTIFICATION HEADERS AGAINST AN + // INTERNAL DATABASE TO VERIFY A CONSOLE IS LEGITIMATE. + // THEY THEN SEEM TO DO FURTHER CHECKS USING THE CONSOLE IDENTIFICATION WHICH I HAVE NOT FIGURED + // OUT YET. BECAUSE OF THIS, ALL CUSTOM SERVERS WILL INHERENTLY BE LESS SECURE. - windowMs: 1*30*1000, - max: 1, - message: json2xml({ - errors: { - error: { - cause: 'Bad Request', - code: '1600', - message: 'Unable to process request' - } - } - }) + windowMs: 1*30*1000, + max: 1, + message: json2xml({ + errors: { + error: { + cause: 'Bad Request', + code: '1600', + message: 'Unable to process request' + } + } + }) }), async (request, response) => { - response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); - response.set('Content-Type', 'application/xml;charset=UTF-8'); + response.set('Server', 'Nintendo 3DS (http)'); + response.set('X-Nintendo-Date', new Date().getTime()); + response.set('Content-Type', 'application/xml;charset=UTF-8'); - let user_data = request.body, - headers = request.headers; + const user_data = request.body; + const headers = request.headers; - let account_exists = await database.user_collection.findOne({ - user_id: user_data.user_id - }); + const account_exists = await database.user_collection.findOne({ + user_id: user_data.user_id + }); - if (account_exists) { - let error = { - errors: { - error: { - cause: 'userId', - code: '0100', - message: 'Account ID already exists' - } - } - } + if (account_exists) { + const error = { + errors: { + error: { + cause: 'userId', + code: '0100', + message: 'Account ID already exists' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - if ( - !headers['x-nintendo-client-id'] || - !headers['x-nintendo-client-secret'] || - !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || - headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] - ) { + if ( + !headers['x-nintendo-client-id'] || + !headers['x-nintendo-client-secret'] || + !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || + headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] + ) { - let error = { - errors: { - error: { - cause: 'client_id', - code: '0004', - message: 'API application invalid or incorrect application credentials' - } - } - } + const error = { + errors: { + error: { + cause: 'client_id', + code: '0004', + message: 'API application invalid or incorrect application credentials' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - let pid = await helpers.generatePID(), - password = bcrypt.hashSync(helpers.generateNintendoHashedPWrd(user_data.password, pid), 10), - create_date = moment().format('YYYY-MM-DDTHH:MM:SS'), - mii_hash = new puid(true).generate(), - email_code = await helpers.generateEmailCode(), - email_token = await helpers.generateEmailToken(); + const pid = await helpers.generatePID(); + const password = bcrypt.hashSync(helpers.generateNintendoHashedPWrd(user_data.password, pid), 10); + const create_date = moment().format('YYYY-MM-DDTHH:MM:SS'); + const mii_hash = new puid(true).generate(); + const email_code = await helpers.generateEmailCode(); + const email_token = await helpers.generateEmailToken(); - let document = { - accounts: [ // WTF even is this?? - { - account: { - attributes: [ - { - attribute: { - id: helpers.generateRandID(8), // THIS IS A PLACE HOLDER - name: 'environment', - updated_by: 'USER', - value: 'PROD' - } - } - ], - domain: 'ESHOP.NINTENDO.NET', - type: 'INTERNAL', - username: helpers.generateRandID(9) // THIS IS A PLACE HOLDER - } - } - ], - device_attributes: user_data.device_attributes, - active_flag: 'Y', // No idea what this is or what it's used for, but it seems to be Boolean based - birth_date: user_data.birth_date, - country: user_data.country, - create_date: create_date, - gender: user_data.gender, - language: user_data.language, - updated: create_date, - marketing_flag: user_data.marketing_flag, - off_device_flag: user_data.off_device_flag, - pid: pid, - email: { - address: user_data.email, - id: helpers.generateRandID(8), // THIS IS A PLACE HOLDER - parent: user_data.parent, - primary: user_data.primary, - reachable: 'N', - type: user_data.type, - updated_by: 'INTERNAL WS', // Uhhhh..... - validated: user_data.validated - }, - mii: { - status: 'COMPLETED', // idk man, idk - data: user_data.mii.data, - id: helpers.generateRandID(10), // THIS IS A PLACE HOLDER - mii_hash: mii_hash, - mii_images: [ - { - mii_image: { - cached_url: constants.URL_ENDPOINTS.mii + mii_hash + '_standard.tga', - id: helpers.generateRandID(10), // THIS IS A PLACE HOLDER - url: constants.URL_ENDPOINTS.mii + mii_hash + '_standard.tga', - type: 'standard' - } - } - ], - name: user_data.mii.name, - primary: user_data.mii.primary, - }, - region: user_data.region, - tz_name: user_data.tz_name, - user_id: user_data.user_id, - user_id_flat: user_data.user_id.toLowerCase(), - utc_offset: (moment.tz(user_data.tz_name).utcOffset() * 60), - sensitive: { - tokens: { - refresh: '', - access: { - ttl: '', - token: '' - }, - }, - email_confirms: { - token: email_token, - code: email_code, - }, - password: password, - linked_devices: { - wiiu: { - serial: headers['x-nintendo-serial-number'], - id: headers['x-nintendo-device-id'], - certificate: headers['x-nintendo-device-cert'] - } - }, - service_agreement: user_data.agreement, - parental_consent: user_data.parental_consent, - } - } + const document = { + accounts: [ // WTF even is this?? + { + account: { + attributes: [ + { + attribute: { + id: helpers.generateRandID(8), // THIS IS A PLACE HOLDER + name: 'environment', + updated_by: 'USER', + value: 'PROD' + } + } + ], + domain: 'ESHOP.NINTENDO.NET', + type: 'INTERNAL', + username: helpers.generateRandID(9) // THIS IS A PLACE HOLDER + } + } + ], + device_attributes: user_data.device_attributes, + active_flag: 'Y', // No idea what this is or what it's used for, but it seems to be Boolean based + birth_date: user_data.birth_date, + country: user_data.country, + create_date: create_date, + gender: user_data.gender, + language: user_data.language, + updated: create_date, + marketing_flag: user_data.marketing_flag, + off_device_flag: user_data.off_device_flag, + pid: pid, + email: { + address: user_data.email, + id: helpers.generateRandID(8), // THIS IS A PLACE HOLDER + parent: user_data.parent, + primary: user_data.primary, + reachable: 'N', + type: user_data.type, + updated_by: 'INTERNAL WS', // Uhhhh..... + validated: user_data.validated + }, + mii: { + status: 'COMPLETED', // idk man, idk + data: user_data.mii.data, + id: helpers.generateRandID(10), // THIS IS A PLACE HOLDER + mii_hash: mii_hash, + mii_images: [ + { + mii_image: { + cached_url: constants.URL_ENDPOINTS.mii + mii_hash + '_standard.tga', + id: helpers.generateRandID(10), // THIS IS A PLACE HOLDER + url: constants.URL_ENDPOINTS.mii + mii_hash + '_standard.tga', + type: 'standard' + } + } + ], + name: user_data.mii.name, + primary: user_data.mii.primary, + }, + region: user_data.region, + tz_name: user_data.tz_name, + user_id: user_data.user_id, + user_id_flat: user_data.user_id.toLowerCase(), + utc_offset: (moment.tz(user_data.tz_name).utcOffset() * 60), + sensitive: { + tokens: { + refresh: '', + access: { + ttl: '', + token: '' + }, + }, + email_confirms: { + token: email_token, + code: email_code, + }, + password: password, + linked_devices: { + wiiu: { + serial: headers['x-nintendo-serial-number'], + id: headers['x-nintendo-device-id'], + certificate: headers['x-nintendo-device-cert'] + } + }, + service_agreement: user_data.agreement, + parental_consent: user_data.parental_consent, + } + }; - // At this point we would take `user_data.mii.data`, unpack/decode it and then generate a Mii image - // using that Mii data. Then save the image as a TGA and upload to the Mii image server. - // I have not yet cracked the Mii data format. All that I know is that it is base64 encoded. + // At this point we would take `user_data.mii.data`, unpack/decode it and then generate a Mii image + // using that Mii data. Then save the image as a TGA and upload to the Mii image server. + // I have not yet cracked the Mii data format. All that I know is that it is base64 encoded. - await database.user_collection.insert(document); + await database.user_collection.insert(document); - mailer.send( - user_data.email, - '[Prentendo Network] Please confirm your e-mail address', - `Hello, + mailer.send( + user_data.email, + '[Prentendo Network] Please confirm your e-mail address', + `Hello, - Your Prentendo 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=` + email_token + ` - - If you are unable to connect to the above URL, please enter the following confirmation code on the device to which your Prentendo Network ID is linked. - - <<Confirmation code: ` + email_code + `>>` - ); + Your Prentendo 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=` + email_token + ` + + If you are unable to connect to the above URL, please enter the following confirmation code on the device to which your Prentendo Network ID is linked. + + <<Confirmation code: ` + email_code + '>>' + ); - console.log('account registered', 'PID:', pid, 'email_token:', email_token, 'email_code:', email_code); + console.log('account registered', 'PID:', pid, 'email_token:', email_token, 'email_code:', email_code); - response.send(json2xml({ - person: { - pid: pid - } - })); + response.send(json2xml({ + person: { + pid: pid + } + })); }); /** @@ -217,41 +216,41 @@ routes.post('/', new RateLimit({ * Description: Checks if username already in use */ routes.get('/:username', async (request, response) => { - response.set('Content-Type', 'text/xml'); - response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('Content-Type', 'text/xml'); + response.set('Server', 'Nintendo 3DS (http)'); + response.set('X-Nintendo-Date', new Date().getTime()); - let username = request.params.username, - headers = request.headers; + const username = request.params.username; + const headers = request.headers; - if ( - !headers['x-nintendo-client-id'] || - !headers['x-nintendo-client-secret'] || - !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || - headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] - ) { - let error = { - errors: { - error: { - cause: 'client_id', - code: '0004', - message: 'API application invalid or incorrect application credentials' - } - } - } + if ( + !headers['x-nintendo-client-id'] || + !headers['x-nintendo-client-secret'] || + !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || + headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] + ) { + const error = { + errors: { + error: { + cause: 'client_id', + code: '0004', + message: 'API application invalid or incorrect application credentials' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - let user_exists = await helpers.doesUserExist(username); + const user_exists = await helpers.doesUserExist(username); - if (user_exists) { - response.status(400); - response.send(); - } - - response.status(200); - response.end(); + if (user_exists) { + response.status(400); + response.send(); + } + + response.status(200); + response.end(); }); /** @@ -260,47 +259,47 @@ routes.get('/:username', async (request, response) => { * Description: Gets profile data */ routes.get('/@me/profile', async (request, response) => { - response.set('Content-Type', 'text/xml'); - response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('Content-Type', 'text/xml'); + response.set('Server', 'Nintendo 3DS (http)'); + response.set('X-Nintendo-Date', new Date().getTime()); - let headers = request.headers; + const headers = request.headers; - if ( - !headers['authorization'] - ) { - let error = { - errors: { - error: { - cause: 'access_token', - code: '0002', - message: 'Invalid access token' - } - } - } + if ( + !headers['authorization'] + ) { + const error = { + errors: { + error: { + cause: 'access_token', + code: '0002', + message: 'Invalid access token' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - let user = await helpers.getUser(headers['authorization'].replace('Bearer ','')); + const user = await helpers.getUser(headers['authorization'].replace('Bearer ','')); - if (!user) { - let error = { - errors: { - error: { - cause: 'access_token', - code: '0002', - message: 'Invalid access token' - } - } - } + if (!user) { + const error = { + errors: { + error: { + cause: 'access_token', + code: '0002', + message: 'Invalid access token' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - let account = helpers.mapUser(user); - - return response.send(json2xml(account)); + const account = helpers.mapUser(user); + + return response.send(json2xml(account)); }); @@ -310,78 +309,78 @@ routes.get('/@me/profile', async (request, response) => { * Description: Updates user Mii */ routes.put('/@me/miis/@primary', async (request, response) => { - response.set('Content-Type', 'text/xml'); - response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('Content-Type', 'text/xml'); + response.set('Server', 'Nintendo 3DS (http)'); + response.set('X-Nintendo-Date', new Date().getTime()); - let headers = request.headers, - _PUT = request.body; + const headers = request.headers; + const _PUT = request.body; - if ( - !headers['x-nintendo-client-id'] || - !headers['x-nintendo-client-secret'] || - !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || - headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] - ) { - let error = { - errors: { - error: { - cause: 'client_id', - code: '0004', - message: 'API application invalid or incorrect application credentials' - } - } - } + if ( + !headers['x-nintendo-client-id'] || + !headers['x-nintendo-client-secret'] || + !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || + headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] + ) { + const error = { + errors: { + error: { + cause: 'client_id', + code: '0004', + message: 'API application invalid or incorrect application credentials' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - if ( - !headers['authorization'] - ) { - let error = { - errors: { - error: { - cause: 'access_token', - code: '0002', - message: 'Invalid access token' - } - } - } + if ( + !headers['authorization'] + ) { + const error = { + errors: { + error: { + cause: 'access_token', + code: '0002', + message: 'Invalid access token' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - let user = await helpers.getUser(headers['authorization'].replace('Bearer ','')); + const user = await helpers.getUser(headers['authorization'].replace('Bearer ','')); - if (!user) { - let error = { - errors: { - error: { - cause: 'access_token', - code: '0002', - message: 'Invalid access token' - } - } - } + if (!user) { + const error = { + errors: { + error: { + cause: 'access_token', + code: '0002', + message: 'Invalid access token' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - user.mii.data = _PUT.data; - user.mii.name = _PUT.name; - user.mii.primary = _PUT.data; + user.mii.data = _PUT.data; + user.mii.name = _PUT.name; + user.mii.primary = _PUT.data; - await database.user_collection.update({ - pid: user.pid - }, { - $set: { - mii: user.mii - } - }); + await database.user_collection.update({ + pid: user.pid + }, { + $set: { + mii: user.mii + } + }); - response.status(200); - response.end(); + response.status(200); + response.end(); }); /** @@ -390,83 +389,81 @@ routes.put('/@me/miis/@primary', async (request, response) => { * Description: Gets user profile, seems to be the same as https://account.nintendo.net/v1/api/people/@me/profile */ routes.get('/@me/devices/owner', async (request, response) => { - response.set('Content-Type', 'text/xml'); - response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('Content-Type', 'text/xml'); + response.set('Server', 'Nintendo 3DS (http)'); + response.set('X-Nintendo-Date', new Date().getTime()); - let headers = request.headers; + const headers = request.headers; - if ( - !headers['x-nintendo-client-id'] || - !headers['x-nintendo-client-secret'] || - !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || - headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] - ) { - let error = { - errors: { - error: { - cause: 'client_id', - code: '0004', - message: 'API application invalid or incorrect application credentials' - } - } - } + if ( + !headers['x-nintendo-client-id'] || + !headers['x-nintendo-client-secret'] || + !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || + headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] + ) { + const error = { + errors: { + error: { + cause: 'client_id', + code: '0004', + message: 'API application invalid or incorrect application credentials' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - - let errors = []; + + const errors = []; - if (!headers['x-nintendo-email']) { - errors.push({ - error: { - cause: 'X-Nintendo-EMail', - code: '1105', - message: 'Email address, username, or password, is not valid' - } - }); - } + if (!headers['x-nintendo-email']) { + errors.push({ + error: { + cause: 'X-Nintendo-EMail', + code: '1105', + message: 'Email address, username, or password, is not valid' + } + }); + } - if ( - !headers['authorization'] || - !headers['authorization'].startsWith('Basic ') - ) { - errors.push({ - error: { - cause: 'Authorization', - code: '0002', - message: 'Authorization format is invalid' - } - }); - } + if ( + !headers['authorization'] || + !headers['authorization'].startsWith('Basic ') + ) { + errors.push({ + error: { + cause: 'Authorization', + code: '0002', + message: 'Authorization format is invalid' + } + }); + } - if (errors.length > 0) { - return response.send(json2xml({ - errors: errors - })); - } + if (errors.length > 0) { + return response.send(json2xml({ + errors: errors + })); + } - let user = await helpers.getUserBasic(headers['authorization'].replace('Basic ', ''), headers['x-nintendo-email']); + const user = await helpers.getUserBasic(headers['authorization'].replace('Basic ', ''), headers['x-nintendo-email']); - if (!user) { - let error = { - errors: { - error: { - code: '1105', - message: 'Email address, username, or password, is not valid' - } - } - } + if (!user) { + const error = { + errors: { + error: { + code: '1105', + message: 'Email address, username, or password, is not valid' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - console.log(user) - - let account = helpers.mapUser(user); - - return response.send(json2xml(account)); + const account = helpers.mapUser(user); + + return response.send(json2xml(account)); }); @@ -476,92 +473,92 @@ routes.get('/@me/devices/owner', async (request, response) => { * Description: Gets user profile, seems to be the same as https://account.nintendo.net/v1/api/people/@me/profile */ routes.post('/@me/devices', async (request, response) => { - response.set('Content-Type', 'text/xml'); - response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('Content-Type', 'text/xml'); + response.set('Server', 'Nintendo 3DS (http)'); + response.set('X-Nintendo-Date', new Date().getTime()); - let headers = request.headers, - _POST = request.body; + const headers = request.headers; + const _POST = request.body; - if ( - !headers['x-nintendo-client-id'] || - !headers['x-nintendo-client-secret'] || - !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || - headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] - ) { - let error = { - errors: { - error: { - cause: 'client_id', - code: '0004', - message: 'API application invalid or incorrect application credentials' - } - } - } + if ( + !headers['x-nintendo-client-id'] || + !headers['x-nintendo-client-secret'] || + !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || + headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] + ) { + const error = { + errors: { + error: { + cause: 'client_id', + code: '0004', + message: 'API application invalid or incorrect application credentials' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - - let errors = []; + + const errors = []; - if (!headers['x-nintendo-email']) { - errors.push({ - error: { - cause: 'X-Nintendo-EMail', - code: '1105', - message: 'Email address, username, or password, is not valid' - } - }); - } + if (!headers['x-nintendo-email']) { + errors.push({ + error: { + cause: 'X-Nintendo-EMail', + code: '1105', + message: 'Email address, username, or password, is not valid' + } + }); + } - if ( - !headers['authorization'] || - !headers['authorization'].startsWith('Basic ') - ) { - errors.push({ - error: { - cause: 'Authorization', - code: '0002', - message: 'Authorization format is invalid' - } - }); - } + if ( + !headers['authorization'] || + !headers['authorization'].startsWith('Basic ') + ) { + errors.push({ + error: { + cause: 'Authorization', + code: '0002', + message: 'Authorization format is invalid' + } + }); + } - if (errors.length > 0) { - return response.send(json2xml({ - errors: errors - })); - } + if (errors.length > 0) { + return response.send(json2xml({ + errors: errors + })); + } - let user = await helpers.getUserBasic(headers['authorization'].replace('Basic ', ''), headers['x-nintendo-email']); + const user = await helpers.getUserBasic(headers['authorization'].replace('Basic ', ''), headers['x-nintendo-email']); - if (!user) { - let error = { - errors: { - error: { - code: '1105', - message: 'Email address, username, or password, is not valid' - } - } - } + if (!user) { + const error = { + errors: { + error: { + code: '1105', + message: 'Email address, username, or password, is not valid' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - user.device_attributes = _POST; + user.device_attributes = _POST; - await database.user_collection.update({ - pid: user.pid - }, { - $set: { - device_attributes: user.device_attributes - } - }); + await database.user_collection.update({ + pid: user.pid + }, { + $set: { + device_attributes: user.device_attributes + } + }); - let account = helpers.mapUser(user); - - return response.send(json2xml(account)); + const account = helpers.mapUser(user); + + return response.send(json2xml(account)); }); /** @@ -570,81 +567,82 @@ routes.post('/@me/devices', async (request, response) => { * Description: Returns only user devices */ routes.get('/@me/devices', async (request, response) => { - response.set('Content-Type', 'text/xml'); - response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('Content-Type', 'text/xml'); + response.set('Server', 'Nintendo 3DS (http)'); + response.set('X-Nintendo-Date', new Date().getTime()); - let headers = request.headers; + const headers = request.headers; - if ( - !headers['x-nintendo-client-id'] || - !headers['x-nintendo-client-secret'] || - !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || - headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] - ) { - let error = { - errors: { - error: { - cause: 'client_id', - code: '0004', - message: 'API application invalid or incorrect application credentials' - } - } - } + if ( + !headers['x-nintendo-client-id'] || + !headers['x-nintendo-client-secret'] || + !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || + headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] + ) { + const error = { + errors: { + error: { + cause: 'client_id', + code: '0004', + message: 'API application invalid or incorrect application credentials' + } + } + }; - return response.send(json2xml(error)); - } - - if ( - !headers['authorization'] - ) { - let error = { - errors: { - error: { - cause: 'access_token', - code: '0002', - message: 'Invalid access token' - } - } - } - - return response.send(json2xml(error)); - } - - let user = await helpers.getUser(headers['authorization'].replace('Bearer ','')); - - if (!user) { - let error = { - errors: { - error: { - cause: 'access_token', - code: '0002', - message: 'Invalid access token' - } - } - } return response.send(json2xml(error)); - } + } - response.send(json2xml({ - devices: [ - { - device: { - device_id: headers['x-nintendo-device-id'], - language: headers['accept-language'], - updated: moment().format('YYYY-MM-DDTHH:MM:SS'), - pid: user.pid, - platform_id: headers['x-nintendo-platform-id'], - region: headers['x-nintendo-region'], - serial_number: headers['x-nintendo-serial-number'], - status: 'ACTIVE', - system_version: headers['x-nintendo-system-version'], - type: 'RETAIL', - updated_by: 'USER' - } - } - ] - })); + if ( + !headers['authorization'] + ) { + const error = { + errors: { + error: { + cause: 'access_token', + code: '0002', + message: 'Invalid access token' + } + } + }; + + return response.send(json2xml(error)); + } + + const user = await helpers.getUser(headers['authorization'].replace('Bearer ','')); + + if (!user) { + const error = { + errors: { + error: { + cause: 'access_token', + code: '0002', + message: 'Invalid access token' + } + } + }; + + return response.send(json2xml(error)); + } + + response.send(json2xml({ + devices: [ + { + device: { + device_id: headers['x-nintendo-device-id'], + language: headers['accept-language'], + updated: moment().format('YYYY-MM-DDTHH:MM:SS'), + pid: user.pid, + platform_id: headers['x-nintendo-platform-id'], + region: headers['x-nintendo-region'], + serial_number: headers['x-nintendo-serial-number'], + status: 'ACTIVE', + system_version: headers['x-nintendo-system-version'], + type: 'RETAIL', + updated_by: 'USER' + } + } + ] + })); }); @@ -656,63 +654,64 @@ routes.get('/@me/devices', async (request, response) => { // THIS CURRENTLY DOES NOT UNLINK A USER. THIS IS BECAUSE PRETENDO ACCOUNTS ARE NOT TIED TO CONSOLES // WE ONLY RETURN WHAT THE CONSOLE EXPECTS TO PREVENT CRASHES routes.put('/@me/devices/@current/inactivate', async (request, response) => { - response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('Server', 'Nintendo 3DS (http)'); + response.set('X-Nintendo-Date', new Date().getTime()); - let headers = request.headers; + const headers = request.headers; - if ( - !headers['x-nintendo-client-id'] || - !headers['x-nintendo-client-secret'] || - !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || - headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] - ) { - let error = { - errors: { - error: { - cause: 'client_id', - code: '0004', - message: 'API application invalid or incorrect application credentials' - } - } - } + if ( + !headers['x-nintendo-client-id'] || + !headers['x-nintendo-client-secret'] || + !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || + headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] + ) { + const error = { + errors: { + error: { + cause: 'client_id', + code: '0004', + message: 'API application invalid or incorrect application credentials' + } + } + }; - return response.send(json2xml(error)); - } - - if ( - !headers['authorization'] - ) { - let error = { - errors: { - error: { - cause: 'access_token', - code: '0002', - message: 'Invalid access token' - } - } - } - - return response.send(json2xml(error)); - } - - let user = await helpers.getUser(headers['authorization'].replace('Bearer ','')); - - if (!user) { - let error = { - errors: { - error: { - cause: 'access_token', - code: '0002', - message: 'Invalid access token' - } - } - } return response.send(json2xml(error)); - } + } - response.status(200); - response.end(); + if ( + !headers['authorization'] + ) { + const error = { + errors: { + error: { + cause: 'access_token', + code: '0002', + message: 'Invalid access token' + } + } + }; + + return response.send(json2xml(error)); + } + + const user = await helpers.getUser(headers['authorization'].replace('Bearer ','')); + + if (!user) { + const error = { + errors: { + error: { + cause: 'access_token', + code: '0002', + message: 'Invalid access token' + } + } + }; + + return response.send(json2xml(error)); + } + + response.status(200); + response.end(); }); /** @@ -721,68 +720,69 @@ routes.put('/@me/devices/@current/inactivate', async (request, response) => { * Description: Deletes a NNID */ routes.post('/@me/deletion', async (request, response) => { - response.set('Content-Type', 'text/xml'); - response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('Content-Type', 'text/xml'); + response.set('Server', 'Nintendo 3DS (http)'); + response.set('X-Nintendo-Date', new Date().getTime()); - let headers = request.headers; + const headers = request.headers; - if ( - !headers['x-nintendo-client-id'] || - !headers['x-nintendo-client-secret'] || - !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || - headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] - ) { - let error = { - errors: { - error: { - cause: 'client_id', - code: '0004', - message: 'API application invalid or incorrect application credentials' - } - } - } + if ( + !headers['x-nintendo-client-id'] || + !headers['x-nintendo-client-secret'] || + !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || + headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] + ) { + const error = { + errors: { + error: { + cause: 'client_id', + code: '0004', + message: 'API application invalid or incorrect application credentials' + } + } + }; - return response.send(json2xml(error)); - } - - if ( - !headers['authorization'] - ) { - let error = { - errors: { - error: { - cause: 'access_token', - code: '0002', - message: 'Invalid access token' - } - } - } - - return response.send(json2xml(error)); - } - - let user = await helpers.getUser(headers['authorization'].replace('Bearer ','')); - - if (!user) { - let error = { - errors: { - error: { - cause: 'access_token', - code: '0002', - message: 'Invalid access token' - } - } - } return response.send(json2xml(error)); - } + } - await database.user_collection.remove({ - pid: user.pid - }, true); + if ( + !headers['authorization'] + ) { + const error = { + errors: { + error: { + cause: 'access_token', + code: '0002', + message: 'Invalid access token' + } + } + }; - response.status(200); - response.end(); + return response.send(json2xml(error)); + } + + const user = await helpers.getUser(headers['authorization'].replace('Bearer ','')); + + if (!user) { + const error = { + errors: { + error: { + cause: 'access_token', + code: '0002', + message: 'Invalid access token' + } + } + }; + + return response.send(json2xml(error)); + } + + await database.user_collection.remove({ + pid: user.pid + }, true); + + response.status(200); + response.end(); }); diff --git a/routes/provider/index.js b/routes/provider/index.js index 3da28bb..d08aad9 100644 --- a/routes/provider/index.js +++ b/routes/provider/index.js @@ -1,5 +1,4 @@ const routes = require('express').Router(); -const RateLimit = require('express-rate-limit'); const json2xml = require('json2xml'); const debug = require('../../debugger'); const route_debugger = new debug('Provider Route'.green); @@ -7,7 +6,7 @@ const route_debugger = new debug('Provider Route'.green); route_debugger.log('Loading \'provider\' API routes'); //The game ips and ports are stored here. When the game tries to access its specific server, it will be given the respecive ip and port. -let gamePort = { +const gamePort = { friends: { ip: '10.0.0.225', port: '1300' @@ -16,7 +15,7 @@ let gamePort = { ip: '10.0.0.225', port: '1301' } -} +}; /** * [GET] @@ -24,15 +23,15 @@ let gamePort = { * Description: Gets service token */ routes.get('/service_token/@me', async (request, response) => { - response.set('Content-Type', 'text/xml'); - response.set('Server', 'Nintendo 3DS (http)'); + response.set('Content-Type', 'text/xml'); + response.set('Server', 'Nintendo 3DS (http)'); response.set('X-Nintendo-Date', new Date().getTime()); - let token = { + const token = { service_token: { token: 'pretendo_test' } - } + }; return response.send(json2xml(token)); }); @@ -43,8 +42,8 @@ routes.get('/service_token/@me', async (request, response) => { * Description: Gets nex token */ routes.get('/nex_token/@me', async (request, response) => { - response.set('Content-Type', 'text/xml'); - response.set('Server', 'Nintendo 3DS (http)'); + response.set('Content-Type', 'text/xml'); + response.set('Server', 'Nintendo 3DS (http)'); response.set('X-Nintendo-Date', new Date().getTime()); let ip = null; @@ -67,21 +66,21 @@ routes.get('/nex_token/@me', async (request, response) => { break; } - if(ip==null || port==null){ - let error = { - errors: { - error: { - cause: 'No game server', - code: '9999', - message: 'No server found' - } - } - } + if (ip==null || port==null){ + const error = { + errors: { + error: { + cause: 'No game server', + code: '9999', + message: 'No server found' + } + } + }; return response.send(json2xml(error)); } - let token = { + const token = { nex_token: { host: ip, nex_password: 'pretendo', @@ -89,7 +88,8 @@ routes.get('/nex_token/@me', async (request, response) => { port: port, token: 'pretendo_test' } - } + }; + return response.send(json2xml(token)); }); diff --git a/routes/root/index.js b/routes/root/index.js index 8fd8596..a7228db 100644 --- a/routes/root/index.js +++ b/routes/root/index.js @@ -10,7 +10,7 @@ route_debugger.log('Loading \'root/misc\' API routes'); * Description: tests the validity of this server by returning a predefined message */ routes.get('/isthisworking', async (req, res) => { - return res.send('{"server": "account.nintendo.net"}') + return res.send('{"server": "account.nintendo.net"}'); }); -module.exports = routes +module.exports = routes; diff --git a/routes/support/index.js b/routes/support/index.js index 6d20493..63c4504 100644 --- a/routes/support/index.js +++ b/routes/support/index.js @@ -1,6 +1,5 @@ const dns = require('dns'); const routes = require('express').Router(); -const helpers = require('../../helpers'); const constants = require('../../constants'); const database = require('../../db'); const json2xml = require('json2xml'); @@ -15,82 +14,82 @@ route_debugger.log('Loading \'support\' API routes'); * Description: Validates an email by attempting to ping it's mail server */ routes.post('/validate/email', async (request, response) => { - response.set('Content-Type', 'text/xml'); - response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('Content-Type', 'text/xml'); + response.set('Server', 'Nintendo 3DS (http)'); + response.set('X-Nintendo-Date', new Date().getTime()); - let POST = request.body, - headers = request.headers - email = POST.email; + const POST = request.body; + const headers = request.headers; + const email = POST.email; - if ( - !headers['x-nintendo-client-id'] || - !headers['x-nintendo-client-secret'] || - !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || - headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] - ) { - let error = { - errors: { - error: { - cause: 'client_id', - code: '0004', - message: 'API application invalid or incorrect application credentials' - } - } - } + if ( + !headers['x-nintendo-client-id'] || + !headers['x-nintendo-client-secret'] || + !constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] || + headers['x-nintendo-client-secret'] !== constants.VALID_CLIENT_ID_SECRET_PAIRS[headers['x-nintendo-client-id']] + ) { + const error = { + errors: { + error: { + cause: 'client_id', + code: '0004', + message: 'API application invalid or incorrect application credentials' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - if ( - !headers['content-type'] || - headers['content-type'].toLowerCase() !== 'application/x-www-form-urlencoded' - ) { - let error = { - errors: { - error: { - code: '2001', - message: 'Internal server error' - } - } - } + if ( + !headers['content-type'] || + headers['content-type'].toLowerCase() !== 'application/x-www-form-urlencoded' + ) { + const error = { + errors: { + error: { + code: '2001', + message: 'Internal server error' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - if (!email) { - let error = { - errors: { - error: { - cause: 'email', - code: '0103', - message: 'Email format is invalid' - } - } - } + if (!email) { + const error = { + errors: { + error: { + cause: 'email', + code: '0103', + message: 'Email format is invalid' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - let domain = email.split('@')[1]; + const domain = email.split('@')[1]; - dns.resolveMx(domain, (error, addr) => { - if (error) { - let error = { - errors: { - error: { - code: '1126', - message: 'The domain "' + domain + '" is not accessible.' - } - } - } + dns.resolveMx(domain, (error) => { + if (error) { + const error = { + errors: { + error: { + code: '1126', + message: 'The domain "' + domain + '" is not accessible.' + } + } + }; - return response.send(json2xml(error)); - } + return response.send(json2xml(error)); + } - response.status(200); - response.end(); - }); + response.status(200); + response.end(); + }); }); @@ -100,64 +99,65 @@ routes.post('/validate/email', async (request, response) => { * Description: Confirms an email */ routes.put('/email_confirmation/:pid/:code', async (request, response) => { - response.set('Content-Type', 'text/xml'); - response.set('Server', 'Nintendo 3DS (http)'); - response.set('X-Nintendo-Date', new Date().getTime()); + response.set('Content-Type', 'text/xml'); + response.set('Server', 'Nintendo 3DS (http)'); + response.set('X-Nintendo-Date', new Date().getTime()); - let user = await database.user_collection.findOne({ - pid: Number(request.params.pid) - }); + const user = await database.user_collection.findOne({ + pid: Number(request.params.pid) + }); if (!user) { - let error = { - errors: { - error: { - code: '0130', - message: 'PID has not been registered yet' - } - } - } - return response.send(json2xml(error)); - } - - if (user.sensitive.email_confirms.code !== request.params.code) { - let error = { - errors: { - error: { - code: '0116', - message: 'Missing or invalid verification code' - } - } - } + const error = { + errors: { + error: { + code: '0130', + message: 'PID has not been registered yet' + } + } + }; return response.send(json2xml(error)); } - - user.email.reachable = 'Y'; - user.email.validated = 'Y'; + + if (user.sensitive.email_confirms.code !== request.params.code) { + const error = { + errors: { + error: { + code: '0116', + message: 'Missing or invalid verification code' + } + } + }; - await database.user_collection.update({ - pid: user.pid - }, { - $set: { - email: user.email - } - }); + return response.send(json2xml(error)); + } + + user.email.reachable = 'Y'; + user.email.validated = 'Y'; - user.sensitive.email_confirms.token = null; - user.sensitive.email_confirms.code = null; + await database.user_collection.update({ + pid: user.pid + }, { + $set: { + email: user.email + } + }); - await database.user_collection.update({ - pid: user.pid - }, { - $set: { - sensitive: user.sensitive - } - }); + user.sensitive.email_confirms.token = null; + user.sensitive.email_confirms.code = null; - response.send(json2xml({ - email: null - })); + await database.user_collection.update({ + pid: user.pid + }, { + $set: { + sensitive: user.sensitive + } + }); + + response.send(json2xml({ + email: null + })); }); diff --git a/server.js b/server.js index 93b04f2..89f3454 100644 --- a/server.js +++ b/server.js @@ -1,31 +1,30 @@ -const path = require('path'); const express = require('express'); const subdomain = require('express-subdomain'); const table = require('cli-table'); -const colors = require('colors'); const morgan = require('morgan'); const XMLMiddleware = require('./xml-middleware'); const debug = require('./debugger'); -const config = require('./config.json') +const config = require('./config.json'); const app = express(); const router = express.Router(); -const testing_env = process.env.NODE_ENV !== "production" +const testing_env = process.env.NODE_ENV !== 'production'; +require('colors'); const server_debugger = new debug('Server'); server_debugger.log('Importing routes'); // API routes const ROUTES = { - ACCOUNT: require('./routes/account'), - ADMIN: require('./routes/admin'), - CONTENT: require('./routes/content'), - DEVICES: require('./routes/devices'), - OAUTH20: require('./routes/oauth20'), - PEOPLE: require('./routes/people'), - PROVIDER: require('./routes/provider'), - SUPPORT: require('./routes/support'), - ROOT: require('./routes/root') -} + ACCOUNT: require('./routes/account'), + ADMIN: require('./routes/admin'), + CONTENT: require('./routes/content'), + DEVICES: require('./routes/devices'), + OAUTH20: require('./routes/oauth20'), + PEOPLE: require('./routes/people'), + PROVIDER: require('./routes/provider'), + SUPPORT: require('./routes/support'), + ROOT: require('./routes/root') +}; // START APPLICATION app.set('etag', false); @@ -36,76 +35,78 @@ app.use(morgan('dev')); router.use(express.json()); router.use(XMLMiddleware()); router.use(express.urlencoded({ - extended: true + extended: true })); server_debugger.log('Creating \'account\' subdomain'); // Create subdomain if (testing_env === false) { - app.use(subdomain('account', router)); + app.use(subdomain('account', router)); } else { - app.use(router) + app.use(router); } server_debugger.log('Applying imported routes'); // Setup routes -router.use('/account', ROUTES.ACCOUNT); // Account API routes (only used for email confirmation) -router.use('/v1/api/admin', ROUTES.ADMIN); // Admin API routes +router.use('/account', ROUTES.ACCOUNT); // Account API routes (only used for email confirmation) +router.use('/v1/api/admin', ROUTES.ADMIN); // Admin API routes router.use('/v1/api/content', ROUTES.CONTENT); // Content API routes router.use('/v1/api/devices', ROUTES.DEVICES); // Device API routes router.use('/v1/api/oauth20', ROUTES.OAUTH20); // oAuth API routes -router.use('/v1/api/people', ROUTES.PEOPLE); // People API routes +router.use('/v1/api/people', ROUTES.PEOPLE); // People API routes router.use('/v1/api/provider', ROUTES.PROVIDER); // Provider API routes -router.use('/v1/api/support', ROUTES.SUPPORT); // Support API routes -router.use('/', ROUTES.ROOT); // Root/Misc routes +router.use('/v1/api/support', ROUTES.SUPPORT); // Support API routes +router.use('/', ROUTES.ROOT); // Root/Misc routes function getRoutes(_router) { - let routes, ret = []; - _router.forEach(layer => { - if (layer.name == 'router') { - routes = layer; - } - }); + const ret = []; + let routes; - let stack = routes.handle.stack; + _router.forEach(layer => { + if (layer.name == 'router') { + routes = layer; + } + }); - stack.forEach(layer => { - if (layer.handle.stack) { - let base = layer.regexp.toString() - .replace('\\/?', '') - .replace('(?=\\/|$)', '$') - .match(/^\/\^((?:\\[.*+?^${}()|[\]\\\/]|[^.*+?^${}()|[\]\\\/])*)\$\//)[1] - .replace(/\\(.)/g, '$1'); + const stack = routes.handle.stack; - layer.handle.stack.forEach(mini_layer => { - ret.push({ - method: Object.keys(mini_layer.route.methods)[0].toUpperCase().replace('_', ''), - path: base + mini_layer.route.path - }) - }) - } - }); + stack.forEach(layer => { + if (layer.handle.stack) { + const base = layer.regexp.toString() + .replace('\\/?', '') + .replace('(?=\\/|$)', '$') + .match(/^\/\^((?:\\[.*+?^${}()|[\]\\/]|[^.*+?^${}()|[\]\\/])*)\$\//)[1] + .replace(/\\(.)/g, '$1'); - return ret; + layer.handle.stack.forEach(mini_layer => { + ret.push({ + method: Object.keys(mini_layer.route.methods)[0].toUpperCase().replace('_', ''), + path: base + mini_layer.route.path + }); + }); + } + }); + + return ret; } server_debugger.log('Creating 404 status handler'); // 404 handler router.use((request, response) => { - response.status(404); - response.send(); + response.status(404); + response.send(); }); server_debugger.log('Creating non-404 status handler'); // non-404 error handler router.use((error, request, response) => { - let status = error.status || 500; - response.status(status); - response.json({ - app: 'api', - status: status, - error: error.message - }); + const status = error.status || 500; + response.status(status); + response.json({ + app: 'api', + status: status, + error: error.message + }); }); @@ -113,19 +114,19 @@ router.use((error, request, response) => { server_debugger.log('Starting server'); // Starts the server app.listen(config.http.port, () => { - let route_table = new table({ - head: ["Method", "Path"] - }), - routes = getRoutes(app._router.stack); + const route_table = new table({ + head: ['Method', 'Path'] + }); + const routes = getRoutes(app._router.stack); - routes.forEach(route => { - let obj = {}; - obj[route.method] = route.path; + routes.forEach(route => { + const obj = {}; + obj[route.method] = route.path; - route_table.push(obj) - }); + route_table.push(obj); + }); - console.log(route_table.toString()); + console.log(route_table.toString()); - server_debugger.log('Started '.green + 'on port '.blue + new String(config.http.port).yellow); + server_debugger.log('Started '.green + 'on port '.blue + new String(config.http.port).yellow); }); diff --git a/xml-middleware.js b/xml-middleware.js index f1e6e01..6d64a25 100644 --- a/xml-middleware.js +++ b/xml-middleware.js @@ -3,36 +3,36 @@ const XML = require('pixl-xml'); module.exports = middleware; function middleware() { - return XMLMiddleware; + return XMLMiddleware; - function XMLMiddleware(request, response, next) { - if (request.method == 'POST' || request.method == 'PUT') { - let headers = request.headers, - body = ''; - - if ( - !headers['content-type'] || - headers['content-type'].toLowerCase() !== 'application/xml' - ) { - return next(); - } + function XMLMiddleware(request, response, next) { + if (request.method == 'POST' || request.method == 'PUT') { + const headers = request.headers; + let body = ''; + + if ( + !headers['content-type'] || + headers['content-type'].toLowerCase() !== 'application/xml' + ) { + return next(); + } - request.setEncoding('utf-8'); - request.on('data', (chunk) => { - body += chunk; - }); + request.setEncoding('utf-8'); + request.on('data', (chunk) => { + body += chunk; + }); - request.on('end', () => { - try { - request.body = XML.parse(body); - } catch (error) { - return next(); - } + request.on('end', () => { + try { + request.body = XML.parse(body); + } catch (error) { + return next(); + } - next(); - }); - } else { - next(); - } - } + next(); + }); + } else { + next(); + } + } } \ No newline at end of file