From efbe814463ad633f8e571f225b67befeacc3081f Mon Sep 17 00:00:00 2001 From: Corentin Mors Date: Tue, 1 Aug 2023 17:08:11 +0200 Subject: [PATCH] Add command to list team credentials Fix #129 --- src/command-handlers/devices.ts | 24 ++++++++--------- src/command-handlers/index.ts | 1 + src/command-handlers/teamDevices.ts | 42 +++++++++++++++++++++++++++++ src/endpoints/index.ts | 1 + src/endpoints/listTeamDevices.ts | 38 ++++++++++++++++++++++++++ src/index.ts | 18 +++++++++---- src/utils/strings.ts | 5 ++++ 7 files changed, 112 insertions(+), 17 deletions(-) create mode 100644 src/command-handlers/teamDevices.ts create mode 100644 src/endpoints/listTeamDevices.ts diff --git a/src/command-handlers/devices.ts b/src/command-handlers/devices.ts index 164abc5e..47e6ba02 100644 --- a/src/command-handlers/devices.ts +++ b/src/command-handlers/devices.ts @@ -1,7 +1,7 @@ import { connectAndPrepare } from '../database'; import { deactivateDevices, listDevices, ListDevicesOutput } from '../endpoints'; import { reset } from '../middleware'; -import { askConfirmReset } from '../utils'; +import { askConfirmReset, unixTimestampToHumanReadable } from '../utils'; type OutputDevice = ListDevicesOutput['devices'][number] & { isCurrentDevice: boolean; @@ -25,17 +25,17 @@ export async function listAllDevices(options: { json: boolean }) { // for human consumption result.sort((a, b) => a.lastActivityDateUnix - b.lastActivityDateUnix); - // print results - for (const device of result) { - console.log( - [ - device.deviceId, - device.deviceName, - device.devicePlatform, - device.isCurrentDevice ? 'current' : 'other', - ].join('\t') - ); - } + const printableResult = result.map((device) => { + return { + id: device.deviceId, + name: device.deviceName, + platform: device.devicePlatform, + lastActivity: unixTimestampToHumanReadable(device.lastActivityDateUnix), + current: device.isCurrentDevice, + }; + }); + + console.table(printableResult); } } diff --git a/src/command-handlers/index.ts b/src/command-handlers/index.ts index b1f8a7ab..dbaf1383 100644 --- a/src/command-handlers/index.ts +++ b/src/command-handlers/index.ts @@ -1 +1,2 @@ export * from './devices'; +export * from './teamDevices'; diff --git a/src/command-handlers/teamDevices.ts b/src/command-handlers/teamDevices.ts new file mode 100644 index 00000000..ed75db60 --- /dev/null +++ b/src/command-handlers/teamDevices.ts @@ -0,0 +1,42 @@ +import { connectAndPrepare } from '../database'; +import { listTeamDevices } from '../endpoints'; +import { unixTimestampToHumanReadable } from '../utils'; + +export async function listAllTeamDevices(options: { json: boolean }) { + const { db, secrets } = await connectAndPrepare({ autoSync: false }); + + const listTeamDevicesResponse = await listTeamDevices({ secrets }); + + db.close(); + + if (options.json) { + const result = listTeamDevicesResponse.teamDevices.map((device) => { + return { + accessKey: device.accessKey, + deviceName: device.deviceName, + platform: device.platform, + creationDateUnix: device.creationDateUnix, + updateDateUnix: device.updateDateUnix, + lastActivityDateUnix: device.lastActivityDateUnix, + }; + }); + + console.log(JSON.stringify(result)); + } else { + const result = listTeamDevicesResponse.teamDevices + .sort((a, b) => a.creationDateUnix - b.creationDateUnix) + .map((device) => { + return { + accessKey: device.accessKey, + name: device.deviceName, + platform: device.platform, + creationDate: unixTimestampToHumanReadable(device.creationDateUnix), + updateDate: unixTimestampToHumanReadable(device.updateDateUnix), + lastActivityDate: unixTimestampToHumanReadable(device.lastActivityDateUnix), + }; + }); + + // print results + console.table(result); + } +} diff --git a/src/endpoints/index.ts b/src/endpoints/index.ts index cb023b3a..e5aff542 100644 --- a/src/endpoints/index.ts +++ b/src/endpoints/index.ts @@ -10,4 +10,5 @@ export * from './requestDeviceRegistration'; export * from './getAuditLogs'; export * from './getTeamReport'; export * from './listDevices'; +export * from './listTeamDevices'; export * from './deactivateDevices'; diff --git a/src/endpoints/listTeamDevices.ts b/src/endpoints/listTeamDevices.ts new file mode 100644 index 00000000..15ab71f4 --- /dev/null +++ b/src/endpoints/listTeamDevices.ts @@ -0,0 +1,38 @@ +import { requestUserApi } from '../requestApi'; +import { Secrets } from '../types'; + +interface ListTeamDevicesParams { + secrets: Secrets; +} + +export interface ListTeamDevicesOutput { + teamDevices: { + creationDateUnix: number; + updateDateUnix: number; + teamId: number; + deviceName: string | null; + platform: string; + version: string | null; + activated: boolean; + accessKey: string; + configVersion: number | null; + hasDraftConfig: boolean; + lastStartDateUnix: number | null; + hosting: string | null; + media: string | null; + hasLatestVersion: boolean; + hasLatestConfig: boolean; + lastActivityDateUnix: number | null; + }[]; +} + +export const listTeamDevices = (params: ListTeamDevicesParams) => + requestUserApi({ + path: 'teams/ListTeamDevices', + login: params.secrets.login, + deviceKeys: { + accessKey: params.secrets.accessKey, + secretKey: params.secrets.secretKey, + }, + payload: {}, + }); diff --git a/src/index.ts b/src/index.ts index 620aa6da..cde4cef9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -22,7 +22,7 @@ import { } from './middleware'; import { cliVersionToString, CLI_VERSION } from './cliVersion'; import { registerTeamDevice } from './endpoints/registerTeamDevice'; -import { listAllDevices, removeAllDevices } from './command-handlers'; +import { listAllDevices, removeAllDevices, listAllTeamDevices } from './command-handlers'; import { deactivateTeamDevice } from './endpoints/deactivateTeamDevice'; const teamDeviceCredentials = getTeamDeviceCredentialsFromEnv(); @@ -153,8 +153,10 @@ Use generate-credentials to generate some team credentials (requires to be a tea ); } -teamGroup - .command('generate-credentials') +const teamCredentialsGroup = teamGroup.command('credentials').alias('c').description('Team credentials operations'); + +teamCredentialsGroup + .command('generate') .option('--json', 'Output in JSON format') .description('Generate new team credentials') .action(async (options: { json: boolean }) => { @@ -177,8 +179,14 @@ teamGroup } }); -teamGroup - .command('revoke-credentials') +teamCredentialsGroup + .command('list') + .option('--json', 'Output in JSON format') + .description('List all team credentials') + .action(listAllTeamDevices); + +teamCredentialsGroup + .command('revoke') .description('Revoke credentials by access key') .argument('', 'Access key of the credentials to revoke') .action(async (accessKey: string) => { diff --git a/src/utils/strings.ts b/src/utils/strings.ts index a21dd2d2..3923cc87 100644 --- a/src/utils/strings.ts +++ b/src/utils/strings.ts @@ -34,3 +34,8 @@ export const removeUnderscoresAndCapitalize = (string: string): string => { .map((word) => word[0].toUpperCase() + word.slice(1)) .join(' '); }; + +/** Unix timestamp to human readable string */ +export const unixTimestampToHumanReadable = (timestamp: number | null): string => { + return timestamp ? new Date(timestamp * 1000).toLocaleString() : 'N/A'; +};