From 99aec607fa41a98e8a2f1a2f846a3d412f78869d Mon Sep 17 00:00:00 2001 From: William Oldham Date: Sat, 22 Mar 2025 21:36:04 +0000 Subject: [PATCH] fix: apply production hot-patches Co-authored-by: Jonathan Barrow --- src/database.ts | 7 ++++++- src/middleware/pnid.ts | 13 ++++++++++++- src/nintendo-certificate.ts | 11 ++++++++++- src/services/api/routes/v1/forgotPassword.ts | 1 + src/services/grpc/api/forgot-password.ts | 2 ++ src/services/nasc/routes/ac.ts | 4 ++-- src/services/nnas/routes/support.ts | 6 +++--- 7 files changed, 36 insertions(+), 8 deletions(-) diff --git a/src/database.ts b/src/database.ts index 72c1f7e..251d8ea 100644 --- a/src/database.ts +++ b/src/database.ts @@ -104,12 +104,17 @@ export async function getPNIDByBasicAuth(token: string): Promise { +export async function getPNIDByTokenAuth(token: string, allowedTypes?: number[]): Promise { verifyConnected(); try { const decryptedToken = decryptToken(Buffer.from(token, 'hex')); const unpackedToken = unpackToken(decryptedToken); + + if (allowedTypes && !allowedTypes.includes(unpackedToken.system_type)) { + return null; + } + const pnid = await getPNIDByPID(unpackedToken.pid); if (pnid) { diff --git a/src/middleware/pnid.ts b/src/middleware/pnid.ts index f858839..5ee7f6b 100644 --- a/src/middleware/pnid.ts +++ b/src/middleware/pnid.ts @@ -21,9 +21,20 @@ async function PNIDMiddleware(request: express.Request, response: express.Respon } if (type === 'Basic') { + if (!request.path.includes('v1/api/people/@me/devices')) { + response.status(401).send(xmlbuilder.create({ + errors: { + error: { + code: '1105', + message: 'Email address, username, or password, is not valid' + } + } + }).end()); + } + pnid = await getPNIDByBasicAuth(token); } else { - pnid = await getPNIDByTokenAuth(token); + pnid = await getPNIDByTokenAuth(token, [1, 2]); } if (!pnid) { diff --git a/src/nintendo-certificate.ts b/src/nintendo-certificate.ts index 38e7a1a..650bc00 100644 --- a/src/nintendo-certificate.ts +++ b/src/nintendo-certificate.ts @@ -125,6 +125,11 @@ class NintendoCertificate { this._certificateBody = this._certificate.subarray(0x4 + signatureTypeSizes.SIZE + signatureTypeSizes.PADDING_SIZE); this.signature = this._certificate.subarray(0x4, 0x4 + signatureTypeSizes.SIZE); + + const padding = this._certificate.subarray(0x4 + signatureTypeSizes.SIZE, 0x4 + signatureTypeSizes.SIZE + signatureTypeSizes.PADDING_SIZE); + + this.valid = padding.every(byte => byte === 0); + this.issuer = this._certificate.subarray(0x80, 0xC0).toString().split('\0')[0]; this.keyType = this._certificate.readUInt32BE(0xC0); this.certificateName = this._certificate.subarray(0xC4, 0x104).toString().split('\0')[0]; @@ -137,7 +142,11 @@ class NintendoCertificate { this.consoleType = '3ds'; } - this._verifySignature(); + if (!this.valid) { + return; + } + + this._verifySignatureECDSA(); } } diff --git a/src/services/api/routes/v1/forgotPassword.ts b/src/services/api/routes/v1/forgotPassword.ts index 99f127d..fd791d1 100644 --- a/src/services/api/routes/v1/forgotPassword.ts +++ b/src/services/api/routes/v1/forgotPassword.ts @@ -58,6 +58,7 @@ router.post('/', async (request: express.Request, response: express.Response): P } if (pnid) { + console.log('API forgot password for', pnid); await sendForgotPasswordEmail(pnid); } diff --git a/src/services/grpc/api/forgot-password.ts b/src/services/grpc/api/forgot-password.ts index 45b9b6e..a3a3bf7 100644 --- a/src/services/grpc/api/forgot-password.ts +++ b/src/services/grpc/api/forgot-password.ts @@ -21,6 +21,8 @@ export async function forgotPassword(request: ForgotPasswordRequest): Promise