mirror of
https://github.com/PretendoNetwork/account.git
synced 2026-04-26 08:16:15 -05:00
242 lines
5.3 KiB
TypeScript
242 lines
5.3 KiB
TypeScript
import express from 'express';
|
|
import xmlbuilder from 'xmlbuilder';
|
|
import { getServerByClientID, getServerByGameServerID } from '@/database';
|
|
import { generateToken, getValueFromHeaders, getValueFromQueryString } from '@/util';
|
|
import { NEXAccount } from '@/models/nex-account';
|
|
|
|
const router = express.Router();
|
|
|
|
/**
|
|
* [GET]
|
|
* Replacement for: https://account.nintendo.net/v1/api/provider/service_token/@me
|
|
* Description: Gets a service token
|
|
*/
|
|
router.get('/service_token/@me', async (request: express.Request, response: express.Response): Promise<void> => {
|
|
const pnid = request.pnid;
|
|
|
|
if (!pnid) {
|
|
response.status(400).send(xmlbuilder.create({
|
|
errors: {
|
|
error: {
|
|
cause: 'access_token',
|
|
code: '0002',
|
|
message: 'Invalid access token'
|
|
}
|
|
}
|
|
}).end());
|
|
|
|
return;
|
|
}
|
|
|
|
const clientID = getValueFromQueryString(request.query, 'client_id');
|
|
|
|
if (!clientID) {
|
|
// TODO - Research this error more
|
|
response.send(xmlbuilder.create({
|
|
errors: {
|
|
error: {
|
|
code: '1021',
|
|
message: 'The requested game server was not found'
|
|
}
|
|
}
|
|
}).end());
|
|
|
|
return;
|
|
}
|
|
|
|
const titleID = getValueFromHeaders(request.headers, 'x-nintendo-title-id');
|
|
|
|
if (!titleID) {
|
|
// TODO - Research this error more
|
|
response.send(xmlbuilder.create({
|
|
errors: {
|
|
error: {
|
|
code: '1021',
|
|
message: 'The requested game server was not found'
|
|
}
|
|
}
|
|
}).end());
|
|
|
|
return;
|
|
}
|
|
|
|
const serverAccessLevel = pnid.server_access_level;
|
|
const server = await getServerByClientID(clientID, serverAccessLevel);
|
|
|
|
if (!server || !server.aes_key) {
|
|
response.send(xmlbuilder.create({
|
|
errors: {
|
|
error: {
|
|
code: '1021',
|
|
message: 'The requested game server was not found'
|
|
}
|
|
}
|
|
}).end());
|
|
|
|
return;
|
|
}
|
|
|
|
if (server.maintenance_mode) {
|
|
response.send(xmlbuilder.create({
|
|
errors: {
|
|
error: {
|
|
code: '2002',
|
|
message: 'The requested game server is under maintenance'
|
|
}
|
|
}
|
|
}).end());
|
|
|
|
return;
|
|
}
|
|
|
|
const tokenOptions = {
|
|
system_type: server.device,
|
|
token_type: 0x4, // * Service token
|
|
pid: pnid.pid,
|
|
access_level: pnid.access_level,
|
|
title_id: BigInt(parseInt(titleID, 16)),
|
|
expire_time: BigInt(Date.now() + (3600 * 1000))
|
|
};
|
|
|
|
const serviceTokenBuffer = await generateToken(server.aes_key, tokenOptions);
|
|
let serviceToken = serviceTokenBuffer ? serviceTokenBuffer.toString('base64') : '';
|
|
|
|
if (request.isCemu) {
|
|
serviceToken = Buffer.from(serviceToken, 'base64').toString('hex');
|
|
}
|
|
|
|
response.send(xmlbuilder.create({
|
|
service_token: {
|
|
token: serviceToken
|
|
}
|
|
}).end());
|
|
});
|
|
|
|
/**
|
|
* [GET]
|
|
* Replacement for: https://account.nintendo.net/v1/api/provider/nex_token/@me
|
|
* Description: Gets a NEX server address and token
|
|
*/
|
|
router.get('/nex_token/@me', async (request: express.Request, response: express.Response): Promise<void> => {
|
|
const pnid = request.pnid;
|
|
|
|
if (!pnid) {
|
|
response.status(400).send(xmlbuilder.create({
|
|
errors: {
|
|
error: {
|
|
cause: 'access_token',
|
|
code: '0002',
|
|
message: 'Invalid access token'
|
|
}
|
|
}
|
|
}).end());
|
|
|
|
return;
|
|
}
|
|
|
|
const nexAccount = await NEXAccount.findOne({
|
|
owning_pid: pnid.pid
|
|
});
|
|
|
|
if (!nexAccount) {
|
|
response.status(404).send(xmlbuilder.create({
|
|
errors: {
|
|
error: {
|
|
cause: '',
|
|
code: '0008',
|
|
message: 'Not Found'
|
|
}
|
|
}
|
|
}).end());
|
|
|
|
return;
|
|
}
|
|
|
|
const gameServerID = getValueFromQueryString(request.query, 'game_server_id');
|
|
|
|
if (!gameServerID) {
|
|
response.send(xmlbuilder.create({
|
|
errors: {
|
|
error: {
|
|
code: '0118',
|
|
message: 'Unique ID and Game Server ID are not linked'
|
|
}
|
|
}
|
|
}).end());
|
|
|
|
return;
|
|
}
|
|
|
|
const serverAccessLevel = pnid.server_access_level;
|
|
const server = await getServerByGameServerID(gameServerID, serverAccessLevel);
|
|
|
|
if (!server || !server.aes_key) {
|
|
response.send(xmlbuilder.create({
|
|
errors: {
|
|
error: {
|
|
code: '1021',
|
|
message: 'The requested game server was not found'
|
|
}
|
|
}
|
|
}).end());
|
|
|
|
return;
|
|
}
|
|
|
|
if (server.maintenance_mode) {
|
|
response.send(xmlbuilder.create({
|
|
errors: {
|
|
error: {
|
|
code: '2002',
|
|
message: 'The requested game server is under maintenance'
|
|
}
|
|
}
|
|
}).end());
|
|
|
|
return;
|
|
}
|
|
|
|
const titleID = getValueFromHeaders(request.headers, 'x-nintendo-title-id');
|
|
|
|
if (!titleID) {
|
|
// TODO - Research this error more
|
|
response.send(xmlbuilder.create({
|
|
errors: {
|
|
error: {
|
|
code: '1021',
|
|
message: 'The requested game server was not found'
|
|
}
|
|
}
|
|
}).end());
|
|
|
|
return;
|
|
}
|
|
|
|
const tokenOptions = {
|
|
system_type: server.device,
|
|
token_type: 0x3, // * nex token,
|
|
pid: pnid.pid,
|
|
access_level: pnid.access_level,
|
|
title_id: BigInt(parseInt(titleID, 16)),
|
|
expire_time: BigInt(Date.now() + (3600 * 1000))
|
|
};
|
|
|
|
const nexTokenBuffer = await generateToken(server.aes_key, tokenOptions);
|
|
let nexToken = nexTokenBuffer ? nexTokenBuffer.toString('base64') : '';
|
|
|
|
if (request.isCemu) {
|
|
nexToken = Buffer.from(nexToken || '', 'base64').toString('hex');
|
|
}
|
|
|
|
response.send(xmlbuilder.create({
|
|
nex_token: {
|
|
host: server.ip,
|
|
nex_password: nexAccount.password,
|
|
pid: nexAccount.pid,
|
|
port: server.port,
|
|
token: nexToken
|
|
}
|
|
}).end());
|
|
});
|
|
|
|
export default router; |