diff --git a/src/api/f.ts b/src/api/f.ts index d55de25..8047e61 100644 --- a/src/api/f.ts +++ b/src/api/f.ts @@ -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, diff --git a/src/api/znc-proxy.ts b/src/api/znc-proxy.ts index 234848a..40a9490 100644 --- a/src/api/znc-proxy.ts +++ b/src/api/znc-proxy.ts @@ -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(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, }); diff --git a/src/api/znc.ts b/src/api/znc.ts index 965caa9..900dacd 100644 --- a/src/api/znc.ts +++ b/src/api/znc.ts @@ -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'); diff --git a/src/util.ts b/src/util.ts index 5159b0a..65e1769 100644 --- a/src/util.ts +++ b/src/util.ts @@ -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 ? R : any; export type Argv = yargs.Argv; export type ArgumentsCamelCase = yargstypes.ArgumentsCamelCase;