mirror of
https://github.com/samuelthomas2774/nxapi.git
synced 2026-07-10 23:07:50 -05:00
Only request a new iksm_session cookie if the previous cookie hasn't been used recently
This commit is contained in:
parent
86fb372722
commit
4736fe55d4
|
|
@ -6,6 +6,7 @@ import { NintendoAccountUser } from './na.js';
|
|||
import { ErrorResponse } from './util.js';
|
||||
import ZncApi from './znc.js';
|
||||
import { ActiveFestivals, CoopResult, CoopResults, CoopSchedules, HeroRecords, NicknameAndIcons, PastFestivals, Records, Result, Results, Schedules, ShareResponse, ShopMerchandises, Stages, Timeline, WebServiceError, XPowerRankingSummary } from './splatnet2-types.js';
|
||||
import { updateIksmSessionLastUsed } from '../cli/splatnet2/util.js';
|
||||
|
||||
const debug = createDebug('api:splatnet2');
|
||||
|
||||
|
|
@ -18,16 +19,6 @@ const SPLATNET2_URL = SPLATNET2_WEBSERVICE_URL + 'api';
|
|||
const XPOWERRANKING_SEASON = /^(\d{2})(\d{2})01T00_(\d{2})(\d{2})01T00$/;
|
||||
const LEAGUE_ID = /^(\d{2})(\d{2})(\d{2})(\d{2})(T|P)$/;
|
||||
|
||||
export interface SavedIksmSessionToken {
|
||||
webserviceToken: WebServiceToken;
|
||||
url: string;
|
||||
cookies: string;
|
||||
|
||||
iksm_session: string;
|
||||
expires_at: number;
|
||||
useragent: string;
|
||||
}
|
||||
|
||||
export default class SplatNet2Api {
|
||||
constructor(
|
||||
public iksm_session: string,
|
||||
|
|
@ -58,6 +49,8 @@ export default class SplatNet2Api {
|
|||
throw new ErrorResponse('[splatnet2] Unknown error', response, data);
|
||||
}
|
||||
|
||||
updateIksmSessionLastUsed(this.iksm_session);
|
||||
|
||||
const data = await response.json() as T | WebServiceError;
|
||||
|
||||
if ('code' in data) {
|
||||
|
|
@ -188,6 +181,16 @@ ${colour}
|
|||
});
|
||||
}
|
||||
|
||||
async shareChallenge(id: string, season: 1 | 2 = 1) {
|
||||
const url = '/share/challenges' + (season === 2 ? '_season_2' : '') + '/' + id;
|
||||
|
||||
return this.fetch<ShareResponse>(url, 'POST', '', {
|
||||
'Referer': 'https://app.splatoon2.nintendo.net/records/challenge' + (season === 2 ? '_season_2' : ''),
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'Origin': 'https://app.splatoon2.nintendo.net',
|
||||
});
|
||||
}
|
||||
|
||||
async shareResultsSummary() {
|
||||
return this.fetch<ShareResponse>('/share/results/summary', 'POST', '', {
|
||||
'Referer': 'https://app.splatoon2.nintendo.net/results',
|
||||
|
|
@ -219,7 +222,7 @@ ${colour}
|
|||
return this.loginWithWebServiceToken(webserviceToken.result, user);
|
||||
}
|
||||
|
||||
static async loginWithWebServiceToken(webserviceToken: WebServiceToken, user: NintendoAccountUser): Promise<SavedIksmSessionToken> {
|
||||
static async loginWithWebServiceToken(webserviceToken: WebServiceToken, user: NintendoAccountUser) {
|
||||
const url = new URL(SPLATNET2_WEBSERVICE_URL);
|
||||
url.search = new URLSearchParams({
|
||||
lang: user.language,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,23 @@
|
|||
import createDebug from 'debug';
|
||||
import persist from 'node-persist';
|
||||
import { getToken } from '../../util.js';
|
||||
import SplatNet2Api, { SavedIksmSessionToken } from '../../api/splatnet2.js';
|
||||
import SplatNet2Api from '../../api/splatnet2.js';
|
||||
import { WebServiceToken } from '../../api/znc-types.js';
|
||||
|
||||
const debug = createDebug('cli:splatnet2');
|
||||
|
||||
export interface SavedIksmSessionToken {
|
||||
webserviceToken: WebServiceToken;
|
||||
url: string;
|
||||
cookies: string;
|
||||
|
||||
iksm_session: string;
|
||||
expires_at: number;
|
||||
useragent: string;
|
||||
|
||||
last_used?: number;
|
||||
}
|
||||
|
||||
export async function getIksmToken(storage: persist.LocalStorage, token: string, proxy_url?: string, allow_fetch_token = false) {
|
||||
if (!token) {
|
||||
console.error('No token set. Set a Nintendo Account session token using the `--token` option or by running `nxapi nso token`.');
|
||||
|
|
@ -13,7 +26,11 @@ export async function getIksmToken(storage: persist.LocalStorage, token: string,
|
|||
|
||||
const existingToken: SavedIksmSessionToken | undefined = await storage.getItem('IksmToken.' + token);
|
||||
|
||||
if (!existingToken || existingToken.expires_at <= Date.now()) {
|
||||
const td = 2 * 24 * 60 * 60 * 1000; // 2 days in ms
|
||||
const last_used_days_ago = existingToken?.last_used && (existingToken.last_used + td) <= Date.now();
|
||||
const expired = existingToken && existingToken.expires_at <= Date.now();
|
||||
|
||||
if (!existingToken || ((!existingToken.last_used || last_used_days_ago) && expired)) {
|
||||
if (!allow_fetch_token) {
|
||||
throw new Error('No valid iksm_session cookie');
|
||||
}
|
||||
|
|
@ -23,10 +40,14 @@ export async function getIksmToken(storage: persist.LocalStorage, token: string,
|
|||
|
||||
const {nso, data} = await getToken(storage, token, proxy_url);
|
||||
|
||||
const existingToken = await SplatNet2Api.loginWithZnc(nso, data.user);
|
||||
const existingToken: SavedIksmSessionToken = await SplatNet2Api.loginWithZnc(nso, data.user);
|
||||
|
||||
await storage.setItem('IksmToken.' + token, existingToken);
|
||||
|
||||
if (!iksm_sessions.has(existingToken.iksm_session)) {
|
||||
iksm_sessions.set(existingToken.iksm_session, [storage, token, null]);
|
||||
}
|
||||
|
||||
return {
|
||||
splatnet: new SplatNet2Api(existingToken.iksm_session, existingToken.useragent),
|
||||
data: existingToken,
|
||||
|
|
@ -35,8 +56,60 @@ export async function getIksmToken(storage: persist.LocalStorage, token: string,
|
|||
|
||||
debug('Using existing token');
|
||||
|
||||
if (!iksm_sessions.has(existingToken.iksm_session)) {
|
||||
iksm_sessions.set(existingToken.iksm_session, [storage, token, null]);
|
||||
}
|
||||
|
||||
return {
|
||||
splatnet: new SplatNet2Api(existingToken.iksm_session, existingToken.useragent),
|
||||
data: existingToken,
|
||||
};
|
||||
}
|
||||
|
||||
export async function renewIksmToken(splatnet: SplatNet2Api, storage: persist.LocalStorage, token: string, proxy_url?: string) {
|
||||
console.warn('Authenticating to SplatNet 2');
|
||||
debug('Authenticating to SplatNet 2');
|
||||
|
||||
const {nso, data} = await getToken(storage, token, proxy_url);
|
||||
|
||||
const existingToken: SavedIksmSessionToken = await SplatNet2Api.loginWithZnc(nso, data.user);
|
||||
|
||||
await storage.setItem('IksmToken.' + token, existingToken);
|
||||
|
||||
if (!iksm_sessions.has(existingToken.iksm_session)) {
|
||||
iksm_sessions.set(existingToken.iksm_session, [storage, token, null]);
|
||||
}
|
||||
|
||||
iksm_sessions.delete(splatnet.iksm_session);
|
||||
|
||||
splatnet.iksm_session = existingToken.iksm_session;
|
||||
splatnet.useragent = existingToken.useragent;
|
||||
}
|
||||
|
||||
const iksm_sessions = new Map<string, [persist.LocalStorage, string, number | null]>();
|
||||
|
||||
export function updateIksmSessionLastUsed(iksm_session: string, last_used: number = Date.now()) {
|
||||
const match = iksm_sessions.get(iksm_session);
|
||||
if (!match) return;
|
||||
|
||||
const [storage, token] = match;
|
||||
|
||||
iksm_sessions.set(iksm_session, [storage, token, last_used]);
|
||||
}
|
||||
|
||||
process.on('exit', () => {
|
||||
for (const [iksm_session, [storage, token, last_used]] of iksm_sessions) {
|
||||
if (!last_used) continue;
|
||||
|
||||
const datum_str = fs.readFileSync(storage.getDatumPath('IksmToken.' + token), 'utf-8');
|
||||
const datum: persist.Datum = storage.parse(datum_str);
|
||||
const data: SavedIksmSessionToken = datum.value;
|
||||
|
||||
if (data.last_used && data.last_used >= last_used) continue;
|
||||
|
||||
data.last_used = last_used;
|
||||
|
||||
const new_datum_str = storage.stringify(datum);
|
||||
fs.writeFileSync(storage.getDatumPath('IksmToken.' + token), new_datum_str, 'utf-8');
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user