From aa480673d2ef5d3d37155134450a0dc93b760102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B3pez=20Guimaraes?= Date: Sun, 5 Nov 2023 01:05:24 +0000 Subject: [PATCH 1/4] Better handling of system transfered devices If a user performs a system transfer, we can't guarantee the validity of the linked PIDs to a device, not this device's existance on the database. Add them to the database if necessary. --- src/middleware/nasc.ts | 63 +++++++++++++++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 10 deletions(-) diff --git a/src/middleware/nasc.ts b/src/middleware/nasc.ts index 7a79e85..8dd6bbe 100644 --- a/src/middleware/nasc.ts +++ b/src/middleware/nasc.ts @@ -95,6 +95,13 @@ async function NASCMiddleware(request: express.Request, response: express.Respon return; } + const nexAccount: HydratedNEXAccountDocument | null = await NEXAccount.findOne({ pid }); + + if (!nexAccount || nexAccount.access_level < 0) { + response.status(200).send(nascError('102').toString()); + return; + } + let device: HydratedDeviceDocument | null = await Device.findOne({ fcdcert_hash: fcdcertHash, }); @@ -108,13 +115,56 @@ async function NASCMiddleware(request: express.Request, response: express.Respon if (pid) { const linkedPIDs: number[] = device.linked_pids; + // * If a user performs a system transfer from + // * a console to another using a Nintendo account + // * during the transfer and both consoles have + // * a Pretendo account, the devices will be swapped + // * since we check it using the LFCS. + // * + // * So, the linked PIDs won't have the user's PID + // * anymore. if (!linkedPIDs.includes(pid)) { - response.status(200).send(nascError('102').toString()); - return; + const session: mongoose.ClientSession = await databaseConnection().startSession(); + await session.startTransaction(); + + device.linked_pids.push(pid); + + await device.save({ session }); + + await session.commitTransaction(); } } } + // * Workaround for edge case on system transfers + // * if a console that has a Pretendo account performs + // * a system transfer using the Nintendo account to + // * another that doesn't have a Pretendo account. + // * + // * This would make the Pretendo account to not have + // * a device on the database. + // * + // * TODO: With this change, now multiple devices can + // * have the same serial number and MAC address. + // * Do we want this? If not, are there other solutions? + if (!device && pid) { + const session: mongoose.ClientSession = await databaseConnection().startSession(); + await session.startTransaction(); + + device = new Device({ + model, + serial: serialNumber, + environment, + mac_hash: macAddressHash, + fcdcert_hash: fcdcertHash, + linked_pids: [pid] + }); + + await device.save({ session }); + + await session.commitTransaction(); + } + if (titleID === '0004013000003202') { if (password && !pid && !pidHmac) { // Register new user @@ -183,13 +233,6 @@ async function NASCMiddleware(request: express.Request, response: express.Respon } } - const nexAccount: HydratedNEXAccountDocument | null = await NEXAccount.findOne({ pid }); - - if (!nexAccount || nexAccount.access_level < 0) { - response.status(200).send(nascError('102').toString()); - return; - } - request.nexAccount = nexAccount; return next(); @@ -234,4 +277,4 @@ function validNintendoMACAddress(macAddress: string): boolean { return MAC_REGEX.test(macAddress); } -export default NASCMiddleware; \ No newline at end of file +export default NASCMiddleware; From dc7d44baf0b9eba6ce8494124ab33d6ee35fe8a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B3pez=20Guimaraes?= Date: Sun, 5 Nov 2023 12:08:47 +0000 Subject: [PATCH 2/4] Remove redundant transactions We can update the data directly without a transaction. --- src/middleware/nasc.ts | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/middleware/nasc.ts b/src/middleware/nasc.ts index 8dd6bbe..c55135a 100644 --- a/src/middleware/nasc.ts +++ b/src/middleware/nasc.ts @@ -124,14 +124,9 @@ async function NASCMiddleware(request: express.Request, response: express.Respon // * So, the linked PIDs won't have the user's PID // * anymore. if (!linkedPIDs.includes(pid)) { - const session: mongoose.ClientSession = await databaseConnection().startSession(); - await session.startTransaction(); - device.linked_pids.push(pid); - await device.save({ session }); - - await session.commitTransaction(); + await device.save(); } } } @@ -148,9 +143,6 @@ async function NASCMiddleware(request: express.Request, response: express.Respon // * have the same serial number and MAC address. // * Do we want this? If not, are there other solutions? if (!device && pid) { - const session: mongoose.ClientSession = await databaseConnection().startSession(); - await session.startTransaction(); - device = new Device({ model, serial: serialNumber, @@ -160,9 +152,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon linked_pids: [pid] }); - await device.save({ session }); - - await session.commitTransaction(); + await device.save(); } if (titleID === '0004013000003202') { From 20eed7fc96b572aacc2efb04b0463bc75e15d6b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B3pez=20Guimaraes?= Date: Mon, 6 Nov 2023 21:59:12 +0000 Subject: [PATCH 3/4] Fix NASC registration path --- src/middleware/nasc.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/middleware/nasc.ts b/src/middleware/nasc.ts index c55135a..ca5a241 100644 --- a/src/middleware/nasc.ts +++ b/src/middleware/nasc.ts @@ -95,13 +95,17 @@ async function NASCMiddleware(request: express.Request, response: express.Respon return; } - const nexAccount: HydratedNEXAccountDocument | null = await NEXAccount.findOne({ pid }); + let nexAccount: HydratedNEXAccountDocument | null = null; + if (pid) { + nexAccount = await NEXAccount.findOne({ pid }); - if (!nexAccount || nexAccount.access_level < 0) { - response.status(200).send(nascError('102').toString()); - return; + if (!nexAccount || nexAccount.access_level < 0) { + response.status(200).send(nascError('102').toString()); + return; + } } + let device: HydratedDeviceDocument | null = await Device.findOne({ fcdcert_hash: fcdcertHash, }); @@ -164,7 +168,7 @@ async function NASCMiddleware(request: express.Request, response: express.Respon try { // Create new NEX account - const nexAccount: HydratedNEXAccountDocument = new NEXAccount({ + nexAccount = new NEXAccount({ device_type: '3ds', password }); From 603b209cb57f4e3d0e30a323f227ca201725755c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20L=C3=B3pez=20Guimaraes?= Date: Sat, 13 Apr 2024 22:37:29 +0100 Subject: [PATCH 4/4] nasc: Add more integrity checks --- src/middleware/nasc.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/middleware/nasc.ts b/src/middleware/nasc.ts index ca5a241..4cc657f 100644 --- a/src/middleware/nasc.ts +++ b/src/middleware/nasc.ts @@ -122,8 +122,8 @@ async function NASCMiddleware(request: express.Request, response: express.Respon // * If a user performs a system transfer from // * a console to another using a Nintendo account // * during the transfer and both consoles have - // * a Pretendo account, the devices will be swapped - // * since we check it using the LFCS. + // * a Pretendo account, the new device won't have + // * the user's PID. // * // * So, the linked PIDs won't have the user's PID // * anymore. @@ -133,6 +133,16 @@ async function NASCMiddleware(request: express.Request, response: express.Respon await device.save(); } } + + if (device.serial !== serialNumber) { + response.status(200).send(nascError('102').toString()); + return; + } + + if (device.mac_hash !== macAddressHash) { + response.status(200).send(nascError('102').toString()); + return; + } } // * Workaround for edge case on system transfers @@ -142,10 +152,6 @@ async function NASCMiddleware(request: express.Request, response: express.Respon // * // * This would make the Pretendo account to not have // * a device on the database. - // * - // * TODO: With this change, now multiple devices can - // * have the same serial number and MAC address. - // * Do we want this? If not, are there other solutions? if (!device && pid) { device = new Device({ model,