feat: granular file access audit logging (viewed/opened/downloaded)
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
Some checks failed
Build and Push Docker Image / build (push) Has been cancelled
Replace single FILE_DOWNLOADED action with three granular actions: - FILE_VIEWED: inline preview loaded in the UI - FILE_OPENED: file opened in a new browser tab - FILE_DOWNLOADED: explicit download button clicked Add 'purpose' field to getDownloadUrl input (preview/open/download). All client callers updated to pass the appropriate purpose. Audit page updated with new filter options and color mappings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -17,6 +17,8 @@ export const fileRouter = router({
|
||||
objectKey: z.string(),
|
||||
forDownload: z.boolean().optional(),
|
||||
fileName: z.string().optional(),
|
||||
/** Why the URL is being requested — drives audit log granularity. */
|
||||
purpose: z.enum(['preview', 'open', 'download']).optional(),
|
||||
})
|
||||
)
|
||||
.query(async ({ ctx, input }) => {
|
||||
@@ -124,14 +126,25 @@ export const fileRouter = router({
|
||||
})
|
||||
}
|
||||
|
||||
// Only log actual downloads, not preview/view URL requests
|
||||
if (input.forDownload) {
|
||||
// Log file access with granular action based on purpose
|
||||
const purpose = input.purpose ?? (input.forDownload ? 'download' : undefined)
|
||||
if (purpose) {
|
||||
const actionMap = {
|
||||
preview: 'FILE_VIEWED',
|
||||
open: 'FILE_OPENED',
|
||||
download: 'FILE_DOWNLOADED',
|
||||
} as const
|
||||
await logAudit({
|
||||
prisma: ctx.prisma,
|
||||
userId: ctx.user.id,
|
||||
action: 'FILE_DOWNLOADED',
|
||||
action: actionMap[purpose],
|
||||
entityType: 'ProjectFile',
|
||||
detailsJson: { bucket: input.bucket, objectKey: input.objectKey, fileName: input.fileName },
|
||||
detailsJson: {
|
||||
bucket: input.bucket,
|
||||
objectKey: input.objectKey,
|
||||
fileName: input.fileName,
|
||||
purpose,
|
||||
},
|
||||
ipAddress: ctx.ip,
|
||||
userAgent: ctx.userAgent,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user