mirror of
https://github.com/PretendoNetwork/account.git
synced 2026-04-24 14:59:39 -05:00
feat(nasc): use NASC keyhash for service tokens
This commit is contained in:
parent
dbac688cfa
commit
d174cf4dbb
|
|
@ -6,10 +6,10 @@ import { connection as databaseConnection } from '@/database';
|
|||
import NintendoCertificate from '@/nintendo-certificate';
|
||||
import { LOG_ERROR } from '@/logger';
|
||||
import type express from 'express';
|
||||
import type { NASCRequestParams } from '@/types/services/nasc/request-params';
|
||||
import type { NASCACRequestParams } from '@/types/services/nasc/ac-request-params';
|
||||
|
||||
async function NASCMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): Promise<void> {
|
||||
const requestParams: NASCRequestParams = request.body;
|
||||
const requestParams: NASCACRequestParams = request.body;
|
||||
|
||||
if (!requestParams.action ||
|
||||
!requestParams.fcdcert ||
|
||||
|
|
@ -37,15 +37,15 @@ async function NASCMiddleware(request: express.Request, response: express.Respon
|
|||
let pidHmac = '';
|
||||
let password = '';
|
||||
|
||||
if (requestParams.userid) {
|
||||
if ('userid' in requestParams) {
|
||||
pid = Number(nintendoBase64Decode(requestParams.userid).toString());
|
||||
}
|
||||
|
||||
if (requestParams.uidhmac) {
|
||||
if ('uidhmac' in requestParams) {
|
||||
pidHmac = nintendoBase64Decode(requestParams.uidhmac).toString();
|
||||
}
|
||||
|
||||
if (requestParams.passwd) {
|
||||
if ('passwd' in requestParams) {
|
||||
password = nintendoBase64Decode(requestParams.passwd).toString();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { nintendoBase64Encode, nintendoBase64Decode, nascDateTime, nascError, cr
|
|||
import { getServerByTitleID } from '@/database';
|
||||
import { IndependentServiceToken } from '@/models/independent_service_token';
|
||||
import { NEXToken } from '@/models/nex_token';
|
||||
import type { NASCRequestParams } from '@/types/services/nasc/request-params';
|
||||
import type { NASCACRequestParams, NASCLoginACRequestParams, NASCServiceTokenACRequestParams } from '@/types/services/nasc/ac-request-params';
|
||||
import type { HydratedServerDocument } from '@/types/mongoose/server';
|
||||
|
||||
const router = express.Router();
|
||||
|
|
@ -17,7 +17,7 @@ const router = express.Router();
|
|||
* Description: Gets a NEX server address and token
|
||||
*/
|
||||
router.post('/', async (request: express.Request, response: express.Response): Promise<void> => {
|
||||
const requestParams: NASCRequestParams = request.body;
|
||||
const requestParams: NASCACRequestParams = request.body;
|
||||
const action = nintendoBase64Decode(requestParams.action).toString();
|
||||
const titleID = nintendoBase64Decode(requestParams.titleid).toString();
|
||||
const gameServerID = nintendoBase64Decode(requestParams.gameid).toString();
|
||||
|
|
@ -63,17 +63,18 @@ router.post('/', async (request: express.Request, response: express.Response): P
|
|||
|
||||
switch (action) {
|
||||
case 'LOGIN':
|
||||
responseData = await processLoginRequest(server, nexAccount.pid, titleID);
|
||||
responseData = await processLoginRequest(server, nexAccount.pid, requestParams as NASCLoginACRequestParams); // TODO - Remove this "as" with field checking
|
||||
break;
|
||||
case 'SVCLOC':
|
||||
responseData = await processServiceTokenRequest(server, nexAccount.pid, titleID);
|
||||
responseData = await processServiceTokenRequest(server, nexAccount.pid, requestParams as NASCServiceTokenACRequestParams); // TODO - Remove this "as" with field checking
|
||||
break;
|
||||
}
|
||||
|
||||
response.status(200).send(responseData.toString());
|
||||
});
|
||||
|
||||
async function processLoginRequest(server: HydratedServerDocument, pid: number, titleID: string): Promise<URLSearchParams> {
|
||||
async function processLoginRequest(server: HydratedServerDocument, pid: number, requestParams: NASCLoginACRequestParams): Promise<URLSearchParams> {
|
||||
const titleID = nintendoBase64Decode(requestParams.titleid).toString();
|
||||
const nexToken = await NEXToken.create({
|
||||
token: nintendoBase64Encode(crypto.randomBytes(112)),
|
||||
game_server_id: server.game_server_id,
|
||||
|
|
@ -96,7 +97,8 @@ async function processLoginRequest(server: HydratedServerDocument, pid: number,
|
|||
});
|
||||
}
|
||||
|
||||
async function processServiceTokenRequest(server: HydratedServerDocument, pid: number, titleID: string): Promise<URLSearchParams> {
|
||||
async function processServiceTokenRequest(server: HydratedServerDocument, pid: number, requestParams: NASCServiceTokenACRequestParams): Promise<URLSearchParams> {
|
||||
const titleID = nintendoBase64Decode(requestParams.titleid).toString();
|
||||
const serviceTokenOptions = {
|
||||
pid: pid,
|
||||
title_id: titleID,
|
||||
|
|
@ -106,7 +108,7 @@ async function processServiceTokenRequest(server: HydratedServerDocument, pid: n
|
|||
|
||||
const serviceToken = await IndependentServiceToken.create({
|
||||
token: nintendoBase64Encode(createServiceToken(server, serviceTokenOptions)),
|
||||
client_id: server.game_server_id,
|
||||
client_id: nintendoBase64Decode(requestParams.keyhash).toString(),
|
||||
title_id: serviceTokenOptions.title_id,
|
||||
pid: serviceTokenOptions.pid,
|
||||
info: {
|
||||
|
|
|
|||
216
src/types/services/nasc/ac-request-params.ts
Normal file
216
src/types/services/nasc/ac-request-params.ts
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
/**
|
||||
* Çommon request parameters found on all NASC `ac` requests.
|
||||
* All fields are base64 encoded using Nintendo's custom alphabet:
|
||||
* '+' -> '.', '/' -> '-', '=' -> '*'
|
||||
*/
|
||||
export interface NASCCommonACRequestParams {
|
||||
/**
|
||||
* Game server ID (`%08X`). This is the same as the `X-GameId` header.
|
||||
* Derived from the games default title ID (usually the Japanese title ID)
|
||||
*/
|
||||
gameid: string;
|
||||
|
||||
/**
|
||||
* Major and minor SDK version (`%03d%03d`). Always `000000`
|
||||
*/
|
||||
sdkver: string;
|
||||
|
||||
/**
|
||||
* Title ID (`%016X`)
|
||||
*/
|
||||
titleid: string;
|
||||
|
||||
/**
|
||||
* Product code. See https://3dsdb.com/
|
||||
*/
|
||||
gamecd: string;
|
||||
|
||||
/**
|
||||
* Title version (`%04X`)
|
||||
*/
|
||||
gamever: string;
|
||||
|
||||
/**
|
||||
* Game type
|
||||
*
|
||||
* - 0 = System
|
||||
* - 1 = Digital
|
||||
* - 2 = Cartridge
|
||||
*/
|
||||
mediatype: string;
|
||||
|
||||
/**
|
||||
* Unique ROM (game) ID.
|
||||
* Only present if the media type is 2 (cartridge)
|
||||
*/
|
||||
romid?: string;
|
||||
|
||||
/**
|
||||
* Product maker (company code)
|
||||
*/
|
||||
makercd: string;
|
||||
|
||||
/**
|
||||
* Unit code
|
||||
*
|
||||
* - 0 = NDS
|
||||
* - 1 = Wii
|
||||
* - 2 = 3DS
|
||||
*/
|
||||
unitcd: string;
|
||||
|
||||
/**
|
||||
* Device MAC address
|
||||
*/
|
||||
macadr: string;
|
||||
|
||||
/**
|
||||
* BSSID of active wifi network
|
||||
*/
|
||||
bssid: string;
|
||||
|
||||
/**
|
||||
* Information about the used Wi-Fi access point in the format `AA:BBBBBBBBBB`.
|
||||
* Example `01:0000000000`. `AA` is the AP slot. `BBBBBBBBBB` comes from either `ACU_GetNZoneApNumService` or `ACU_GetConnectingHotspotSubset` based on the result from `ACU_GetWifiStatus`
|
||||
*/
|
||||
apinfo: string;
|
||||
|
||||
/**
|
||||
* LocalFriendCodeSeed_B
|
||||
*/
|
||||
fcdcert: string;
|
||||
|
||||
/**
|
||||
* Device name (UTF-16-LE)
|
||||
*/
|
||||
devname: string;
|
||||
|
||||
/**
|
||||
* Environment (`L1` for production)
|
||||
*/
|
||||
servertype: string;
|
||||
|
||||
/**
|
||||
* FPD version (`%04X`). This is also included in the user agent.
|
||||
*/
|
||||
fpdver: string;
|
||||
|
||||
/**
|
||||
* Current device time (`%y%m%d%H%M%S`)
|
||||
*/
|
||||
devtime: string;
|
||||
|
||||
/**
|
||||
* Language code (`%02X`)
|
||||
*/
|
||||
lang: string;
|
||||
|
||||
/**
|
||||
* Region code (`%02X`)
|
||||
*/
|
||||
region: string;
|
||||
|
||||
/**
|
||||
* Serial number
|
||||
*/
|
||||
csnum: string;
|
||||
|
||||
/**
|
||||
* The type of action the console wishes to perform:
|
||||
*
|
||||
* - LOGIN = Register new game server account or login to existing on
|
||||
* - SVCLOC = Request service token
|
||||
* - nzchk = Unknown, but seems related to Nintendo Zone
|
||||
* - parse = Unknown
|
||||
* - message = Unknown
|
||||
*/
|
||||
action: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for when a console wants to register a new game server account.
|
||||
* See also NASCCommonRequestParams.
|
||||
* All fields are base64 encoded using Nintendo's custom alphabet:
|
||||
* '+' -> '.', '/' -> '-', '=' -> '*'
|
||||
*/
|
||||
export interface NASCRegistrationACRequestParams extends NASCCommonACRequestParams {
|
||||
/**
|
||||
* Game server account password the console wishes to use for the new account.
|
||||
* Can be any character between `\x21-\x5B` and `\x5D-\x7D`. Always 16 characters long
|
||||
*/
|
||||
passwd: string;
|
||||
|
||||
/**
|
||||
* Nickname provided by game.
|
||||
* Usually unused, leftover from the Wii
|
||||
*/
|
||||
ingamesn: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for when a console wants to login to an existing game server account.
|
||||
* See also NASCCommonRequestParams.
|
||||
* All fields are base64 encoded using Nintendo's custom alphabet:
|
||||
* '+' -> '.', '/' -> '-', '=' -> '*'
|
||||
*/
|
||||
export interface NASCLoginACRequestParams extends NASCCommonACRequestParams {
|
||||
/**
|
||||
* Hash of the user ID
|
||||
*/
|
||||
uidhmac: string;
|
||||
|
||||
/**
|
||||
* Game server account user ID/username.
|
||||
* Always the NEX account PID on 3DS
|
||||
*/
|
||||
userid: string;
|
||||
|
||||
/**
|
||||
* Nickname provided by game.
|
||||
* Usually unused, leftover from the Wii
|
||||
*/
|
||||
ingamesn: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Request parameters for when a console wants to request a service token.
|
||||
* See also NASCCommonRequestParams.
|
||||
* All fields are base64 encoded using Nintendo's custom alphabet:
|
||||
* '+' -> '.', '/' -> '-', '=' -> '*'
|
||||
*/
|
||||
export interface NASCServiceTokenACRequestParams extends NASCCommonACRequestParams {
|
||||
/**
|
||||
* Hash of the user ID
|
||||
*/
|
||||
uidhmac: string;
|
||||
|
||||
/**
|
||||
* Game server account user ID/username.
|
||||
* Always the NEX account PID on 3DS
|
||||
*/
|
||||
userid: string;
|
||||
|
||||
/**
|
||||
* Unique hash assigned to each game, regardless of title ID.
|
||||
* Analogous to the NNAS client ID
|
||||
*/
|
||||
keyhash: string;
|
||||
|
||||
/**
|
||||
* Service request type. Changes the `svchost` response field.
|
||||
* This is likely a remnant from the original NAS/NASWII servers.
|
||||
*
|
||||
* - 0000 = "n/a"
|
||||
* - 9001 = "dls1.nintendowifi.net"
|
||||
*/
|
||||
svc: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Union type representing all possible NASC request parameter types.
|
||||
* The specific type used depends on the `action` field value:
|
||||
*
|
||||
* - `action: 'LOGIN'` = `NASCRegistrationRequestParams` or `NASCLoginRequestParams`
|
||||
* - `action: 'SVCLOC'` = `NASCServiceTokenRequestParams`
|
||||
*/
|
||||
export type NASCACRequestParams = NASCRegistrationACRequestParams | NASCLoginACRequestParams | NASCServiceTokenACRequestParams;
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
export interface NASCRequestParams {
|
||||
action: string;
|
||||
fcdcert: string;
|
||||
csnum: string;
|
||||
macadr: string;
|
||||
titleid: string;
|
||||
servertype: string;
|
||||
gameid: string;
|
||||
userid?: string;
|
||||
uidhmac?: string;
|
||||
passwd?: string;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user