Add SplatNet 2 constructor helper functions and always send player ID

This commit is contained in:
Samuel Elliott
2022-07-29 18:45:13 +01:00
parent 2d52f17022
commit fc2dec15c0
5 changed files with 85 additions and 41 deletions

View File

@@ -25,9 +25,10 @@ export const updateIksmSessionLastUsed: {
} = {};
export default class SplatNet2Api {
constructor(
protected constructor(
public iksm_session: string,
public useragent: string
public unique_id: string,
public useragent: string,
) {}
async fetch<T = unknown>(url: string, method = 'GET', body?: string | FormData, headers?: object) {
@@ -35,13 +36,15 @@ export default class SplatNet2Api {
const response = await fetch(SPLATNET2_URL + url, {
method,
headers: Object.assign({
'Upgrade-Insecure-Requests': '1',
'User-Agent': this.useragent,
'Cookie': 'iksm_session=' + encodeURIComponent(this.iksm_session),
'dnt': '1',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept': '*/*',
'Accept-Language': 'en-GB,en-US;q=0.8',
'X-Requested-With': 'com.nintendo.znca',
'Referrer': 'https://app.splatoon2.nintendo.net/home',
'X-Requested-With': 'XMLHttpRequest',
// 'X-Timezone-Offset': (new Date()).getTimezoneOffset().toString(),
'X-Timezone-Offset': '0',
'X-Unique-Id': this.unique_id,
}, headers),
body,
signal,
@@ -229,11 +232,31 @@ ${colour}
static async createWithCoral(nso: CoralApi, user: NintendoAccountUser) {
const data = await this.loginWithCoral(nso, user);
return {splatnet: this.createWithSavedToken(data), data};
}
return {
splatnet: new this(data.iksm_session, data.useragent),
data,
};
static createWithSavedToken(data: SplatNet2AuthData) {
return new this(
data.iksm_session,
data.user_id,
data.useragent,
);
}
static createWithCliTokenData(data: SplatNet2CliTokenData) {
return new this(
data.iksm_session,
data.user_id,
SPLATNET2_WEBSERVICE_USERAGENT,
);
}
static createWithIksmSession(iksm_session: string, unique_id: string) {
return new this(
iksm_session,
unique_id,
SPLATNET2_WEBSERVICE_USERAGENT,
);
}
static async loginWithCoral(nso: CoralApi, user: NintendoAccountUser) {
@@ -242,7 +265,9 @@ ${colour}
return this.loginWithWebServiceToken(webserviceToken.result, user);
}
static async loginWithWebServiceToken(webserviceToken: WebServiceToken, user: NintendoAccountUser) {
static async loginWithWebServiceToken(
webserviceToken: WebServiceToken, user: NintendoAccountUser
): Promise<SplatNet2AuthData> {
const url = new URL(SPLATNET2_WEBSERVICE_URL);
url.search = new URLSearchParams({
lang: user.language,
@@ -295,6 +320,11 @@ ${colour}
const mn = body.match(/<html(?:\s+[a-z0-9-]+(?:=(?:"[^"]*"|[^\s>]*))?)*\s+data-nsa-id=(?:"([^"]*)"|([^\s>]*))/i);
const [language, region, user_id, nsa_id] = [ml, mr, mu, mn].map(m => m?.[1] || m?.[2] || null);
if (!language) throw new Error('[splatnet2] Invalid language in response');
if (!region) throw new Error('[splatnet2] Invalid region in response');
if (!user_id) throw new Error('[splatnet2] Invalid unique player ID in response');
if (!nsa_id) throw new Error('[splatnet2] Invalid NSA ID in response');
debug('SplatNet 2 user', {
language,
region,
@@ -319,6 +349,31 @@ ${colour}
}
}
export interface SplatNet2AuthData {
webserviceToken: WebServiceToken;
url: string;
cookies: string;
body: string;
language: string;
region: string;
/** Splatoon 2 player ID aka. unique_id */
user_id: string;
nsa_id: string;
iksm_session: string;
expires_at: number;
useragent: string;
}
export interface SplatNet2CliTokenData {
iksm_session: string;
language: string;
region: string;
user_id: string;
nsa_id: string;
}
export function toLeagueId(date: Date, type: LeagueType) {
const year = date.getUTCFullYear();
const month = date.getUTCMonth() + 1;

View File

@@ -3,6 +3,7 @@ import type { Arguments as ParentArguments } from '../splatnet2.js';
import { ArgumentsCamelCase, Argv, YargsArguments } from '../../util/yargs.js';
import { initStorage } from '../../util/storage.js';
import { getIksmToken } from '../../common/auth/splatnet2.js';
import { SplatNet2CliTokenData } from '../../api/splatnet2.js';
const debug = createDebug('cli:splatnet2:token');
@@ -35,7 +36,7 @@ export async function handler(argv: ArgumentsCamelCase<Arguments>) {
const {splatnet, data} = await getIksmToken(storage, token, argv.zncProxyUrl, argv.autoUpdateSession);
if (argv.json || argv.jsonPrettyPrint) {
const result = {
const result: SplatNet2CliTokenData = {
iksm_session: data.iksm_session,
language: data.language,
region: data.region,

View File

@@ -3,30 +3,14 @@ import * as fs from 'node:fs';
import createDebug from 'debug';
import persist from 'node-persist';
import { getToken } from './coral.js';
import SplatNet2Api, { updateIksmSessionLastUsed } from '../../api/splatnet2.js';
import { WebServiceToken } from '../../api/coral-types.js';
import SplatNet2Api, { SplatNet2AuthData, updateIksmSessionLastUsed } from '../../api/splatnet2.js';
import { checkUseLimit, SHOULD_LIMIT_USE } from './util.js';
import { Jwt } from '../../util/jwt.js';
import { NintendoAccountSessionTokenJwtPayload } from '../../api/na.js';
const debug = createDebug('nxapi:auth:splatnet2');
export interface SavedIksmSessionToken {
webserviceToken: WebServiceToken;
url: string;
cookies: string;
body: string;
language: string | null;
region: string | null;
/** Splatoon 2 player ID aka. unique_id */
user_id: string | null;
nsa_id: string | null;
iksm_session: string;
expires_at: number;
useragent: string;
export interface SavedIksmSessionToken extends SplatNet2AuthData {
last_used?: number;
}
@@ -69,7 +53,7 @@ export async function getIksmToken(
}
return {
splatnet: new SplatNet2Api(existingToken.iksm_session, existingToken.useragent),
splatnet: SplatNet2Api.createWithSavedToken(existingToken),
data: existingToken,
};
}
@@ -81,7 +65,7 @@ export async function getIksmToken(
}
return {
splatnet: new SplatNet2Api(existingToken.iksm_session, existingToken.useragent),
splatnet: SplatNet2Api.createWithSavedToken(existingToken),
data: existingToken,
};
}

View File

@@ -1,5 +1,7 @@
export {
default,
SplatNet2AuthData,
LeagueType,
LeagueRegion,
ShareColour as ShareProfileColour,