mirror of
https://github.com/samuelthomas2774/nxapi.git
synced 2026-09-10 20:35:10 -05:00
Prevent using expired tokens
This commit is contained in:
@@ -41,9 +41,11 @@ export interface ResultData<T> {
|
||||
}
|
||||
|
||||
export default class CoralApi {
|
||||
onTokenExpired: ((data: CoralErrorResponse, res: Response) => Promise<CoralAuthData | void>) | null = null;
|
||||
onTokenExpired: ((data?: CoralErrorResponse, res?: Response) => Promise<CoralAuthData | void>) | null = null;
|
||||
/** @internal */
|
||||
_renewToken: Promise<void> | null = null;
|
||||
/** @internal */
|
||||
_token_expired = false;
|
||||
|
||||
protected constructor(
|
||||
public token: string,
|
||||
@@ -57,8 +59,18 @@ export default class CoralApi {
|
||||
async fetch<T = unknown>(
|
||||
url: string, method = 'GET', body?: string, headers?: object,
|
||||
/** @internal */ _autoRenewToken = true,
|
||||
/** @internal */ _attempt = 0
|
||||
/** @internal */ _attempt = 0,
|
||||
): Promise<Result<T>> {
|
||||
if (this._token_expired && _autoRenewToken && !this._renewToken) {
|
||||
if (!this.onTokenExpired || _attempt) throw new Error('Token expired');
|
||||
|
||||
this._renewToken = this.onTokenExpired.call(null).then(data => {
|
||||
if (data) this.setTokenWithSavedToken(data);
|
||||
}).finally(() => {
|
||||
this._renewToken = null;
|
||||
});
|
||||
}
|
||||
|
||||
if (this._renewToken && _autoRenewToken) {
|
||||
await this._renewToken;
|
||||
}
|
||||
@@ -86,6 +98,7 @@ export default class CoralApi {
|
||||
const data = await response.json() as CoralResponse<T>;
|
||||
|
||||
if (data.status === CoralStatus.TOKEN_EXPIRED && _autoRenewToken && !_attempt && this.onTokenExpired) {
|
||||
this._token_expired = true;
|
||||
// _renewToken will be awaited when calling fetch
|
||||
this._renewToken = this._renewToken ?? this.onTokenExpired.call(null, data, response).then(data => {
|
||||
if (data) this.setTokenWithSavedToken(data);
|
||||
@@ -286,6 +299,7 @@ export default class CoralApi {
|
||||
this.token = data.credential.accessToken;
|
||||
this.coral_user_id = '' + data.nsoAccount.user.id;
|
||||
if ('user' in data) this.na_id = data.user.id;
|
||||
this._token_expired = false;
|
||||
}
|
||||
|
||||
static async createWithSessionToken(token: string, useragent = getAdditionalUserAgents()) {
|
||||
|
||||
@@ -16,9 +16,10 @@ const ZNMA_USER_AGENT = 'moon_ANDROID/' + ZNMA_VERSION + ' (com.nintendo.znma; b
|
||||
'; ANDROID 26)';
|
||||
|
||||
export default class MoonApi {
|
||||
onTokenExpired: ((data: MoonError, res: Response) => Promise<MoonAuthData | PartialMoonAuthData | void>) | null = null;
|
||||
onTokenExpired: ((data?: MoonError, res?: Response) => Promise<MoonAuthData | PartialMoonAuthData | void>) | null = null;
|
||||
/** @internal */
|
||||
_renewToken: Promise<void> | null = null;
|
||||
protected _token_expired = false;
|
||||
|
||||
protected constructor(
|
||||
public token: string,
|
||||
@@ -31,8 +32,18 @@ export default class MoonApi {
|
||||
async fetch<T extends object>(
|
||||
url: string, method = 'GET', body?: string, headers?: object,
|
||||
/** @internal */ _autoRenewToken = true,
|
||||
/** @internal */ _attempt = 0
|
||||
/** @internal */ _attempt = 0,
|
||||
): Promise<HasResponse<T, Response>> {
|
||||
if (this._token_expired && _autoRenewToken && !this._renewToken) {
|
||||
if (!this.onTokenExpired || _attempt) throw new Error('Token expired');
|
||||
|
||||
this._renewToken = this.onTokenExpired.call(null).then(data => {
|
||||
if (data) this.setTokenWithSavedToken(data);
|
||||
}).finally(() => {
|
||||
this._renewToken = null;
|
||||
});
|
||||
}
|
||||
|
||||
if (this._renewToken && _autoRenewToken) {
|
||||
await this._renewToken;
|
||||
}
|
||||
@@ -62,6 +73,7 @@ export default class MoonApi {
|
||||
debug('fetch %s %s, response %s', method, url, response.status);
|
||||
|
||||
if (response.status === 401 && _autoRenewToken && !_attempt && this.onTokenExpired) {
|
||||
this._token_expired = true;
|
||||
const data = await response.json() as MoonError;
|
||||
|
||||
// _renewToken will be awaited when calling fetch
|
||||
@@ -123,6 +135,7 @@ export default class MoonApi {
|
||||
private setTokenWithSavedToken(data: MoonAuthData | PartialMoonAuthData) {
|
||||
this.token = data.nintendoAccountToken.access_token!;
|
||||
if ('user' in data) this.naId = data.user.id;
|
||||
this._token_expired = false;
|
||||
}
|
||||
|
||||
static async createWithSessionToken(token: string) {
|
||||
|
||||
@@ -17,9 +17,10 @@ const NOOKLINK_URL = NOOKLINK_WEBSERVICE_URL + '/api';
|
||||
const BLANCO_VERSION = '2.1.1';
|
||||
|
||||
export default class NooklinkApi {
|
||||
onTokenExpired: ((data: WebServiceError, res: Response) => Promise<NooklinkAuthData | void>) | null = null;
|
||||
onTokenExpired: ((data?: WebServiceError, res?: Response) => Promise<NooklinkAuthData | void>) | null = null;
|
||||
/** @internal */
|
||||
_renewToken: Promise<void> | null = null;
|
||||
protected _token_expired = false;
|
||||
|
||||
protected constructor(
|
||||
public gtoken: string,
|
||||
@@ -30,8 +31,18 @@ export default class NooklinkApi {
|
||||
async fetch<T extends object>(
|
||||
url: string, method = 'GET', body?: string | FormData, headers?: object,
|
||||
/** @internal */ _autoRenewToken = true,
|
||||
/** @internal */ _attempt = 0
|
||||
/** @internal */ _attempt = 0,
|
||||
): Promise<HasResponse<T, Response>> {
|
||||
if (this._token_expired && _autoRenewToken && !this._renewToken) {
|
||||
if (!this.onTokenExpired || _attempt) throw new Error('Token expired');
|
||||
|
||||
this._renewToken = this.onTokenExpired.call(null).then(data => {
|
||||
if (data) this.setTokenWithSavedToken(data);
|
||||
}).finally(() => {
|
||||
this._renewToken = null;
|
||||
});
|
||||
}
|
||||
|
||||
if (this._renewToken && _autoRenewToken) {
|
||||
await this._renewToken;
|
||||
}
|
||||
@@ -57,6 +68,7 @@ export default class NooklinkApi {
|
||||
debug('fetch %s %s, response %s', method, url, response.status);
|
||||
|
||||
if (response.status === 401 && _autoRenewToken && !_attempt && this.onTokenExpired) {
|
||||
this._token_expired = true;
|
||||
const data = await response.json() as WebServiceError;
|
||||
|
||||
// _renewToken will be awaited when calling fetch
|
||||
@@ -109,6 +121,7 @@ export default class NooklinkApi {
|
||||
|
||||
private setTokenWithSavedToken(data: NooklinkAuthData) {
|
||||
this.gtoken = data.gtoken;
|
||||
this._token_expired = false;
|
||||
}
|
||||
|
||||
static async createWithCoral(nso: CoralApi, user: NintendoAccountUser) {
|
||||
@@ -195,9 +208,10 @@ export default class NooklinkApi {
|
||||
}
|
||||
|
||||
export class NooklinkUserApi {
|
||||
onTokenExpired: ((data: WebServiceError, res: Response) => Promise<NooklinkUserAuthData | PartialNooklinkUserAuthData | void>) | null = null;
|
||||
onTokenExpired: ((data?: WebServiceError, res?: Response) => Promise<NooklinkUserAuthData | PartialNooklinkUserAuthData | void>) | null = null;
|
||||
/** @internal */
|
||||
_renewToken: Promise<void> | null = null;
|
||||
protected _token_expired = false;
|
||||
|
||||
protected constructor(
|
||||
public user_id: string,
|
||||
@@ -211,8 +225,18 @@ export class NooklinkUserApi {
|
||||
async fetch<T extends object>(
|
||||
url: string, method = 'GET', body?: string | FormData, headers?: object,
|
||||
/** @internal */ _autoRenewToken = true,
|
||||
/** @internal */ _attempt = 0
|
||||
/** @internal */ _attempt = 0,
|
||||
): Promise<HasResponse<T, Response>> {
|
||||
if (this._token_expired && _autoRenewToken && !this._renewToken) {
|
||||
if (!this.onTokenExpired || _attempt) throw new Error('Token expired');
|
||||
|
||||
this._renewToken = this.onTokenExpired.call(null).then(data => {
|
||||
if (data) this.setTokenWithSavedToken(data);
|
||||
}).finally(() => {
|
||||
this._renewToken = null;
|
||||
});
|
||||
}
|
||||
|
||||
if (this._renewToken && _autoRenewToken) {
|
||||
await this._renewToken;
|
||||
}
|
||||
@@ -239,6 +263,7 @@ export class NooklinkUserApi {
|
||||
debug('fetch %s %s, response %s', method, url, response.status);
|
||||
|
||||
if (response.status === 401 && _autoRenewToken && !_attempt && this.onTokenExpired) {
|
||||
this._token_expired = true;
|
||||
const data = await response.json() as WebServiceError;
|
||||
|
||||
// _renewToken will be awaited when calling fetch
|
||||
@@ -327,6 +352,7 @@ export class NooklinkUserApi {
|
||||
this.user_id = data.user_id;
|
||||
this.auth_token = data.token.token;
|
||||
this.gtoken = data.gtoken;
|
||||
this._token_expired = false;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
|
||||
@@ -25,6 +25,8 @@ export const updateIksmSessionLastUsed: {
|
||||
} = {};
|
||||
|
||||
export default class SplatNet2Api {
|
||||
protected _session_expired = false;
|
||||
|
||||
protected constructor(
|
||||
public iksm_session: string,
|
||||
public unique_id: string,
|
||||
@@ -32,6 +34,10 @@ export default class SplatNet2Api {
|
||||
) {}
|
||||
|
||||
async fetch<T extends object>(url: string, method = 'GET', body?: string | FormData, headers?: object) {
|
||||
if (this._session_expired) {
|
||||
throw new Error('Session expired');
|
||||
}
|
||||
|
||||
const [signal, cancel] = timeoutSignal();
|
||||
const response = await fetch(SPLATNET2_URL + url, {
|
||||
method,
|
||||
@@ -52,6 +58,10 @@ export default class SplatNet2Api {
|
||||
|
||||
debug('fetch %s %s, response %s', method, url, response.status);
|
||||
|
||||
if (response.status === 401) {
|
||||
this._session_expired = true;
|
||||
}
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new ErrorResponse('[splatnet2] Non-200 status code', response, await response.text());
|
||||
}
|
||||
|
||||
@@ -74,9 +74,10 @@ enum MapQueriesMode {
|
||||
|
||||
export default class SplatNet3Api {
|
||||
onTokenShouldRenew: ((remaining: number, res: Response) => Promise<SplatNet3AuthData | void>) | null = null;
|
||||
onTokenExpired: ((res: Response) => Promise<SplatNet3AuthData | void>) | null = null;
|
||||
onTokenExpired: ((res?: Response) => Promise<SplatNet3AuthData | void>) | null = null;
|
||||
/** @internal */
|
||||
_renewToken: Promise<void> | null = null;
|
||||
protected _token_expired = false;
|
||||
|
||||
graphql_strict = process.env.NXAPI_SPLATNET3_STRICT !== '0';
|
||||
|
||||
@@ -93,8 +94,18 @@ export default class SplatNet3Api {
|
||||
async fetch<T = unknown>(
|
||||
url: string, method = 'GET', body?: string | FormData, headers?: object,
|
||||
/** @internal */ _log?: string,
|
||||
/** @internal */ _attempt = 0
|
||||
/** @internal */ _attempt = 0,
|
||||
): Promise<HasResponse<T, Response>> {
|
||||
if (this._token_expired && !this._renewToken) {
|
||||
if (!this.onTokenExpired || _attempt) throw new Error('Token expired');
|
||||
|
||||
this._renewToken = this.onTokenExpired.call(null).then(data => {
|
||||
if (data) this.setTokenWithSavedToken(data);
|
||||
}).finally(() => {
|
||||
this._renewToken = null;
|
||||
});
|
||||
}
|
||||
|
||||
if (this._renewToken) {
|
||||
await this._renewToken;
|
||||
}
|
||||
@@ -121,6 +132,7 @@ export default class SplatNet3Api {
|
||||
response.status, version);
|
||||
|
||||
if (response.status === 401 && !_attempt && this.onTokenExpired) {
|
||||
this._token_expired = true;
|
||||
// _renewToken will be awaited when calling fetch
|
||||
this._renewToken = this._renewToken ?? this.onTokenExpired.call(null, response).then(data => {
|
||||
if (data) this.setTokenWithSavedToken(data);
|
||||
@@ -933,6 +945,7 @@ export default class SplatNet3Api {
|
||||
this.version = data.version;
|
||||
this.language = data.bullet_token.lang;
|
||||
this.useragent = data.useragent;
|
||||
this._token_expired = false;
|
||||
}
|
||||
|
||||
static async createWithCoral(nso: CoralApi, user: NintendoAccountUser) {
|
||||
|
||||
@@ -12,10 +12,12 @@ const debug = createDebug('nxapi:api:znc-proxy');
|
||||
|
||||
export default class ZncProxyApi implements CoralApi {
|
||||
// Not used by ZncProxyApi
|
||||
onTokenExpired: ((data: CoralErrorResponse, res: Response) => Promise<CoralAuthData | void>) | null = null;
|
||||
onTokenExpired: ((data?: CoralErrorResponse, res?: Response) => Promise<CoralAuthData | void>) | null = null;
|
||||
/** @internal */
|
||||
_renewToken: Promise<void> | null = null;
|
||||
|
||||
/** @internal */
|
||||
_token_expired = false;
|
||||
/** @internal */
|
||||
na_id = '';
|
||||
/** @internal */
|
||||
|
||||
@@ -148,7 +148,7 @@ function createTokenExpiredHandler(
|
||||
data: {coral: Coral; auth_data: SavedToken; znc_proxy_url?: string},
|
||||
ratelimit = true
|
||||
) {
|
||||
return (response: Response) => {
|
||||
return (response?: Response) => {
|
||||
debug('Token expired, renewing');
|
||||
return renewToken(session, splatnet, data, ratelimit);
|
||||
};
|
||||
|
||||
@@ -99,7 +99,7 @@ function createTokenExpiredHandler(
|
||||
storage: persist.LocalStorage, token: string, nso: CoralApi,
|
||||
renew_token_data: {existingToken: SavedToken}, ratelimit = true
|
||||
) {
|
||||
return (data: CoralErrorResponse, response: Response) => {
|
||||
return (data?: CoralErrorResponse, response?: Response) => {
|
||||
debug('Token expired', renew_token_data.existingToken.user.id, data);
|
||||
return renewToken(storage, token, nso, renew_token_data, ratelimit);
|
||||
};
|
||||
|
||||
@@ -76,7 +76,7 @@ function createTokenExpiredHandler(
|
||||
storage: persist.LocalStorage, token: string, moon: MoonApi,
|
||||
renew_token_data: {existingToken: SavedMoonToken}, ratelimit = true
|
||||
) {
|
||||
return (data: MoonError, response: Response) => {
|
||||
return (data?: MoonError, response?: Response) => {
|
||||
debug('Token expired', renew_token_data.existingToken.user.id, data);
|
||||
return renewToken(storage, token, moon, renew_token_data, ratelimit);
|
||||
};
|
||||
|
||||
@@ -79,7 +79,7 @@ function createTokenExpiredHandler(
|
||||
renew_token_data: {existingToken: SavedToken; znc_proxy_url?: string},
|
||||
ratelimit = true
|
||||
) {
|
||||
return (data: WebServiceError, response: Response) => {
|
||||
return (data?: WebServiceError, response?: Response) => {
|
||||
debug('Token expired, renewing', data);
|
||||
return renewToken(storage, token, nooklink, renew_token_data, ratelimit);
|
||||
};
|
||||
@@ -196,7 +196,7 @@ function createUserTokenExpiredHandler(
|
||||
renew_token_data: {existingToken: SavedUserToken; znc_proxy_url?: string; nooklink: NooklinkApi | null},
|
||||
ratelimit = true
|
||||
) {
|
||||
return (data: WebServiceError, response: Response) => {
|
||||
return (data?: WebServiceError, response?: Response) => {
|
||||
debug('Token expired', nooklinkuser.user_id, data);
|
||||
return renewUserToken(storage, token, nooklinkuser, renew_token_data);
|
||||
};
|
||||
|
||||
@@ -79,7 +79,7 @@ function createTokenExpiredHandler(
|
||||
data: {existingToken: SavedBulletToken; znc_proxy_url?: string},
|
||||
ratelimit = true
|
||||
) {
|
||||
return (response: Response) => {
|
||||
return (response?: Response) => {
|
||||
debug('Token expired, renewing');
|
||||
return renewToken(storage, token, splatnet, data, ratelimit);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user