mirror of
https://github.com/samuelthomas2774/nxapi.git
synced 2026-10-22 01:21:33 -05:00
Add parental controls
This commit is contained in:
114
src/cli/pctl/auth.ts
Normal file
114
src/cli/pctl/auth.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import * as util from 'util';
|
||||
import createDebug from 'debug';
|
||||
import * as crypto from 'crypto';
|
||||
import type { Arguments as ParentArguments } from '../../cli.js';
|
||||
import { ArgumentsCamelCase, Argv, getPctlToken, initStorage, YargsArguments } from '../../util.js';
|
||||
import { getNintendoAccountSessionToken } from '../../api/na.js';
|
||||
import { MOON_CLIENT_ID } from '../../api/moon.js';
|
||||
|
||||
const debug = createDebug('cli:pctl:auth');
|
||||
|
||||
export const command = 'auth';
|
||||
export const desc = 'Generate a link to login to a Nintendo Account';
|
||||
|
||||
export function builder(yargs: Argv<ParentArguments>) {
|
||||
return yargs.option('auth', {
|
||||
describe: 'Authenticate immediately',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
}).option('select', {
|
||||
describe: 'Set as default user (default: true if only user)',
|
||||
type: 'boolean',
|
||||
});
|
||||
}
|
||||
|
||||
type Arguments = YargsArguments<ReturnType<typeof builder>>;
|
||||
|
||||
export async function handler(argv: ArgumentsCamelCase<Arguments>) {
|
||||
const state = crypto.randomBytes(36).toString('base64url');
|
||||
const verifier = crypto.randomBytes(32).toString('base64url');
|
||||
const challenge = crypto.createHash('sha256').update(verifier).digest().toString('base64url');
|
||||
|
||||
const params = {
|
||||
state,
|
||||
redirect_uri: 'npf54789befb391a838://auth',
|
||||
client_id: MOON_CLIENT_ID,
|
||||
scope: [
|
||||
'openid',
|
||||
'user',
|
||||
'user.mii',
|
||||
'moonUser:administration',
|
||||
'moonDevice:create',
|
||||
'moonOwnedDevice:administration',
|
||||
'moonParentalControlSetting',
|
||||
'moonParentalControlSetting:update',
|
||||
'moonParentalControlSettingState',
|
||||
'moonPairingState',
|
||||
'moonSmartDevice:administration',
|
||||
'moonDailySummary',
|
||||
'moonMonthlySummary',
|
||||
].join(' '),
|
||||
response_type: 'session_token_code',
|
||||
session_token_code_challenge: challenge,
|
||||
session_token_code_challenge_method: 'S256',
|
||||
};
|
||||
|
||||
const authoriseurl = 'https://accounts.nintendo.com/connect/1.0.0/authorize?' +
|
||||
new URLSearchParams(params).toString();
|
||||
|
||||
debug('Authentication parameters', {
|
||||
state,
|
||||
verifier,
|
||||
challenge,
|
||||
}, params);
|
||||
|
||||
console.log('1. Open this URL and login to your Nintendo Account:');
|
||||
console.log('');
|
||||
console.log(authoriseurl);
|
||||
console.log('');
|
||||
|
||||
console.log('2. On the "Linking an External Account" page, right click "Select this person" and copy the link. It should start with "npf54789befb391a838://auth".');
|
||||
console.log('');
|
||||
|
||||
const read = await import('read');
|
||||
// @ts-expect-error
|
||||
const prompt = util.promisify(read.default as typeof read);
|
||||
|
||||
const applink = await prompt({
|
||||
prompt: `Paste the link: `,
|
||||
// silent: true,
|
||||
output: process.stderr,
|
||||
});
|
||||
|
||||
console.log('');
|
||||
|
||||
const authorisedurl = new URL(applink);
|
||||
const authorisedparams = new URLSearchParams(authorisedurl.hash.substr(1));
|
||||
debug('Redirect URL parameters', [...authorisedparams.entries()]);
|
||||
|
||||
const code = authorisedparams.get('session_token_code')!;
|
||||
const token = await getNintendoAccountSessionToken(code, verifier, MOON_CLIENT_ID);
|
||||
|
||||
console.log('Session token', token);
|
||||
|
||||
if (argv.auth) {
|
||||
const storage = await initStorage(argv.dataPath);
|
||||
|
||||
const {moon, data} = await getPctlToken(storage, token.session_token);
|
||||
|
||||
console.log('Authenticated as Nintendo Account %s (%s)',
|
||||
data.user.nickname, data.user.id);
|
||||
|
||||
await storage.setItem('NintendoAccountToken-pctl.' + data.user.id, token.session_token);
|
||||
|
||||
const users = new Set(await storage.getItem('NintendoAccountIds') ?? []);
|
||||
users.add(data.user.id);
|
||||
await storage.setItem('NintendoAccountIds', [...users]);
|
||||
|
||||
if ('select' in argv ? argv.select : users.size === 1) {
|
||||
await storage.setItem('SelectedUser', data.user.id);
|
||||
|
||||
console.log('Set as default user');
|
||||
}
|
||||
}
|
||||
}
|
||||
79
src/cli/pctl/daily-summaries.ts
Normal file
79
src/cli/pctl/daily-summaries.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import type { Arguments as ParentArguments } from '../../cli.js';
|
||||
import { ArgumentsCamelCase, Argv, getPctlToken, hrduration, initStorage, YargsArguments } from '../../util.js';
|
||||
|
||||
const debug = createDebug('cli:pctl:daily-summaries');
|
||||
|
||||
export const command = 'daily-summaries <device>';
|
||||
export const desc = 'Show daily summaries';
|
||||
|
||||
export function builder(yargs: Argv<ParentArguments>) {
|
||||
return yargs.positional('device', {
|
||||
describe: 'Nintendo Switch device ID',
|
||||
type: 'string',
|
||||
demandOption: true,
|
||||
}).option('user', {
|
||||
describe: 'Nintendo Account ID',
|
||||
type: 'string',
|
||||
}).option('token', {
|
||||
describe: 'Nintendo Account session token',
|
||||
type: 'string',
|
||||
}).option('json', {
|
||||
describe: 'Output raw JSON',
|
||||
type: 'boolean',
|
||||
}).option('json-pretty-print', {
|
||||
describe: 'Output pretty-printed JSON',
|
||||
type: 'boolean',
|
||||
});
|
||||
}
|
||||
|
||||
type Arguments = YargsArguments<ReturnType<typeof builder>>;
|
||||
|
||||
export async function handler(argv: ArgumentsCamelCase<Arguments>) {
|
||||
const storage = await initStorage(argv.dataPath);
|
||||
|
||||
const usernsid = argv.user ?? await storage.getItem('SelectedUser');
|
||||
const token: string = argv.token ||
|
||||
await storage.getItem('NintendoAccountToken-pctl.' + usernsid);
|
||||
const {moon, data} = await getPctlToken(storage, token);
|
||||
|
||||
const summaries = await moon.getDailySummaries(argv.device);
|
||||
|
||||
if (argv.jsonPrettyPrint) {
|
||||
console.log(JSON.stringify(summaries, null, 4));
|
||||
return;
|
||||
}
|
||||
if (argv.json) {
|
||||
console.log(JSON.stringify(summaries));
|
||||
return;
|
||||
}
|
||||
|
||||
const table = new Table({
|
||||
head: [
|
||||
'Date',
|
||||
'Status',
|
||||
'Play time',
|
||||
'Misc. time',
|
||||
'Titles played',
|
||||
'Users played',
|
||||
'Notices',
|
||||
],
|
||||
});
|
||||
|
||||
for (const summary of summaries.items) {
|
||||
table.push([
|
||||
summary.date,
|
||||
summary.result,
|
||||
hrduration(summary.playingTime / 60, true),
|
||||
hrduration(summary.miscTime / 60, true),
|
||||
summary.playedApps.map(t => t.title).join('\n'),
|
||||
summary.devicePlayers.map(p => p.nickname)
|
||||
.concat(summary.anonymousPlayer ? ['Unknown user'] : []).join('\n'),
|
||||
[...summary.importantInfos, ...summary.observations.map(o => o.type)].join('\n'),
|
||||
]);
|
||||
}
|
||||
|
||||
console.log(table.toString());
|
||||
}
|
||||
59
src/cli/pctl/devices.ts
Normal file
59
src/cli/pctl/devices.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import type { Arguments as ParentArguments } from '../../cli.js';
|
||||
import { ArgumentsCamelCase, Argv, getPctlToken, initStorage, YargsArguments } from '../../util.js';
|
||||
|
||||
const debug = createDebug('cli:pctl:devices');
|
||||
|
||||
export const command = 'devices';
|
||||
export const desc = 'List Nintendo Switch consoles';
|
||||
|
||||
export function builder(yargs: Argv<ParentArguments>) {
|
||||
return yargs.option('user', {
|
||||
describe: 'Nintendo Account ID',
|
||||
type: 'string',
|
||||
}).option('token', {
|
||||
describe: 'Nintendo Account session token',
|
||||
type: 'string',
|
||||
});
|
||||
}
|
||||
|
||||
type Arguments = YargsArguments<ReturnType<typeof builder>>;
|
||||
|
||||
export async function handler(argv: ArgumentsCamelCase<Arguments>) {
|
||||
console.warn('Listing devices');
|
||||
|
||||
const storage = await initStorage(argv.dataPath);
|
||||
|
||||
const usernsid = argv.user ?? await storage.getItem('SelectedUser');
|
||||
const token: string = argv.token ||
|
||||
await storage.getItem('NintendoAccountToken-pctl.' + usernsid);
|
||||
const {moon, data} = await getPctlToken(storage, token);
|
||||
|
||||
const devices = await moon.getDevices();
|
||||
|
||||
const table = new Table({
|
||||
head: [
|
||||
'ID',
|
||||
'Label',
|
||||
'Serial number',
|
||||
'Software version',
|
||||
'PIN',
|
||||
'Last synchronised',
|
||||
],
|
||||
});
|
||||
|
||||
for (const device of devices.items) {
|
||||
table.push([
|
||||
device.deviceId,
|
||||
device.label,
|
||||
device.device.serialNumber,
|
||||
device.device.firmwareVersion.displayedVersion + ' (' + device.device.firmwareVersion.internalVersion + ')',
|
||||
device.device.synchronizedUnlockCode,
|
||||
new Date(device.device.synchronizedParentalControlSetting.synchronizedAt * 1000).toISOString(),
|
||||
]);
|
||||
}
|
||||
|
||||
console.log(table.toString());
|
||||
}
|
||||
95
src/cli/pctl/dump-summaries.ts
Normal file
95
src/cli/pctl/dump-summaries.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import createDebug from 'debug';
|
||||
import * as fs from 'fs/promises';
|
||||
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 { DailySummaryResult } from '../../api/moon-types.js';
|
||||
import MoonApi from '../../api/moon.js';
|
||||
|
||||
const debug = createDebug('cli:pctl:dump-summaries');
|
||||
|
||||
export const command = 'dump-summaries <directory>';
|
||||
export const desc = 'Download all daily and monthly summaries';
|
||||
|
||||
export function builder(yargs: Argv<ParentArguments>) {
|
||||
return yargs.positional('directory', {
|
||||
describe: 'Directory to write summary data to',
|
||||
type: 'string',
|
||||
demandOption: true,
|
||||
}).option('user', {
|
||||
describe: 'Nintendo Account ID',
|
||||
type: 'string',
|
||||
}).option('token', {
|
||||
describe: 'Nintendo Account session token',
|
||||
type: 'string',
|
||||
}).option('device', {
|
||||
describe: 'Nintendo Switch device ID',
|
||||
type: 'array',
|
||||
});
|
||||
}
|
||||
|
||||
type Arguments = YargsArguments<ReturnType<typeof builder>>;
|
||||
|
||||
export async function handler(argv: ArgumentsCamelCase<Arguments>) {
|
||||
const storage = await initStorage(argv.dataPath);
|
||||
|
||||
const usernsid = argv.user ?? await storage.getItem('SelectedUser');
|
||||
const token: string = argv.token ||
|
||||
await storage.getItem('NintendoAccountToken-pctl.' + usernsid);
|
||||
const {moon, data} = await getPctlToken(storage, token);
|
||||
|
||||
await mkdirp(argv.directory);
|
||||
|
||||
const devices = await moon.getDevices();
|
||||
|
||||
for (const device of argv.device ?? devices.items.map(d => d.deviceId)) {
|
||||
console.warn('Downloading summaries for device %s', device);
|
||||
|
||||
await dumpMonthlySummariesForDevice(moon, argv.directory, '' + device);
|
||||
await dumpDailySummariesForDevice(moon, argv.directory, '' + device);
|
||||
}
|
||||
}
|
||||
|
||||
async function dumpMonthlySummariesForDevice(moon: MoonApi, directory: string, device: string) {
|
||||
debug('Fetching monthly summaries for device %s', device);
|
||||
const monthlySummaries = await moon.getMonthlySummaries(device);
|
||||
|
||||
for (const item of monthlySummaries.items) {
|
||||
const filename = 'pctl-monthly-' + item.deviceId + '-' + item.month + '.json';
|
||||
const file = path.join(directory, filename);
|
||||
|
||||
try {
|
||||
await fs.stat(file);
|
||||
debug('Skipping monthly summary %s for device %s, file already exists', item.month, item.deviceId);
|
||||
continue;
|
||||
} catch (err) {}
|
||||
|
||||
debug('Fetching monthly summary %s for device %s', item.month, item.deviceId);
|
||||
const summary = await moon.getMonthlySummary(item.deviceId, item.month);
|
||||
|
||||
debug('Writing %s', filename);
|
||||
await fs.writeFile(file, JSON.stringify(summary, null, 4) + '\n', 'utf-8');
|
||||
}
|
||||
}
|
||||
|
||||
async function dumpDailySummariesForDevice(moon: MoonApi, directory: string, device: string) {
|
||||
debug('Fetching daily summaries for device %s', device);
|
||||
const summaries = await moon.getDailySummaries(device);
|
||||
const timestamp = Date.now();
|
||||
|
||||
for (const summary of summaries.items) {
|
||||
const filename = 'pctl-daily-' + summary.deviceId + '-' + summary.date +
|
||||
(summary.result === DailySummaryResult.ACHIEVED ? '' : '-' + timestamp) + '.json';
|
||||
const file = path.join(directory, filename);
|
||||
|
||||
try {
|
||||
await fs.stat(file);
|
||||
debug('Skipping daily summary %s for device %s, file already exists', summary.date, summary.deviceId);
|
||||
continue;
|
||||
} catch (err) {}
|
||||
|
||||
debug('Writing %s', filename);
|
||||
await fs.writeFile(file, JSON.stringify(summary, null, 4) + '\n', 'utf-8');
|
||||
}
|
||||
}
|
||||
8
src/cli/pctl/index.ts
Normal file
8
src/cli/pctl/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export * as token from './token.js';
|
||||
export * as auth from './auth.js';
|
||||
export * as devices from './devices.js';
|
||||
export * as dailySummaries from './daily-summaries.js';
|
||||
export * as monthlySummaries from './monthly-summaries.js';
|
||||
export * as monthlySummary from './monthly-summary.js';
|
||||
export * as settings from './settings.js';
|
||||
export * as dumpSummaries from './dump-summaries.js';
|
||||
51
src/cli/pctl/monthly-summaries.ts
Normal file
51
src/cli/pctl/monthly-summaries.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import type { Arguments as ParentArguments } from '../../cli.js';
|
||||
import { ArgumentsCamelCase, Argv, getPctlToken, initStorage, YargsArguments } from '../../util.js';
|
||||
|
||||
const debug = createDebug('cli:pctl:monthly-summaries');
|
||||
|
||||
export const command = 'monthly-summaries <device>';
|
||||
export const desc = 'List monthly summaries';
|
||||
|
||||
export function builder(yargs: Argv<ParentArguments>) {
|
||||
return yargs.positional('device', {
|
||||
describe: 'Nintendo Switch device ID',
|
||||
type: 'string',
|
||||
demandOption: true,
|
||||
}).option('user', {
|
||||
describe: 'Nintendo Account ID',
|
||||
type: 'string',
|
||||
}).option('token', {
|
||||
describe: 'Nintendo Account session token',
|
||||
type: 'string',
|
||||
});
|
||||
}
|
||||
|
||||
type Arguments = YargsArguments<ReturnType<typeof builder>>;
|
||||
|
||||
export async function handler(argv: ArgumentsCamelCase<Arguments>) {
|
||||
const storage = await initStorage(argv.dataPath);
|
||||
|
||||
const usernsid = argv.user ?? await storage.getItem('SelectedUser');
|
||||
const token: string = argv.token ||
|
||||
await storage.getItem('NintendoAccountToken-pctl.' + usernsid);
|
||||
const {moon, data} = await getPctlToken(storage, token);
|
||||
|
||||
const summaries = await moon.getMonthlySummaries(argv.device);
|
||||
|
||||
const table = new Table({
|
||||
head: [
|
||||
'Month',
|
||||
],
|
||||
});
|
||||
|
||||
for (const summary of summaries.items) {
|
||||
table.push([
|
||||
summary.month,
|
||||
]);
|
||||
}
|
||||
|
||||
console.log(table.toString());
|
||||
}
|
||||
76
src/cli/pctl/monthly-summary.ts
Normal file
76
src/cli/pctl/monthly-summary.ts
Normal file
@@ -0,0 +1,76 @@
|
||||
import createDebug from 'debug';
|
||||
// @ts-expect-error
|
||||
import Table from 'cli-table/lib/index.js';
|
||||
import type { Arguments as ParentArguments } from '../../cli.js';
|
||||
import { ArgumentsCamelCase, Argv, getPctlToken, initStorage, YargsArguments } from '../../util.js';
|
||||
|
||||
const debug = createDebug('cli:pctl:monthly-summary');
|
||||
|
||||
export const command = 'monthly-summary <device> <month>';
|
||||
export const desc = 'Show monthly summary data';
|
||||
|
||||
export function builder(yargs: Argv<ParentArguments>) {
|
||||
return yargs.positional('device', {
|
||||
describe: 'Nintendo Switch device ID',
|
||||
type: 'string',
|
||||
demandOption: true,
|
||||
}).positional('month', {
|
||||
describe: 'Report month',
|
||||
type: 'string',
|
||||
demandOption: true,
|
||||
}).option('user', {
|
||||
describe: 'Nintendo Account ID',
|
||||
type: 'string',
|
||||
}).option('token', {
|
||||
describe: 'Nintendo Account session token',
|
||||
type: 'string',
|
||||
}).option('json', {
|
||||
describe: 'Output raw JSON',
|
||||
type: 'boolean',
|
||||
}).option('json-pretty-print', {
|
||||
describe: 'Output pretty-printed JSON',
|
||||
type: 'boolean',
|
||||
});
|
||||
}
|
||||
|
||||
type Arguments = YargsArguments<ReturnType<typeof builder>>;
|
||||
|
||||
export async function handler(argv: ArgumentsCamelCase<Arguments>) {
|
||||
const storage = await initStorage(argv.dataPath);
|
||||
|
||||
const usernsid = argv.user ?? await storage.getItem('SelectedUser');
|
||||
const token: string = argv.token ||
|
||||
await storage.getItem('NintendoAccountToken-pctl.' + usernsid);
|
||||
const {moon, data} = await getPctlToken(storage, token);
|
||||
|
||||
const summary = await moon.getMonthlySummary(argv.device, argv.month);
|
||||
|
||||
if (argv.jsonPrettyPrint) {
|
||||
console.log(JSON.stringify(summary, null, 4));
|
||||
return;
|
||||
}
|
||||
if (argv.json) {
|
||||
console.log(JSON.stringify(summary));
|
||||
return;
|
||||
}
|
||||
|
||||
const titles = new Table({
|
||||
head: [
|
||||
'Title',
|
||||
'First played',
|
||||
'Days',
|
||||
'Ranking',
|
||||
],
|
||||
});
|
||||
|
||||
for (const title of summary.playedApps) {
|
||||
titles.push([
|
||||
title.title,
|
||||
title.firstPlayDate,
|
||||
title.playingDays,
|
||||
title.position,
|
||||
]);
|
||||
}
|
||||
|
||||
console.log(titles.toString());
|
||||
}
|
||||
37
src/cli/pctl/settings.ts
Normal file
37
src/cli/pctl/settings.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import createDebug from 'debug';
|
||||
import type { Arguments as ParentArguments } from '../../cli.js';
|
||||
import { ArgumentsCamelCase, Argv, getPctlToken, initStorage, YargsArguments } from '../../util.js';
|
||||
|
||||
const debug = createDebug('cli:pctl:settings');
|
||||
|
||||
export const command = 'settings <device>';
|
||||
export const desc = 'Show parental control setting state';
|
||||
|
||||
export function builder(yargs: Argv<ParentArguments>) {
|
||||
return yargs.positional('device', {
|
||||
describe: 'Nintendo Switch device ID',
|
||||
type: 'string',
|
||||
demandOption: true,
|
||||
}).option('user', {
|
||||
describe: 'Nintendo Account ID',
|
||||
type: 'string',
|
||||
}).option('token', {
|
||||
describe: 'Nintendo Account session token',
|
||||
type: 'string',
|
||||
});
|
||||
}
|
||||
|
||||
type Arguments = YargsArguments<ReturnType<typeof builder>>;
|
||||
|
||||
export async function handler(argv: ArgumentsCamelCase<Arguments>) {
|
||||
const storage = await initStorage(argv.dataPath);
|
||||
|
||||
const usernsid = argv.user ?? await storage.getItem('SelectedUser');
|
||||
const token: string = argv.token ||
|
||||
await storage.getItem('NintendoAccountToken-pctl.' + usernsid);
|
||||
const {moon, data} = await getPctlToken(storage, token);
|
||||
|
||||
const d = await moon.getParentalControlSettingState(argv.device);
|
||||
|
||||
console.log(d);
|
||||
}
|
||||
56
src/cli/pctl/token.ts
Normal file
56
src/cli/pctl/token.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
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';
|
||||
|
||||
const debug = createDebug('cli:pctl:token');
|
||||
|
||||
export const command = 'token [token]';
|
||||
export const desc = 'Authenticate with a Nintendo Account session token';
|
||||
|
||||
export function builder(yargs: Argv<ParentArguments>) {
|
||||
return yargs.positional('token', {
|
||||
describe: 'Nintendo Account session token (it is recommended this is not set and you enter it interactively)',
|
||||
type: 'string',
|
||||
}).option('select', {
|
||||
describe: 'Set as default user (default: true if only user)',
|
||||
type: 'boolean',
|
||||
});
|
||||
}
|
||||
|
||||
type Arguments = YargsArguments<ReturnType<typeof builder>>;
|
||||
|
||||
export async function handler(argv: ArgumentsCamelCase<Arguments>) {
|
||||
const storage = await initStorage(argv.dataPath);
|
||||
|
||||
if (!argv.token) {
|
||||
const read = await import('read');
|
||||
// @ts-expect-error
|
||||
const prompt = util.promisify(read.default as typeof read);
|
||||
|
||||
argv.token = await prompt({
|
||||
prompt: `Token: `,
|
||||
silent: true,
|
||||
output: process.stderr,
|
||||
});
|
||||
}
|
||||
|
||||
const {moon, data} = await getPctlToken(storage, argv.token);
|
||||
|
||||
console.warn('Authenticated as Nintendo Account %s (%s)',
|
||||
data.user.nickname, data.user.id);
|
||||
|
||||
await storage.setItem('NintendoAccountToken-pctl.' + data.user.id, argv.token);
|
||||
|
||||
const users = new Set(await storage.getItem('NintendoAccountIds') ?? []);
|
||||
users.add(data.user.id);
|
||||
await storage.setItem('NintendoAccountIds', [...users]);
|
||||
|
||||
console.log('Saved token');
|
||||
|
||||
if ('select' in argv ? argv.select : users.size === 1) {
|
||||
await storage.setItem('SelectedUser', data.user.id);
|
||||
|
||||
console.log('Set as default user');
|
||||
}
|
||||
}
|
||||
31
src/cli/pctl/user.ts
Normal file
31
src/cli/pctl/user.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import createDebug from 'debug';
|
||||
import type { Arguments as ParentArguments } from '../../cli.js';
|
||||
import { ArgumentsCamelCase, Argv, getPctlToken, initStorage, YargsArguments } from '../../util.js';
|
||||
|
||||
const debug = createDebug('cli:pctl:user');
|
||||
|
||||
export const command = 'user';
|
||||
export const desc = 'Get the authenticated Nintendo Account';
|
||||
|
||||
export function builder(yargs: Argv<ParentArguments>) {
|
||||
return yargs.option('user', {
|
||||
describe: 'Nintendo Account ID',
|
||||
type: 'string',
|
||||
}).option('token', {
|
||||
describe: 'Nintendo Account session token',
|
||||
type: 'string',
|
||||
});
|
||||
}
|
||||
|
||||
type Arguments = YargsArguments<ReturnType<typeof builder>>;
|
||||
|
||||
export async function handler(argv: ArgumentsCamelCase<Arguments>) {
|
||||
const storage = await initStorage(argv.dataPath);
|
||||
|
||||
const usernsid = argv.user ?? await storage.getItem('SelectedUser');
|
||||
const token: string = argv.token ||
|
||||
await storage.getItem('NintendoAccountToken-pctl.' + usernsid);
|
||||
const {moon, data} = await getPctlToken(storage, token);
|
||||
|
||||
console.log('Nintendo Account', data.user);
|
||||
}
|
||||
Reference in New Issue
Block a user