Convert Maps to JSON objects on request body

This commit is contained in:
Jonathan Barrow
2023-03-19 16:21:30 -04:00
parent f977d77c5c
commit 39ccd942cb
6 changed files with 53 additions and 47 deletions

View File

@@ -1,7 +1,7 @@
import express from 'express';
import xmlbuilder from 'xmlbuilder';
import { document as xmlParser } from 'xmlbuilder2';
import { getValueFromHeaders } from '@/util';
import { getValueFromHeaders, mapToObject } from '@/util';
function XMLMiddleware(request: express.Request, response: express.Response, next: express.NextFunction): void {
if (request.method == 'POST' || request.method == 'PUT') {
@@ -32,6 +32,7 @@ function XMLMiddleware(request: express.Request, response: express.Response, nex
try {
request.body = xmlParser(body);
request.body = request.body.toObject();
request.body = mapToObject(request.body);
} catch (error) {
response.status(401);

View File

@@ -121,8 +121,6 @@ router.get('/', async (request: express.Request, response: express.Response) =>
});
}
//console.log(results[0].mii.data.replace(/(\r\n|\n|\r)/gm, ''));
response.send(xmlbuilder.create({
miis: {
mii: miis

View File

@@ -69,10 +69,9 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request: express
}).end());
}
// * request.body is a Map, as is request.body.person
const person: Person = request.body.get('person');
const person: Person = request.body.person;
const userExists: boolean = await doesPNIDExist(person.get('user_id'));
const userExists: boolean = await doesPNIDExist(person.user_id);
if (userExists) {
response.status(400);
@@ -111,12 +110,12 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request: express
await nexAccount.save({ session });
const primaryPasswordHash: string = nintendoPasswordHash(person.get('password'), nexAccount.pid);
const primaryPasswordHash: string = nintendoPasswordHash(person.password, nexAccount.pid);
const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10);
const countryCode: string = person.get('country');
const language: string = person.get('language');
const timezoneName: string = person.get('tz_name');
const countryCode: string = person.country;
const language: string = person.language;
const timezoneName: string = person.tz_name;
const regionLanguages: RegionLanguages = timezones[countryCode as keyof typeof timezones];
const regionTimezones: RegionTimezones = regionLanguages[language] ? regionLanguages[language] : Object.values(regionLanguages)[0];
@@ -137,30 +136,30 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request: express
pid: nexAccount.pid,
creation_date: creationDate,
updated: creationDate,
username: person.get('user_id'),
usernameLower: person.get('user_id').toLowerCase(),
username: person.user_id,
usernameLower: person.user_id.toLowerCase(),
password: passwordHash,
birthdate: person.get('birth_date'),
gender: person.get('gender'),
birthdate: person.birth_date,
gender: person.gender,
country: countryCode,
language: language,
email: {
address: person.get('email').get('address').toLowerCase(),
primary: person.get('email').get('primary') === 'Y',
parent: person.get('email').get('parent') === 'Y',
address: person.email.address.toLowerCase(),
primary: person.email.primary === 'Y',
parent: person.email.parent === 'Y',
reachable: false,
validated: person.get('email').get('validated') === 'Y',
validated: person.email.validated === 'Y',
id: crypto.randomBytes(4).readUInt32LE()
},
region: person.get('region'),
region: person.region,
timezone: {
name: timezoneName,
offset: Number(timezone.utc_offset)
},
mii: {
name: person.get('mii').get('name'),
primary: person.get('mii').get('name') === 'Y',
data: person.get('mii').get('data'),
name: person.mii.name,
primary: person.mii.name === 'Y',
data: person.mii.data,
id: crypto.randomBytes(4).readUInt32LE(),
hash: crypto.randomBytes(7).toString('hex'),
image_url: '', // deprecated, will be removed in the future
@@ -168,8 +167,8 @@ router.post('/', ratelimit, deviceCertificateMiddleware, async (request: express
},
flags: {
active: true,
marketing: person.get('marketing_flag') === 'Y',
off_device: person.get('off_device_flag') === 'Y'
marketing: person.marketing_flag === 'Y',
off_device: person.off_device_flag === 'Y'
},
identification: {
email_code: 1, // will be overwritten before saving
@@ -456,14 +455,17 @@ router.put('/@me/miis/@primary', async (request: express.Request, response: expr
}).end());
}
// TODO - Make this more strictly typed?
const mii: Map<string, string> = request.body.get('mii');
const mii: {
name: string;
primary: string;
data: string;
} = request.body.mii;
// TODO - Better checks
const name: string | undefined = mii.get('name') || '';
const primary: string | undefined = mii.get('primary') || '';
const data: string | undefined = mii.get('data') || '';
const name: string = mii.name;
const primary: string = mii.primary;
const data: string = mii.data;
await pnid.updateMii({ name, primary, data });
@@ -531,7 +533,7 @@ router.put('/@me/deletion', async (request: express.Request, response: express.R
*/
router.put('/@me', async (request: express.Request, response: express.Response) => {
const pnid: HydratedPNIDDocument | null = request.pnid;
const person: Person = request.body.get('person');
const person: Person = request.body.person;
if (!pnid) {
response.status(400);
@@ -547,13 +549,13 @@ router.put('/@me', async (request: express.Request, response: express.Response)
}).end());
}
const gender: string = person.get('gender') ? person.get('gender') : pnid.gender;
const region: string = person.get('region') ? person.get('region') : pnid.region;
const countryCode: string = person.get('country') ? person.get('country') : pnid.country;
const language: string = person.get('language') ? person.get('language') : pnid.language;
const timezoneName: string = person.get('tz_name') ? person.get('tz_name') : pnid.timezone.name;
const marketingFlag: boolean = person.get('marketing_flag') ? person.get('marketing_flag') === 'Y' : pnid.flags.marketing;
const offDeviceFlag: boolean = person.get('off_device_flag') ? person.get('off_device_flag') === 'Y' : pnid.flags.off_device;
const gender: string = person.gender ? person.gender : pnid.gender;
const region: number = person.region ? person.region : pnid.region;
const countryCode: string = person.country ? person.country : pnid.country;
const language: string = person.language ? person.language : pnid.language;
const timezoneName: string = person.tz_name ? person.tz_name : pnid.timezone.name;
const marketingFlag: boolean = person.marketing_flag ? person.marketing_flag === 'Y' : pnid.flags.marketing;
const offDeviceFlag: boolean = person.off_device_flag ? person.off_device_flag === 'Y' : pnid.flags.off_device;
const regionLanguages: RegionLanguages = timezones[countryCode as keyof typeof timezones];
const regionTimezones: RegionTimezones = regionLanguages[language] ? regionLanguages[language] : Object.values(regionLanguages)[0];
@@ -570,15 +572,15 @@ router.put('/@me', async (request: express.Request, response: express.Response)
};
}
if (person.get('password')) {
const primaryPasswordHash: string = nintendoPasswordHash(person.get('password'), pnid.pid);
if (person.password) {
const primaryPasswordHash: string = nintendoPasswordHash(person.password, pnid.pid);
const passwordHash: string = await bcrypt.hash(primaryPasswordHash, 10);
pnid.password = passwordHash;
}
pnid.gender = gender;
pnid.region = Number(region);
pnid.region = region;
pnid.timezone.name = timezoneName;
pnid.timezone.offset = Number(timezone.utc_offset);
pnid.timezone.marketing = marketingFlag;
@@ -638,10 +640,11 @@ router.get('/@me/emails', async (request: express.Request, response: express.Res
router.put('/@me/emails/@primary', async (request: express.Request, response: express.Response) => {
const pnid: HydratedPNIDDocument | null = request.pnid;
// TODO - Make this more strictly typed?
const email: Map<string, string> = request.body.get('email');
const email: {
address: string;
} = request.body.email;
if (!pnid || !email) {
if (!pnid || !email || !email.address) {
response.status(400);
return response.end(xmlbuilder.create({
@@ -656,7 +659,7 @@ router.put('/@me/emails/@primary', async (request: express.Request, response: ex
}
// TODO - Better email check
pnid.email.address = (email.get('address') || '').toLowerCase();
pnid.email.address = email.address.toLowerCase();
pnid.email.reachable = false;
pnid.email.validated = false;
pnid.email.validated_date = '';

View File

@@ -14,7 +14,7 @@ const router: express.Router = express.Router();
* Description: Verifies a provided email address is valid
*/
router.post('/validate/email', async (request: express.Request, response: express.Response) => {
const email: string = request.body;
const email: string = request.body.email;
if (!email) {
return response.send(xmlbuilder.create({

View File

@@ -2,7 +2,7 @@ import { YesNoBoolString } from '@/types/common/yes-no-bool-string';
import { IDeviceAttribute } from '@/types/mongoose/device-attribute';
// TODO - Change this Map type to something more strongly typed
export interface Person extends Map<string, any> {
export interface Person {
birth_date: string;
user_id: string;
password: string;
@@ -35,7 +35,7 @@ export interface Person extends Map<string, any> {
approval_id: string;
};
gender: string;
region: string;
region: number;
marketing_flag: YesNoBoolString;
device_attributes: {
device_attribute: IDeviceAttribute[]

View File

@@ -374,4 +374,8 @@ export function getValueFromHeaders(headers: IncomingHttpHeaders, key: string):
}
return value;
}
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 ]));
}