From f294daa5bcf032afe4c9a314856789f9b55cc11d Mon Sep 17 00:00:00 2001 From: Samuel Elliott Date: Thu, 21 Apr 2022 18:05:24 +0100 Subject: [PATCH] Fix getting current user presence with API proxy --- src/cli/nso/http-server.ts | 117 +++++++++++++++++++------------------ 1 file changed, 60 insertions(+), 57 deletions(-) diff --git a/src/cli/nso/http-server.ts b/src/cli/nso/http-server.ts index 299ba56..cb3a9ee 100644 --- a/src/cli/nso/http-server.ts +++ b/src/cli/nso/http-server.ts @@ -2,9 +2,8 @@ import createDebug from 'debug'; import express, { Request, Response } from 'express'; import bodyParser from 'body-parser'; import * as net from 'net'; -import persist from 'node-persist'; import { v4 as uuidgen } from 'uuid'; -import { ActiveEvent, Announcement, CurrentUser, Friend, GetActiveEventResult, Presence, WebService } from '../../api/znc-types.js'; +import { Announcement, CurrentUser, Friend, GetActiveEventResult, Presence, WebService } from '../../api/znc-types.js'; import ZncApi from '../../api/znc.js'; import type { Arguments as ParentArguments } from '../nso.js'; import { ArgumentsCamelCase, Argv, getToken, initStorage, SavedToken, YargsArguments } from '../../util.js'; @@ -75,9 +74,9 @@ export async function handler(argv: ArgumentsCamelCase) { app.use('/api/znc', (req, res, next) => { console.log('[%s] %s %s HTTP/%s from %s, port %d%s, %s', - new Date(), req.method, req.url, req.httpVersion, + new Date(), req.method, req.path, req.httpVersion, req.socket.remoteAddress, req.socket.remotePort, - req.headers['x-forwarded-for'] ? ', ' + req.headers['x-forwarded-for'] : '', + req.headers['x-forwarded-for'] ? ' (' + req.headers['x-forwarded-for'] + ')' : '', req.headers['user-agent']); next(); @@ -263,6 +262,59 @@ export async function handler(argv: ArgumentsCamelCase) { } }); + // + // Nintendo Switch user data + // + + const cached_userdata = new Map(); + + const getUserData: express.RequestHandler = async (req, res, next) => { + const cache = cached_userdata.get(req.zncAuth!.user.id); + + if (cache && ((cache[1] + updateInterval) > Date.now())) { + debug('Using cached user data for %s', req.zncAuth!.user.id); + next(); + return; + } + + try { + const user = await req.znc!.getCurrentUser(); + cached_userdata.set(req.zncAuth!.user.id, [user.result, Date.now()]); + + next(); + } catch (err) { + res.statusCode = 500; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({ + error: err, + error_message: (err as Error).message, + })); + } + }; + + app.get('/api/znc/user', authToken, (req, res, next) => { + if (!req.zncAuthPolicy) return next(); + if (!req.zncAuthPolicy.current_user) return tokenUnauthorised(req, res); + next(); + }, localAuth, nsoAuth, getUserData, async (req, res) => { + const [user, updated] = cached_userdata.get(req.zncAuth!.user.id)!; + + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({user, updated})); + }); + + app.get('/api/znc/user/presence', authToken, (req, res, next) => { + if (!req.zncAuthPolicy) return next(); + if (!req.zncAuthPolicy.current_user_presence) return tokenUnauthorised(req, res); + if (!('current_user_presence' in req.zncAuthPolicy) && !req.zncAuthPolicy.current_user) return tokenUnauthorised(req, res); + next(); + }, localAuth, nsoAuth, getUserData, async (req, res) => { + const [user, updated] = cached_userdata.get(req.zncAuth!.user.id)!; + + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify(user.presence)); + }); + // // Nintendo Switch friends, NSO app web services, events // @@ -564,6 +616,10 @@ export async function handler(argv: ArgumentsCamelCase) { app.get('/api/znc/user/:id', nsoAuth, async (req, res) => { try { + if (!req.params.id.match(/^[0-9a-f]{16}$/)) { + throw new Error('Invalid NSA ID'); + } + const response = await req.znc!.getUser(parseInt(req.params.id)); res.setHeader('Content-Type', 'application/json'); @@ -580,59 +636,6 @@ export async function handler(argv: ArgumentsCamelCase) { } }); - // - // Nintendo Switch user data - // - - const cached_userdata = new Map(); - - const getUserData: express.RequestHandler = async (req, res, next) => { - const cache = cached_userdata.get(req.zncAuth!.user.id); - - if (cache && ((cache[1] + updateInterval) > Date.now())) { - debug('Using cached user data for %s', req.zncAuth!.user.id); - next(); - return; - } - - try { - const user = await req.znc!.getCurrentUser(); - cached_userdata.set(req.zncAuth!.user.id, [user.result, Date.now()]); - - next(); - } catch (err) { - res.statusCode = 500; - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({ - error: err, - error_message: (err as Error).message, - })); - } - }; - - app.get('/api/znc/user', authToken, (req, res, next) => { - if (!req.zncAuthPolicy) return next(); - if (!req.zncAuthPolicy.current_user) return tokenUnauthorised(req, res); - next(); - }, localAuth, nsoAuth, getUserData, async (req, res) => { - const [user, updated] = cached_userdata.get(req.zncAuth!.user.id)!; - - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify({user, updated})); - }); - - app.get('/api/znc/user/presence', authToken, (req, res, next) => { - if (!req.zncAuthPolicy) return next(); - if (!req.zncAuthPolicy.current_user_presence) return tokenUnauthorised(req, res); - if (!('current_user_presence' in req.zncAuthPolicy) && !req.zncAuthPolicy.current_user) return tokenUnauthorised(req, res); - next(); - }, localAuth, nsoAuth, getUserData, async (req, res) => { - const [user, updated] = cached_userdata.get(req.zncAuth!.user.id)!; - - res.setHeader('Content-Type', 'application/json'); - res.end(JSON.stringify(user.presence)); - }); - // // Event stream //