From 635e830af3d4e8f082f63fec75aa8a0b5a034f49 Mon Sep 17 00:00:00 2001 From: Jonathan Barrow Date: Mon, 26 Sep 2022 22:48:56 -0400 Subject: [PATCH] /v1/people POST not uses mongo transaction --- src/services/nnid/routes/people.js | 155 +++++++++++++++++------------ 1 file changed, 91 insertions(+), 64 deletions(-) diff --git a/src/services/nnid/routes/people.js b/src/services/nnid/routes/people.js index ebc058a..2ceffa1 100644 --- a/src/services/nnid/routes/people.js +++ b/src/services/nnid/routes/people.js @@ -8,6 +8,7 @@ const deviceCertificateMiddleware = require('../../../middleware/device-certific const ratelimit = require('../../../middleware/ratelimit'); const database = require('../../../database'); const mailer = require('../../../mailer'); +const logger = require('../../../../logger'); require('moment-timezone'); /** @@ -73,88 +74,114 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request, respons }).end()); } - // Create new NEX account - const newNEXAccount = new NEXAccount({ - pid: 0, - password: '', - owning_pid: 0, - }); - await newNEXAccount.save(); - const creationDate = moment().format('YYYY-MM-DDTHH:MM:SS'); + let pnid; + let nexAccount; - const document = { - pid: newNEXAccount.get('pid'), - creation_date: creationDate, - updated: creationDate, - username: person.get('user_id'), - password: person.get('password'), // will be hashed before saving - birthdate: person.get('birth_date'), - gender: person.get('gender'), - country: person.get('country'), - language: person.get('language'), - email: { - address: person.get('email').get('address'), - primary: person.get('email').get('primary') === 'Y', - parent: person.get('email').get('parent') === 'Y', - reachable: false, - validated: person.get('email').get('validated') === 'Y', - id: crypto.randomBytes(4).readUInt32LE() - }, - region: person.get('region'), - timezone: { - name: person.get('tz_name'), - offset: (moment.tz(person.get('tz_name')).utcOffset() * 60) - }, - mii: { - name: person.get('mii').get('name'), - primary: person.get('mii').get('name') === 'Y', - data: person.get('mii').get('data'), - id: crypto.randomBytes(4).readUInt32LE(), - hash: crypto.randomBytes(7).toString('hex'), - image_url: '', // deprecated, will be removed in the future - image_id: crypto.randomBytes(4).readUInt32LE() - }, - flags: { - active: true, - marketing: person.get('marketing_flag') === 'Y', - off_device: person.get('off_device_flag') === 'Y' - }, - validation: { - email_code: 1, // will be overwritten before saving - email_token: '' // will be overwritten before saving - } - }; + const session = await database.connection.startSession(); + await session.startTransaction(); - const newPNID = new PNID(document); - await newPNID.save(); + try { + const nexAccountResult = await NEXAccount.create([{ + pid: 0, + password: '', + owning_pid: 0, + }], { session }); - // Quick hack to get the PIDs to match - // TODO: Change this - // NN with a NNID will always use the NNID PID - // even if the provided NEX PID is different - // To fix this we make them the same PID - await NEXAccount.updateOne({ pid: newNEXAccount.get('pid') }, { - owning_pid: newNEXAccount.get('pid') - }); + nexAccount = nexAccountResult[0]; + + const pnidResult = await PNID.create([{ + pid: nexAccount.get('pid'), + creation_date: creationDate, + updated: creationDate, + username: person.get('user_id'), + password: person.get('password'), // will be hashed before saving + birthdate: person.get('birth_date'), + gender: person.get('gender'), + country: person.get('country'), + language: person.get('language'), + email: { + address: person.get('email').get('address'), + primary: person.get('email').get('primary') === 'Y', + parent: person.get('email').get('parent') === 'Y', + reachable: false, + validated: person.get('email').get('validated') === 'Y', + id: crypto.randomBytes(4).readUInt32LE() + }, + region: person.get('region'), + timezone: { + name: person.get('tz_name'), + offset: (moment.tz(person.get('tz_name')).utcOffset() * 60) + }, + mii: { + name: person.get('mii').get('name'), + primary: person.get('mii').get('name') === 'Y', + data: person.get('mii').get('data'), + id: crypto.randomBytes(4).readUInt32LE(), + hash: crypto.randomBytes(7).toString('hex'), + image_url: '', // deprecated, will be removed in the future + image_id: crypto.randomBytes(4).readUInt32LE() + }, + flags: { + active: true, + marketing: person.get('marketing_flag') === 'Y', + off_device: person.get('off_device_flag') === 'Y' + }, + validation: { + email_code: 1, // will be overwritten before saving + email_token: '' // will be overwritten before saving + } + }], { session }) + + pnid = pnidResult[0]; + + // Quick hack to get the PIDs to match + // TODO: Change this + // NN with a NNID will always use the NNID PID + // even if the provided NEX PID is different + // To fix this we make them the same PID + await NEXAccount.updateOne({ pid: nexAccount.get('pid') }, { + owning_pid: nexAccount.get('pid') + }, { session }); + + await session.commitTransaction(); + } catch (error) { + logger.error('[POST] /v1/api/people: ' + error); + + await session.abortTransaction(); + + response.status(400); + + return response.send(xmlbuilder.create({ + error: { + cause: 'Bad Request', + code: '1600', + message: 'Unable to process request' + } + }).end()); + } finally { + // * This runs regardless of failure + // * Returning on catch will not prevent this from running + await session.endSession(); + } await mailer.send( - newPNID.get('email'), + pnid.get('email'), '[Pretendo Network] Please confirm your e-mail address', `Hello, Your Pretendo Network ID activation is almost complete. Please click the link below to confirm your e-mail address and complete the activation process. - https://account.pretendo.cc/account/email-confirmation?token=` + newPNID.get('identification.email_token') + ` + https://account.pretendo.cc/account/email-confirmation?token=` + pnid.get('identification.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: ` + newPNID.get('identification.email_code') + '>>' + <<Confirmation code: ` + pnid.get('identification.email_code') + '>>' ); response.send(xmlbuilder.create({ person: { - pid: newPNID.get('pid') + pid: pnid.get('pid') } }).end()); });