mirror of
https://github.com/samuelthomas2774/nxapi.git
synced 2026-07-11 23:46:10 -05:00
Move getToken/getMoonToken and add cli-table types
This commit is contained in:
parent
992f8900f2
commit
784e882dd4
|
|
@ -3,8 +3,9 @@ import createDebug from 'debug';
|
|||
import { ActiveEvent, Announcements, CurrentUser, Event, Friend, Presence, PresencePermissions, User, WebService, WebServiceToken, ZncStatus, ZncSuccessResponse } from './znc-types.js';
|
||||
import { ErrorResponse } from './util.js';
|
||||
import ZncApi from './znc.js';
|
||||
import { SavedToken, version } from '../util.js';
|
||||
import { version } from '../util.js';
|
||||
import { NintendoAccountUser } from './na.js';
|
||||
import { SavedToken } from '../cli/nso/util.js';
|
||||
|
||||
const debug = createDebug('api:znc-proxy');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
import React, { useCallback } from 'react';
|
||||
import { StyleSheet, Text, useColorScheme, View } from 'react-native';
|
||||
import { NintendoAccountUser } from '../../api/na.js';
|
||||
import { SavedMoonToken, SavedToken } from '../../util.js';
|
||||
import { SavedToken } from '../../cli/nso/util.js';
|
||||
import { SavedMoonToken } from '../../cli/pctl/util.js';
|
||||
import ipc from './ipc.js';
|
||||
import { useAsync } from './util.js';
|
||||
|
||||
export interface AppProps {
|
||||
//
|
||||
}
|
||||
|
||||
async function getAccounts() {
|
||||
const ids = await ipc.listNintendoAccounts();
|
||||
|
||||
|
|
@ -29,7 +34,7 @@ async function getAccounts() {
|
|||
return accounts;
|
||||
}
|
||||
|
||||
function App() {
|
||||
function App(props: AppProps) {
|
||||
const theme = useColorScheme() === 'light' ? light : dark;
|
||||
|
||||
const [users] = useAsync(useCallback(() => getAccounts(), [ipc]));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { AppRegistry } from 'react-native';
|
||||
import { config } from './ipc.js';
|
||||
import App from './app.jsx';
|
||||
|
||||
AppRegistry.registerComponent('App', () => App);
|
||||
|
|
@ -8,6 +9,7 @@ const rootTag = window.document.createElement('div');
|
|||
rootTag.style.minHeight = '100vh';
|
||||
window.document.body.appendChild(rootTag);
|
||||
|
||||
AppRegistry.runApplication('App', {
|
||||
AppRegistry.runApplication(config.type, {
|
||||
rootTag,
|
||||
initialProps: config.props,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
import type { EventEmitter } from 'events';
|
||||
import createDebug from 'debug';
|
||||
import type { NxapiElectronIpc } from '../preload/index.js';
|
||||
|
||||
const debug = createDebug('app:browser:ipc');
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
nxapiElectronIpc: NxapiElectronIpc;
|
||||
|
|
@ -9,3 +13,7 @@ declare global {
|
|||
const ipc = window.nxapiElectronIpc;
|
||||
|
||||
export default ipc;
|
||||
|
||||
export const config = ipc.getWindowData();
|
||||
|
||||
debug('Window configuration', config);
|
||||
|
|
|
|||
14
src/app/common/types.ts
Normal file
14
src/app/common/types.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import type { AppProps } from '../browser/app.js';
|
||||
|
||||
export enum WindowType {
|
||||
MAIN_WINDOW = 'App',
|
||||
}
|
||||
|
||||
interface WindowProps {
|
||||
[WindowType.MAIN_WINDOW]: AppProps;
|
||||
}
|
||||
|
||||
export interface WindowConfiguration<T extends WindowType = WindowType> {
|
||||
type: T;
|
||||
props: WindowProps[T];
|
||||
}
|
||||
|
|
@ -6,32 +6,25 @@ import * as persist from 'node-persist';
|
|||
import fetch from 'node-fetch';
|
||||
import dotenv from 'dotenv';
|
||||
import dotenvExpand from 'dotenv-expand';
|
||||
import { dev, dir, getToken, initStorage, LoopResult, paths } from '../../util.js';
|
||||
import { dir, initStorage, LoopResult, paths } from '../../util.js';
|
||||
import MenuApp from './menu.js';
|
||||
import { ZncDiscordPresence } from '../../cli/nso/presence.js';
|
||||
import { WebServiceIpc } from './webservices.js';
|
||||
import { createWindow, getWindowConfiguration } from './windows.js';
|
||||
import { WindowType } from '../common/types.js';
|
||||
import { CurrentUser, Friend, Game, ZncErrorResponse } from '../../api/znc-types.js';
|
||||
import { NotificationManager } from '../../cli/nso/notify.js';
|
||||
import { ErrorResponse } from '../../api/util.js';
|
||||
import { ZncDiscordPresence } from '../../cli/nso/presence.js';
|
||||
import { NotificationManager } from '../../cli/nso/notify.js';
|
||||
import { getToken } from '../../cli/nso/util.js';
|
||||
|
||||
const debug = createDebug('app:main');
|
||||
|
||||
export const bundlepath = path.resolve(dir, 'dist', 'bundle');
|
||||
export const bundlepath = path.resolve(dir, 'dist', 'app', 'bundle');
|
||||
|
||||
function createWindow() {
|
||||
// Create the browser window.
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
vibrancy: 'content',
|
||||
webPreferences: {
|
||||
preload: path.join(bundlepath, 'preload.cjs'),
|
||||
scrollBounce: true,
|
||||
},
|
||||
});
|
||||
function createMainWindow() {
|
||||
const window = createWindow(WindowType.MAIN_WINDOW, {});
|
||||
|
||||
mainWindow.loadFile(path.join(bundlepath, 'index.html'));
|
||||
if (dev) mainWindow.webContents.openDevTools();
|
||||
return window;
|
||||
}
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
|
|
@ -47,6 +40,8 @@ app.whenReady().then(async () => {
|
|||
const storage = await initStorage(process.env.NXAPI_DATA_PATH ?? paths.data);
|
||||
const store = new Store(storage);
|
||||
|
||||
ipcMain.on('nxapi:browser:getwindowdata', e => e.returnValue = getWindowConfiguration(e.sender));
|
||||
|
||||
ipcMain.handle('nxapi:accounts:list', () => storage.getItem('NintendoAccountIds'));
|
||||
ipcMain.handle('nxapi:nso:gettoken', (e, id: string) => storage.getItem('NintendoAccountToken.' + id));
|
||||
ipcMain.handle('nxapi:nso:getcachedtoken', (e, token: string) => storage.getItem('NsoToken.' + token));
|
||||
|
|
@ -71,7 +66,7 @@ app.whenReady().then(async () => {
|
|||
const menu = new MenuApp(store, monitors);
|
||||
|
||||
app.on('activate', () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) createWindow();
|
||||
if (BrowserWindow.getAllWindows().length === 0) createMainWindow();
|
||||
});
|
||||
|
||||
debug('App started');
|
||||
|
|
@ -248,7 +243,7 @@ export class EmbeddedPresenceMonitor extends ZncDiscordPresence {
|
|||
|
||||
async handleError(err: ErrorResponse<ZncErrorResponse> | NodeJS.ErrnoException): Promise<LoopResult> {
|
||||
try {
|
||||
return super.handleError(err);
|
||||
return await super.handleError(err);
|
||||
} catch (err) {
|
||||
if (err instanceof Error) {
|
||||
dialog.showErrorBox(err.name, err.stack ?? err.message);
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ import { app, dialog, Menu, Tray, nativeImage, MenuItem } from '../electron.js';
|
|||
import createDebug from 'debug';
|
||||
import { addNsoAccount, addPctlAccount } from './na-auth.js';
|
||||
import { PresenceMonitorManager, Store } from './index.js';
|
||||
import { getToken, SavedMoonToken, SavedToken } from '../../util.js';
|
||||
import { WebService } from '../../api/znc-types.js';
|
||||
import openWebService from './webservices.js';
|
||||
import { getToken, SavedToken } from '../../cli/nso/util.js';
|
||||
import { SavedMoonToken } from '../../cli/pctl/util.js';
|
||||
|
||||
const debug = createDebug('app:main:menu');
|
||||
|
||||
|
|
|
|||
|
|
@ -6,8 +6,9 @@ import { BrowserWindow, nativeImage, Notification, session, shell } from '../ele
|
|||
import { getNintendoAccountSessionToken, NintendoAccountSessionToken } from '../../api/na.js';
|
||||
import { Jwt } from '../../api/util.js';
|
||||
import { ZNCA_CLIENT_ID } from '../../api/znc.js';
|
||||
import { getPctlToken, getToken, SavedMoonToken, SavedToken } from '../../util.js';
|
||||
import { ZNMA_CLIENT_ID } from '../../api/moon.js';
|
||||
import { getToken, SavedToken } from '../../cli/nso/util.js';
|
||||
import { getPctlToken, SavedMoonToken } from '../../cli/pctl/util.js';
|
||||
|
||||
const debug = createDebug('app:main:na-auth');
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@ import * as path from 'path';
|
|||
import createDebug from 'debug';
|
||||
import { BrowserWindow, IpcMainInvokeEvent, session, shell, WebContents } from '../electron.js';
|
||||
import ZncApi from '../../api/znc.js';
|
||||
import { dev, SavedToken } from '../../util.js';
|
||||
import { dev } from '../../util.js';
|
||||
import { WebService } from '../../api/znc-types.js';
|
||||
import { bundlepath, Store } from './index.js';
|
||||
import type { NativeShareRequest, NativeShareUrlRequest } from '../preload-webservice/znca-js-api.js';
|
||||
import { SavedToken } from '../../cli/nso/util.js';
|
||||
|
||||
const debug = createDebug('app:main:webservices');
|
||||
|
||||
|
|
|
|||
42
src/app/main/windows.ts
Normal file
42
src/app/main/windows.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import { app, BrowserWindow, dialog, ipcMain, nativeImage, Notification, WebContents } from '../electron.js';
|
||||
import * as path from 'path';
|
||||
import { bundlepath } from './index.js';
|
||||
import { dev } from '../../util.js';
|
||||
import { WindowConfiguration, WindowType } from '../common/types.js';
|
||||
|
||||
const windows = new Map<WebContents, WindowConfiguration>();
|
||||
|
||||
export function createWindow<T extends WindowType>(type: T, props: WindowConfiguration<T>['props']) {
|
||||
// Create the browser window
|
||||
const window = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
vibrancy: 'content',
|
||||
webPreferences: {
|
||||
preload: path.join(bundlepath, 'preload.cjs'),
|
||||
scrollBounce: true,
|
||||
},
|
||||
});
|
||||
|
||||
const data: WindowConfiguration<T> = {
|
||||
type,
|
||||
props,
|
||||
};
|
||||
|
||||
windows.set(window.webContents, data);
|
||||
|
||||
window.loadFile(path.join(bundlepath, 'index.html'));
|
||||
if (dev) window.webContents.openDevTools();
|
||||
|
||||
return window;
|
||||
}
|
||||
|
||||
export function getWindowConfiguration(webcontents: WebContents): WindowConfiguration {
|
||||
const data = windows.get(webcontents);
|
||||
|
||||
if (!data) {
|
||||
throw new Error('Unknown window');
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
|
@ -1,8 +1,12 @@
|
|||
import { contextBridge, ipcRenderer } from 'electron';
|
||||
import { EventEmitter } from 'events';
|
||||
import { SavedMoonToken, SavedToken } from '../../util.js';
|
||||
import { WindowConfiguration } from '../common/types.js';
|
||||
import { SavedToken } from '../../cli/nso/util.js';
|
||||
import { SavedMoonToken } from '../../cli/pctl/util.js';
|
||||
|
||||
const ipc = {
|
||||
getWindowData: () => ipcRenderer.sendSync('nxapi:browser:getwindowdata') as WindowConfiguration,
|
||||
|
||||
listNintendoAccounts: () => ipcRenderer.invoke('nxapi:accounts:list') as Promise<string[] | undefined>,
|
||||
getNintendoAccountNsoToken: (id: string) => ipcRenderer.invoke('nxapi:nso:gettoken', id) as Promise<string | undefined>,
|
||||
getSavedNsoToken: (token: string) => ipcRenderer.invoke('nxapi:nso:getcachedtoken', token) as Promise<SavedToken | undefined>,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../nooklink.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getUserToken, getWebServiceToken } from './util.js';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../nooklink.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getUserToken } from './util.js';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../nooklink.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getUserToken } from './util.js';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../nooklink.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getUserToken } from './util.js';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../nooklink.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getWebServiceToken } from './util.js';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import createDebug from 'debug';
|
||||
import persist from 'node-persist';
|
||||
import { getToken } from '../../util.js';
|
||||
import { getToken } from '../nso/util.js';
|
||||
import NooklinkApi, { NooklinkUserApi } from '../../api/nooklink.js';
|
||||
import { AuthToken, Users } from '../../api/nooklink-types.js';
|
||||
import { WebServiceToken } from '../../api/znc-types.js';
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../nso.js';
|
||||
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getToken } from './util.js';
|
||||
|
||||
const debug = createDebug('cli:nso:announcements');
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@ import * as util from 'util';
|
|||
import createDebug from 'debug';
|
||||
import * as crypto from 'crypto';
|
||||
import type { Arguments as ParentArguments } from '../nso.js';
|
||||
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getToken } from './util.js';
|
||||
import { getNintendoAccountSessionToken } from '../../api/na.js';
|
||||
import { ZNCA_CLIENT_ID } from '../../api/znc.js';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import { PresenceState } from '../../api/znc-types.js';
|
||||
import type { Arguments as ParentArguments } from '../nso.js';
|
||||
import { ArgumentsCamelCase, Argv, getToken, hrduration, initStorage, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, hrduration, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getToken } from './util.js';
|
||||
|
||||
const debug = createDebug('cli:nso:friends');
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ import { v4 as uuidgen } from 'uuid';
|
|||
import { Announcement, CurrentUser, Friend, GetActiveEventResult, Presence, WebService } from '../../api/znc-types.js';
|
||||
import ZncApi from '../../api/znc.js';
|
||||
import type { Arguments as ParentArguments } from '../nso.js';
|
||||
import { ArgumentsCamelCase, Argv, getToken, initStorage, SavedToken, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getToken, SavedToken } from './util.js';
|
||||
import { NotificationManager, ZncNotifications } from './notify.js';
|
||||
|
||||
declare global {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@ import * as path from 'path';
|
|||
import { ActiveEvent, Announcements, CurrentUser, Friend, Game, Presence, PresenceState, WebServices, ZncErrorResponse } from '../../api/znc-types.js';
|
||||
import ZncApi from '../../api/znc.js';
|
||||
import type { Arguments as ParentArguments } from '../nso.js';
|
||||
import { ArgumentsCamelCase, Argv, getTitleIdFromEcUrl, getToken, hrduration, initStorage, Loop, LoopResult, SavedToken, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, getTitleIdFromEcUrl, hrduration, initStorage, Loop, LoopResult, YargsArguments } from '../../util.js';
|
||||
import { getToken, SavedToken } from './util.js';
|
||||
import ZncProxyApi from '../../api/znc-proxy.js';
|
||||
import { SplatNet2RecordsMonitor } from '../splatnet2/monitor.js';
|
||||
import { getIksmToken } from '../splatnet2/util.js';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import createDebug from 'debug';
|
||||
import { PresencePermissions } from '../../api/znc-types.js';
|
||||
import type { Arguments as ParentArguments } from '../nso.js';
|
||||
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getToken } from './util.js';
|
||||
|
||||
const debug = createDebug('cli:nso:permissions');
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ import DiscordRPC from 'discord-rpc';
|
|||
import { ActiveEvent, CurrentUser, Friend, Presence, PresenceState, ZncErrorResponse } from '../../api/znc-types.js';
|
||||
import ZncApi from '../../api/znc.js';
|
||||
import type { Arguments as ParentArguments } from '../nso.js';
|
||||
import { ArgumentsCamelCase, Argv, getToken, initStorage, LoopResult, SavedToken, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, LoopResult, YargsArguments } from '../../util.js';
|
||||
import { getToken, SavedToken } from './util.js';
|
||||
import { DiscordPresencePlayTime, DiscordPresenceContext, getDiscordPresence, getInactiveDiscordPresence } from '../../discord/util.js';
|
||||
import { handleEnableSplatNet2Monitoring, ZncNotifications } from './notify.js';
|
||||
import { ErrorResponse } from '../../index.js';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import * as util from 'util';
|
||||
import createDebug from 'debug';
|
||||
import type { Arguments as ParentArguments } from '../nso.js';
|
||||
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getToken } from './util.js';
|
||||
|
||||
const debug = createDebug('cli:nso:token');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import createDebug from 'debug';
|
||||
import type { Arguments as ParentArguments } from '../nso.js';
|
||||
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getToken } from './util.js';
|
||||
|
||||
const debug = createDebug('cli:nso:user');
|
||||
|
||||
|
|
|
|||
86
src/cli/nso/util.ts
Normal file
86
src/cli/nso/util.ts
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
import createDebug from 'debug';
|
||||
import * as persist from 'node-persist';
|
||||
import { FlapgApiResponse } from '../../api/f.js';
|
||||
import { NintendoAccountSessionTokenJwtPayload, NintendoAccountToken, NintendoAccountUser } from '../../api/na.js';
|
||||
import { Jwt } from '../../api/util.js';
|
||||
import { AccountLogin } from '../../api/znc-types.js';
|
||||
import ZncApi, { ZNCA_CLIENT_ID } from '../../api/znc.js';
|
||||
import ZncProxyApi from '../../api/znc-proxy.js';
|
||||
|
||||
const debug = createDebug('cli:nso');
|
||||
|
||||
export interface SavedToken {
|
||||
uuid: string;
|
||||
timestamp: string;
|
||||
nintendoAccountToken: NintendoAccountToken;
|
||||
user: NintendoAccountUser;
|
||||
flapg: FlapgApiResponse['result'];
|
||||
nsoAccount: AccountLogin;
|
||||
credential: AccountLogin['webApiServerCredential'];
|
||||
|
||||
expires_at: number;
|
||||
proxy_url?: string;
|
||||
}
|
||||
|
||||
export async function getToken(storage: persist.LocalStorage, token: string, proxy_url: string): Promise<{
|
||||
nso: ZncProxyApi;
|
||||
data: SavedToken;
|
||||
}>
|
||||
export async function getToken(storage: persist.LocalStorage, token: string, proxy_url?: string): Promise<{
|
||||
nso: ZncApi;
|
||||
data: SavedToken;
|
||||
}>
|
||||
export async function getToken(storage: persist.LocalStorage, token: string, proxy_url?: string) {
|
||||
if (!token) {
|
||||
console.error('No token set. Set a Nintendo Account session token using the `--token` option or by running `nxapi nso token`.');
|
||||
throw new Error('Invalid token');
|
||||
}
|
||||
|
||||
const [jwt, sig] = Jwt.decode<NintendoAccountSessionTokenJwtPayload>(token);
|
||||
|
||||
if (jwt.payload.iss !== 'https://accounts.nintendo.com') {
|
||||
throw new Error('Invalid Nintendo Account session token issuer');
|
||||
}
|
||||
if (jwt.payload.typ !== 'session_token') {
|
||||
throw new Error('Invalid Nintendo Account session token type');
|
||||
}
|
||||
if (jwt.payload.aud !== ZNCA_CLIENT_ID) {
|
||||
throw new Error('Invalid Nintendo Account session token audience');
|
||||
}
|
||||
if (jwt.payload.exp <= (Date.now() / 1000)) {
|
||||
throw new Error('Nintendo Account session token expired');
|
||||
}
|
||||
|
||||
// Nintendo Account session tokens use a HMAC SHA256 signature, so we can't verify this is valid
|
||||
|
||||
const existingToken: SavedToken | undefined = await storage.getItem('NsoToken.' + token);
|
||||
|
||||
if (!existingToken || existingToken.expires_at <= Date.now()) {
|
||||
console.warn('Authenticating to Nintendo Switch Online app');
|
||||
debug('Authenticating to znc with session token');
|
||||
|
||||
const {nso, data} = proxy_url ?
|
||||
await ZncProxyApi.createWithSessionToken(proxy_url, token) :
|
||||
await ZncApi.createWithSessionToken(token);
|
||||
|
||||
const existingToken: SavedToken = {
|
||||
...data,
|
||||
expires_at: Date.now() + (data.credential.expiresIn * 1000),
|
||||
};
|
||||
|
||||
await storage.setItem('NsoToken.' + token, existingToken);
|
||||
await storage.setItem('NintendoAccountToken.' + data.user.id, token);
|
||||
|
||||
return {nso, data: existingToken};
|
||||
}
|
||||
|
||||
debug('Using existing token');
|
||||
await storage.setItem('NintendoAccountToken.' + existingToken.user.id, token);
|
||||
|
||||
return {
|
||||
nso: proxy_url ?
|
||||
new ZncProxyApi(proxy_url, token) :
|
||||
new ZncApi(existingToken.credential.accessToken),
|
||||
data: existingToken,
|
||||
};
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../nso.js';
|
||||
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getToken } from './util.js';
|
||||
|
||||
const debug = createDebug('cli:nso:webservices');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import createDebug from 'debug';
|
||||
import type { Arguments as ParentArguments } from '../nso.js';
|
||||
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getToken } from './util.js';
|
||||
|
||||
const debug = createDebug('cli:nso:webservicetoken');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import createDebug from 'debug';
|
||||
import fetch from 'node-fetch';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../nso.js';
|
||||
import { Argv, getToken, initStorage } from '../../util.js';
|
||||
import { Argv, initStorage } from '../../util.js';
|
||||
import { getToken } from './util.js';
|
||||
import { AuthPolicy, AuthToken } from './http-server.js';
|
||||
|
||||
const debug = createDebug('cli:nso:znc-proxy-tokens');
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import * as util from 'util';
|
||||
import createDebug from 'debug';
|
||||
import * as crypto from 'crypto';
|
||||
import createDebug from 'debug';
|
||||
import type { Arguments as ParentArguments } from '../../cli.js';
|
||||
import { ArgumentsCamelCase, Argv, getPctlToken, initStorage, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getPctlToken } from './util.js';
|
||||
import { getNintendoAccountSessionToken } from '../../api/na.js';
|
||||
import { ZNMA_CLIENT_ID } from '../../api/moon.js';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../../cli.js';
|
||||
import { ArgumentsCamelCase, Argv, getPctlToken, hrduration, initStorage, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, hrduration, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getPctlToken } from './util.js';
|
||||
|
||||
const debug = createDebug('cli:pctl:daily-summaries');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../../cli.js';
|
||||
import { ArgumentsCamelCase, Argv, getPctlToken, initStorage, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getPctlToken } from './util.js';
|
||||
|
||||
const debug = createDebug('cli:pctl:devices');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import createDebug from 'debug';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs/promises';
|
||||
import createDebug from 'debug';
|
||||
import mkdirp from 'mkdirp';
|
||||
import type { Arguments as ParentArguments } from '../../cli.js';
|
||||
import { ArgumentsCamelCase, Argv, getPctlToken, initStorage, YargsArguments } from '../../util.js';
|
||||
import * as path from 'path';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getPctlToken } from './util.js';
|
||||
import { DailySummaryResult } from '../../api/moon-types.js';
|
||||
import MoonApi from '../../api/moon.js';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../../cli.js';
|
||||
import { ArgumentsCamelCase, Argv, getPctlToken, initStorage, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getPctlToken } from './util.js';
|
||||
|
||||
const debug = createDebug('cli:pctl:monthly-summaries');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../../cli.js';
|
||||
import { ArgumentsCamelCase, Argv, getPctlToken, initStorage, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getPctlToken } from './util.js';
|
||||
|
||||
const debug = createDebug('cli:pctl:monthly-summary');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import createDebug from 'debug';
|
||||
import type { Arguments as ParentArguments } from '../../cli.js';
|
||||
import { ArgumentsCamelCase, Argv, getPctlToken, initStorage, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getPctlToken } from './util.js';
|
||||
|
||||
const debug = createDebug('cli:pctl:settings');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import * as util from 'util';
|
||||
import createDebug from 'debug';
|
||||
import type { Arguments as ParentArguments } from '../../cli.js';
|
||||
import { ArgumentsCamelCase, Argv, getPctlToken, initStorage, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getPctlToken } from './util.js';
|
||||
|
||||
const debug = createDebug('cli:pctl:token');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import createDebug from 'debug';
|
||||
import type { Arguments as ParentArguments } from '../../cli.js';
|
||||
import { ArgumentsCamelCase, Argv, getPctlToken, initStorage, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getPctlToken } from './util.js';
|
||||
|
||||
const debug = createDebug('cli:pctl:user');
|
||||
|
||||
|
|
|
|||
66
src/cli/pctl/util.ts
Normal file
66
src/cli/pctl/util.ts
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
import createDebug from 'debug';
|
||||
import * as persist from 'node-persist';
|
||||
import { ZNMA_CLIENT_ID } from '../../api/moon.js';
|
||||
import { NintendoAccountSessionTokenJwtPayload, NintendoAccountToken, NintendoAccountUser } from '../../api/na.js';
|
||||
import { Jwt } from '../../api/util.js';
|
||||
import MoonApi from '../../api/moon.js';
|
||||
|
||||
const debug = createDebug('cli:nso');
|
||||
|
||||
export interface SavedMoonToken {
|
||||
nintendoAccountToken: NintendoAccountToken;
|
||||
user: NintendoAccountUser;
|
||||
|
||||
expires_at: number;
|
||||
}
|
||||
|
||||
export async function getPctlToken(storage: persist.LocalStorage, token: string) {
|
||||
if (!token) {
|
||||
console.error('No token set. Set a Nintendo Account session token using the `--token` option or by running `nxapi pctl auth`.');
|
||||
throw new Error('Invalid token');
|
||||
}
|
||||
|
||||
const [jwt, sig] = Jwt.decode<NintendoAccountSessionTokenJwtPayload>(token);
|
||||
|
||||
if (jwt.payload.iss !== 'https://accounts.nintendo.com') {
|
||||
throw new Error('Invalid Nintendo Account session token issuer');
|
||||
}
|
||||
if (jwt.payload.typ !== 'session_token') {
|
||||
throw new Error('Invalid Nintendo Account session token type');
|
||||
}
|
||||
if (jwt.payload.aud !== ZNMA_CLIENT_ID) {
|
||||
throw new Error('Invalid Nintendo Account session token audience');
|
||||
}
|
||||
if (jwt.payload.exp <= (Date.now() / 1000)) {
|
||||
throw new Error('Nintendo Account session token expired');
|
||||
}
|
||||
|
||||
// Nintendo Account session tokens use a HMAC SHA256 signature, so we can't verify this is valid
|
||||
|
||||
const existingToken: SavedMoonToken | undefined = await storage.getItem('MoonToken.' + token);
|
||||
|
||||
if (!existingToken || existingToken.expires_at <= Date.now()) {
|
||||
console.warn('Authenticating to Nintendo Switch Parental Controls app');
|
||||
debug('Authenticating to pctl with session token');
|
||||
|
||||
const {moon, data} = await MoonApi.createWithSessionToken(token);
|
||||
|
||||
const existingToken: SavedMoonToken = {
|
||||
...data,
|
||||
expires_at: Date.now() + (data.nintendoAccountToken.expires_in * 1000),
|
||||
};
|
||||
|
||||
await storage.setItem('MoonToken.' + token, existingToken);
|
||||
await storage.setItem('NintendoAccountToken-pctl.' + data.user.id, token);
|
||||
|
||||
return {moon, data: existingToken};
|
||||
}
|
||||
|
||||
debug('Using existing token');
|
||||
await storage.setItem('NintendoAccountToken-pctl.' + existingToken.user.id, token);
|
||||
|
||||
return {
|
||||
moon: new MoonApi(existingToken.nintendoAccountToken.access_token!, existingToken.user.id),
|
||||
data: existingToken,
|
||||
};
|
||||
}
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../splatnet2.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getIksmToken } from './util.js';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../splatnet2.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getIksmToken } from './util.js';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../splatnet2.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getIksmToken } from './util.js';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../splatnet2.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getIksmToken } from './util.js';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../splatnet2.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getIksmToken } from './util.js';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import createDebug from 'debug';
|
||||
import persist from 'node-persist';
|
||||
import * as fs from 'fs';
|
||||
import { getToken } from '../../util.js';
|
||||
import { getToken } from '../nso/util.js';
|
||||
import SplatNet2Api from '../../api/splatnet2.js';
|
||||
import { WebServiceToken } from '../../api/znc-types.js';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from '../util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../splatnet2.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getIksmToken } from './util.js';
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import Table from './util/table.js';
|
||||
import type { Arguments as ParentArguments } from '../cli.js';
|
||||
import { Argv, initStorage, SavedMoonToken, SavedToken } from '../util.js';
|
||||
import { Argv, initStorage } from '../util.js';
|
||||
import { SavedToken } from './nso/util.js';
|
||||
import { SavedMoonToken } from './pctl/util.js';
|
||||
|
||||
const debug = createDebug('cli:users');
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import * as crypto from 'crypto';
|
||||
import { Buffer } from 'buffer';
|
||||
import createDebug from 'debug';
|
||||
import type { Arguments as ParentArguments } from '../../cli.js';
|
||||
import { Argv } from '../../util.js';
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@ import { getPresenceFromUrl } from '../../api/znc-proxy.js';
|
|||
import { ActiveEvent, CurrentUser, Friend, Game, Presence, PresenceState } from '../../api/znc-types.js';
|
||||
import type { Arguments as ParentArguments } from '../../cli.js';
|
||||
import { DiscordPresenceContext, DiscordPresencePlayTime, getDiscordPresence, getInactiveDiscordPresence } from '../../discord/util.js';
|
||||
import { ArgumentsCamelCase, Argv, getToken, initStorage, YargsArguments } from '../../util.js';
|
||||
import { ArgumentsCamelCase, Argv, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getToken } from '../nso/util.js';
|
||||
|
||||
const debug = createDebug('cli:util:discord-activity');
|
||||
|
||||
|
|
|
|||
127
src/cli/util/table.ts
Normal file
127
src/cli/util/table.ts
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
// @ts-expect-error
|
||||
import __Table from 'cli-table/lib/index.js';
|
||||
|
||||
export type Cell = string | number;
|
||||
export type Row = Cell[];
|
||||
|
||||
export enum CellAlign {
|
||||
LEFT = 'left',
|
||||
MIDDLE = 'middle',
|
||||
RIGHT = 'right',
|
||||
}
|
||||
|
||||
export enum Style {
|
||||
BLACK = 'black',
|
||||
RED = 'red',
|
||||
GREEN = 'green',
|
||||
YELLOW = 'yellow',
|
||||
BLUE = 'blue',
|
||||
MAGENTA = 'magenta',
|
||||
CYAN = 'cyan',
|
||||
WHITE = 'white',
|
||||
GREY = 'grey',
|
||||
|
||||
BRIGHTRED = 'brightRed',
|
||||
BRIGHTGREEN = 'brightGreen',
|
||||
BRIGHTYELLOW = 'brightYellow',
|
||||
BRIGHTBLUE = 'brightBlue',
|
||||
BRIGHTMAGENTA = 'brightMagenta',
|
||||
BRIGHTCYAN = 'brightCyan',
|
||||
BRIGHTWHITE = 'brightWhite',
|
||||
|
||||
BG_BLACK = 'bgBlack',
|
||||
BG_RED = 'bgRed',
|
||||
BG_GREEN = 'bgGreen',
|
||||
BG_YELLOW = 'bgYellow',
|
||||
BG_BLUE = 'bgBlue',
|
||||
BG_MAGENTA = 'bgMagenta',
|
||||
BG_CYAN = 'bgCyan',
|
||||
BG_WHITE = 'bgWhite',
|
||||
BG_GREY = 'bgGrey',
|
||||
|
||||
BG_BRIGHTRED = 'bgBrightRed',
|
||||
BG_BRIGHTGREEN = 'bgBrightGreen',
|
||||
BG_BRIGHTYELLOW = 'bgBrightYellow',
|
||||
BG_BRIGHTBLUE = 'bgBrightBlue',
|
||||
BG_BRIGHTMAGENTA = 'bgBrightMagenta',
|
||||
BG_BRIGHTCYAN = 'bgBrightCyan',
|
||||
BG_BRIGHTWHITE = 'bgBrightWhite',
|
||||
|
||||
RESET = 'reset',
|
||||
BOLD = 'bold',
|
||||
DIM = 'dim',
|
||||
ITALIC = 'italic',
|
||||
UNDERLINE = 'underline',
|
||||
INVERSE = 'inverse',
|
||||
HIDDEN = 'hidden',
|
||||
STRIKETHROUGH = 'strikethrough',
|
||||
|
||||
RAINBOW = 'rainbow',
|
||||
ZEBRA = 'zebra',
|
||||
AMERICA = 'america',
|
||||
TRAP = 'trap',
|
||||
RANDOM = 'random',
|
||||
}
|
||||
|
||||
export interface TableOptions {
|
||||
chars: {
|
||||
'top': string;
|
||||
'top-mid': string;
|
||||
'top-left': string;
|
||||
'top-right': string;
|
||||
'bottom': string;
|
||||
'bottom-mid': string;
|
||||
'bottom-left': string;
|
||||
'bottom-right': string;
|
||||
'left': string;
|
||||
'left-mid': string;
|
||||
'mid': string;
|
||||
'mid-mid': string;
|
||||
'right': string;
|
||||
'right-mid': string;
|
||||
'middle': string;
|
||||
};
|
||||
truncate: string;
|
||||
colWidths: number[];
|
||||
colAligns: CellAlign[];
|
||||
style: {
|
||||
'padding-left': number;
|
||||
'padding-right': number;
|
||||
/** @default [Style.RED] */
|
||||
head: Style[];
|
||||
/** @default [Style.GREY] */
|
||||
border: Style[];
|
||||
compact: boolean;
|
||||
};
|
||||
head: Row;
|
||||
rows: Row[];
|
||||
}
|
||||
|
||||
type RecursivePartial<T extends {}> = {
|
||||
[P in keyof T]?: (T[P] extends Array<unknown> ? T[P] : RecursivePartial<T[P]>) | undefined;
|
||||
};
|
||||
|
||||
export type PartialTableOptions = RecursivePartial<TableOptions>;
|
||||
|
||||
declare class Table extends Array<Row> {
|
||||
options: TableOptions;
|
||||
constructor(options: PartialTableOptions);
|
||||
/**
|
||||
* Width getter
|
||||
*/
|
||||
get width(): number;
|
||||
/**
|
||||
* Render to a string.
|
||||
*/
|
||||
render(): string;
|
||||
/**
|
||||
* Render to a string.
|
||||
*/
|
||||
toString(): string;
|
||||
static version: string;
|
||||
}
|
||||
|
||||
const _Table: typeof Table = __Table;
|
||||
type _Table = Table;
|
||||
|
||||
export default _Table;
|
||||
179
src/util.ts
179
src/util.ts
|
|
@ -2,23 +2,21 @@ import * as path from 'path';
|
|||
import * as fs from 'fs';
|
||||
import * as child_process from 'child_process';
|
||||
import * as yargs from 'yargs';
|
||||
import type * as yargstypes from '../node_modules/@types/yargs/index.js';
|
||||
// import type * as yargstypes from '../node_modules/@types/yargs/index.js';
|
||||
import createDebug from 'debug';
|
||||
import persist from 'node-persist';
|
||||
import getPaths from 'env-paths';
|
||||
import fetch from 'node-fetch';
|
||||
import { FlapgApiResponse } from './api/f.js';
|
||||
import { NintendoAccountSessionTokenJwtPayload, NintendoAccountToken, NintendoAccountUser } from './api/na.js';
|
||||
import { AccountLogin } from './api/znc-types.js';
|
||||
import ZncApi, { ZNCA_CLIENT_ID } from './api/znc.js';
|
||||
import ZncProxyApi from './api/znc-proxy.js';
|
||||
import MoonApi, { ZNMA_CLIENT_ID } from './api/moon.js';
|
||||
import { Jwks, Jwt } from './api/util.js';
|
||||
import { Jwks } from './api/util.js';
|
||||
|
||||
const debug = createDebug('cli');
|
||||
|
||||
export const paths = getPaths('nxapi');
|
||||
|
||||
//
|
||||
// Package/version info
|
||||
//
|
||||
|
||||
export const dir = path.resolve(decodeURI(import.meta.url.substr(process.platform === 'win32' ? 8 : 7)), '..', '..');
|
||||
export const pkg = JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf-8'));
|
||||
export const version = pkg.version;
|
||||
|
|
@ -42,29 +40,40 @@ export const git = (() => {
|
|||
})();
|
||||
export const dev = !!git || process.env.NODE_ENV === 'development';
|
||||
|
||||
//
|
||||
// Yargs types
|
||||
//
|
||||
|
||||
export type YargsArguments<T extends yargs.Argv> = T extends yargs.Argv<infer R> ? R : any;
|
||||
export type Argv<T = {}> = yargs.Argv<T>;
|
||||
export type ArgumentsCamelCase<T = {}> = yargstypes.ArgumentsCamelCase<T>;
|
||||
// export type ArgumentsCamelCase<T = {}> = yargstypes.ArgumentsCamelCase<T>;
|
||||
|
||||
export interface SavedToken {
|
||||
uuid: string;
|
||||
timestamp: string;
|
||||
nintendoAccountToken: NintendoAccountToken;
|
||||
user: NintendoAccountUser;
|
||||
flapg: FlapgApiResponse['result'];
|
||||
nsoAccount: AccountLogin;
|
||||
credential: AccountLogin['webApiServerCredential'];
|
||||
/** Convert literal string types like 'foo-bar' to 'FooBar' */
|
||||
type PascalCase<S extends string> = string extends S ?
|
||||
string : S extends `${infer T}-${infer U}` ?
|
||||
`${Capitalize<T>}${PascalCase<U>}` : Capitalize<S>;
|
||||
|
||||
expires_at: number;
|
||||
proxy_url?: string;
|
||||
}
|
||||
/** Convert literal string types like 'foo-bar' to 'fooBar' */
|
||||
type CamelCase<S extends string> = string extends S ?
|
||||
string : S extends `${infer T}-${infer U}` ?
|
||||
`${T}${PascalCase<U>}` : S;
|
||||
|
||||
export interface SavedMoonToken {
|
||||
nintendoAccountToken: NintendoAccountToken;
|
||||
user: NintendoAccountUser;
|
||||
/** Convert literal string types like 'foo-bar' to 'fooBar', allowing all `PropertyKey` types */
|
||||
type CamelCaseKey<K extends PropertyKey> = K extends string ? Exclude<CamelCase<K>, ''> : K;
|
||||
|
||||
expires_at: number;
|
||||
}
|
||||
/** Arguments type, with camelcased keys */
|
||||
export type ArgumentsCamelCase<T = {}> = { [key in keyof T as key | CamelCaseKey<key>]: T[key] } & {
|
||||
/** Non-option arguments */
|
||||
_: Array<string | number>;
|
||||
/** The script name or node command */
|
||||
$0: string;
|
||||
/** All remaining options */
|
||||
[argName: string]: unknown;
|
||||
};
|
||||
|
||||
//
|
||||
// Other
|
||||
//
|
||||
|
||||
export async function initStorage(dir: string) {
|
||||
const storage = persist.create({
|
||||
|
|
@ -75,120 +84,6 @@ export async function initStorage(dir: string) {
|
|||
return storage;
|
||||
}
|
||||
|
||||
export async function getToken(storage: persist.LocalStorage, token: string, proxy_url: string): Promise<{
|
||||
nso: ZncProxyApi;
|
||||
data: SavedToken;
|
||||
}>
|
||||
export async function getToken(storage: persist.LocalStorage, token: string, proxy_url?: string): Promise<{
|
||||
nso: ZncApi;
|
||||
data: SavedToken;
|
||||
}>
|
||||
export async function getToken(storage: persist.LocalStorage, token: string, proxy_url?: string) {
|
||||
if (!token) {
|
||||
console.error('No token set. Set a Nintendo Account session token using the `--token` option or by running `nxapi nso token`.');
|
||||
throw new Error('Invalid token');
|
||||
}
|
||||
|
||||
const [jwt, sig] = Jwt.decode<NintendoAccountSessionTokenJwtPayload>(token);
|
||||
|
||||
if (jwt.payload.iss !== 'https://accounts.nintendo.com') {
|
||||
throw new Error('Invalid Nintendo Account session token issuer');
|
||||
}
|
||||
if (jwt.payload.typ !== 'session_token') {
|
||||
throw new Error('Invalid Nintendo Account session token type');
|
||||
}
|
||||
if (jwt.payload.aud !== ZNCA_CLIENT_ID) {
|
||||
throw new Error('Invalid Nintendo Account session token audience');
|
||||
}
|
||||
if (jwt.payload.exp <= (Date.now() / 1000)) {
|
||||
throw new Error('Nintendo Account session token expired');
|
||||
}
|
||||
|
||||
// Nintendo Account session tokens use a HMAC SHA256 signature, so we can't verify this is valid
|
||||
|
||||
const existingToken: SavedToken | undefined = await storage.getItem('NsoToken.' + token);
|
||||
|
||||
if (!existingToken || existingToken.expires_at <= Date.now()) {
|
||||
console.warn('Authenticating to Nintendo Switch Online app');
|
||||
debug('Authenticating to znc with session token');
|
||||
|
||||
const {nso, data} = proxy_url ?
|
||||
await ZncProxyApi.createWithSessionToken(proxy_url, token) :
|
||||
await ZncApi.createWithSessionToken(token);
|
||||
|
||||
const existingToken: SavedToken = {
|
||||
...data,
|
||||
expires_at: Date.now() + (data.credential.expiresIn * 1000),
|
||||
};
|
||||
|
||||
await storage.setItem('NsoToken.' + token, existingToken);
|
||||
await storage.setItem('NintendoAccountToken.' + data.user.id, token);
|
||||
|
||||
return {nso, data: existingToken};
|
||||
}
|
||||
|
||||
debug('Using existing token');
|
||||
await storage.setItem('NintendoAccountToken.' + existingToken.user.id, token);
|
||||
|
||||
return {
|
||||
nso: proxy_url ?
|
||||
new ZncProxyApi(proxy_url, token) :
|
||||
new ZncApi(existingToken.credential.accessToken),
|
||||
data: existingToken,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getPctlToken(storage: persist.LocalStorage, token: string) {
|
||||
if (!token) {
|
||||
console.error('No token set. Set a Nintendo Account session token using the `--token` option or by running `nxapi pctl auth`.');
|
||||
throw new Error('Invalid token');
|
||||
}
|
||||
|
||||
const [jwt, sig] = Jwt.decode<NintendoAccountSessionTokenJwtPayload>(token);
|
||||
|
||||
if (jwt.payload.iss !== 'https://accounts.nintendo.com') {
|
||||
throw new Error('Invalid Nintendo Account session token issuer');
|
||||
}
|
||||
if (jwt.payload.typ !== 'session_token') {
|
||||
throw new Error('Invalid Nintendo Account session token type');
|
||||
}
|
||||
if (jwt.payload.aud !== ZNMA_CLIENT_ID) {
|
||||
throw new Error('Invalid Nintendo Account session token audience');
|
||||
}
|
||||
if (jwt.payload.exp <= (Date.now() / 1000)) {
|
||||
throw new Error('Nintendo Account session token expired');
|
||||
}
|
||||
|
||||
// Nintendo Account session tokens use a HMAC SHA256 signature, so we can't verify this is valid
|
||||
|
||||
const existingToken: SavedMoonToken | undefined = await storage.getItem('MoonToken.' + token);
|
||||
|
||||
if (!existingToken || existingToken.expires_at <= Date.now()) {
|
||||
console.warn('Authenticating to Nintendo Switch Parental Controls app');
|
||||
debug('Authenticating to pctl with session token');
|
||||
|
||||
const {moon, data} = await MoonApi.createWithSessionToken(token);
|
||||
|
||||
const existingToken: SavedMoonToken = {
|
||||
...data,
|
||||
expires_at: Date.now() + (data.nintendoAccountToken.expires_in * 1000),
|
||||
};
|
||||
|
||||
await storage.setItem('MoonToken.' + token, existingToken);
|
||||
await storage.setItem('NintendoAccountToken-pctl.' + data.user.id, token);
|
||||
|
||||
return {moon, data: existingToken};
|
||||
}
|
||||
|
||||
debug('Using existing token');
|
||||
await storage.setItem('NintendoAccountToken-pctl.' + existingToken.user.id, token);
|
||||
|
||||
return {
|
||||
moon: new MoonApi(existingToken.nintendoAccountToken.access_token!, existingToken.user.id),
|
||||
data: existingToken,
|
||||
};
|
||||
}
|
||||
|
||||
export function getTitleIdFromEcUrl(url: string) {
|
||||
const match = url.match(/^https:\/\/ec\.nintendo\.com\/apps\/([0-9a-f]{16})\//);
|
||||
return match?.[1] ?? null;
|
||||
|
|
@ -272,6 +167,12 @@ export enum LoopResult {
|
|||
OK_SKIP_INTERVAL = LoopRunOkSkipInterval as any,
|
||||
}
|
||||
|
||||
//
|
||||
// JSON Web Key Sets
|
||||
//
|
||||
// Used for verifying JSON Web Tokens
|
||||
//
|
||||
|
||||
interface SavedJwks {
|
||||
jwks: Jwks;
|
||||
expires_at: number;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user