mirror of https://github.com/boxyhq/jackson.git
Audit Logs for Jackson + SaaS App
This commit is contained in:
parent
add539869f
commit
533c7449a8
|
@ -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=
|
|
@ -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;
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue