diff --git a/src/app/i18n/locale/de-de.ts b/src/app/i18n/locale/de-de.ts index c9e4fd9..11e649f 100644 --- a/src/app/i18n/locale/de-de.ts +++ b/src/app/i18n/locale/de-de.ts @@ -107,15 +107,6 @@ export const na_auth = { znca_api_use: { title: 'Verwendung einer Drittanbieter-API', - text: `Um Zugriff auf die API der Nintendo Switch Online App zu erhalten, muss nxapi einige Daten an Drittanbieter-APIs senden. Dieser Schritt wird benötigt, um Daten zu generieren, damit Nintendo denkt, dass du die echte Nintendo Switch Online App verwendest. -Standardmäßig wird nxapi-znca-api.fancy.org.uk oder api.imink.app benutzt. Ein anderer Service kann ebenfalls benutzt werden, indem eine Umgebungsvariable gesetzt wird. Die standardmäßige API könnte sich jederzeit ohne Hinweis ändern, wenn du keinen spezifischen Service erzwingst. - -Die gesendeten Daten beinhalten: - -- Deine Nintendo Account ID -- Bei Authorisierung mit der Nintendo Switch Online App: Ein Nintendo Account ID Token, welcher dein Land beinhaltet und für 15 Minuten gültig ist -- Bei Authorisierung mit Spielspezifischen Services: Deine Coral (Nintendo Switch Online App) User ID und ein Coral ID Token, welcher deine aktuelle Nintendo Switch Online Mitgliedschaft und Altersbeschränkungsstatus beinhaltet und für 2 Stunden gültig ist`, - ok: 'OK', cancel: 'Abbrechen', more_information: 'Weitere Informationen', diff --git a/src/app/i18n/locale/es-es.ts b/src/app/i18n/locale/es-es.ts index 5cc780b..e40e05c 100644 --- a/src/app/i18n/locale/es-es.ts +++ b/src/app/i18n/locale/es-es.ts @@ -107,16 +107,6 @@ export const na_auth = { znca_api_use: { title: 'Uso de API de terceros', - text: `Para acceder a la API de la aplicación Nintendo Switch Online, nxapi debe enviar algunos datos a APIs de terceros. Esto es necesario para generar ciertos datos y hacer que Nintendo piense que estás utilizando la aplicación real de Nintendo Switch Online. - -Por defecto se utiliza nxapi-znca-api.fancy.org.uk o api.imink.app, pero se puede utilizar otro servicio mediante la configuración de una variable de entorno. La API predeterminada puede cambiar sin previo aviso si no se especifica un servicio específico. - -Los datos enviados incluyen: - -- La ID de tu cuenta Nintendo -- Al autenticar a la aplicación Nintendo Switch Online: un token de la cuenta Nintendo que contiene tu país, válido durante 15 minutos -- Al autenticar en servicios específicos de juegos: tu ID de usuario de Coral (aplicación Nintendo Switch Online) y un token ID de Coral que contiene tu estado de suscripción a Nintendo Switch Online y el estado de restricciones en tu cuenta, válido durante 2 horas`, - ok: 'OK', cancel: 'Cancelar', more_information: 'Más Información', diff --git a/src/app/main/index.ts b/src/app/main/index.ts index 5ec1834..b28ee84 100644 --- a/src/app/main/index.ts +++ b/src/app/main/index.ts @@ -12,7 +12,7 @@ import { createModalWindow, createWindow } from './windows.js'; import { sendToAllWindows, setupIpc } from './ipc.js'; import { askUserForUri, buildElectronProxyAgent, showErrorDialog } from './util.js'; import { setAppInstance, updateMenuLanguage } from './app-menu.js'; -import { handleAuthUri } from './na-auth.js'; +import { checkZncaApiUseAllowed, handleAuthUri } from './na-auth.js'; import { DiscordPresenceConfiguration, LoginItem, LoginItemOptions, WindowType } from '../common/types.js'; import { init as initGlobals } from '../../common/globals.js'; import { CREDITS_NOTICE, GITLAB_URL, LICENCE_NOTICE } from '../../common/constants.js'; @@ -413,6 +413,32 @@ export class Store extends EventEmitter { // ratelimit = false, as most users.get calls are triggered by user interaction (or at startup) this.users = Users.coral(this, process.env.ZNC_PROXY_URL, false); + + this.setAskZncaApiConsent(); + } + + private _znca_api_use_consent_promise: Promise | null = null; + + private setAskZncaApiConsent() { + // @ts-expect-error + const get_user = this.users._get; + + // @ts-expect-error + this.users._get = async token => { + if (!this._znca_api_use_consent_promise) { + this._znca_api_use_consent_promise = checkZncaApiUseAllowed(this.app) + // Don't clear _znca_api_use_consent_promise on completion as if successful this + // doesn't need to be called again anyway + .catch(err => { + this._znca_api_use_consent_promise = null; + throw err; + }); + } + + await this._znca_api_use_consent_promise; + + return get_user.call(null, token); + }; } async getLoginItem(): Promise { diff --git a/src/app/main/na-auth.ts b/src/app/main/na-auth.ts index 8c5de66..a7b34ff 100644 --- a/src/app/main/na-auth.ts +++ b/src/app/main/na-auth.ts @@ -11,7 +11,7 @@ import { getToken } from '../../common/auth/coral.js'; import { getPctlToken } from '../../common/auth/moon.js'; import createDebug from '../../util/debug.js'; import { Jwt } from '../../util/jwt.js'; -import { ZNCA_API_USE_TEXT, ZNCA_API_USE_URL } from '../../common/constants.js'; +import { ZNCA_API_USE_TEXT, ZNCA_API_USE_URL, ZNCA_API_USE_VERSION } from '../../common/constants.js'; import { InvalidNintendoAccountTokenError } from '../../common/auth/na.js'; const debug = createDebug('app:main:na-auth'); @@ -395,32 +395,25 @@ export async function askAddNsoAccount(app: App, iab = true) { } } -async function checkZncaApiUseAllowed(app: App, window?: BrowserWindow, force = false) { +export async function checkZncaApiUseAllowed(app: App, window?: BrowserWindow, force = false) { if (!force) { - if (await app.store.storage.getItem('ZncaApiConsent')) { + const saved = await app.store.storage.getItem('ZncaApiConsent'); + const consent_version = typeof saved === 'number' ? saved : + typeof saved === 'boolean' ? (saved ? 1 : null) : null; + + if (consent_version && consent_version === ZNCA_API_USE_VERSION) { return; } if (process.env.ZNC_PROXY_URL) { debug('Skipping znca API consent; znc proxy URL set'); - await app.store.storage.setItem('ZncaApiConsent', true); - return; - } - - const ids: string[] | undefined = await app.store.storage.getItem('NintendoAccountIds'); - - for (const id of ids ?? []) { - const nsotoken: string | undefined = await app.store.storage.getItem('NintendoAccountToken.' + id); - if (!nsotoken) continue; - - debug('Skipping znca API consent; Nintendo Switch Online account already linked'); - await app.store.storage.setItem('ZncaApiConsent', true); + await app.store.storage.setItem('ZncaApiConsent', ZNCA_API_USE_VERSION); return; } } if (await askZncaApiUseAllowed(app, window)) { - await app.store.storage.setItem('ZncaApiConsent', true); + await app.store.storage.setItem('ZncaApiConsent', ZNCA_API_USE_VERSION); } else { throw new Error('Cannot continue without third-party APIs allowed'); } diff --git a/src/common/constants.ts b/src/common/constants.ts index da1a80d..36468bf 100644 --- a/src/common/constants.ts +++ b/src/common/constants.ts @@ -21,14 +21,18 @@ export const CREDITS_NOTICE = ` This product uses services provided by Nintendo (https://nintendo.co.jp), Samuel Elliott (https://gitlab.fancy.org.uk/samuel/nxapi-znca-api) and Jone Wang (https://imink.app). `.trim(); -export const ZNCA_API_USE_TEXT = ` -To access the Nintendo Switch Online app API, nxapi must send some data to third-party APIs. This is required to generate some data to make Nintendo think you\'re using the real Nintendo Switch Online app. +export const ZNCA_API_USE_VERSION = 2; -By default, this uses nxapi-znca-api.fancy.org.uk or api.imink.app, but another service can be used by setting an environment variable. The default API may change without notice if you do not force use of a specific service. +export const ZNCA_API_USE_TEXT = ` +To access the Nintendo Switch App API, nxapi must send some data to third-party APIs. This is required to make Nintendo\'s API think you\'re using the real Nintendo Switch App. + +This uses nxapi-znca-api.fancy.org.uk, but another service can be used by setting an environment variable. The default API may change without notice if you do not force use of a specific service. The data sent includes: - Your Nintendo Account ID -- When authenticating to the Nintendo Switch Online app: a Nintendo Account ID token, containing your Nintendo Account country, which is valid for 15 minutes -- When authenticating to game-specific services: your Coral (Nintendo Switch Online app) user ID and a Coral ID token, containing your Nintendo Switch Online membership status, and Nintendo Account child restriction status, which is valid for 2 hours +- When authenticating to the Nintendo Switch App API: a Nintendo Account ID token, containing your Nintendo Account country +- When authenticating to game-specific services, your Coral (Nintendo Switch Online app) user ID and a Coral token, containing your Nintendo Switch Online membership status, and Nintendo Account child restriction status + +Since June 2025 (v3.0.1), all data sent to/from the Nintendo Switch App API must also be sent for encryption. `.trim();