mirror of
https://github.com/PretendoNetwork/account.git
synced 2026-03-21 17:44:49 -05:00
style: do eslint format
This commit is contained in:
parent
82b3a44645
commit
6c04fbd68c
|
|
@ -31,4 +31,4 @@ database.connect().then(async function () {
|
|||
console.log('Migrated accounts');
|
||||
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ database.connect().then(async function () {
|
|||
});
|
||||
|
||||
for (const nexAccount of nexAccountsToBeChanged) {
|
||||
|
||||
if (!nexAccount.friend_code) {
|
||||
const pid = nexAccount.pid;
|
||||
const pidBuffer = Buffer.alloc(4);
|
||||
|
|
@ -33,4 +32,4 @@ database.connect().then(async function () {
|
|||
console.log('Migrated accounts');
|
||||
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ database.connect().then(async function () {
|
|||
});
|
||||
|
||||
for (const server of servers) {
|
||||
|
||||
if (!server.aes_key) {
|
||||
server.aes_key = crypto.randomBytes(32).toString('hex');
|
||||
|
||||
|
|
@ -21,4 +20,4 @@ database.connect().then(async function () {
|
|||
console.log('Migrated accounts');
|
||||
|
||||
process.exit(0);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,38 +1,41 @@
|
|||
const { confirm, input } = require('@inquirer/prompts');
|
||||
const { connect } = require('./dist/database');
|
||||
const { PNID } = require('./dist/models/pnid');
|
||||
const { confirm, input } = require('@inquirer/prompts');
|
||||
|
||||
async function bootstrap() {
|
||||
await connect();
|
||||
|
||||
const pnidName = await input({ message: 'What PNID do you want to delete?' });
|
||||
const pnid = await PNID.findOne({ username:pnidName.trim() });
|
||||
if (!pnid) {
|
||||
console.log("Could not find PNID");
|
||||
process.exit(1);
|
||||
}
|
||||
await connect();
|
||||
|
||||
console.log('Before:', pnid);
|
||||
|
||||
if (pnid.deleted) {
|
||||
console.log("PNID is already marked as deleted");
|
||||
process.exit(1);
|
||||
}
|
||||
const pnidName = await input({ message: 'What PNID do you want to delete?' });
|
||||
const pnid = await PNID.findOne({ username: pnidName.trim() });
|
||||
if (!pnid) {
|
||||
console.log('Could not find PNID');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const confirmed = await confirm({ message: 'Do you want to delete this PNID',default: false });
|
||||
if (!confirmed) {
|
||||
console.log("Aborted");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await pnid.scrub();
|
||||
await pnid.save();
|
||||
|
||||
console.log('After:', pnid);
|
||||
if (pnid.deleted) console.log("SUCCESSFULLY DELETED");
|
||||
else console.log("COULD NOT DELETE");
|
||||
|
||||
process.exit(0);
|
||||
console.log('Before:', pnid);
|
||||
|
||||
if (pnid.deleted) {
|
||||
console.log('PNID is already marked as deleted');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const confirmed = await confirm({ message: 'Do you want to delete this PNID', default: false });
|
||||
if (!confirmed) {
|
||||
console.log('Aborted');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await pnid.scrub();
|
||||
await pnid.save();
|
||||
|
||||
console.log('After:', pnid);
|
||||
if (pnid.deleted) {
|
||||
console.log('SUCCESSFULLY DELETED');
|
||||
} else {
|
||||
console.log('COULD NOT DELETE');
|
||||
}
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
bootstrap();
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ const LOCAL_CDN_BASE = `${__dirname}/../cdn`;
|
|||
export async function connect(): Promise<void> {
|
||||
if (!disabledFeatures.redis) {
|
||||
client = redis.createClient(config.redis.client);
|
||||
client.on('error', (err) => console.log('Redis Client Error', err));
|
||||
client.on('error', err => console.log('Redis Client Error', err));
|
||||
|
||||
await client.connect();
|
||||
}
|
||||
|
|
@ -58,4 +58,4 @@ export async function getLocalCDNFile(name: string, encoding?: BufferEncoding):
|
|||
|
||||
export async function setLocalCDNFile(name: string, value: Buffer): Promise<void> {
|
||||
await setCachedFile(`local_cdn:${name}`, value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import fs from 'fs-extra';
|
||||
import mongoose from 'mongoose';
|
||||
import dotenv from 'dotenv';
|
||||
import isValidHostname from 'is-valid-hostname';
|
||||
import { LOG_INFO, LOG_WARN, LOG_ERROR, formatHostnames } from '@/logger';
|
||||
import { type Config, domainServices, optionalDomainServices } from '@/types/common/config';
|
||||
import { domainServices, optionalDomainServices } from '@/types/common/config';
|
||||
import type mongoose from 'mongoose';
|
||||
import type { Config } from '@/types/common/config';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
|
|
@ -74,9 +75,9 @@ export const config: Config = {
|
|||
grpc: {
|
||||
master_api_keys: {
|
||||
account: process.env.PN_ACT_CONFIG_GRPC_MASTER_API_KEY_ACCOUNT || '',
|
||||
api: process.env.PN_ACT_CONFIG_GRPC_MASTER_API_KEY_API || '',
|
||||
api: process.env.PN_ACT_CONFIG_GRPC_MASTER_API_KEY_API || ''
|
||||
},
|
||||
port: Number(process.env.PN_ACT_CONFIG_GRPC_PORT || ''),
|
||||
port: Number(process.env.PN_ACT_CONFIG_GRPC_PORT || '')
|
||||
},
|
||||
server_environment: process.env.PN_ACT_CONFIG_SERVER_ENVIRONMENT || '',
|
||||
datastore: {
|
||||
|
|
@ -90,7 +91,7 @@ export const config: Config = {
|
|||
datastore: (process.env.PN_ACT_CONFIG_DOMAINS_DATASTORE || 'datastore.pretendo.cc').split(','),
|
||||
local_cdn: (process.env.PN_ACT_CONFIG_DOMAINS_LOCAL_CDN || '').split(','),
|
||||
nasc: (process.env.PN_ACT_CONFIG_DOMAINS_NASC || 'nasc.pretendo.cc').split(','),
|
||||
nnas: (process.env.PN_ACT_CONFIG_DOMAINS_NNAS || 'c.account.pretendo.cc,account.pretendo.cc').split(','),
|
||||
nnas: (process.env.PN_ACT_CONFIG_DOMAINS_NNAS || 'c.account.pretendo.cc,account.pretendo.cc').split(',')
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -116,7 +117,11 @@ for (const service of domainServices) {
|
|||
const uniqueDomains = [...new Set(config.domains[service])];
|
||||
|
||||
for (const domain of uniqueDomains) {
|
||||
isValidHostname(domain) ? validDomains.push(domain) : invalidDomains.push(domain);
|
||||
if (isValidHostname(domain)) {
|
||||
validDomains.push(domain);
|
||||
} else {
|
||||
invalidDomains.push(domain);
|
||||
}
|
||||
}
|
||||
|
||||
if (validDomains.length === 0 && !optionalDomainServices.includes(service)) {
|
||||
|
|
@ -230,7 +235,7 @@ if (disabledFeatures.s3) {
|
|||
if (disabledFeatures.redis) {
|
||||
LOG_WARN('Both S3 and Redis are disabled. Large CDN files will use the in-memory cache, which may result in high memory use. Please enable S3 if you\'re running a production server.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!config.aes_key) {
|
||||
|
|
@ -270,4 +275,4 @@ if (!config.datastore.signature_secret) {
|
|||
if (!configValid) {
|
||||
LOG_ERROR('Config is invalid. Exiting');
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,13 @@ import { PNID } from '@/models/pnid';
|
|||
import { Server } from '@/models/server';
|
||||
import { LOG_ERROR } from '@/logger';
|
||||
import { config } from '@/config-manager';
|
||||
import { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
import { IDeviceAttribute } from '@/types/mongoose/device-attribute';
|
||||
import { HydratedServerDocument } from '@/types/mongoose/server';
|
||||
import { PNIDProfile } from '@/types/services/nnas/pnid-profile';
|
||||
import { ConnectionData } from '@/types/services/api/connection-data';
|
||||
import { ConnectionResponse } from '@/types/services/api/connection-response';
|
||||
import { DiscordConnectionData } from '@/types/services/api/discord-connection-data';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
import type { IDeviceAttribute } from '@/types/mongoose/device-attribute';
|
||||
import type { HydratedServerDocument } from '@/types/mongoose/server';
|
||||
import type { PNIDProfile } from '@/types/services/nnas/pnid-profile';
|
||||
import type { ConnectionData } from '@/types/services/api/connection-data';
|
||||
import type { ConnectionResponse } from '@/types/services/api/connection-response';
|
||||
import type { DiscordConnectionData } from '@/types/services/api/discord-connection-data';
|
||||
|
||||
const connection_string = config.mongoose.connection_string;
|
||||
const options = config.mongoose.options;
|
||||
|
|
@ -202,7 +202,7 @@ export async function getPNIDProfileJSONByPID(pid: number): Promise<PNIDProfile
|
|||
}
|
||||
},
|
||||
name: pnid.mii.name,
|
||||
primary: pnid.mii.primary ? 'Y' : 'N',
|
||||
primary: pnid.mii.primary ? 'Y' : 'N'
|
||||
},
|
||||
region: pnid.region,
|
||||
tz_name: pnid.timezone.name,
|
||||
|
|
@ -221,7 +221,9 @@ export async function getServerByGameServerID(gameServerID: string, accessMode:
|
|||
|
||||
for (const mode of searchModes) {
|
||||
const server = servers.find(s => s.access_mode === mode);
|
||||
if (server) return server;
|
||||
if (server) {
|
||||
return server;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
@ -237,7 +239,9 @@ export async function getServerByTitleID(titleID: string, accessMode: string): P
|
|||
|
||||
for (const mode of searchModes) {
|
||||
const server = servers.find(s => s.access_mode === mode);
|
||||
if (server) return server;
|
||||
if (server) {
|
||||
return server;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
@ -253,7 +257,9 @@ export async function getServerByClientID(clientID: string, accessMode: string):
|
|||
|
||||
for (const mode of searchModes) {
|
||||
const server = servers.find(s => s.access_mode === mode);
|
||||
if (server) return server;
|
||||
if (server) {
|
||||
return server;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
@ -306,4 +312,4 @@ export async function removePNIDConnectionDiscord(pnid: HydratedPNIDDocument): P
|
|||
app: 'api',
|
||||
status: 200
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,4 +53,4 @@ export function LOG_INFO(input: string): void {
|
|||
|
||||
export function formatHostnames(hostnames: string[]): string {
|
||||
return hostnames.map(d => `'${d}'`).join(', ');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import fs from 'node:fs';
|
|||
import nodemailer from 'nodemailer';
|
||||
import * as aws from '@aws-sdk/client-ses';
|
||||
import { config, disabledFeatures } from '@/config-manager';
|
||||
import { MailerOptions } from '@/types/common/mailer-options';
|
||||
import type { MailerOptions } from '@/types/common/mailer-options';
|
||||
|
||||
const genericEmailTemplate = fs.readFileSync(path.join(__dirname, './assets/emails/genericTemplate.html'), 'utf8');
|
||||
const confirmationEmailTemplate = fs.readFileSync(path.join(__dirname, './assets/emails/confirmationTemplate.html'), 'utf8');
|
||||
|
|
@ -30,7 +30,7 @@ if (!disabledFeatures.email) {
|
|||
|
||||
export async function sendMail(options: MailerOptions): Promise<void> {
|
||||
if (!disabledFeatures.email) {
|
||||
const { to, subject, username, paragraph, preview, text, link, confirmation } = options;
|
||||
const { to, subject, username, paragraph, preview, text, link, confirmation } = options;
|
||||
|
||||
let html = confirmation ? confirmationEmailTemplate : genericEmailTemplate;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import express from 'express';
|
||||
import { getValueFromHeaders } from '@/util';
|
||||
import { getPNIDByTokenAuth } from '@/database';
|
||||
import { LOG_ERROR } from '@/logger';
|
||||
import type express from 'express';
|
||||
async function APIMiddleware(request: express.Request, _response: express.Response, next: express.NextFunction): Promise<void> {
|
||||
const authHeader = getValueFromHeaders(request.headers, 'authorization');
|
||||
|
||||
|
|
@ -16,10 +16,12 @@ async function APIMiddleware(request: express.Request, _response: express.Respon
|
|||
request.pnid = pnid;
|
||||
} catch (error: any) {
|
||||
LOG_ERROR('api middleware - decode pnid: ' + error);
|
||||
if (error.stack) console.error(error.stack);
|
||||
if (error.stack) {
|
||||
console.error(error.stack);
|
||||
}
|
||||
}
|
||||
|
||||
return next();
|
||||
}
|
||||
|
||||
export default APIMiddleware;
|
||||
export default APIMiddleware;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import express from 'express';
|
||||
import type express from 'express';
|
||||
|
||||
function CemuMiddleware(request: express.Request, _response: express.Response, next: express.NextFunction): void {
|
||||
const subdomain = request.subdomains.reverse().join('.');
|
||||
|
|
@ -8,4 +8,4 @@ function CemuMiddleware(request: express.Request, _response: express.Response, n
|
|||
return next();
|
||||
}
|
||||
|
||||
export default CemuMiddleware;
|
||||
export default CemuMiddleware;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import express from 'express';
|
||||
import xmlbuilder from 'xmlbuilder';
|
||||
import { getValueFromHeaders } from '@/util';
|
||||
import type express from 'express';
|
||||
|
||||
const VALID_CLIENT_ID_SECRET_PAIRS: Record<string, string> = {
|
||||
// * 'Key' is the client ID, 'Value' is the client secret
|
||||
'a2efa818a34fa16b8afbc8a74eba3eda': 'c91cdb5658bd4954ade78533a339cf9a', // * Possibly WiiU exclusive?
|
||||
'daf6227853bcbdce3d75baee8332b': '3eff548eac636e2bf45bb7b375e7b6b0', // * Possibly 3DS exclusive?
|
||||
'ea25c66c26b403376b4c5ed94ab9cdea': 'd137be62cb6a2b831cad8c013b92fb55', // * Possibly 3DS exclusive?
|
||||
a2efa818a34fa16b8afbc8a74eba3eda: 'c91cdb5658bd4954ade78533a339cf9a', // * Possibly WiiU exclusive?
|
||||
daf6227853bcbdce3d75baee8332b: '3eff548eac636e2bf45bb7b375e7b6b0', // * Possibly 3DS exclusive?
|
||||
ea25c66c26b403376b4c5ed94ab9cdea: 'd137be62cb6a2b831cad8c013b92fb55' // * Possibly 3DS exclusive?
|
||||
};
|
||||
|
||||
function nintendoClientHeaderCheck(request: express.Request, response: express.Response, next: express.NextFunction): void {
|
||||
|
|
@ -39,4 +39,4 @@ function nintendoClientHeaderCheck(request: express.Request, response: express.R
|
|||
return next();
|
||||
}
|
||||
|
||||
export default nintendoClientHeaderCheck;
|
||||
export default nintendoClientHeaderCheck;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import crypto from 'node:crypto';
|
||||
import express from 'express';
|
||||
import xmlbuilder from 'xmlbuilder';
|
||||
import { Device } from '@/models/device';
|
||||
import { getValueFromHeaders } from '@/util';
|
||||
import type express from 'express';
|
||||
|
||||
async function consoleStatusVerificationMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): Promise<void> {
|
||||
if (!request.certificate || !request.certificate.valid) {
|
||||
|
|
@ -69,7 +69,7 @@ async function consoleStatusVerificationMiddleware(request: express.Request, res
|
|||
}
|
||||
|
||||
let device = await Device.findOne({
|
||||
serial: serialNumber,
|
||||
serial: serialNumber
|
||||
});
|
||||
|
||||
const certificateHash = crypto.createHash('sha256').update(request.certificate._certificate).digest('base64');
|
||||
|
|
@ -95,7 +95,7 @@ async function consoleStatusVerificationMiddleware(request: express.Request, res
|
|||
}
|
||||
|
||||
device = await Device.findOne({
|
||||
certificate_hash: certificateHash,
|
||||
certificate_hash: certificateHash
|
||||
});
|
||||
|
||||
if (!device) {
|
||||
|
|
@ -155,4 +155,4 @@ async function consoleStatusVerificationMiddleware(request: express.Request, res
|
|||
return next();
|
||||
}
|
||||
|
||||
export default consoleStatusVerificationMiddleware;
|
||||
export default consoleStatusVerificationMiddleware;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import express from 'express';
|
||||
import NintendoCertificate from '@/nintendo-certificate';
|
||||
import { getValueFromHeaders } from '@/util';
|
||||
import type express from 'express';
|
||||
|
||||
function deviceCertificateMiddleware(request: express.Request, _response: express.Response, next: express.NextFunction): void {
|
||||
const certificate = getValueFromHeaders(request.headers, 'x-nintendo-device-cert');
|
||||
|
|
@ -14,4 +14,4 @@ function deviceCertificateMiddleware(request: express.Request, _response: expres
|
|||
return next();
|
||||
}
|
||||
|
||||
export default deviceCertificateMiddleware;
|
||||
export default deviceCertificateMiddleware;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import express from 'express';
|
||||
import type express from 'express';
|
||||
|
||||
export function restrictHostnames<TFn extends express.Router>(
|
||||
allowedHostnames: string[],
|
||||
|
|
@ -11,4 +11,4 @@ export function restrictHostnames<TFn extends express.Router>(
|
|||
|
||||
return next();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import crypto from 'node:crypto';
|
||||
import express from 'express';
|
||||
import { Device } from '@/models/device';
|
||||
import { NEXAccount } from '@/models/nex-account';
|
||||
import { nascError, nintendoBase64Decode } from '@/util';
|
||||
import { connection as databaseConnection } from '@/database';
|
||||
import NintendoCertificate from '@/nintendo-certificate';
|
||||
import { LOG_ERROR } from '@/logger';
|
||||
import { NASCRequestParams } from '@/types/services/nasc/request-params';
|
||||
import type express from 'express';
|
||||
import type { NASCRequestParams } from '@/types/services/nasc/request-params';
|
||||
|
||||
async function NASCMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): Promise<void> {
|
||||
const requestParams: NASCRequestParams = request.body;
|
||||
|
|
@ -103,9 +103,8 @@ async function NASCMiddleware(request: express.Request, response: express.Respon
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
let device = await Device.findOne({
|
||||
fcdcert_hash: fcdcertHash,
|
||||
fcdcert_hash: fcdcertHash
|
||||
});
|
||||
|
||||
if (device) {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import express from 'express';
|
||||
import xmlbuilder from 'xmlbuilder';
|
||||
import { getValueFromHeaders } from '@/util';
|
||||
import { getPNIDByBasicAuth, getPNIDByTokenAuth } from '@/database';
|
||||
import { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
import type express from 'express';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
|
||||
async function PNIDMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): Promise<void> {
|
||||
const authHeader = getValueFromHeaders(request.headers, 'authorization');
|
||||
|
|
@ -84,4 +84,4 @@ async function PNIDMiddleware(request: express.Request, response: express.Respon
|
|||
return next();
|
||||
}
|
||||
|
||||
export default PNIDMiddleware;
|
||||
export default PNIDMiddleware;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import crypto from 'node:crypto';
|
||||
import express from 'express';
|
||||
import ratelimit from 'express-rate-limit';
|
||||
import { getValueFromHeaders } from '@/util';
|
||||
import type express from 'express';
|
||||
|
||||
export default ratelimit({
|
||||
windowMs: 60 * 1000,
|
||||
|
|
@ -15,4 +15,4 @@ export default ratelimit({
|
|||
|
||||
return crypto.createHash('md5').update(data).digest('hex');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import express from 'express';
|
||||
import xmlbuilder from 'xmlbuilder';
|
||||
import { document as xmlParser } from 'xmlbuilder2';
|
||||
import { getValueFromHeaders, mapToObject } from '@/util';
|
||||
import type express from 'express';
|
||||
|
||||
function XMLMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): void {
|
||||
if (request.method == 'POST' || request.method == 'PUT') {
|
||||
|
|
@ -33,7 +33,7 @@ function XMLMiddleware(request: express.Request, response: express.Response, nex
|
|||
request.body = xmlParser(body);
|
||||
request.body = request.body.toObject();
|
||||
request.body = mapToObject(request.body);
|
||||
} catch (error) {
|
||||
} catch {
|
||||
// TODO - This is not a real error code, check to see if better one exists
|
||||
return response.status(401).send(xmlbuilder.create({
|
||||
errors: {
|
||||
|
|
@ -52,4 +52,4 @@ function XMLMiddleware(request: express.Request, response: express.Response, nex
|
|||
}
|
||||
}
|
||||
|
||||
export default XMLMiddleware;
|
||||
export default XMLMiddleware;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Schema, model } from 'mongoose';
|
||||
import { IDeviceAttribute, IDeviceAttributeMethods, DeviceAttributeModel } from '@/types/mongoose/device-attribute';
|
||||
import { IDevice, IDeviceMethods, DeviceModel } from '@/types/mongoose/device';
|
||||
import type { IDeviceAttribute, IDeviceAttributeMethods, DeviceAttributeModel } from '@/types/mongoose/device-attribute';
|
||||
import type { IDevice, IDeviceMethods, DeviceModel } from '@/types/mongoose/device';
|
||||
|
||||
const DeviceAttributeSchema = new Schema<IDeviceAttribute, DeviceAttributeModel, IDeviceAttributeMethods>({
|
||||
created_date: String,
|
||||
|
|
@ -18,7 +18,7 @@ export const DeviceSchema = new Schema<IDevice, DeviceModel, IDeviceMethods>({
|
|||
'ftr', // * Nintendo 2DS
|
||||
'ktr', // * New Nintendo 3DS
|
||||
'red', // * New Nintendo 3DS XL
|
||||
'jan' // * New Nintendo 2DS XL
|
||||
'jan' // * New Nintendo 2DS XL
|
||||
]
|
||||
},
|
||||
device_id: Number,
|
||||
|
|
@ -27,15 +27,15 @@ export const DeviceSchema = new Schema<IDevice, DeviceModel, IDeviceMethods>({
|
|||
device_attributes: [DeviceAttributeSchema],
|
||||
soap: {
|
||||
token: String,
|
||||
account_id: Number,
|
||||
account_id: Number
|
||||
},
|
||||
environment: String,
|
||||
mac_hash: String, // * 3DS-specific
|
||||
mac_hash: String, // * 3DS-specific
|
||||
fcdcert_hash: String, // * 3DS-specific
|
||||
linked_pids: [Number],
|
||||
access_level: {
|
||||
type: Number,
|
||||
default: 0 // * 0: standard, 1: tester, 2: mod?, 3: dev
|
||||
default: 0 // * 0: standard, 1: tester, 2: mod?, 3: dev
|
||||
},
|
||||
server_access_level: {
|
||||
type: String,
|
||||
|
|
@ -44,4 +44,4 @@ export const DeviceSchema = new Schema<IDevice, DeviceModel, IDeviceMethods>({
|
|||
certificate_hash: String
|
||||
});
|
||||
|
||||
export const Device = model<IDevice, DeviceModel>('Device', DeviceSchema);
|
||||
export const Device = model<IDevice, DeviceModel>('Device', DeviceSchema);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Schema, model } from 'mongoose';
|
||||
import uniqueValidator from 'mongoose-unique-validator';
|
||||
import { INEXAccount, INEXAccountMethods, NEXAccountModel } from '@/types/mongoose/nex-account';
|
||||
import type { INEXAccount, INEXAccountMethods, NEXAccountModel } from '@/types/mongoose/nex-account';
|
||||
|
||||
const NEXAccountSchema = new Schema<INEXAccount, NEXAccountModel, INEXAccountMethods>({
|
||||
device_type: {
|
||||
|
|
@ -8,7 +8,7 @@ const NEXAccountSchema = new Schema<INEXAccount, NEXAccountModel, INEXAccountMet
|
|||
enum: [
|
||||
// * Only track the family here not the model
|
||||
'wiiu',
|
||||
'3ds',
|
||||
'3ds'
|
||||
]
|
||||
},
|
||||
pid: {
|
||||
|
|
@ -19,7 +19,7 @@ const NEXAccountSchema = new Schema<INEXAccount, NEXAccountModel, INEXAccountMet
|
|||
owning_pid: Number,
|
||||
access_level: {
|
||||
type: Number,
|
||||
default: 0 // * 0: standard, 1: tester, 2: mod?, 3: dev
|
||||
default: 0 // * 0: standard, 1: tester, 2: mod?, 3: dev
|
||||
},
|
||||
server_access_level: {
|
||||
type: String,
|
||||
|
|
@ -56,8 +56,12 @@ NEXAccountSchema.method('generatePID', async function generatePID(): Promise<voi
|
|||
NEXAccountSchema.method('generatePassword', function generatePassword(): void {
|
||||
function character(): string | number {
|
||||
const offset = Math.floor(Math.random() * 62);
|
||||
if (offset < 10) return offset;
|
||||
if (offset < 36) return String.fromCharCode(offset + 55);
|
||||
if (offset < 10) {
|
||||
return offset;
|
||||
}
|
||||
if (offset < 36) {
|
||||
return String.fromCharCode(offset + 55);
|
||||
}
|
||||
return String.fromCharCode(offset + 61);
|
||||
}
|
||||
|
||||
|
|
@ -70,4 +74,4 @@ NEXAccountSchema.method('generatePassword', function generatePassword(): void {
|
|||
this.password = output.join('');
|
||||
});
|
||||
|
||||
export const NEXAccount = model<INEXAccount, NEXAccountModel>('NEXAccount', NEXAccountSchema);
|
||||
export const NEXAccount = model<INEXAccount, NEXAccountModel>('NEXAccount', NEXAccountSchema);
|
||||
|
|
|
|||
|
|
@ -9,16 +9,16 @@ import Stripe from 'stripe';
|
|||
import { DeviceSchema } from '@/models/device';
|
||||
import { uploadCDNAsset } from '@/util';
|
||||
import { LOG_ERROR, LOG_WARN } from '@/logger';
|
||||
import { IPNID, IPNIDMethods, PNIDModel } from '@/types/mongoose/pnid';
|
||||
import { PNIDPermissionFlag } from '@/types/common/permission-flags';
|
||||
import { config } from '@/config-manager';
|
||||
import type { IPNID, IPNIDMethods, PNIDModel } from '@/types/mongoose/pnid';
|
||||
import type { PNIDPermissionFlag } from '@/types/common/permission-flags';
|
||||
|
||||
let stripe: Stripe;
|
||||
|
||||
if (config.stripe?.secret_key) {
|
||||
stripe = new Stripe(config.stripe.secret_key, {
|
||||
apiVersion: '2022-11-15',
|
||||
typescript: true,
|
||||
typescript: true
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ const PNIDSchema = new Schema<IPNID, PNIDModel, IPNIDMethods>({
|
|||
},
|
||||
access_level: {
|
||||
type: Number,
|
||||
default: 0 // * 0: standard, 1: tester, 2: mod?, 3: dev
|
||||
default: 0 // * 0: standard, 1: tester, 2: mod?, 3: dev
|
||||
},
|
||||
server_access_level: {
|
||||
type: String,
|
||||
|
|
@ -81,7 +81,7 @@ const PNIDSchema = new Schema<IPNID, PNIDModel, IPNIDMethods>({
|
|||
id: Number,
|
||||
hash: String,
|
||||
image_url: String,
|
||||
image_id: Number,
|
||||
image_id: Number
|
||||
},
|
||||
flags: {
|
||||
active: Boolean,
|
||||
|
|
@ -122,7 +122,7 @@ const PNIDSchema = new Schema<IPNID, PNIDModel, IPNIDMethods>({
|
|||
}
|
||||
}, { id: false });
|
||||
|
||||
PNIDSchema.plugin(uniqueValidator, {message: '{PATH} already in use.'});
|
||||
PNIDSchema.plugin(uniqueValidator, { message: '{PATH} already in use.' });
|
||||
|
||||
/*
|
||||
According to http://pf2m.com/tools/rank.php Nintendo PID's start at 1,800,000,000 and count down with each account
|
||||
|
|
@ -136,7 +136,7 @@ PNIDSchema.method('generatePID', async function generatePID(): Promise<void> {
|
|||
const min = 1000000000; // * The console (WiiU) seems to not accept PIDs smaller than this
|
||||
const max = 1799999999;
|
||||
|
||||
const pid = Math.floor(Math.random() * (max - min + 1) + min);
|
||||
const pid = Math.floor(Math.random() * (max - min + 1) + min);
|
||||
|
||||
const inuse = await PNID.findOne({
|
||||
pid
|
||||
|
|
@ -171,7 +171,7 @@ PNIDSchema.method('generateEmailValidationToken', async function generateEmailVa
|
|||
}
|
||||
});
|
||||
|
||||
PNIDSchema.method('updateMii', async function updateMii({ name, primary, data }: { name: string; primary: string; data: string; }): Promise<void> {
|
||||
PNIDSchema.method('updateMii', async function updateMii({ name, primary, data }: { name: string; primary: string; data: string }): Promise<void> {
|
||||
this.mii.name = name;
|
||||
this.mii.primary = primary === 'Y';
|
||||
this.mii.data = data;
|
||||
|
|
@ -190,7 +190,7 @@ PNIDSchema.method('generateMiiImages', async function generateMiiImages(): Promi
|
|||
const miiStudioUrl = mii.studioUrl({
|
||||
type: 'face',
|
||||
width: 128,
|
||||
instanceCount: 1,
|
||||
instanceCount: 1
|
||||
});
|
||||
const miiStudioNormalFaceImageData = await got(miiStudioUrl).buffer();
|
||||
const pngData = await imagePixels(miiStudioNormalFaceImageData);
|
||||
|
|
@ -207,7 +207,7 @@ PNIDSchema.method('generateMiiImages', async function generateMiiImages(): Promi
|
|||
type: 'face',
|
||||
expression: expression,
|
||||
width: 128,
|
||||
instanceCount: 1,
|
||||
instanceCount: 1
|
||||
});
|
||||
const miiStudioExpressionImageData = await got(miiStudioExpressionUrl).buffer();
|
||||
await uploadCDNAsset(config.s3.bucket, `${userMiiKey}/${expression}.png`, miiStudioExpressionImageData, 'public-read');
|
||||
|
|
@ -216,7 +216,7 @@ PNIDSchema.method('generateMiiImages', async function generateMiiImages(): Promi
|
|||
const miiStudioBodyUrl = mii.studioUrl({
|
||||
type: 'all_body',
|
||||
width: 270,
|
||||
instanceCount: 1,
|
||||
instanceCount: 1
|
||||
});
|
||||
const miiStudioBodyImageData = await got(miiStudioBodyUrl).buffer();
|
||||
await uploadCDNAsset(config.s3.bucket, `${userMiiKey}/body.png`, miiStudioBodyImageData, 'public-read');
|
||||
|
|
@ -290,4 +290,4 @@ PNIDSchema.method('clearPermission', function clearPermission(flag: PNIDPermissi
|
|||
this.permissions &= ~flag;
|
||||
});
|
||||
|
||||
export const PNID = model<IPNID, PNIDModel>('PNID', PNIDSchema);
|
||||
export const PNID = model<IPNID, PNIDModel>('PNID', PNIDSchema);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Schema, model } from 'mongoose';
|
||||
import uniqueValidator from 'mongoose-unique-validator';
|
||||
import { IServer, IServerMethods, ServerModel } from '@/types/mongoose/server';
|
||||
import type { IServer, IServerMethods, ServerModel } from '@/types/mongoose/server';
|
||||
|
||||
const ServerSchema = new Schema<IServer, ServerModel, IServerMethods>({
|
||||
client_id: String,
|
||||
|
|
@ -18,4 +18,4 @@ const ServerSchema = new Schema<IServer, ServerModel, IServerMethods>({
|
|||
|
||||
ServerSchema.plugin(uniqueValidator, { message: '{PATH} already in use.' });
|
||||
|
||||
export const Server = model<IServer, ServerModel>('Server', ServerSchema);
|
||||
export const Server = model<IServer, ServerModel>('Server', ServerSchema);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import crypto from 'node:crypto';
|
||||
import NodeRSA from 'node-rsa';
|
||||
import { SignatureSize } from '@/types/common/signature-size';
|
||||
import type { SignatureSize } from '@/types/common/signature-size';
|
||||
|
||||
const WIIU_DEVICE_PUB_PEM = `-----BEGIN PUBLIC KEY-----
|
||||
MFIwEAYHKoZIzj0CAQYFK4EEABsDPgAEAP1WBBgs8XUJIQDDCK5IOZEbb5+h1TqV
|
||||
|
|
@ -229,11 +229,11 @@ class NintendoCertificate {
|
|||
|
||||
publicKey.importKey({
|
||||
n: CTR_LFCS_B_PUB,
|
||||
e: 65537,
|
||||
e: 65537
|
||||
}, 'components-public');
|
||||
|
||||
this.valid = publicKey.verify(this._certificateBody, this.signature);
|
||||
}
|
||||
}
|
||||
|
||||
export default NintendoCertificate;
|
||||
export default NintendoCertificate;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,3 @@
|
|||
process.title = 'Pretendo - Account';
|
||||
process.on('uncaughtException', (err, origin) => {
|
||||
console.log(err);
|
||||
console.log(origin);
|
||||
});
|
||||
process.on('SIGTERM', () => {
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
import express from 'express';
|
||||
import morgan from 'morgan';
|
||||
import xmlbuilder from 'xmlbuilder';
|
||||
|
|
@ -16,7 +7,6 @@ import { connect as connectDatabase } from '@/database';
|
|||
import { startGRPCServer } from '@/services/grpc/server';
|
||||
import { fullUrl, getValueFromHeaders } from '@/util';
|
||||
import { LOG_INFO, LOG_SUCCESS, LOG_WARN } from '@/logger';
|
||||
|
||||
import conntest from '@/services/conntest';
|
||||
import cbvc from '@/services/cbvc';
|
||||
import nnas from '@/services/nnas';
|
||||
|
|
@ -25,9 +15,17 @@ import datastore from '@/services/datastore';
|
|||
import api from '@/services/api';
|
||||
import localcdn from '@/services/local-cdn';
|
||||
import assets from '@/services/assets';
|
||||
|
||||
import { config, disabledFeatures } from '@/config-manager';
|
||||
|
||||
process.title = 'Pretendo - Account';
|
||||
process.on('uncaughtException', (err, origin) => {
|
||||
console.log(err);
|
||||
console.log(origin);
|
||||
});
|
||||
process.on('SIGTERM', () => {
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
const app = express();
|
||||
|
||||
// * START APPLICATION
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import express from 'express';
|
|||
import cors from 'cors';
|
||||
import APIMiddleware from '@/middleware/api';
|
||||
import { formatHostnames, LOG_INFO } from '@/logger';
|
||||
|
||||
import { V1 } from '@/services/api/routes';
|
||||
import { config } from '@/config-manager';
|
||||
import { restrictHostnames } from '@/middleware/host-limit';
|
||||
|
|
@ -25,7 +24,6 @@ api.use('/v1/register', V1.REGISTER);
|
|||
api.use('/v1/reset-password', V1.RESET_PASSWORD);
|
||||
api.use('/v1/user', V1.USER);
|
||||
|
||||
|
||||
// * Main router for endpoints
|
||||
const router = express.Router();
|
||||
|
||||
|
|
@ -33,4 +31,4 @@ const router = express.Router();
|
|||
LOG_INFO(`[USER API] Registering api router with domains: ${formatHostnames(config.domains.api)}`);
|
||||
router.use(restrictHostnames(config.domains.api, api));
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -14,4 +14,4 @@ export const V1 = {
|
|||
REGISTER: register_v1,
|
||||
RESET_PASSWORD: resetPassword_v1,
|
||||
USER: user_v1
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -102,4 +102,4 @@ router.delete('/remove/:type', async (request: express.Request, response: expres
|
|||
response.status(result.status).json(result);
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -45,4 +45,4 @@ router.get('/verify', async (request: express.Request, response: express.Respons
|
|||
response.status(200).send('Email validated. You may close this window');
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import hcaptcha from 'hcaptcha';
|
|||
import { getPNIDByEmailAddress, getPNIDByUsername } from '@/database';
|
||||
import { sendForgotPasswordEmail } from '@/util';
|
||||
import { config, disabledFeatures } from '@/config-manager';
|
||||
import { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
|
@ -17,7 +17,7 @@ router.post('/', async (request: express.Request, response: express.Response): P
|
|||
response.status(400).json({
|
||||
app: 'api',
|
||||
status: 400,
|
||||
error: 'Must fill in captcha',
|
||||
error: 'Must fill in captcha'
|
||||
});
|
||||
|
||||
return;
|
||||
|
|
@ -32,7 +32,7 @@ router.post('/', async (request: express.Request, response: express.Response): P
|
|||
response.status(400).json({
|
||||
app: 'api',
|
||||
status: 400,
|
||||
error: 'Captcha verification failed',
|
||||
error: 'Captcha verification failed'
|
||||
});
|
||||
|
||||
return;
|
||||
|
|
@ -67,4 +67,4 @@ router.post('/', async (request: express.Request, response: express.Response): P
|
|||
});
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import express from 'express';
|
||||
import bcrypt from 'bcrypt';
|
||||
import { getPNIDByUsername, getPNIDByTokenAuth } from '@/database';
|
||||
import { nintendoPasswordHash, generateToken} from '@/util';
|
||||
import { nintendoPasswordHash, generateToken } from '@/util';
|
||||
import { config } from '@/config-manager';
|
||||
import { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
import { LOG_ERROR } from '@/logger';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
|
@ -127,9 +127,8 @@ router.post('/', async (request: express.Request, response: express.Response): P
|
|||
title_id: BigInt(0),
|
||||
expire_time: BigInt(Date.now() + (3600 * 1000))
|
||||
};
|
||||
|
||||
try {
|
||||
|
||||
try {
|
||||
const accessTokenBuffer = await generateToken(config.aes_key, accessTokenOptions);
|
||||
const refreshTokenBuffer = await generateToken(config.aes_key, refreshTokenOptions);
|
||||
|
||||
|
|
@ -146,8 +145,10 @@ router.post('/', async (request: express.Request, response: express.Response): P
|
|||
});
|
||||
} catch (error: any) {
|
||||
LOG_ERROR('/v1/login - token generation: ' + error);
|
||||
if (error.stack) console.error(error.stack);
|
||||
|
||||
if (error.stack) {
|
||||
console.error(error.stack);
|
||||
}
|
||||
|
||||
response.status(500).json({
|
||||
app: 'api',
|
||||
status: 500,
|
||||
|
|
@ -156,4 +157,4 @@ router.post('/', async (request: express.Request, response: express.Response): P
|
|||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
import crypto from 'node:crypto';
|
||||
import express from 'express';
|
||||
import emailvalidator from 'email-validator';
|
||||
|
|
@ -12,8 +11,8 @@ import { LOG_ERROR } from '@/logger';
|
|||
import { PNID } from '@/models/pnid';
|
||||
import { NEXAccount } from '@/models/nex-account';
|
||||
import { config, disabledFeatures } from '@/config-manager';
|
||||
import { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account';
|
||||
import { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
import type { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
|
@ -276,7 +275,7 @@ router.post('/', async (request: express.Request, response: express.Response): P
|
|||
// * PNIDs can only be registered from a Wii U
|
||||
// * So assume website users are WiiU NEX accounts
|
||||
nexAccount = new NEXAccount({
|
||||
device_type: 'wiiu',
|
||||
device_type: 'wiiu'
|
||||
});
|
||||
|
||||
await nexAccount.generatePID();
|
||||
|
|
@ -347,7 +346,9 @@ router.post('/', async (request: express.Request, response: express.Response): P
|
|||
await session.commitTransaction();
|
||||
} catch (error: any) {
|
||||
LOG_ERROR('[POST] /v1/register: ' + error);
|
||||
if (error.stack) console.error(error.stack);
|
||||
if (error.stack) {
|
||||
console.error(error.stack);
|
||||
}
|
||||
|
||||
await session.abortTransaction();
|
||||
|
||||
|
|
@ -401,7 +402,9 @@ router.post('/', async (request: express.Request, response: express.Response): P
|
|||
});
|
||||
} catch (error: any) {
|
||||
LOG_ERROR('/v1/register - token generation: ' + error);
|
||||
if (error.stack) console.error(error.stack);
|
||||
if (error.stack) {
|
||||
console.error(error.stack);
|
||||
}
|
||||
|
||||
response.status(500).json({
|
||||
app: 'api',
|
||||
|
|
@ -411,4 +414,4 @@ router.post('/', async (request: express.Request, response: express.Response): P
|
|||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import express from 'express';
|
|||
import bcrypt from 'bcrypt';
|
||||
import { PNID } from '@/models/pnid';
|
||||
import { decryptToken, unpackToken, nintendoPasswordHash } from '@/util';
|
||||
import { Token } from '@/types/common/token';
|
||||
import type { Token } from '@/types/common/token';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ router.post('/', async (request: express.Request, response: express.Response): P
|
|||
try {
|
||||
const decryptedToken = await decryptToken(Buffer.from(token, 'hex'));
|
||||
unpackedToken = unpackToken(decryptedToken);
|
||||
} catch (error) {
|
||||
} catch {
|
||||
response.status(400).json({
|
||||
app: 'api',
|
||||
status: 400,
|
||||
|
|
@ -63,7 +63,6 @@ router.post('/', async (request: express.Request, response: express.Response): P
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!password || password === '') {
|
||||
response.status(400).json({
|
||||
app: 'api',
|
||||
|
|
@ -147,4 +146,4 @@ router.post('/', async (request: express.Request, response: express.Response): P
|
|||
});
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { z } from 'zod';
|
|||
import Mii from 'mii-js';
|
||||
import { config } from '@/config-manager';
|
||||
import { PNID } from '@/models/pnid';
|
||||
import { UpdateUserRequest } from '@/types/services/api/update-user-request';
|
||||
import type { UpdateUserRequest } from '@/types/services/api/update-user-request';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ const userSchema = z.object({
|
|||
mii: z.object({
|
||||
name: z.string().trim(),
|
||||
primary: z.enum(['Y', 'N']),
|
||||
data: z.string(),
|
||||
data: z.string()
|
||||
}).optional(),
|
||||
environment: z.enum(['prod', 'test', 'dev']).optional()
|
||||
});
|
||||
|
|
@ -46,7 +46,7 @@ router.get('/', async (request: express.Request, response: express.Response): Pr
|
|||
gender: pnid.gender,
|
||||
country: pnid.country,
|
||||
email: {
|
||||
address: pnid.email.address,
|
||||
address: pnid.email.address
|
||||
},
|
||||
timezone: {
|
||||
name: pnid.timezone.name
|
||||
|
|
@ -150,7 +150,7 @@ router.post('/', async (request: express.Request, response: express.Response): P
|
|||
|
||||
const mii = new Mii(miiDataBuffer);
|
||||
mii.validate();
|
||||
} catch (_) {
|
||||
} catch {
|
||||
response.status(400).json({
|
||||
app: 'api',
|
||||
status: 400,
|
||||
|
|
@ -208,7 +208,7 @@ router.post('/', async (request: express.Request, response: express.Response): P
|
|||
gender: pnid.gender,
|
||||
country: pnid.country,
|
||||
email: {
|
||||
address: pnid.email.address,
|
||||
address: pnid.email.address
|
||||
},
|
||||
timezone: {
|
||||
name: pnid.timezone.name
|
||||
|
|
@ -229,4 +229,4 @@ router.post('/', async (request: express.Request, response: express.Response): P
|
|||
});
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// * handles serving assets
|
||||
// * handles serving assets
|
||||
|
||||
import path from 'node:path';
|
||||
import express from 'express';
|
||||
|
|
@ -20,4 +20,4 @@ const router = express.Router();
|
|||
LOG_INFO(`[assets] Creating assets router with domains: ${formatHostnames(config.domains.assets)}`);
|
||||
router.use(restrictHostnames(config.domains.assets, assets));
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -34,4 +34,4 @@ const router = express.Router();
|
|||
LOG_INFO(`[conntest] Creating conntest router with domains: ${formatHostnames(config.domains.conntest)}`);
|
||||
router.use(restrictHostnames(config.domains.conntest, conntest));
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import express from 'express';
|
||||
import { LOG_INFO, formatHostnames } from '@/logger';
|
||||
|
||||
import upload from '@/services/datastore/routes/upload';
|
||||
import { restrictHostnames } from '@/middleware/host-limit';
|
||||
import { config } from '@/config-manager';
|
||||
|
|
@ -19,4 +18,4 @@ const router = express.Router();
|
|||
LOG_INFO(`[DATASTORE] Creating datastore router with domains: ${formatHostnames(config.domains.datastore)}`);
|
||||
router.use(restrictHostnames(config.domains.datastore, datastore));
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ function multipartParser(request: express.Request, response: express.Response, n
|
|||
let fileBuffer = Buffer.alloc(0);
|
||||
let fileName = '';
|
||||
|
||||
part.on('header', header => {
|
||||
part.on('header', (header) => {
|
||||
const contentDisposition = header['content-disposition' as keyof object];
|
||||
const regexResult = RE_FILE_NAME.exec(contentDisposition);
|
||||
|
||||
|
|
@ -97,4 +97,4 @@ router.post('/upload', multipartParser, async (request: express.Request, respons
|
|||
response.sendStatus(200);
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { Status, ServerMiddlewareCall, CallContext, ServerError } from 'nice-grpc';
|
||||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { config } from '@/config-manager';
|
||||
import type { ServerMiddlewareCall, CallContext } from 'nice-grpc';
|
||||
|
||||
export async function* apiKeyMiddleware<Request, Response>(
|
||||
call: ServerMiddlewareCall<Request, Response>,
|
||||
context: CallContext,
|
||||
context: CallContext
|
||||
): AsyncGenerator<Response, Response | void, undefined> {
|
||||
const apiKey = context.metadata.get('X-API-Key');
|
||||
|
||||
|
|
@ -12,4 +13,4 @@ export async function* apiKeyMiddleware<Request, Response>(
|
|||
}
|
||||
|
||||
return yield* call.next(call.request, context);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { ExchangeTokenForUserDataRequest } from '@pretendonetwork/grpc/account/exchange_token_for_user_data';
|
||||
import { GetUserDataResponse } from '@pretendonetwork/grpc/account/get_user_data_rpc';
|
||||
import { getPNIDByTokenAuth } from '@/database';
|
||||
import { PNID_PERMISSION_FLAGS } from '@/types/common/permission-flags';
|
||||
import { config } from '@/config-manager';
|
||||
import type { GetUserDataResponse } from '@pretendonetwork/grpc/account/get_user_data_rpc';
|
||||
import type { ExchangeTokenForUserDataRequest } from '@pretendonetwork/grpc/account/exchange_token_for_user_data';
|
||||
|
||||
export async function exchangeTokenForUserData(request: ExchangeTokenForUserDataRequest): Promise<GetUserDataResponse> {
|
||||
if (!request.token.trim()) {
|
||||
|
|
@ -25,7 +25,7 @@ export async function exchangeTokenForUserData(request: ExchangeTokenForUserData
|
|||
mii: {
|
||||
name: pnid.mii.name,
|
||||
data: pnid.mii.data,
|
||||
url: `${config.cdn.base_url}/mii/${pnid.pid}/standard.tga`,
|
||||
url: `${config.cdn.base_url}/mii/${pnid.pid}/standard.tga`
|
||||
},
|
||||
creationDate: pnid.creation_date,
|
||||
birthdate: pnid.birthdate,
|
||||
|
|
@ -59,4 +59,4 @@ export async function exchangeTokenForUserData(request: ExchangeTokenForUserData
|
|||
updatePnidPermissions: pnid.hasPermission(PNID_PERMISSION_FLAGS.UPDATE_PNID_PERMISSIONS)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Status, ServerError } from 'nice-grpc';
|
||||
import {GetNEXDataRequest,GetNEXDataResponse, DeepPartial } from '@pretendonetwork/grpc/account/get_nex_data_rpc';
|
||||
import { NEXAccount } from '@/models/nex-account';
|
||||
import type { GetNEXDataRequest, GetNEXDataResponse, DeepPartial } from '@pretendonetwork/grpc/account/get_nex_data_rpc';
|
||||
|
||||
export async function getNEXData(request: GetNEXDataRequest): Promise<DeepPartial<GetNEXDataResponse>> {
|
||||
const nexAccount = await NEXAccount.findOne({ pid: request.pid });
|
||||
|
|
@ -8,7 +8,7 @@ export async function getNEXData(request: GetNEXDataRequest): Promise<DeepPartia
|
|||
if (!nexAccount) {
|
||||
throw new ServerError(
|
||||
Status.INVALID_ARGUMENT,
|
||||
'No NEX account found',
|
||||
'No NEX account found'
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Status, ServerError } from 'nice-grpc';
|
||||
import {GetNEXPasswordRequest,GetNEXPasswordResponse, DeepPartial } from '@pretendonetwork/grpc/account/get_nex_password_rpc';
|
||||
import { NEXAccount } from '@/models/nex-account';
|
||||
import type { GetNEXPasswordRequest, GetNEXPasswordResponse, DeepPartial } from '@pretendonetwork/grpc/account/get_nex_password_rpc';
|
||||
|
||||
export async function getNEXPassword(request: GetNEXPasswordRequest): Promise<DeepPartial<GetNEXPasswordResponse>> {
|
||||
const nexAccount = await NEXAccount.findOne({ pid: request.pid });
|
||||
|
|
@ -8,7 +8,7 @@ export async function getNEXPassword(request: GetNEXPasswordRequest): Promise<De
|
|||
if (!nexAccount) {
|
||||
throw new ServerError(
|
||||
Status.INVALID_ARGUMENT,
|
||||
'No NEX account found',
|
||||
'No NEX account found'
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { GetUserDataRequest, GetUserDataResponse } from '@pretendonetwork/grpc/account/get_user_data_rpc';
|
||||
import { getPNIDByPID } from '@/database';
|
||||
import { PNID_PERMISSION_FLAGS } from '@/types/common/permission-flags';
|
||||
import { config } from '@/config-manager';
|
||||
import type { GetUserDataRequest, GetUserDataResponse } from '@pretendonetwork/grpc/account/get_user_data_rpc';
|
||||
|
||||
export async function getUserData(request: GetUserDataRequest): Promise<GetUserDataResponse> {
|
||||
const pnid = await getPNIDByPID(request.pid);
|
||||
|
|
@ -10,7 +10,7 @@ export async function getUserData(request: GetUserDataRequest): Promise<GetUserD
|
|||
if (!pnid) {
|
||||
throw new ServerError(
|
||||
Status.INVALID_ARGUMENT,
|
||||
'No PNID found',
|
||||
'No PNID found'
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -23,7 +23,7 @@ export async function getUserData(request: GetUserDataRequest): Promise<GetUserD
|
|||
mii: {
|
||||
name: pnid.mii.name,
|
||||
data: pnid.mii.data,
|
||||
url: `${config.cdn.base_url}/mii/${pnid.pid}/standard.tga`,
|
||||
url: `${config.cdn.base_url}/mii/${pnid.pid}/standard.tga`
|
||||
},
|
||||
creationDate: pnid.creation_date,
|
||||
birthdate: pnid.birthdate,
|
||||
|
|
@ -57,4 +57,4 @@ export async function getUserData(request: GetUserDataRequest): Promise<GetUserD
|
|||
updatePnidPermissions: pnid.hasPermission(PNID_PERMISSION_FLAGS.UPDATE_PNID_PERMISSIONS)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { UpdatePNIDPermissionsRequest } from '@pretendonetwork/grpc/account/update_pnid_permissions';
|
||||
import { getPNIDByPID } from '@/database';
|
||||
import { PNID_PERMISSION_FLAGS } from '@/types/common/permission-flags';
|
||||
import type { UpdatePNIDPermissionsRequest } from '@pretendonetwork/grpc/account/update_pnid_permissions';
|
||||
import type { Empty } from '@pretendonetwork/grpc/api/google/protobuf/empty';
|
||||
|
||||
export async function updatePNIDPermissions(request: UpdatePNIDPermissionsRequest): Promise<Empty> {
|
||||
|
|
@ -10,14 +10,14 @@ export async function updatePNIDPermissions(request: UpdatePNIDPermissionsReques
|
|||
if (!pnid) {
|
||||
throw new ServerError(
|
||||
Status.INVALID_ARGUMENT,
|
||||
'No PNID found',
|
||||
'No PNID found'
|
||||
);
|
||||
}
|
||||
|
||||
if (!request.permissions) {
|
||||
throw new ServerError(
|
||||
Status.INVALID_ARGUMENT,
|
||||
'Permissions flags not found',
|
||||
'Permissions flags not found'
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -156,4 +156,4 @@ export async function updatePNIDPermissions(request: UpdatePNIDPermissionsReques
|
|||
await pnid.save();
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { Status, ServerMiddlewareCall, CallContext, ServerError } from 'nice-grpc';
|
||||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { config } from '@/config-manager';
|
||||
import type { ServerMiddlewareCall, CallContext } from 'nice-grpc';
|
||||
|
||||
export async function* apiKeyMiddleware<Request, Response>(
|
||||
call: ServerMiddlewareCall<Request, Response>,
|
||||
context: CallContext,
|
||||
context: CallContext
|
||||
): AsyncGenerator<Response, Response | void, undefined> {
|
||||
const apiKey = context.metadata.get('X-API-Key');
|
||||
|
||||
|
|
@ -12,4 +13,4 @@ export async function* apiKeyMiddleware<Request, Response>(
|
|||
}
|
||||
|
||||
return yield* call.next(call.request, context);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { Status, ServerMiddlewareCall, CallContext, ServerError } from 'nice-grpc';
|
||||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { getPNIDByTokenAuth } from '@/database';
|
||||
import type { ServerMiddlewareCall, CallContext } from 'nice-grpc';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
|
||||
// * These paths require that a token be present
|
||||
|
|
@ -18,7 +19,7 @@ export type AuthenticationCallContextExt = {
|
|||
|
||||
export async function* authenticationMiddleware<Request, Response>(
|
||||
call: ServerMiddlewareCall<Request, Response, AuthenticationCallContextExt>,
|
||||
context: CallContext,
|
||||
context: CallContext
|
||||
): AsyncGenerator<Response, Response | void, undefined> {
|
||||
const token = context.metadata.get('X-Token')?.trim();
|
||||
|
||||
|
|
@ -52,4 +53,4 @@ export async function* authenticationMiddleware<Request, Response>(
|
|||
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { Status, ServerError } from 'nice-grpc';
|
||||
import validator from 'validator';
|
||||
import { ForgotPasswordRequest } from '@pretendonetwork/grpc/api/forgot_password_rpc';
|
||||
import { getPNIDByEmailAddress, getPNIDByUsername } from '@/database';
|
||||
import { sendForgotPasswordEmail } from '@/util';
|
||||
import type { ForgotPasswordRequest } from '@pretendonetwork/grpc/api/forgot_password_rpc';
|
||||
import type { Empty } from '@pretendonetwork/grpc/api/google/protobuf/empty';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
|
||||
|
|
@ -26,4 +26,4 @@ export async function forgotPassword(request: ForgotPasswordRequest): Promise<Em
|
|||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { CallContext } from 'nice-grpc';
|
||||
import { GetUserDataResponse, DeepPartial } from '@pretendonetwork/grpc/api/get_user_data_rpc';
|
||||
import { config } from '@/config-manager';
|
||||
import type { CallContext } from 'nice-grpc';
|
||||
import type { GetUserDataResponse, DeepPartial } from '@pretendonetwork/grpc/api/get_user_data_rpc';
|
||||
import type { Empty } from '@pretendonetwork/grpc/api/google/protobuf/empty';
|
||||
import type { AuthenticationCallContextExt } from '@/services/grpc/api/authentication-middleware';
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ export async function getUserData(_request: Empty, context: CallContext & Authen
|
|||
mii: {
|
||||
name: pnid.mii.name,
|
||||
data: pnid.mii.data,
|
||||
url: `${config.cdn.base_url}/mii/${pnid.pid}/standard.tga`,
|
||||
url: `${config.cdn.base_url}/mii/${pnid.pid}/standard.tga`
|
||||
},
|
||||
birthday: pnid.birthdate,
|
||||
gender: pnid.gender,
|
||||
|
|
|
|||
|
|
@ -16,4 +16,4 @@ export const apiServiceImplementation = {
|
|||
resetPassword,
|
||||
setDiscordConnectionData,
|
||||
setStripeConnectionData
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { LoginRequest, LoginResponse, DeepPartial } from '@pretendonetwork/grpc/api/login_rpc';
|
||||
import bcrypt from 'bcrypt';
|
||||
import { getPNIDByUsername, getPNIDByTokenAuth } from '@/database';
|
||||
import { nintendoPasswordHash, generateToken} from '@/util';
|
||||
import { nintendoPasswordHash, generateToken } from '@/util';
|
||||
import { config } from '@/config-manager';
|
||||
import type { LoginRequest, LoginResponse, DeepPartial } from '@pretendonetwork/grpc/api/login_rpc';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
|
||||
export async function login(request: LoginRequest): Promise<DeepPartial<LoginResponse>> {
|
||||
|
|
@ -86,4 +86,4 @@ export async function login(request: LoginRequest): Promise<DeepPartial<LoginRes
|
|||
expiresIn: 3600,
|
||||
refreshToken: newRefreshToken
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
import crypto from 'node:crypto';
|
||||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { RegisterRequest, DeepPartial } from '@pretendonetwork/grpc/api/register_rpc';
|
||||
import { LoginResponse } from '@pretendonetwork/grpc/api/login_rpc';
|
||||
import emailvalidator from 'email-validator';
|
||||
import bcrypt from 'bcrypt';
|
||||
import moment from 'moment';
|
||||
|
|
@ -13,6 +11,8 @@ import { LOG_ERROR } from '@/logger';
|
|||
import { PNID } from '@/models/pnid';
|
||||
import { NEXAccount } from '@/models/nex-account';
|
||||
import { config, disabledFeatures } from '@/config-manager';
|
||||
import type { LoginResponse } from '@pretendonetwork/grpc/api/login_rpc';
|
||||
import type { RegisterRequest, DeepPartial } from '@pretendonetwork/grpc/api/register_rpc';
|
||||
import type { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
|
||||
|
|
@ -140,7 +140,7 @@ export async function register(request: RegisterRequest): Promise<DeepPartial<Lo
|
|||
// * PNIDs can only be registered from a Wii U
|
||||
// * So assume website users are WiiU NEX accounts
|
||||
nexAccount = new NEXAccount({
|
||||
device_type: 'wiiu',
|
||||
device_type: 'wiiu'
|
||||
});
|
||||
|
||||
await nexAccount.generatePID();
|
||||
|
|
@ -261,4 +261,4 @@ export async function register(request: RegisterRequest): Promise<DeepPartial<Lo
|
|||
expiresIn: 3600,
|
||||
refreshToken: refreshToken
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import bcrypt from 'bcrypt';
|
||||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { ResetPasswordRequest } from '@pretendonetwork/grpc/api/reset_password_rpc';
|
||||
import { decryptToken, unpackToken, nintendoPasswordHash } from '@/util';
|
||||
import { getPNIDByPID } from '@/database';
|
||||
import type { ResetPasswordRequest } from '@pretendonetwork/grpc/api/reset_password_rpc';
|
||||
import type { Empty } from '@pretendonetwork/grpc/api/google/protobuf/empty';
|
||||
import type { Token } from '@/types/common/token';
|
||||
|
||||
|
|
@ -25,7 +25,7 @@ export async function resetPassword(request: ResetPasswordRequest): Promise<Empt
|
|||
try {
|
||||
const decryptedToken = await decryptToken(Buffer.from(token, 'base64'));
|
||||
unpackedToken = unpackToken(decryptedToken);
|
||||
} catch (error) {
|
||||
} catch {
|
||||
throw new ServerError(Status.INVALID_ARGUMENT, 'Invalid token');
|
||||
}
|
||||
|
||||
|
|
@ -75,4 +75,4 @@ export async function resetPassword(request: ResetPasswordRequest): Promise<Empt
|
|||
await pnid.save();
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { Status, ServerError, CallContext } from 'nice-grpc';
|
||||
import { SetDiscordConnectionDataRequest } from '@pretendonetwork/grpc/api/set_discord_connection_data_rpc';
|
||||
import { Status, ServerError } from 'nice-grpc';
|
||||
import type { CallContext } from 'nice-grpc';
|
||||
import type { SetDiscordConnectionDataRequest } from '@pretendonetwork/grpc/api/set_discord_connection_data_rpc';
|
||||
import type { Empty } from '@pretendonetwork/grpc/api/google/protobuf/empty';
|
||||
import type { AuthenticationCallContextExt } from '@/services/grpc/api/authentication-middleware';
|
||||
|
||||
export async function setDiscordConnectionData(request: SetDiscordConnectionDataRequest, context: CallContext & AuthenticationCallContextExt): Promise<Empty>{
|
||||
export async function setDiscordConnectionData(request: SetDiscordConnectionDataRequest, context: CallContext & AuthenticationCallContextExt): Promise<Empty> {
|
||||
// * This is asserted in authentication-middleware, we know this is never null
|
||||
const pnid = context.pnid!;
|
||||
|
||||
|
|
@ -22,4 +23,4 @@ export async function setDiscordConnectionData(request: SetDiscordConnectionData
|
|||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import { Status, ServerError, CallContext } from 'nice-grpc';
|
||||
import { SetStripeConnectionDataRequest } from '@pretendonetwork/grpc/api/set_stripe_connection_data_rpc';
|
||||
import { Status, ServerError } from 'nice-grpc';
|
||||
import { PNID } from '@/models/pnid';
|
||||
import type { CallContext } from 'nice-grpc';
|
||||
import type { SetStripeConnectionDataRequest } from '@pretendonetwork/grpc/api/set_stripe_connection_data_rpc';
|
||||
import type { Empty } from '@pretendonetwork/grpc/api/google/protobuf/empty';
|
||||
import type { AuthenticationCallContextExt } from '@/services/grpc/api/authentication-middleware';
|
||||
|
||||
type StripeMongoUpdateScheme = {
|
||||
access_level?: number;
|
||||
server_access_level?: string;
|
||||
'access_level'?: number;
|
||||
'server_access_level'?: string;
|
||||
'connections.stripe.customer_id'?: string;
|
||||
'connections.stripe.subscription_id'?: string;
|
||||
'connections.stripe.price_id'?: string;
|
||||
|
|
@ -15,7 +16,7 @@ type StripeMongoUpdateScheme = {
|
|||
'connections.stripe.latest_webhook_timestamp': number;
|
||||
};
|
||||
|
||||
export async function setStripeConnectionData(request: SetStripeConnectionDataRequest, context: CallContext & AuthenticationCallContextExt): Promise<Empty>{
|
||||
export async function setStripeConnectionData(request: SetStripeConnectionDataRequest, context: CallContext & AuthenticationCallContextExt): Promise<Empty> {
|
||||
// * This is asserted in authentication-middleware, we know this is never null
|
||||
const pnid = context.pnid!;
|
||||
|
||||
|
|
@ -61,7 +62,7 @@ export async function setStripeConnectionData(request: SetStripeConnectionDataRe
|
|||
if (pnid.connections.stripe.latest_webhook_timestamp && pnid.connections.stripe.customer_id) {
|
||||
// * Stripe customer data has already been initialized, update it
|
||||
await PNID.updateOne({
|
||||
pid: pnid.pid,
|
||||
'pid': pnid.pid,
|
||||
'connections.stripe.latest_webhook_timestamp': {
|
||||
$lte: request.timestamp
|
||||
}
|
||||
|
|
@ -87,4 +88,4 @@ export async function setStripeConnectionData(request: SetStripeConnectionDataRe
|
|||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { CallContext } from 'nice-grpc';
|
||||
import { UpdateUserDataRequest, DeepPartial } from '@pretendonetwork/grpc/api/update_user_data_rpc';
|
||||
import { GetUserDataResponse } from '@pretendonetwork/grpc/api/get_user_data_rpc';
|
||||
import { config } from '@/config-manager';
|
||||
import type { CallContext } from 'nice-grpc';
|
||||
import type { UpdateUserDataRequest, DeepPartial } from '@pretendonetwork/grpc/api/update_user_data_rpc';
|
||||
import type { GetUserDataResponse } from '@pretendonetwork/grpc/api/get_user_data_rpc';
|
||||
import type { AuthenticationCallContextExt } from '@/services/grpc/api/authentication-middleware';
|
||||
|
||||
export async function updateUserData(_request: UpdateUserDataRequest, context: CallContext & AuthenticationCallContextExt): Promise<DeepPartial<GetUserDataResponse>> {
|
||||
|
|
@ -21,7 +21,7 @@ export async function updateUserData(_request: UpdateUserDataRequest, context: C
|
|||
mii: {
|
||||
name: pnid.mii.name,
|
||||
data: pnid.mii.data,
|
||||
url: `${config.cdn.base_url}/mii/${pnid.pid}/standard.tga`,
|
||||
url: `${config.cdn.base_url}/mii/${pnid.pid}/standard.tga`
|
||||
},
|
||||
birthday: pnid.birthdate,
|
||||
gender: pnid.gender,
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
import { createServer } from 'nice-grpc';
|
||||
import { AccountDefinition } from '@pretendonetwork/grpc/account/account_service';
|
||||
import { APIDefinition } from '@pretendonetwork/grpc/api/api_service';
|
||||
|
||||
import { apiKeyMiddleware as accountApiKeyMiddleware } from '@/services/grpc/account/api-key-middleware';
|
||||
import { apiKeyMiddleware as apiApiKeyMiddleware } from '@/services/grpc/api/api-key-middleware';
|
||||
import { authenticationMiddleware as apiAuthenticationMiddleware } from '@/services/grpc/api/authentication-middleware';
|
||||
|
||||
import { accountServiceImplementation } from '@/services/grpc/account/implementation';
|
||||
import { apiServiceImplementation } from '@/services/grpc/api/implementation';
|
||||
|
||||
import { config } from '@/config-manager';
|
||||
|
||||
export async function startGRPCServer(): Promise<void> {
|
||||
|
|
@ -18,4 +15,4 @@ export async function startGRPCServer(): Promise<void> {
|
|||
server.with(apiApiKeyMiddleware).with(apiAuthenticationMiddleware).add(APIDefinition, apiServiceImplementation);
|
||||
|
||||
await server.listen(`0.0.0.0:${config.grpc.port}`);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import express from 'express';
|
||||
import { config, disabledFeatures } from '@/config-manager';
|
||||
import { LOG_INFO, formatHostnames } from '@/logger';
|
||||
|
||||
import get from '@/services/local-cdn/routes/get';
|
||||
import { restrictHostnames } from '@/middleware/host-limit';
|
||||
|
||||
|
|
@ -24,4 +23,4 @@ if (disabledFeatures.s3) {
|
|||
LOG_INFO('[LOCAL-CDN] s3 enabled, skipping local CDN');
|
||||
}
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -15,4 +15,4 @@ router.get('/*', async (request: express.Request, response: express.Response): P
|
|||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
import express from 'express';
|
||||
import NASCMiddleware from '@/middleware/nasc';
|
||||
import { LOG_INFO, formatHostnames } from '@/logger';
|
||||
|
||||
import ac from '@/services/nasc/routes/ac';
|
||||
import { restrictHostnames } from '@/middleware/host-limit';
|
||||
import { config } from '@/config-manager';
|
||||
|
|
@ -25,4 +24,4 @@ const router = express.Router();
|
|||
LOG_INFO(`[NASC] Creating nasc router with domains: ${formatHostnames(config.domains.nasc)}`);
|
||||
router.use(restrictHostnames(config.domains.nasc, nasc));
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import express from 'express';
|
||||
import { nintendoBase64Encode, nintendoBase64Decode, nascDateTime, nascError, generateToken } from '@/util';
|
||||
import { getServerByTitleID } from '@/database';
|
||||
import { NASCRequestParams } from '@/types/services/nasc/request-params';
|
||||
import { HydratedServerDocument } from '@/types/mongoose/server';
|
||||
import type { NASCRequestParams } from '@/types/services/nasc/request-params';
|
||||
import type { HydratedServerDocument } from '@/types/mongoose/server';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
|
@ -83,7 +83,7 @@ async function processLoginRequest(server: HydratedServerDocument, pid: number,
|
|||
retry: nintendoBase64Encode('0'),
|
||||
returncd: nintendoBase64Encode('001'),
|
||||
token: nexToken,
|
||||
datetime: nintendoBase64Encode(nascDateTime()),
|
||||
datetime: nintendoBase64Encode(nascDateTime())
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -108,8 +108,8 @@ async function processServiceTokenRequest(server: HydratedServerDocument, pid: n
|
|||
servicetoken: serviceToken,
|
||||
statusdata: nintendoBase64Encode('Y'),
|
||||
svchost: nintendoBase64Encode('n/a'),
|
||||
datetime: nintendoBase64Encode(nascDateTime()),
|
||||
datetime: nintendoBase64Encode(nascDateTime())
|
||||
});
|
||||
}
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import clientHeaderCheck from '@/middleware/client-header';
|
|||
import cemuMiddleware from '@/middleware/cemu';
|
||||
import pnidMiddleware from '@/middleware/pnid';
|
||||
import { LOG_INFO, formatHostnames } from '@/logger';
|
||||
|
||||
import admin from '@/services/nnas/routes/admin';
|
||||
import content from '@/services/nnas/routes/content';
|
||||
import devices from '@/services/nnas/routes/devices';
|
||||
|
|
@ -66,4 +65,4 @@ const router = express.Router();
|
|||
LOG_INFO(`[NNAS] Creating nnas router with domains: ${formatHostnames(config.domains.nnas)}`);
|
||||
router.use(restrictHostnames(config.domains.nnas, nnas));
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -6,15 +6,15 @@ import { getServerByClientID, getPNIDByPID } from '@/database';
|
|||
import { LOG_ERROR } from '@/logger';
|
||||
import { decryptToken, unpackToken, getValueFromHeaders, sendConfirmationEmail } from '@/util';
|
||||
import { config } from '@/config-manager';
|
||||
import { HydratedServerDocument } from '@/types/mongoose/server';
|
||||
import { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
import { AccountSettings } from '@/types/services/nnas/account-settings';
|
||||
import { Token } from '@/types/common/token';
|
||||
import { RegionLanguages } from '@/types/services/nnas/region-languages';
|
||||
import { RegionTimezone, RegionTimezones } from '@/types/services/nnas/region-timezones';
|
||||
import { Country, Region } from '@/types/services/nnas/regions';
|
||||
import timezones from '@/services/nnas/timezones.json';
|
||||
import regionsList from '@/services/nnas/regions.json';
|
||||
import type { HydratedServerDocument } from '@/types/mongoose/server';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
import type { AccountSettings } from '@/types/services/nnas/account-settings';
|
||||
import type { Token } from '@/types/common/token';
|
||||
import type { RegionLanguages } from '@/types/services/nnas/region-languages';
|
||||
import type { RegionTimezone, RegionTimezones } from '@/types/services/nnas/region-timezones';
|
||||
import type { Country, Region } from '@/types/services/nnas/regions';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
|
@ -26,8 +26,8 @@ const accountSettingsSchema = z.object({
|
|||
country: z.string(),
|
||||
email: z.string().email(),
|
||||
server_selection: z.enum(['prod', 'test', 'dev']),
|
||||
marketing_flag: z.enum(['true', 'false']).transform((value) => value === 'true'),
|
||||
off_device_flag: z.enum(['true', 'false']).transform((value) => value === 'true'),
|
||||
marketing_flag: z.enum(['true', 'false']).transform(value => value === 'true'),
|
||||
off_device_flag: z.enum(['true', 'false']).transform(value => value === 'true')
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
@ -63,7 +63,7 @@ router.get('/ui/profile', async function (request: express.Request, response: ex
|
|||
const regionLanguages: RegionLanguages = timezones[countryCode as keyof typeof timezones];
|
||||
const regionTimezones: RegionTimezones = regionLanguages[language] ? regionLanguages[language] : Object.values(regionLanguages)[0];
|
||||
|
||||
const region: Country | undefined = regionsList.find((region) => region.iso_code === countryCode);
|
||||
const region: Country | undefined = regionsList.find(region => region.iso_code === countryCode);
|
||||
|
||||
const miiFaces = ['normal_face', 'smile_open_mouth', 'sorrow', 'surprise_open_mouth', 'wink_left', 'frustrated'];
|
||||
const face = miiFaces[crypto.randomInt(5)];
|
||||
|
|
@ -78,7 +78,7 @@ router.get('/ui/profile', async function (request: express.Request, response: ex
|
|||
face,
|
||||
notice,
|
||||
accountLevel,
|
||||
regions: region ? region.regions: [],
|
||||
regions: region ? region.regions : [],
|
||||
regionsList
|
||||
});
|
||||
} catch (error: any) {
|
||||
|
|
@ -154,7 +154,7 @@ router.post('/update', async function (request: express.Request, response: expre
|
|||
const regionLanguages: RegionLanguages = timezones[pnid.country as keyof typeof timezones];
|
||||
const regionTimezones: RegionTimezones = regionLanguages[pnid.language] ? regionLanguages[pnid.language] : Object.values(regionLanguages)[0];
|
||||
const timezone: RegionTimezone | undefined = regionTimezones.find(tz => tz.area === timezoneName);
|
||||
const country: Country | undefined = regionsList.find((region) => region.iso_code === pnid.country);
|
||||
const country: Country | undefined = regionsList.find(region => region.iso_code === pnid.country);
|
||||
let notice = '';
|
||||
|
||||
if (!country) {
|
||||
|
|
@ -163,7 +163,7 @@ router.post('/update', async function (request: express.Request, response: expre
|
|||
return;
|
||||
}
|
||||
|
||||
const regionObject: Region | undefined = country.regions.find((region) => region.id === person.data.region);
|
||||
const regionObject: Region | undefined = country.regions.find(region => region.id === person.data.region);
|
||||
const region = regionObject ? regionObject.id : pnid.region;
|
||||
|
||||
if (!timezone) {
|
||||
|
|
|
|||
|
|
@ -117,5 +117,4 @@ router.get('/time', async (request: express.Request, response: express.Response)
|
|||
response.send('');
|
||||
});
|
||||
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -26,29 +26,29 @@ router.get('/agreements/:type/:region/:version', (request: express.Request, resp
|
|||
'@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||
'@xsi:type': 'chunkedStoredAgreementText',
|
||||
|
||||
main_title: {
|
||||
'main_title': {
|
||||
'#cdata': 'Pretendo Network Services Agreement'
|
||||
},
|
||||
agree_text: {
|
||||
'agree_text': {
|
||||
'#cdata': 'I Accept'
|
||||
},
|
||||
non_agree_text: {
|
||||
'non_agree_text': {
|
||||
'#cdata': 'I Decline'
|
||||
},
|
||||
main_text: {
|
||||
'main_text': {
|
||||
'@index': '1',
|
||||
'#cdata': 'Welcome to Pretendo\'s Christmas public beta! This is supplied with no liability or warranty, and is a stress test of our current services.This test is not expected to last long- term, and the data may be kept for later testing; this data will not be shared outside of Pretendo, and will be deleted at the end of our testing period.'
|
||||
},
|
||||
sub_title: {
|
||||
'sub_title': {
|
||||
'#cdata': 'Privacy Policy'
|
||||
},
|
||||
sub_text: {
|
||||
'sub_text': {
|
||||
'@index': '1',
|
||||
'#cdata': 'Welcome to Pretendo\'s Christmas public beta! This is supplied with no liability or warranty, and is a stress test of our current services.This test is not expected to last long- term, and the data may be kept for later testing; this data will not be shared outside of Pretendo, and will be deleted at the end of our testing period.'
|
||||
},
|
||||
}
|
||||
},
|
||||
type: 'NINTENDO-NETWORK-EULA',
|
||||
version: '0300',
|
||||
version: '0300'
|
||||
},
|
||||
{
|
||||
country: 'US',
|
||||
|
|
@ -59,29 +59,29 @@ router.get('/agreements/:type/:region/:version', (request: express.Request, resp
|
|||
'@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||
'@xsi:type': 'chunkedStoredAgreementText',
|
||||
|
||||
main_title: {
|
||||
'main_title': {
|
||||
'#cdata': 'Pretendo Network Services Agreement'
|
||||
},
|
||||
agree_text: {
|
||||
'agree_text': {
|
||||
'#cdata': 'I Accept'
|
||||
},
|
||||
non_agree_text: {
|
||||
'non_agree_text': {
|
||||
'#cdata': 'I Decline'
|
||||
},
|
||||
main_text: {
|
||||
'main_text': {
|
||||
'@index': '1',
|
||||
'#cdata': 'Welcome to Pretendo\'s Christmas public beta! This is supplied with no liability or warranty, and is a stress test of our current services.This test is not expected to last long- term, and the data may be kept for later testing; this data will not be shared outside of Pretendo, and will be deleted at the end of our testing period.'
|
||||
},
|
||||
sub_title: {
|
||||
'sub_title': {
|
||||
'#cdata': 'Privacy Policy'
|
||||
},
|
||||
sub_text: {
|
||||
'sub_text': {
|
||||
'@index': '1',
|
||||
'#cdata': 'Welcome to Pretendo\'s Christmas public beta! This is supplied with no liability or warranty, and is a stress test of our current services.This test is not expected to last long- term, and the data may be kept for later testing; this data will not be shared outside of Pretendo, and will be deleted at the end of our testing period.'
|
||||
},
|
||||
}
|
||||
},
|
||||
type: 'NINTENDO-NETWORK-EULA',
|
||||
version: '0300',
|
||||
version: '0300'
|
||||
},
|
||||
{
|
||||
country: 'US',
|
||||
|
|
@ -92,29 +92,29 @@ router.get('/agreements/:type/:region/:version', (request: express.Request, resp
|
|||
'@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||
'@xsi:type': 'chunkedStoredAgreementText',
|
||||
|
||||
main_title: {
|
||||
'main_title': {
|
||||
'#cdata': 'Pretendo Network Services Agreement'
|
||||
},
|
||||
agree_text: {
|
||||
'agree_text': {
|
||||
'#cdata': 'I Accept'
|
||||
},
|
||||
non_agree_text: {
|
||||
'non_agree_text': {
|
||||
'#cdata': 'I Decline'
|
||||
},
|
||||
main_text: {
|
||||
'main_text': {
|
||||
'@index': '1',
|
||||
'#cdata': 'Welcome to Pretendo\'s Christmas public beta! This is supplied with no liability or warranty, and is a stress test of our current services.This test is not expected to last long- term, and the data may be kept for later testing; this data will not be shared outside of Pretendo, and will be deleted at the end of our testing period.'
|
||||
},
|
||||
sub_title: {
|
||||
'sub_title': {
|
||||
'#cdata': 'Privacy Policy'
|
||||
},
|
||||
sub_text: {
|
||||
'sub_text': {
|
||||
'@index': '1',
|
||||
'#cdata': 'Welcome to Pretendo\'s Christmas public beta! This is supplied with no liability or warranty, and is a stress test of our current services.This test is not expected to last long- term, and the data may be kept for later testing; this data will not be shared outside of Pretendo, and will be deleted at the end of our testing period.'
|
||||
},
|
||||
}
|
||||
},
|
||||
type: 'NINTENDO-NETWORK-EULA',
|
||||
version: '0300',
|
||||
version: '0300'
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -162,4 +162,4 @@ router.get('/time_zones/:countryCode/:language', (request: express.Request, resp
|
|||
}).end());
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -15,4 +15,4 @@ router.get('/@current/status', async (request: express.Request, response: expres
|
|||
}).end());
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import xmlbuilder from 'xmlbuilder';
|
|||
import { getValueFromQueryString } from '@/util';
|
||||
import { PNID } from '@/models/pnid';
|
||||
import { config } from '@/config-manager';
|
||||
import { YesNoBoolString } from '@/types/common/yes-no-bool-string';
|
||||
import type { YesNoBoolString } from '@/types/common/yes-no-bool-string';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ router.get('/', async (request: express.Request, response: express.Response): Pr
|
|||
id: number;
|
||||
url: string;
|
||||
type: string;
|
||||
}[]
|
||||
}[];
|
||||
};
|
||||
name: string;
|
||||
pid: number;
|
||||
|
|
@ -127,4 +127,4 @@ router.get('/', async (request: express.Request, response: express.Response): Pr
|
|||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ router.post('/access_token/generate', deviceCertificateMiddleware, consoleStatus
|
|||
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
} catch {
|
||||
response.status(400).send(xmlbuilder.create({
|
||||
error: {
|
||||
cause: 'refresh_token',
|
||||
|
|
@ -186,4 +186,4 @@ router.post('/access_token/generate', deviceCertificateMiddleware, consoleStatus
|
|||
}).end());
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -11,10 +11,9 @@ import { PNID } from '@/models/pnid';
|
|||
import { NEXAccount } from '@/models/nex-account';
|
||||
import { LOG_ERROR } from '@/logger';
|
||||
import timezones from '@/services/nnas/timezones.json';
|
||||
|
||||
import { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
import { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account';
|
||||
import { Person } from '@/types/services/nnas/person';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
import type { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account';
|
||||
import type { Person } from '@/types/services/nnas/person';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
|
|
@ -89,7 +88,7 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request: express
|
|||
|
||||
try {
|
||||
nexAccount = new NEXAccount({
|
||||
device_type: 'wiiu',
|
||||
device_type: 'wiiu'
|
||||
});
|
||||
|
||||
await nexAccount.generatePID();
|
||||
|
|
@ -443,7 +442,6 @@ router.get('/@me/devices/status', async (_request: express.Request, response: ex
|
|||
}).end());
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* [PUT]
|
||||
* Replacement for: https://account.nintendo.net/v1/api/people/@me/miis/@primary
|
||||
|
|
@ -657,7 +655,7 @@ router.get('/@me/emails', async (request: express.Request, response: express.Res
|
|||
type: 'DEFAULT', // * what is this?
|
||||
updated_by: 'USER', // * need to actually update this
|
||||
validated: pnid.email.validated ? 'Y' : 'N',
|
||||
validated_date: pnid.email.validated_date,
|
||||
validated_date: pnid.email.validated_date
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -239,4 +239,4 @@ router.get('/nex_token/@me', async (request: express.Request, response: express.
|
|||
}).end());
|
||||
});
|
||||
|
||||
export default router;
|
||||
export default router;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import mongoose from 'mongoose';
|
||||
import type mongoose from 'mongoose';
|
||||
|
||||
export const domainServices = ['api', 'assets', 'cbvc', 'conntest', 'datastore', 'nasc', 'nnas', 'local_cdn'] as const;
|
||||
export type DomainService = typeof domainServices[number];
|
||||
|
|
@ -16,7 +16,7 @@ export interface Config {
|
|||
redis: {
|
||||
client: {
|
||||
url: string;
|
||||
}
|
||||
};
|
||||
};
|
||||
email: {
|
||||
ses: {
|
||||
|
|
@ -38,7 +38,7 @@ export interface Config {
|
|||
secret: string;
|
||||
};
|
||||
cdn: {
|
||||
/**
|
||||
/**
|
||||
* @deprecated Use `domains.cdn` instead
|
||||
*/
|
||||
subdomain?: string;
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
export type GenderTypes = 'M' | 'F';
|
||||
export type GenderTypes = 'M' | 'F';
|
||||
|
|
|
|||
|
|
@ -13,4 +13,4 @@ export interface MailerOptions {
|
|||
href: string;
|
||||
code: string;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,26 @@
|
|||
export const PNID_PERMISSION_FLAGS = {
|
||||
BANNED_ALL_PERMANENTLY: 1n << 0n,
|
||||
BANNED_ALL_TEMPORARILY: 1n << 1n,
|
||||
BETA_ACCESS: 1n << 2n,
|
||||
ACCESS_ADMIN_PANEL: 1n << 3n,
|
||||
CREATE_SERVER_CONFIGS: 1n << 4n,
|
||||
MODIFY_SERVER_CONFIGS: 1n << 5n,
|
||||
DEPLOY_SERVER: 1n << 6n,
|
||||
MODIFY_PNIDS: 1n << 7n,
|
||||
MODIFY_NEX_ACCOUNTS: 1n << 8n,
|
||||
MODIFY_CONSOLES: 1n << 9n,
|
||||
BAN_PNIDS: 1n << 10n,
|
||||
BAN_NEX_ACCOUNTS: 1n << 11n,
|
||||
BAN_CONSOLES: 1n << 12n,
|
||||
MODERATE_MIIVERSE: 1n << 13n,
|
||||
CREATE_API_KEYS: 1n << 14n, // * This applies to all services
|
||||
CREATE_BOSS_TASKS: 1n << 15n,
|
||||
UPDATE_BOSS_TASKS: 1n << 16n,
|
||||
DELETE_BOSS_TASKS: 1n << 17n,
|
||||
UPLOAD_BOSS_FILES: 1n << 18n,
|
||||
UPDATE_BOSS_FILES: 1n << 18n,
|
||||
DELETE_BOSS_FILES: 1n << 19n,
|
||||
BANNED_ALL_PERMANENTLY: 1n << 0n,
|
||||
BANNED_ALL_TEMPORARILY: 1n << 1n,
|
||||
BETA_ACCESS: 1n << 2n,
|
||||
ACCESS_ADMIN_PANEL: 1n << 3n,
|
||||
CREATE_SERVER_CONFIGS: 1n << 4n,
|
||||
MODIFY_SERVER_CONFIGS: 1n << 5n,
|
||||
DEPLOY_SERVER: 1n << 6n,
|
||||
MODIFY_PNIDS: 1n << 7n,
|
||||
MODIFY_NEX_ACCOUNTS: 1n << 8n,
|
||||
MODIFY_CONSOLES: 1n << 9n,
|
||||
BAN_PNIDS: 1n << 10n,
|
||||
BAN_NEX_ACCOUNTS: 1n << 11n,
|
||||
BAN_CONSOLES: 1n << 12n,
|
||||
MODERATE_MIIVERSE: 1n << 13n,
|
||||
CREATE_API_KEYS: 1n << 14n, // * This applies to all services
|
||||
CREATE_BOSS_TASKS: 1n << 15n,
|
||||
UPDATE_BOSS_TASKS: 1n << 16n,
|
||||
DELETE_BOSS_TASKS: 1n << 17n,
|
||||
UPLOAD_BOSS_FILES: 1n << 18n,
|
||||
UPDATE_BOSS_FILES: 1n << 18n,
|
||||
DELETE_BOSS_FILES: 1n << 19n,
|
||||
UPDATE_PNID_PERMISSIONS: 1n << 20n
|
||||
} as const;
|
||||
|
||||
export type PNIDPermissionFlag = (typeof PNID_PERMISSION_FLAGS)[keyof typeof PNID_PERMISSION_FLAGS];
|
||||
export type PNIDPermissionFlag = (typeof PNID_PERMISSION_FLAGS)[keyof typeof PNID_PERMISSION_FLAGS];
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
export interface SafeQs {
|
||||
[key: string]: string | undefined
|
||||
}
|
||||
[key: string]: string | undefined;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
export interface SignatureSize {
|
||||
SIZE: number;
|
||||
PADDING_SIZE: number;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ export interface TokenOptions {
|
|||
access_level?: number;
|
||||
title_id?: bigint;
|
||||
expire_time: bigint;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ export interface Token {
|
|||
access_level?: number;
|
||||
title_id?: bigint;
|
||||
expire_time: bigint;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
export type YesNoBoolString = 'Y' | 'N';
|
||||
export type YesNoBoolString = 'Y' | 'N';
|
||||
|
|
|
|||
10
src/types/express.d.ts
vendored
10
src/types/express.d.ts
vendored
|
|
@ -1,7 +1,7 @@
|
|||
import NintendoCertificate from '@/nintendo-certificate';
|
||||
import { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
import { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account';
|
||||
import { HydratedDeviceDocument } from '@/types/mongoose/device';
|
||||
import type NintendoCertificate from '@/nintendo-certificate';
|
||||
import type { HydratedPNIDDocument } from '@/types/mongoose/pnid';
|
||||
import type { HydratedNEXAccountDocument } from '@/types/mongoose/nex-account';
|
||||
import type { HydratedDeviceDocument } from '@/types/mongoose/device';
|
||||
|
||||
declare global {
|
||||
namespace Express {
|
||||
|
|
@ -14,4 +14,4 @@ declare global {
|
|||
device?: HydratedDeviceDocument;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
4
src/types/image-pixels.d.ts
vendored
4
src/types/image-pixels.d.ts
vendored
|
|
@ -1,5 +1,5 @@
|
|||
declare module 'image-pixels' {
|
||||
import { NdArray } from 'ndarray';
|
||||
import type { NdArray } from 'ndarray';
|
||||
|
||||
export interface ImagePixelsOptions {
|
||||
source: ImageSource;
|
||||
|
|
@ -29,4 +29,4 @@ declare module 'image-pixels' {
|
|||
export default function pixels(
|
||||
src: ImageSource | Promise<ImageSource>
|
||||
): ImageData;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
src/types/mii-js.d.ts
vendored
2
src/types/mii-js.d.ts
vendored
|
|
@ -97,4 +97,4 @@ type Mii = {
|
|||
studioUrl: (options: MiiStudioURLOptions) => string;
|
||||
encode: () => Buffer;
|
||||
validate: () => void;
|
||||
};
|
||||
};
|
||||
|
|
|
|||
2
src/types/mongoose-unique-validator.d.ts
vendored
2
src/types/mongoose-unique-validator.d.ts
vendored
|
|
@ -1 +1 @@
|
|||
declare module 'mongoose-unique-validator';
|
||||
declare module 'mongoose-unique-validator';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Model } from 'mongoose';
|
||||
import type { Model } from 'mongoose';
|
||||
|
||||
export interface IDeviceAttribute {
|
||||
created_date?: string;
|
||||
|
|
@ -10,4 +10,4 @@ export interface IDeviceAttributeMethods {}
|
|||
|
||||
interface IDeviceAttributeQueryHelpers {}
|
||||
|
||||
export interface DeviceAttributeModel extends Model<IDeviceAttribute, IDeviceAttributeQueryHelpers, IDeviceAttributeMethods> {}
|
||||
export interface DeviceAttributeModel extends Model<IDeviceAttribute, IDeviceAttributeQueryHelpers, IDeviceAttributeMethods> {}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { Model, Types, HydratedDocument } from 'mongoose';
|
||||
import { IDeviceAttribute } from '@/types/mongoose/device-attribute';
|
||||
import type { Model, Types, HydratedDocument } from 'mongoose';
|
||||
import type { IDeviceAttribute } from '@/types/mongoose/device-attribute';
|
||||
|
||||
type MODEL = 'wup' | 'ctr' | 'spr' | 'ftr' | 'ktr' | 'red' | 'jan';
|
||||
type ACCESS_LEVEL = -1 | 0 | 1 | 2 | 3;
|
||||
|
|
@ -16,7 +16,7 @@ export interface IDevice {
|
|||
account_id: number;
|
||||
};
|
||||
environment: string;
|
||||
mac_hash: string; // * 3DS-specific
|
||||
mac_hash: string; // * 3DS-specific
|
||||
fcdcert_hash: string; // * 3DS-specific
|
||||
linked_pids: number[];
|
||||
access_level: ACCESS_LEVEL;
|
||||
|
|
@ -30,4 +30,4 @@ interface IDeviceQueryHelpers {}
|
|||
|
||||
export interface DeviceModel extends Model<IDevice, IDeviceQueryHelpers, IDeviceMethods> {}
|
||||
|
||||
export type HydratedDeviceDocument = HydratedDocument<IDevice, IDeviceMethods>
|
||||
export type HydratedDeviceDocument = HydratedDocument<IDevice, IDeviceMethods>;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Model, HydratedDocument } from 'mongoose';
|
||||
import type { Model, HydratedDocument } from 'mongoose';
|
||||
|
||||
type DEVICE = 'wiiu' | '3ds';
|
||||
enum ACCESS_LEVEL {
|
||||
|
|
@ -27,4 +27,4 @@ interface INEXAccountQueryHelpers {}
|
|||
|
||||
export interface NEXAccountModel extends Model<INEXAccount, INEXAccountQueryHelpers, INEXAccountMethods> {}
|
||||
|
||||
export type HydratedNEXAccountDocument = HydratedDocument<INEXAccount, INEXAccountMethods>
|
||||
export type HydratedNEXAccountDocument = HydratedDocument<INEXAccount, INEXAccountMethods>;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Model, Types, HydratedDocument } from 'mongoose';
|
||||
import { IDevice } from '@/types/mongoose/device';
|
||||
import { PNIDPermissionFlag } from '@/types/common/permission-flags';
|
||||
import type { Model, Types, HydratedDocument } from 'mongoose';
|
||||
import type { IDevice } from '@/types/mongoose/device';
|
||||
import type { PNIDPermissionFlag } from '@/types/common/permission-flags';
|
||||
|
||||
export interface IPNID {
|
||||
deleted: boolean;
|
||||
|
|
@ -58,7 +58,7 @@ export interface IPNID {
|
|||
refresh_token: {
|
||||
value: string;
|
||||
ttl: number;
|
||||
}
|
||||
};
|
||||
};
|
||||
connections: {
|
||||
discord: {
|
||||
|
|
@ -79,7 +79,7 @@ export interface IPNIDMethods {
|
|||
generatePID(): Promise<void>;
|
||||
generateEmailValidationCode(): Promise<void>;
|
||||
generateEmailValidationToken(): Promise<void>;
|
||||
updateMii(mii: { name: string, primary: string, data: string}): Promise<void>;
|
||||
updateMii(mii: { name: string; primary: string; data: string }): Promise<void>;
|
||||
generateMiiImages(): Promise<void>;
|
||||
scrub(): Promise<void>;
|
||||
hasPermission(flag: PNIDPermissionFlag): boolean;
|
||||
|
|
@ -91,4 +91,4 @@ interface IPNIDQueryHelpers {}
|
|||
|
||||
export interface PNIDModel extends Model<IPNID, IPNIDQueryHelpers, IPNIDMethods> {}
|
||||
|
||||
export type HydratedPNIDDocument = HydratedDocument<IPNID, IPNIDMethods>
|
||||
export type HydratedPNIDDocument = HydratedDocument<IPNID, IPNIDMethods>;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Model, HydratedDocument } from 'mongoose';
|
||||
import type { Model, HydratedDocument } from 'mongoose';
|
||||
|
||||
export interface IServer {
|
||||
client_id: string;
|
||||
|
|
@ -20,4 +20,4 @@ interface IServerQueryHelpers {}
|
|||
|
||||
export interface ServerModel extends Model<IServer, IServerQueryHelpers, IServerMethods> {}
|
||||
|
||||
export type HydratedServerDocument = HydratedDocument<IServer, IServerMethods>
|
||||
export type HydratedServerDocument = HydratedDocument<IServer, IServerMethods>;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { DiscordConnectionData } from '@/types/services/api/discord-connection-data';
|
||||
import type { DiscordConnectionData } from '@/types/services/api/discord-connection-data';
|
||||
|
||||
// TODO - This will be a union of all ConnectionData types when more connections are added
|
||||
export type ConnectionData = DiscordConnectionData;
|
||||
export type ConnectionData = DiscordConnectionData;
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@ export interface ConnectionResponse {
|
|||
app: string;
|
||||
status: number;
|
||||
error?: string;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
export interface DiscordConnectionData {
|
||||
id: string;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@ export interface UpdateUserRequest {
|
|||
name: string;
|
||||
primary: string;
|
||||
data: string;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,4 +8,4 @@ export interface NASCRequestParams {
|
|||
userid?: string;
|
||||
uidhmac?: string;
|
||||
passwd?: string;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { GenderTypes } from '@/types/common/gender-types';
|
||||
import type { GenderTypes } from '@/types/common/gender-types';
|
||||
|
||||
export interface AccountSettings {
|
||||
birthdate: string;
|
||||
|
|
@ -9,4 +9,4 @@ export interface AccountSettings {
|
|||
server_selection: string;
|
||||
marketing_flag: boolean;
|
||||
off_device_flag: boolean;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { YesNoBoolString } from '@/types/common/yes-no-bool-string';
|
||||
import { IDeviceAttribute } from '@/types/mongoose/device-attribute';
|
||||
import type { YesNoBoolString } from '@/types/common/yes-no-bool-string';
|
||||
import type { IDeviceAttribute } from '@/types/mongoose/device-attribute';
|
||||
|
||||
// TODO - Change this Map type to something more strongly typed
|
||||
export interface Person {
|
||||
|
|
@ -38,7 +38,7 @@ export interface Person {
|
|||
region: number;
|
||||
marketing_flag: YesNoBoolString;
|
||||
device_attributes: {
|
||||
device_attribute: IDeviceAttribute[]
|
||||
device_attribute: IDeviceAttribute[];
|
||||
};
|
||||
off_device_flag: YesNoBoolString;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { YesNoBoolString } from '@/types/common/yes-no-bool-string';
|
||||
import type { YesNoBoolString } from '@/types/common/yes-no-bool-string';
|
||||
|
||||
export interface PNIDProfile {
|
||||
// *accounts: {}; // * We need to figure this out; no idea what these values mean or what they do
|
||||
|
|
@ -41,7 +41,7 @@ export interface PNIDProfile {
|
|||
id: number;
|
||||
url: string;
|
||||
type: 'standard';
|
||||
}
|
||||
};
|
||||
};
|
||||
name: string;
|
||||
primary: YesNoBoolString;
|
||||
|
|
@ -50,4 +50,4 @@ export interface PNIDProfile {
|
|||
tz_name: string;
|
||||
user_id: string;
|
||||
utc_offset: number;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { RegionTimezones } from '@/types/services/nnas/region-timezones';
|
||||
import type { RegionTimezones } from '@/types/services/nnas/region-timezones';
|
||||
|
||||
export interface RegionLanguages {
|
||||
[myKey: string]: RegionTimezones
|
||||
}
|
||||
[myKey: string]: RegionTimezones;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,4 +6,4 @@ export interface RegionTimezone {
|
|||
order: string;
|
||||
}
|
||||
|
||||
export type RegionTimezones = RegionTimezone[];
|
||||
export type RegionTimezones = RegionTimezone[];
|
||||
|
|
|
|||
2
src/types/tga.d.ts
vendored
2
src/types/tga.d.ts
vendored
|
|
@ -55,4 +55,4 @@ declare module 'tga' {
|
|||
|
||||
public pixels: Uint8Array;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
41
src/util.ts
41
src/util.ts
|
|
@ -1,19 +1,20 @@
|
|||
import crypto from 'node:crypto';
|
||||
import path from 'node:path';
|
||||
import { IncomingHttpHeaders } from 'node:http';
|
||||
import { ObjectCannedACL, S3 } from '@aws-sdk/client-s3';
|
||||
import { S3 } from '@aws-sdk/client-s3';
|
||||
import fs from 'fs-extra';
|
||||
import express from 'express';
|
||||
import mongoose from 'mongoose';
|
||||
import { ParsedQs } from 'qs';
|
||||
import crc32 from 'buffer-crc32';
|
||||
import crc from 'crc';
|
||||
import bufferCrc32 from 'buffer-crc32';
|
||||
import { crc32 } from 'crc';
|
||||
import { sendMail } from '@/mailer';
|
||||
import { config, disabledFeatures } from '@/config-manager';
|
||||
import { TokenOptions } from '@/types/common/token-options';
|
||||
import { Token } from '@/types/common/token';
|
||||
import { IPNID, IPNIDMethods } from '@/types/mongoose/pnid';
|
||||
import { SafeQs } from '@/types/common/safe-qs';
|
||||
import type { ParsedQs } from 'qs';
|
||||
import type mongoose from 'mongoose';
|
||||
import type express from 'express';
|
||||
import type { ObjectCannedACL } from '@aws-sdk/client-s3';
|
||||
import type { IncomingHttpHeaders } from 'node:http';
|
||||
import type { TokenOptions } from '@/types/common/token-options';
|
||||
import type { Token } from '@/types/common/token';
|
||||
import type { IPNID, IPNIDMethods } from '@/types/mongoose/pnid';
|
||||
import type { SafeQs } from '@/types/common/safe-qs';
|
||||
|
||||
let s3: S3;
|
||||
|
||||
|
|
@ -25,8 +26,8 @@ if (!disabledFeatures.s3) {
|
|||
|
||||
credentials: {
|
||||
accessKeyId: config.s3.key,
|
||||
secretAccessKey: config.s3.secret,
|
||||
},
|
||||
secretAccessKey: config.s3.secret
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -89,7 +90,7 @@ export function generateToken(key: string, options: TokenOptions): Buffer | null
|
|||
|
||||
if ((options.token_type !== 0x1 && options.token_type !== 0x2) || options.system_type === 0x3) {
|
||||
// * Access and refresh tokens don't get a checksum due to size constraints
|
||||
const checksum = crc32(dataBuffer);
|
||||
const checksum = bufferCrc32(dataBuffer);
|
||||
|
||||
final = Buffer.concat([
|
||||
checksum,
|
||||
|
|
@ -124,7 +125,7 @@ export function decryptToken(token: Buffer, key?: string): Buffer {
|
|||
decipher.final()
|
||||
]);
|
||||
|
||||
if (expectedChecksum && (expectedChecksum !== crc.crc32(decrypted))) {
|
||||
if (expectedChecksum && (expectedChecksum !== crc32(decrypted))) {
|
||||
throw new Error('Checksum did not match. Failed decrypt. Are you using the right key?');
|
||||
}
|
||||
|
||||
|
|
@ -193,7 +194,7 @@ export function nascError(errorCode: string): URLSearchParams {
|
|||
return new URLSearchParams({
|
||||
retry: nintendoBase64Encode('1'),
|
||||
returncd: errorCode == 'null' ? errorCode : nintendoBase64Encode(errorCode),
|
||||
datetime: nintendoBase64Encode(nascDateTime()),
|
||||
datetime: nintendoBase64Encode(nascDateTime())
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -212,7 +213,7 @@ export async function sendConfirmationEmail(pnid: mongoose.HydratedDocument<IPNI
|
|||
await sendMail(options);
|
||||
}
|
||||
|
||||
export async function sendEmailConfirmedEmail(pnid: mongoose.HydratedDocument<IPNID, IPNIDMethods>): Promise<void> {
|
||||
export async function sendEmailConfirmedEmail(pnid: mongoose.HydratedDocument<IPNID, IPNIDMethods>): Promise<void> {
|
||||
const options = {
|
||||
to: pnid.email.address,
|
||||
subject: '[Pretendo Network] Email address confirmed',
|
||||
|
|
@ -224,7 +225,7 @@ export async function sendEmailConfirmedEmail(pnid: mongoose.HydratedDocument<IP
|
|||
await sendMail(options);
|
||||
}
|
||||
|
||||
export async function sendEmailConfirmedParentalControlsEmail(pnid: mongoose.HydratedDocument<IPNID, IPNIDMethods>): Promise<void> {
|
||||
export async function sendEmailConfirmedParentalControlsEmail(pnid: mongoose.HydratedDocument<IPNID, IPNIDMethods>): Promise<void> {
|
||||
const options = {
|
||||
to: pnid.email.address,
|
||||
subject: '[Pretendo Network] Email address confirmed for Parental Controls',
|
||||
|
|
@ -333,5 +334,5 @@ export function getValueFromHeaders(headers: IncomingHttpHeaders, key: string):
|
|||
}
|
||||
|
||||
export function mapToObject(map: Map<any, any>): object {
|
||||
return Object.fromEntries(Array.from(map.entries(), ([ k, v ]) => v instanceof Map ? [ k, mapToObject(v) ] : [ k, v ]));
|
||||
}
|
||||
return Object.fromEntries(Array.from(map.entries(), ([k, v]) => v instanceof Map ? [k, mapToObject(v)] : [k, v]));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user