Allow dependents to set the user agent for s2s, flapg and nxapi APIs

This commit is contained in:
Samuel Elliott 2022-04-05 20:42:38 +01:00
parent 2bc251a58b
commit 3c66bbd95d
No known key found for this signature in database
GPG Key ID: 8420C7CDE43DC4D6
4 changed files with 47 additions and 16 deletions

View File

@ -1,19 +1,20 @@
import fetch from 'node-fetch';
import createDebug from 'debug';
import { ErrorResponse } from './util.js';
import { version } from '../util.js';
const debugS2s = createDebug('api:s2s');
const debugFlapg = createDebug('api:flapg');
const debugZncaApi = createDebug('api:znca-api');
export async function getLoginHash(token: string, timestamp: string | number) {
export async function getLoginHash(token: string, timestamp: string | number, useragent?: string) {
debugS2s('Getting login hash');
const response = await fetch('https://elifessler.com/s2s/api/gen2', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'User-Agent': 'discord-switch-presence/1.0.0',
'User-Agent': (useragent ? useragent + ' ' : '') + 'nxapi/' + version,
},
body: new URLSearchParams({
naIdToken: token,
@ -32,8 +33,11 @@ export async function getLoginHash(token: string, timestamp: string | number) {
return data.hash;
}
export async function flapg(token: string, timestamp: string | number, guid: string, iid: FlapgIid) {
const hash = await getLoginHash(token, timestamp);
export async function flapg(
token: string, timestamp: string | number, guid: string, iid: FlapgIid,
useragent?: string
) {
const hash = await getLoginHash(token, timestamp, useragent);
debugFlapg('Getting f parameter', {
token, timestamp, guid, iid,
@ -41,6 +45,7 @@ export async function flapg(token: string, timestamp: string | number, guid: str
const response = await fetch('https://flapg.com/ika2/api/login?public', {
headers: {
'User-Agent': (useragent ? useragent + ' ' : '') + 'nxapi/' + version,
'x-token': token,
'x-time': '' + timestamp,
'x-guid': guid,
@ -57,7 +62,10 @@ export async function flapg(token: string, timestamp: string | number, guid: str
return data.result;
}
export async function genf(url: string, token: string, timestamp: string | number, uuid: string, type: FlapgIid) {
export async function genf(
url: string, token: string, timestamp: string | number, uuid: string, type: FlapgIid,
useragent?: string
) {
debugZncaApi('Getting f parameter', {
url, token, timestamp, uuid,
});
@ -73,6 +81,7 @@ export async function genf(url: string, token: string, timestamp: string | numbe
method: 'POST',
headers: {
'Content-Type': 'application/json',
'User-Agent': (useragent ? useragent + ' ' : '') + 'nxapi/' + version,
},
body: JSON.stringify(req),
});
@ -89,8 +98,11 @@ export async function genf(url: string, token: string, timestamp: string | numbe
return data.f;
}
export async function genfc(url: string, token: string, timestamp: string | number, uuid: string, type: FlapgIid) {
const f = await genf(url, token, timestamp, uuid, type);
export async function genfc(
url: string, token: string, timestamp: string | number, uuid: string, type: FlapgIid,
useragent?: string
) {
const f = await genf(url, token, timestamp, uuid, type, useragent);
return {
f,

View File

@ -3,16 +3,19 @@ import createDebug from 'debug';
import { ActiveEvent, Announcement, CurrentUser, Friend, WebService, WebServiceToken } from './znc-types.js';
import { ErrorResponse } from './util.js';
import ZncApi from './znc.js';
import { SavedToken } from '../util.js';
import { SavedToken, version } from '../util.js';
const debug = createDebug('api:znc-proxy');
export default class ZncProxyApi implements ZncApi {
static useragent: string | null = null;
constructor(
private url: string,
// ZncApi uses the NSO token (valid for a few hours)
// ZncProxyApi uses the Nintendo Account session token (valid for two years)
public token: string
public token: string,
public useragent = ZncProxyApi.useragent
) {}
async fetch<T = unknown>(url: string, method = 'GET', body?: string, headers?: object) {
@ -20,6 +23,7 @@ export default class ZncProxyApi implements ZncApi {
method: method,
headers: Object.assign({
'Authorization': 'na ' + this.token,
'User-Agent': (this.useragent ? this.useragent + ' ' : '') + 'nxapi/' + version,
}, headers),
body: body,
});

View File

@ -17,6 +17,8 @@ const ZNC_URL = 'https://api-lp1.znc.srv.nintendo.net';
export const ZNCA_CLIENT_ID = '71b963c1b7b6d119';
export default class ZncApi {
static useragent: string | null = null;
constructor(
public token: string
) {}
@ -93,8 +95,8 @@ export default class ZncApi {
}));
}
static async createWithSessionToken(token: string) {
const data = await this.loginWithSessionToken(token);
static async createWithSessionToken(token: string, useragent = ZncApi.useragent) {
const data = await this.loginWithSessionToken(token, useragent);
return {
nso: new this(data.credential.accessToken),
@ -102,15 +104,15 @@ export default class ZncApi {
};
}
async renewToken(token: string) {
const data = await ZncApi.loginWithSessionToken(token);
async renewToken(token: string, useragent = ZncApi.useragent) {
const data = await ZncApi.loginWithSessionToken(token, useragent);
this.token = data.credential.accessToken;
return data;
}
static async loginWithSessionToken(token: string) {
static async loginWithSessionToken(token: string, useragent = ZncApi.useragent) {
const uuid = uuidgen();
const timestamp = '' + Math.floor(Date.now() / 1000);
@ -120,9 +122,10 @@ export default class ZncApi {
// Nintendo Account user data
const user = await getNintendoAccountUser(nintendoAccountToken);
const id_token = nintendoAccountToken.id_token;
const flapgdata = process.env.ZNCA_API_URL ?
await genfc(process.env.ZNCA_API_URL + '/f', nintendoAccountToken.id_token, timestamp, uuid, FlapgIid.NSO) :
await flapg(nintendoAccountToken.id_token, timestamp, uuid, FlapgIid.NSO);
await genfc(process.env.ZNCA_API_URL + '/f', id_token, timestamp, uuid, FlapgIid.NSO, useragent ?? undefined) :
await flapg(id_token, timestamp, uuid, FlapgIid.NSO, useragent ?? undefined);
debug('Getting Nintendo Switch Online app token');

View File

@ -1,4 +1,5 @@
import * as path from 'path';
import * as fs from 'fs';
import * as yargs from 'yargs';
import type * as yargstypes from '../node_modules/@types/yargs/index.js';
import createDebug from 'debug';
@ -17,6 +18,17 @@ const debug = createDebug('cli');
export const paths = getPaths('nxapi');
export const dir = path.resolve(import.meta.url.substr(7), '..', '..');
export const pkg = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf-8'));
export const version = pkg.version;
export const dev = (() => {
try {
fs.statSync(path.join(dir, '.git'));
return true;
} catch (err) {}
return false;
})();
export type YargsArguments<T extends yargs.Argv> = T extends yargs.Argv<infer R> ? R : any;
export type Argv<T = {}> = yargs.Argv<T>;
export type ArgumentsCamelCase<T = {}> = yargstypes.ArgumentsCamelCase<T>;