From 2e0002bbd31965d2c8ecace0a0f6c718d627f7dd Mon Sep 17 00:00:00 2001 From: Jose Arroyo Rodriguez Date: Thu, 8 Aug 2024 18:26:13 +0200 Subject: [PATCH] (Feature) Get team audit logs through secure tunnel --- src/command-handlers/teamLogs.ts | 58 ++------------- src/commands/team/index.ts | 2 - src/endpoints/getAuditLogs.ts | 120 +++++++++++++++++-------------- 3 files changed, 72 insertions(+), 108 deletions(-) diff --git a/src/command-handlers/teamLogs.ts b/src/command-handlers/teamLogs.ts index 1d64a609..24987959 100644 --- a/src/command-handlers/teamLogs.ts +++ b/src/command-handlers/teamLogs.ts @@ -1,26 +1,17 @@ -import { StartAuditLogsQueryParams, startAuditLogsQuery, getAuditLogQueryResults } from '../endpoints/index.js'; +import { getAuditLogs } from '../endpoints/index.js'; import { getTeamDeviceCredentials, jsonToCsv, epochTimestampToIso } from '../utils/index.js'; -import { GenericLog } from '../types/logs.js'; import { logger } from '../logger.js'; -export const runTeamLogs = async (options: { - start: string; - end: string; - type: string; - category: string; - csv: boolean; - humanReadable: boolean; -}) => { +export const runTeamLogs = async (options: { start: string; end: string; csv: boolean; humanReadable: boolean }) => { const teamDeviceCredentials = getTeamDeviceCredentials(); - - const { start, end, type, category } = options; + const { start, end } = options; let logs = await getAuditLogs({ teamDeviceCredentials, - startDateRangeUnix: parseInt(start), - endDateRangeUnix: parseInt(end), - logType: type, - category, + queryParams: { + startDateRangeUnixMs: parseInt(start), + endDateRangeUnixMs: parseInt(end), + }, }); if (options.humanReadable) { @@ -39,38 +30,3 @@ export const runTeamLogs = async (options: { logs.forEach((log) => logger.content(JSON.stringify(log))); }; - -const MAX_RESULT = 1000; - -export const getAuditLogs = async (params: StartAuditLogsQueryParams): Promise => { - const { teamDeviceCredentials } = params; - - const { queryExecutionId } = await startAuditLogsQuery(params); - - let result = await getAuditLogQueryResults({ teamDeviceCredentials, queryExecutionId, maxResults: MAX_RESULT }); - logger.debug(`Query state: ${result.state}`); - - while (['QUEUED', 'RUNNING'].includes(result.state)) { - await new Promise((resolve) => setTimeout(resolve, 2000)); - result = await getAuditLogQueryResults({ teamDeviceCredentials, queryExecutionId, maxResults: MAX_RESULT }); - logger.debug(`Query state: ${result.state}`); - } - - if (result.state !== 'SUCCEEDED') { - throw new Error(`Query execution did not succeed: ${result.state}`); - } - - let logs = result.results; - while (result.nextToken) { - result = await getAuditLogQueryResults({ - teamDeviceCredentials, - queryExecutionId, - maxResults: MAX_RESULT, - nextToken: result.nextToken, - }); - logger.debug(`Query state: ${result.state}`); - logs = logs.concat(result.results); - } - - return logs.map((log) => JSON.parse(log) as GenericLog); -}; diff --git a/src/commands/team/index.ts b/src/commands/team/index.ts index a1b3ab31..7271be01 100644 --- a/src/commands/team/index.ts +++ b/src/commands/team/index.ts @@ -49,8 +49,6 @@ export const teamCommands = (params: { program: Command }) => { customParseTimestampMilliseconds, Date.now() ) - .option('--type ', 'log type') - .option('--category ', 'log category') .option('--csv', 'Output in CSV format') .option('--human-readable', 'Output dates in human readable format') .action(runTeamLogs); diff --git a/src/endpoints/getAuditLogs.ts b/src/endpoints/getAuditLogs.ts index 2a38d493..8c7ba61a 100644 --- a/src/endpoints/getAuditLogs.ts +++ b/src/endpoints/getAuditLogs.ts @@ -1,44 +1,17 @@ -import { requestTeamApi } from '../requestApi.js'; +import { apiConnect } from '../modules/tunnel-api-connect/apiconnect.js'; +import { logger } from '../logger.js'; import { TeamDeviceCredentials } from '../types.js'; +import { GenericLog } from '../types/logs.js'; export interface StartAuditLogsQueryParams { - teamDeviceCredentials: TeamDeviceCredentials; - /** * The start of the date range to query audit logs by. The format is unix timestamp in seconds. Only the date is used, not the time. */ - startDateRangeUnix: number; + startDateRangeUnixMs: number; /** * The end of the date range of to query audit logs by. The format is unix timestamp in seconds. Only the date is used, not the time. */ - endDateRangeUnix: number; - /** - * The user ID of the author of the audit log. - */ - authorUserId?: number; - /** - * The ID of the user targeted by the audit log action. - */ - targetUserId?: number; - /** - * The ID of the sharing group targeted by the audit log action. - */ - sharingGroupId?: number; - /** - * The types of audit logs to filter by. - */ - logType?: string; - /** - * The categories audit logs to filter by. - */ - category?: string; - /** - * Additional properties to filter by. Refer to the specific audit log schema for property details. - */ - properties?: { - propName: string; - value: string; - }[]; + endDateRangeUnixMs: number; } export interface StartAuditLogsQueryOutput { @@ -48,22 +21,13 @@ export interface StartAuditLogsQueryOutput { queryExecutionId: string; } -export const startAuditLogsQuery = (params: StartAuditLogsQueryParams) => { - const { teamDeviceCredentials, ...payload } = params; - return requestTeamApi({ - path: 'auditlogs-teamdevice/StartAuditLogsQuery', - teamUuid: teamDeviceCredentials.uuid, - teamDeviceKeys: { - accessKey: teamDeviceCredentials.accessKey, - secretKey: teamDeviceCredentials.secretKey, - }, - payload, - }); -}; +export interface StartAuditLogsQueryRequest { + path: 'logs-teamdevice/StartAuditLogsQuery'; + input: StartAuditLogsQueryParams; + output: StartAuditLogsQueryOutput; +} export interface GetAuditLogQueryResultsParams { - teamDeviceCredentials: TeamDeviceCredentials; - /** * The ID associated with the query executed by the RequestAuditLogs endpoint. */ @@ -93,15 +57,61 @@ export interface GetAuditLogQueryResultsOutput { nextToken?: string; } -export const getAuditLogQueryResults = (params: GetAuditLogQueryResultsParams) => { - const { teamDeviceCredentials, ...payload } = params; - return requestTeamApi({ - path: 'auditlogs-teamdevice/GetAuditLogQueryResults', - teamUuid: teamDeviceCredentials.uuid, - teamDeviceKeys: { - accessKey: teamDeviceCredentials.accessKey, - secretKey: teamDeviceCredentials.secretKey, +export interface GetAuditLogQueryResultsRequest { + path: 'logs-teamdevice/GetAuditLogQueryResults'; + input: GetAuditLogQueryResultsParams; + output: GetAuditLogQueryResultsOutput; +} + +const MAX_RESULT = 1000; + +export const getAuditLogs = async (params: { + queryParams: StartAuditLogsQueryParams; + teamDeviceCredentials: TeamDeviceCredentials; +}): Promise => { + const { teamDeviceCredentials, queryParams } = params; + + const api = await apiConnect({ + isProduction: true, + enclavePcrList: [ + [3, 'dfb6428f132530b8c021bea8cbdba2c87c96308ba7e81c7aff0655ec71228122a9297fd31fe5db7927a7322e396e4c16'], + [8, '4dbb92401207e019e132d86677857081d8e4d21f946f3561b264b7389c6982d3a86bcf9560cef4a2327eac5c5c6ab820'], + ], + }); + + const { queryExecutionId } = await api.sendSecureContent({ + ...api, + path: 'logs-teamdevice/StartAuditLogsQuery', + payload: queryParams, + authentication: { + type: 'teamDevice', + teamDeviceKeys: teamDeviceCredentials, + teamUuid: teamDeviceCredentials.uuid, }, - payload, }); + + let result: GetAuditLogQueryResultsOutput | undefined; + let logs: string[] = []; + + do { + await new Promise((resolve) => setTimeout(resolve, 2000)); + result = await api.sendSecureContent({ + ...api, + path: 'logs-teamdevice/GetAuditLogQueryResults', + payload: { queryExecutionId, maxResults: MAX_RESULT, nextToken: result?.nextToken }, + authentication: { + type: 'teamDevice', + teamDeviceKeys: teamDeviceCredentials, + teamUuid: teamDeviceCredentials.uuid, + }, + }); + logger.debug(`Query state: ${result.state}`); + logs = logs.concat(result.results); + } while (['QUEUED', 'RUNNING'].includes(result.state) || result.nextToken); + + if (result.state !== 'SUCCEEDED') { + throw new Error(`Query execution did not succeed: ${result.state}`); + } + + return logs.map((log) => JSON.parse(log) as GenericLog); };