Audit Logs for Jackson + SaaS App

This commit is contained in:
Kiran K 2023-11-23 21:22:35 +05:30
parent add539869f
commit 533c7449a8
4 changed files with 102 additions and 2 deletions

View File

@ -95,4 +95,9 @@ DSYNC_WEBHOOK_BATCH_SIZE=
# Google workspace directory sync
DSYNC_GOOGLE_CLIENT_ID=
DSYNC_GOOGLE_CLIENT_SECRET=
DSYNC_GOOGLE_REDIRECT_URI=
DSYNC_GOOGLE_REDIRECT_URI=
# Retraced
RETRACED_HOST_URL=
RETRACED_API_KEY=
RETRACED_PROJECT_ID=

82
ee/retraced/index.ts Normal file
View File

@ -0,0 +1,82 @@
import * as Retraced from '@retracedhq/retraced';
import type { Event } from '@retracedhq/retraced';
import jackson from '@lib/jackson';
import { retracedOptions } from '@lib/env';
import type { AuditEventType } from 'types/retraced';
interface ReportEventParams extends Event {
action: AuditEventType;
productId: string;
}
// Cache retraced client
let client: Retraced.Client | null = null;
// Create a Retraced client
const getClient = async () => {
if (!retracedOptions.hostUrl || !retracedOptions.apiKey || !retracedOptions.projectId) {
return;
}
if (client) {
return client;
}
client = new Retraced.Client({
endpoint: retracedOptions.hostUrl,
apiKey: retracedOptions.apiKey,
projectId: retracedOptions.projectId,
});
return client;
};
// Send an event to Retraced
const reportEvent = async ({ action, crud, group, actor, productId }: ReportEventParams) => {
try {
const retracedClient = await getClient();
if (!retracedClient) {
return;
}
const { checkLicense, productController } = await jackson();
if (!(await checkLicense())) {
throw new Error('BoxyHQ license not valid. Cannot report event to Retraced.');
}
const retracedEvent: Event = {
action,
crud,
group,
actor,
};
// Find team info for the product
if (productId && !group) {
try {
const productInfo = await productController.get(productId);
retracedEvent.group = {
id: productInfo.teamId,
name: productInfo.teamName,
};
} catch (err: any) {
console.error('Error getting product info', err);
}
}
await retracedClient.reportEvent(retracedEvent);
} catch (err: any) {
console.error('Error reporting event to Retraced', err);
}
};
const retraced = {
getClient,
reportEvent,
};
export default retraced;

View File

@ -21,6 +21,8 @@ const retraced = {
hostUrl: process.env.RETRACED_HOST_URL,
externalUrl: process.env.RETRACED_EXTERNAL_URL || process.env.RETRACED_HOST_URL,
adminToken: process.env.RETRACED_ADMIN_ROOT_TOKEN,
apiKey: process.env.RETRACED_API_KEY,
projectId: process.env.RETRACED_PROJECT_ID,
};
// Terminus

View File

@ -1,6 +1,7 @@
import { NextApiRequest, NextApiResponse } from 'next';
import jackson from '@lib/jackson';
import { extractAuthToken } from '@lib/auth';
import retraced from '@ee/retraced';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
@ -8,7 +9,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
throw { message: 'Method not allowed', statusCode: 405 };
}
const { oauthController } = await jackson();
const { oauthController, productController } = await jackson();
let token: string | null = extractAuthToken(req);
// check for query param
@ -27,6 +28,16 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
const profile = await oauthController.userInfo(token);
retraced.reportEvent({
action: 'sso.user.login',
crud: 'r',
actor: {
id: profile.email,
name: `${profile.firstName} ${profile.lastName}`,
},
productId: profile.requested.product,
});
res.json(profile);
} catch (err: any) {
console.error('userinfo error:', err);