Add logActionAudit and query endpoint

This commit is contained in:
Owen
2025-10-19 21:53:00 -07:00
parent dce84b9b09
commit 1f50bc3752
12 changed files with 488 additions and 108 deletions

View File

@@ -230,6 +230,28 @@ export const actionAuditLog = pgTable("actionAuditLog", {
index("idx_actionAuditLog_org_timestamp").on(table.orgId, table.timestamp)
]));
export const identityAuditLog = pgTable("identityAuditLog", {
id: serial("id").primaryKey(),
timestamp: bigint("timestamp", { mode: "number" }).notNull(), // this is EPOCH time in seconds
orgId: varchar("orgId")
.notNull()
.references(() => orgs.orgId, { onDelete: "cascade" }),
actorType: varchar("actorType", { length: 50 }).notNull(),
actor: varchar("actor", { length: 255 }).notNull(),
actorId: varchar("actorId", { length: 255 }).notNull(),
resourceId: integer("resourceId"),
ip: varchar("ip", { length: 45 }).notNull(),
type: varchar("type", { length: 100 }).notNull(),
action: varchar("action", { length: 100 }).notNull(),
location: text("location"),
path: text("path"),
userAgent: text("userAgent"),
metadata: text("details")
}, (table) => ([
index("idx_identityAuditLog_timestamp").on(table.timestamp),
index("idx_identityAuditLog_org_timestamp").on(table.orgId, table.timestamp)
]));
export type Limit = InferSelectModel<typeof limits>;
export type Account = InferSelectModel<typeof account>;
export type Certificate = InferSelectModel<typeof certificates>;
@@ -248,3 +270,4 @@ export type RemoteExitNodeSession = InferSelectModel<
export type ExitNodeOrg = InferSelectModel<typeof exitNodeOrgs>;
export type LoginPage = InferSelectModel<typeof loginPage>;
export type ActionAuditLog = InferSelectModel<typeof actionAuditLog>;
export type IdentityAuditLog = InferSelectModel<typeof identityAuditLog>;

View File

@@ -6,7 +6,8 @@ import {
integer,
bigint,
real,
text
text,
index
} from "drizzle-orm/pg-core";
import { InferSelectModel } from "drizzle-orm";
import { randomUUID } from "crypto";
@@ -671,6 +672,28 @@ export const setupTokens = pgTable("setupTokens", {
dateUsed: varchar("dateUsed")
});
export const requestAuditLog = pgTable("requestAuditLog", {
id: serial("id").primaryKey(),
timestamp: integer("timestamp").notNull(), // this is EPOCH time in seconds
orgId: varchar("orgId")
.notNull()
.references(() => orgs.orgId, { onDelete: "cascade" }),
actorType: varchar("actorType").notNull(),
actor: varchar("actor").notNull(),
actorId: varchar("actorId").notNull(),
resourceId: integer("resourceId"),
ip: varchar("ip").notNull(),
type: varchar("type").notNull(),
action: varchar("action").notNull(),
event: varchar("event").notNull(),
location: varchar("location"),
userAgent: varchar("userAgent"),
metadata: text("details")
}, (table) => ([
index("idx_actionAuditLog_timestamp").on(table.timestamp),
index("idx_actionAuditLog_org_timestamp").on(table.orgId, table.timestamp)
]));
export type Org = InferSelectModel<typeof orgs>;
export type User = InferSelectModel<typeof users>;
export type Site = InferSelectModel<typeof sites>;
@@ -722,3 +745,7 @@ export type SetupToken = InferSelectModel<typeof setupTokens>;
export type HostMeta = InferSelectModel<typeof hostMeta>;
export type TargetHealthCheck = InferSelectModel<typeof targetHealthCheck>;
export type IdpOidcConfig = InferSelectModel<typeof idpOidcConfig>;
export type LicenseKey = InferSelectModel<typeof licenseKey>;
export type SecurityKey = InferSelectModel<typeof securityKeys>;
export type WebauthnChallenge = InferSelectModel<typeof webauthnChallenge>;
export type RequestAuditLog = InferSelectModel<typeof requestAuditLog>;

View File

@@ -225,6 +225,28 @@ export const actionAuditLog = sqliteTable("actionAuditLog", {
index("idx_actionAuditLog_org_timestamp").on(table.orgId, table.timestamp)
]));
export const identityAuditLog = sqliteTable("identityAuditLog", {
id: integer("id").primaryKey({ autoIncrement: true }),
timestamp: integer("timestamp").notNull(), // this is EPOCH time in seconds
orgId: text("orgId")
.notNull()
.references(() => orgs.orgId, { onDelete: "cascade" }),
actorType: text("actorType").notNull(),
actor: text("actor").notNull(),
actorId: text("actorId").notNull(),
resourceId: integer("resourceId"),
ip: text("ip").notNull(),
type: text("type").notNull(),
action: text("action").notNull(),
location: text("location"),
path: text("path"),
userAgent: text("userAgent"),
metadata: text("details")
}, (table) => ([
index("idx_actionAuditLog_timestamp").on(table.timestamp),
index("idx_actionAuditLog_org_timestamp").on(table.orgId, table.timestamp)
]));
export type Limit = InferSelectModel<typeof limits>;
export type Account = InferSelectModel<typeof account>;
export type Certificate = InferSelectModel<typeof certificates>;

View File

@@ -1,6 +1,6 @@
import { randomUUID } from "crypto";
import { InferSelectModel } from "drizzle-orm";
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
import { sqliteTable, text, integer, index } from "drizzle-orm/sqlite-core";
export const domains = sqliteTable("domains", {
domainId: text("domainId").primaryKey(),
@@ -710,6 +710,28 @@ export const idpOrg = sqliteTable("idpOrg", {
orgMapping: text("orgMapping")
});
export const requestAuditLog = sqliteTable("requestAuditLog", {
id: integer("id").primaryKey({ autoIncrement: true }),
timestamp: integer("timestamp").notNull(), // this is EPOCH time in seconds
orgId: text("orgId")
.notNull()
.references(() => orgs.orgId, { onDelete: "cascade" }),
actorType: text("actorType").notNull(),
actor: text("actor").notNull(),
actorId: text("actorId").notNull(),
resourceId: integer("resourceId"),
ip: text("ip").notNull(),
type: text("type").notNull(),
action: text("action").notNull(),
event: text("event").notNull(),
location: text("location"),
userAgent: text("userAgent"),
metadata: text("details")
}, (table) => ([
index("idx_actionAuditLog_timestamp").on(table.timestamp),
index("idx_actionAuditLog_org_timestamp").on(table.orgId, table.timestamp)
]));
export type Org = InferSelectModel<typeof orgs>;
export type User = InferSelectModel<typeof users>;
export type Site = InferSelectModel<typeof sites>;
@@ -761,3 +783,7 @@ export type SetupToken = InferSelectModel<typeof setupTokens>;
export type HostMeta = InferSelectModel<typeof hostMeta>;
export type TargetHealthCheck = InferSelectModel<typeof targetHealthCheck>;
export type IdpOidcConfig = InferSelectModel<typeof idpOidcConfig>;
export type LicenseKey = InferSelectModel<typeof licenseKey>;
export type SecurityKey = InferSelectModel<typeof securityKeys>;
export type WebauthnChallenge = InferSelectModel<typeof webauthnChallenge>;
export type RequestAuditLog = InferSelectModel<typeof requestAuditLog>;

View File

@@ -0,0 +1,12 @@
import { ActionsEnum } from "@server/auth/actions";
import { Request, Response, NextFunction } from "express";
export function logActionAudit(action: ActionsEnum) {
return async function (
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
next();
};
}

View File

@@ -0,0 +1,147 @@
import { actionAuditLog, db } from "@server/db";
import { registry } from "@server/openApi";
import { NextFunction } from "express";
import { Request, Response } from "express";
import { eq, gt, lt, and, count } from "drizzle-orm";
import { OpenAPITags } from "@server/openApi";
import { z } from "zod";
import createHttpError from "http-errors";
import HttpCode from "@server/types/HttpCode";
import { fromError } from "zod-validation-error";
import { QueryActionAuditLogResponse } from "@server/routers/auditLogs/types";
import response from "@server/lib/response";
import logger from "@server/logger";
export const queryAccessAuditLogsQuery = z.object({
// iso string just validate its a parseable date
timeStart: z
.string()
.refine((val) => !isNaN(Date.parse(val)), {
message: "timeStart must be a valid ISO date string"
})
.transform((val) => Math.floor(new Date(val).getTime() / 1000)),
timeEnd: z
.string()
.refine((val) => !isNaN(Date.parse(val)), {
message: "timeEnd must be a valid ISO date string"
})
.transform((val) => Math.floor(new Date(val).getTime() / 1000))
.optional()
.default(new Date().toISOString()),
limit: z
.string()
.optional()
.default("1000")
.transform(Number)
.pipe(z.number().int().positive()),
offset: z
.string()
.optional()
.default("0")
.transform(Number)
.pipe(z.number().int().nonnegative())
});
export const queryAccessAuditLogsParams = z.object({
orgId: z.string()
});
function querySites(timeStart: number, timeEnd: number, orgId: string) {
return db
.select({
orgId: actionAuditLog.orgId,
action: actionAuditLog.action,
actorType: actionAuditLog.actorType,
timestamp: actionAuditLog.timestamp,
actor: actionAuditLog.actor
})
.from(actionAuditLog)
.where(
and(
gt(actionAuditLog.timestamp, timeStart),
lt(actionAuditLog.timestamp, timeEnd),
eq(actionAuditLog.orgId, orgId)
)
)
.orderBy(actionAuditLog.timestamp);
}
registry.registerPath({
method: "get",
path: "/org/{orgId}/logs/action",
description: "Query the action audit log for an organization",
tags: [OpenAPITags.Org],
request: {
query: queryAccessAuditLogsQuery,
params: queryAccessAuditLogsParams
},
responses: {}
});
export async function queryAccessAuditLogs(
req: Request,
res: Response,
next: NextFunction
): Promise<any> {
try {
const parsedQuery = queryAccessAuditLogsQuery.safeParse(req.query);
if (!parsedQuery.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedQuery.error)
)
);
}
const { timeStart, timeEnd, limit, offset } = parsedQuery.data;
const parsedParams = queryAccessAuditLogsParams.safeParse(req.params);
if (!parsedParams.success) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
fromError(parsedParams.error)
)
);
}
const { orgId } = parsedParams.data;
const baseQuery = querySites(timeStart, timeEnd, orgId);
const log = await baseQuery.limit(limit).offset(offset);
const countQuery = db
.select({ count: count() })
.from(actionAuditLog)
.where(
and(
gt(actionAuditLog.timestamp, timeStart),
lt(actionAuditLog.timestamp, timeEnd),
eq(actionAuditLog.orgId, orgId)
)
);
const totalCountResult = await countQuery;
const totalCount = totalCountResult[0].count;
return response<QueryActionAuditLogResponse>(res, {
data: {
log: log,
pagination: {
total: totalCount,
limit,
offset
}
},
success: true,
error: false,
message: "Action audit logs retrieved successfully",
status: HttpCode.OK
});
} catch (error) {
logger.error(error);
return next(
createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred")
);
}
}

View File

@@ -31,6 +31,7 @@ import {
} from "@server/middlewares";
import { ActionsEnum } from "@server/auth/actions";
import {
logActionAudit,
verifyCertificateAccess,
verifyIdpAccess,
verifyLoginPageAccess,
@@ -72,7 +73,8 @@ authenticated.put(
verifyValidLicense,
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.createIdp),
orgIdp.createOrgOidcIdp
orgIdp.createOrgOidcIdp,
logActionAudit(ActionsEnum.createIdp)
);
authenticated.post(
@@ -81,7 +83,8 @@ authenticated.post(
verifyOrgAccess,
verifyIdpAccess,
verifyUserHasAction(ActionsEnum.updateIdp),
orgIdp.updateOrgOidcIdp
orgIdp.updateOrgOidcIdp,
logActionAudit(ActionsEnum.updateIdp)
);
authenticated.delete(
@@ -90,7 +93,8 @@ authenticated.delete(
verifyOrgAccess,
verifyIdpAccess,
verifyUserHasAction(ActionsEnum.deleteIdp),
orgIdp.deleteOrgIdp
orgIdp.deleteOrgIdp,
logActionAudit(ActionsEnum.deleteIdp)
);
authenticated.get(
@@ -127,7 +131,8 @@ authenticated.post(
verifyOrgAccess,
verifyCertificateAccess,
verifyUserHasAction(ActionsEnum.restartCertificate),
certificates.restartCertificate
certificates.restartCertificate,
logActionAudit(ActionsEnum.restartCertificate)
);
if (build === "saas") {
@@ -152,14 +157,16 @@ if (build === "saas") {
"/org/:orgId/billing/create-checkout-session",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.billing),
billing.createCheckoutSession
billing.createCheckoutSession,
logActionAudit(ActionsEnum.billing)
);
authenticated.post(
"/org/:orgId/billing/create-portal-session",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.billing),
billing.createPortalSession
billing.createPortalSession,
logActionAudit(ActionsEnum.billing)
);
authenticated.get(
@@ -206,7 +213,8 @@ authenticated.put(
verifyValidLicense,
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.createRemoteExitNode),
remoteExitNode.createRemoteExitNode
remoteExitNode.createRemoteExitNode,
logActionAudit(ActionsEnum.createRemoteExitNode)
);
authenticated.get(
@@ -240,7 +248,8 @@ authenticated.delete(
verifyOrgAccess,
verifyRemoteExitNodeAccess,
verifyUserHasAction(ActionsEnum.deleteRemoteExitNode),
remoteExitNode.deleteRemoteExitNode
remoteExitNode.deleteRemoteExitNode,
logActionAudit(ActionsEnum.deleteRemoteExitNode)
);
authenticated.put(
@@ -248,7 +257,8 @@ authenticated.put(
verifyValidLicense,
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.createLoginPage),
loginPage.createLoginPage
loginPage.createLoginPage,
logActionAudit(ActionsEnum.createLoginPage)
);
authenticated.post(
@@ -257,7 +267,8 @@ authenticated.post(
verifyOrgAccess,
verifyLoginPageAccess,
verifyUserHasAction(ActionsEnum.updateLoginPage),
loginPage.updateLoginPage
loginPage.updateLoginPage,
logActionAudit(ActionsEnum.updateLoginPage)
);
authenticated.delete(
@@ -266,7 +277,8 @@ authenticated.delete(
verifyOrgAccess,
verifyLoginPageAccess,
verifyUserHasAction(ActionsEnum.deleteLoginPage),
loginPage.deleteLoginPage
loginPage.deleteLoginPage,
logActionAudit(ActionsEnum.deleteLoginPage)
);
authenticated.get(

View File

@@ -23,6 +23,7 @@ import {
import { ActionsEnum } from "@server/auth/actions";
import { unauthenticated as ua, authenticated as a } from "@server/routers/integration";
import { logActionAudit } from "#private/middlewares";
export const unauthenticated = ua;
export const authenticated = a;
@@ -31,12 +32,14 @@ authenticated.post(
`/org/:orgId/send-usage-notification`,
verifyApiKeyIsRoot, // We are the only ones who can use root key so its fine
verifyApiKeyHasAction(ActionsEnum.sendUsageNotification),
org.sendUsageNotification
org.sendUsageNotification,
logActionAudit(ActionsEnum.sendUsageNotification)
);
authenticated.delete(
"/idp/:idpId",
verifyApiKeyIsRoot,
verifyApiKeyHasAction(ActionsEnum.deleteIdp),
orgIdp.deleteOrgIdp
orgIdp.deleteOrgIdp,
logActionAudit(ActionsEnum.deleteIdp)
);

View File

@@ -0,0 +1,14 @@
export type QueryActionAuditLogResponse = {
log: {
orgId: string;
action: string;
actorType: string;
timestamp: number;
actor: string;
}[];
pagination: {
total: number;
limit: number;
offset: number;
};
};

View File

@@ -44,6 +44,7 @@ import rateLimit, { ipKeyGenerator } from "express-rate-limit";
import createHttpError from "http-errors";
import { build } from "@server/build";
import { createStore } from "#dynamic/lib/rateLimitStore";
import { logActionAudit } from "#dynamic/middlewares";
// Root routes
export const unauthenticated = Router();
@@ -75,7 +76,8 @@ authenticated.post(
"/org/:orgId",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.updateOrg),
org.updateOrg
org.updateOrg,
logActionAudit(ActionsEnum.updateOrg)
);
if (build !== "saas") {
@@ -84,7 +86,8 @@ if (build !== "saas") {
verifyOrgAccess,
verifyUserIsOrgOwner,
verifyUserHasAction(ActionsEnum.deleteOrg),
org.deleteOrg
org.deleteOrg,
logActionAudit(ActionsEnum.deleteOrg)
);
}
@@ -92,7 +95,8 @@ authenticated.put(
"/org/:orgId/site",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.createSite),
site.createSite
site.createSite,
logActionAudit(ActionsEnum.createSite)
);
authenticated.get(
"/org/:orgId/sites",
@@ -149,7 +153,8 @@ authenticated.put(
verifyClientsEnabled,
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.createClient),
client.createClient
client.createClient,
logActionAudit(ActionsEnum.createClient)
);
authenticated.delete(
@@ -157,7 +162,8 @@ authenticated.delete(
verifyClientsEnabled,
verifyClientAccess,
verifyUserHasAction(ActionsEnum.deleteClient),
client.deleteClient
client.deleteClient,
logActionAudit(ActionsEnum.deleteClient)
);
authenticated.post(
@@ -165,7 +171,8 @@ authenticated.post(
verifyClientsEnabled,
verifyClientAccess, // this will check if the user has access to the client
verifyUserHasAction(ActionsEnum.updateClient), // this will check if the user has permission to update the client
client.updateClient
client.updateClient,
logActionAudit(ActionsEnum.updateClient)
);
// authenticated.get(
@@ -178,15 +185,18 @@ authenticated.post(
"/site/:siteId",
verifySiteAccess,
verifyUserHasAction(ActionsEnum.updateSite),
site.updateSite
site.updateSite,
logActionAudit(ActionsEnum.updateSite)
);
authenticated.delete(
"/site/:siteId",
verifySiteAccess,
verifyUserHasAction(ActionsEnum.deleteSite),
site.deleteSite
site.deleteSite,
logActionAudit(ActionsEnum.deleteSite)
);
// TODO: BREAK OUT THESE ACTIONS SO THEY ARE NOT ALL "getSite"
authenticated.get(
"/site/:siteId/docker/status",
verifySiteAccess,
@@ -203,13 +213,15 @@ authenticated.post(
"/site/:siteId/docker/check",
verifySiteAccess,
verifyUserHasAction(ActionsEnum.getSite),
site.checkDockerSocket
site.checkDockerSocket,
// logActionAudit(ActionsEnum.getSite)
);
authenticated.post(
"/site/:siteId/docker/trigger",
verifySiteAccess,
verifyUserHasAction(ActionsEnum.getSite),
site.triggerFetchContainers
site.triggerFetchContainers,
// logActionAudit(ActionsEnum.getSite)
);
authenticated.get(
"/site/:siteId/docker/containers",
@@ -224,7 +236,8 @@ authenticated.put(
verifyOrgAccess,
verifySiteAccess,
verifyUserHasAction(ActionsEnum.createSiteResource),
siteResource.createSiteResource
siteResource.createSiteResource,
logActionAudit(ActionsEnum.createSiteResource)
);
authenticated.get(
@@ -257,7 +270,8 @@ authenticated.post(
verifySiteAccess,
verifySiteResourceAccess,
verifyUserHasAction(ActionsEnum.updateSiteResource),
siteResource.updateSiteResource
siteResource.updateSiteResource,
logActionAudit(ActionsEnum.updateSiteResource)
);
authenticated.delete(
@@ -266,14 +280,16 @@ authenticated.delete(
verifySiteAccess,
verifySiteResourceAccess,
verifyUserHasAction(ActionsEnum.deleteSiteResource),
siteResource.deleteSiteResource
siteResource.deleteSiteResource,
logActionAudit(ActionsEnum.deleteSiteResource)
);
authenticated.put(
"/org/:orgId/resource",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.createResource),
resource.createResource
resource.createResource,
logActionAudit(ActionsEnum.createResource)
);
authenticated.get(
@@ -313,15 +329,18 @@ authenticated.delete(
"/org/:orgId/invitations/:inviteId",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.removeInvitation),
user.removeInvitation
user.removeInvitation,
logActionAudit(ActionsEnum.removeInvitation)
);
authenticated.post(
"/org/:orgId/create-invite",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.inviteUser),
user.inviteUser
user.inviteUser,
logActionAudit(ActionsEnum.inviteUser)
); // maybe make this /invite/create instead
unauthenticated.post("/invite/accept", user.acceptInvite); // this is supposed to be unauthenticated
authenticated.get(
@@ -354,20 +373,23 @@ authenticated.post(
"/resource/:resourceId",
verifyResourceAccess,
verifyUserHasAction(ActionsEnum.updateResource),
resource.updateResource
resource.updateResource,
logActionAudit(ActionsEnum.updateResource)
);
authenticated.delete(
"/resource/:resourceId",
verifyResourceAccess,
verifyUserHasAction(ActionsEnum.deleteResource),
resource.deleteResource
resource.deleteResource,
logActionAudit(ActionsEnum.deleteResource)
);
authenticated.put(
"/resource/:resourceId/target",
verifyResourceAccess,
verifyUserHasAction(ActionsEnum.createTarget),
target.createTarget
target.createTarget,
logActionAudit(ActionsEnum.createTarget)
);
authenticated.get(
"/resource/:resourceId/targets",
@@ -380,7 +402,8 @@ authenticated.put(
"/resource/:resourceId/rule",
verifyResourceAccess,
verifyUserHasAction(ActionsEnum.createResourceRule),
resource.createResourceRule
resource.createResourceRule,
logActionAudit(ActionsEnum.createResourceRule)
);
authenticated.get(
"/resource/:resourceId/rules",
@@ -392,13 +415,15 @@ authenticated.post(
"/resource/:resourceId/rule/:ruleId",
verifyResourceAccess,
verifyUserHasAction(ActionsEnum.updateResourceRule),
resource.updateResourceRule
resource.updateResourceRule,
logActionAudit(ActionsEnum.updateResourceRule)
);
authenticated.delete(
"/resource/:resourceId/rule/:ruleId",
verifyResourceAccess,
verifyUserHasAction(ActionsEnum.deleteResourceRule),
resource.deleteResourceRule
resource.deleteResourceRule,
logActionAudit(ActionsEnum.deleteResourceRule)
);
authenticated.get(
@@ -411,20 +436,23 @@ authenticated.post(
"/target/:targetId",
verifyTargetAccess,
verifyUserHasAction(ActionsEnum.updateTarget),
target.updateTarget
target.updateTarget,
logActionAudit(ActionsEnum.updateTarget)
);
authenticated.delete(
"/target/:targetId",
verifyTargetAccess,
verifyUserHasAction(ActionsEnum.deleteTarget),
target.deleteTarget
target.deleteTarget,
logActionAudit(ActionsEnum.deleteTarget)
);
authenticated.put(
"/org/:orgId/role",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.createRole),
role.createRole
role.createRole,
logActionAudit(ActionsEnum.createRole)
);
authenticated.get(
"/org/:orgId/roles",
@@ -449,14 +477,16 @@ authenticated.delete(
"/role/:roleId",
verifyRoleAccess,
verifyUserHasAction(ActionsEnum.deleteRole),
role.deleteRole
role.deleteRole,
logActionAudit(ActionsEnum.deleteRole)
);
authenticated.post(
"/role/:roleId/add/:userId",
verifyRoleAccess,
verifyUserAccess,
verifyUserHasAction(ActionsEnum.addUserRole),
user.addUserRole
user.addUserRole,
logActionAudit(ActionsEnum.addUserRole)
);
authenticated.post(
@@ -464,7 +494,8 @@ authenticated.post(
verifyResourceAccess,
verifyRoleAccess,
verifyUserHasAction(ActionsEnum.setResourceRoles),
resource.setResourceRoles
resource.setResourceRoles,
logActionAudit(ActionsEnum.setResourceRoles)
);
authenticated.post(
@@ -472,35 +503,40 @@ authenticated.post(
verifyResourceAccess,
verifySetResourceUsers,
verifyUserHasAction(ActionsEnum.setResourceUsers),
resource.setResourceUsers
resource.setResourceUsers,
logActionAudit(ActionsEnum.setResourceUsers)
);
authenticated.post(
`/resource/:resourceId/password`,
verifyResourceAccess,
verifyUserHasAction(ActionsEnum.setResourcePassword),
resource.setResourcePassword
resource.setResourcePassword,
logActionAudit(ActionsEnum.setResourcePassword)
);
authenticated.post(
`/resource/:resourceId/pincode`,
verifyResourceAccess,
verifyUserHasAction(ActionsEnum.setResourcePincode),
resource.setResourcePincode
resource.setResourcePincode,
logActionAudit(ActionsEnum.setResourcePincode)
);
authenticated.post(
`/resource/:resourceId/header-auth`,
verifyResourceAccess,
verifyUserHasAction(ActionsEnum.setResourceHeaderAuth),
resource.setResourceHeaderAuth
resource.setResourceHeaderAuth,
logActionAudit(ActionsEnum.setResourceHeaderAuth)
);
authenticated.post(
`/resource/:resourceId/whitelist`,
verifyResourceAccess,
verifyUserHasAction(ActionsEnum.setResourceWhitelist),
resource.setResourceWhitelist
resource.setResourceWhitelist,
logActionAudit(ActionsEnum.setResourceWhitelist)
);
authenticated.get(
@@ -514,14 +550,16 @@ authenticated.post(
`/resource/:resourceId/access-token`,
verifyResourceAccess,
verifyUserHasAction(ActionsEnum.generateAccessToken),
accessToken.generateAccessToken
accessToken.generateAccessToken,
logActionAudit(ActionsEnum.generateAccessToken)
);
authenticated.delete(
`/access-token/:accessTokenId`,
verifyAccessTokenAccess,
verifyUserHasAction(ActionsEnum.deleteAcessToken),
accessToken.deleteAccessToken
accessToken.deleteAccessToken,
logActionAudit(ActionsEnum.deleteAcessToken)
);
authenticated.get(
@@ -594,7 +632,8 @@ authenticated.put(
"/org/:orgId/user",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.createOrgUser),
user.createOrgUser
user.createOrgUser,
logActionAudit(ActionsEnum.createOrgUser)
);
authenticated.post(
@@ -602,7 +641,8 @@ authenticated.post(
verifyOrgAccess,
verifyUserAccess,
verifyUserHasAction(ActionsEnum.updateOrgUser),
user.updateOrgUser
user.updateOrgUser,
logActionAudit(ActionsEnum.updateOrgUser)
);
authenticated.get("/org/:orgId/user/:userId", verifyOrgAccess, user.getOrgUser);
@@ -624,7 +664,8 @@ authenticated.delete(
verifyOrgAccess,
verifyUserAccess,
verifyUserHasAction(ActionsEnum.removeUser),
user.removeUserOrg
user.removeUserOrg,
logActionAudit(ActionsEnum.removeUser)
);
// authenticated.put(
@@ -757,7 +798,8 @@ authenticated.post(
verifyOrgAccess,
verifyApiKeyAccess,
verifyUserHasAction(ActionsEnum.setApiKeyActions),
apiKeys.setApiKeyActions
apiKeys.setApiKeyActions,
logActionAudit(ActionsEnum.setApiKeyActions)
);
authenticated.get(
@@ -772,7 +814,8 @@ authenticated.put(
`/org/:orgId/api-key`,
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.createApiKey),
apiKeys.createOrgApiKey
apiKeys.createOrgApiKey,
logActionAudit(ActionsEnum.createApiKey)
);
authenticated.delete(
@@ -780,7 +823,8 @@ authenticated.delete(
verifyOrgAccess,
verifyApiKeyAccess,
verifyUserHasAction(ActionsEnum.deleteApiKey),
apiKeys.deleteOrgApiKey
apiKeys.deleteOrgApiKey,
logActionAudit(ActionsEnum.deleteApiKey)
);
authenticated.get(
@@ -795,7 +839,8 @@ authenticated.put(
`/org/:orgId/domain`,
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.createOrgDomain),
domain.createOrgDomain
domain.createOrgDomain,
logActionAudit(ActionsEnum.createOrgDomain)
);
authenticated.post(
@@ -803,7 +848,8 @@ authenticated.post(
verifyOrgAccess,
verifyDomainAccess,
verifyUserHasAction(ActionsEnum.restartOrgDomain),
domain.restartOrgDomain
domain.restartOrgDomain,
logActionAudit(ActionsEnum.restartOrgDomain)
);
authenticated.delete(
@@ -811,7 +857,8 @@ authenticated.delete(
verifyOrgAccess,
verifyDomainAccess,
verifyUserHasAction(ActionsEnum.deleteOrgDomain),
domain.deleteAccountDomain
domain.deleteAccountDomain,
logActionAudit(ActionsEnum.deleteOrgDomain)
);
// Auth routes

View File

@@ -29,7 +29,7 @@ import {
import HttpCode from "@server/types/HttpCode";
import { Router } from "express";
import { ActionsEnum } from "@server/auth/actions";
import { build } from "@server/build";
import { logActionAudit } from "#dynamic/middlewares";
export const unauthenticated = Router();
@@ -51,7 +51,8 @@ authenticated.put(
"/org",
verifyApiKeyIsRoot,
verifyApiKeyHasAction(ActionsEnum.createOrg),
org.createOrg
org.createOrg,
logActionAudit(ActionsEnum.createOrg)
);
authenticated.get(
@@ -72,21 +73,24 @@ authenticated.post(
"/org/:orgId",
verifyApiKeyOrgAccess,
verifyApiKeyHasAction(ActionsEnum.updateOrg),
org.updateOrg
org.updateOrg,
logActionAudit(ActionsEnum.updateOrg)
);
authenticated.delete(
"/org/:orgId",
verifyApiKeyIsRoot,
verifyApiKeyHasAction(ActionsEnum.deleteOrg),
org.deleteOrg
org.deleteOrg,
logActionAudit(ActionsEnum.deleteOrg)
);
authenticated.put(
"/org/:orgId/site",
verifyApiKeyOrgAccess,
verifyApiKeyHasAction(ActionsEnum.createSite),
site.createSite
site.createSite,
logActionAudit(ActionsEnum.createSite)
);
authenticated.get(
@@ -121,14 +125,16 @@ authenticated.post(
"/site/:siteId",
verifyApiKeySiteAccess,
verifyApiKeyHasAction(ActionsEnum.updateSite),
site.updateSite
site.updateSite,
logActionAudit(ActionsEnum.updateSite)
);
authenticated.delete(
"/site/:siteId",
verifyApiKeySiteAccess,
verifyApiKeyHasAction(ActionsEnum.deleteSite),
site.deleteSite
site.deleteSite,
logActionAudit(ActionsEnum.deleteSite)
);
authenticated.get(
@@ -142,7 +148,8 @@ authenticated.put(
verifyApiKeyOrgAccess,
verifyApiKeySiteAccess,
verifyApiKeyHasAction(ActionsEnum.createSiteResource),
siteResource.createSiteResource
siteResource.createSiteResource,
logActionAudit(ActionsEnum.createSiteResource)
);
authenticated.get(
@@ -175,7 +182,8 @@ authenticated.post(
verifyApiKeySiteAccess,
verifyApiKeySiteResourceAccess,
verifyApiKeyHasAction(ActionsEnum.updateSiteResource),
siteResource.updateSiteResource
siteResource.updateSiteResource,
logActionAudit(ActionsEnum.updateSiteResource)
);
authenticated.delete(
@@ -184,21 +192,24 @@ authenticated.delete(
verifyApiKeySiteAccess,
verifyApiKeySiteResourceAccess,
verifyApiKeyHasAction(ActionsEnum.deleteSiteResource),
siteResource.deleteSiteResource
siteResource.deleteSiteResource,
logActionAudit(ActionsEnum.deleteSiteResource)
);
authenticated.put(
"/org/:orgId/resource",
verifyApiKeyOrgAccess,
verifyApiKeyHasAction(ActionsEnum.createResource),
resource.createResource
resource.createResource,
logActionAudit(ActionsEnum.createResource)
);
authenticated.put(
"/org/:orgId/site/:siteId/resource",
verifyApiKeyOrgAccess,
verifyApiKeyHasAction(ActionsEnum.createResource),
resource.createResource
resource.createResource,
logActionAudit(ActionsEnum.createResource)
);
authenticated.get(
@@ -233,7 +244,8 @@ authenticated.post(
"/org/:orgId/create-invite",
verifyApiKeyOrgAccess,
verifyApiKeyHasAction(ActionsEnum.inviteUser),
user.inviteUser
user.inviteUser,
logActionAudit(ActionsEnum.inviteUser)
);
authenticated.get(
@@ -261,21 +273,24 @@ authenticated.post(
"/resource/:resourceId",
verifyApiKeyResourceAccess,
verifyApiKeyHasAction(ActionsEnum.updateResource),
resource.updateResource
resource.updateResource,
logActionAudit(ActionsEnum.updateResource)
);
authenticated.delete(
"/resource/:resourceId",
verifyApiKeyResourceAccess,
verifyApiKeyHasAction(ActionsEnum.deleteResource),
resource.deleteResource
resource.deleteResource,
logActionAudit(ActionsEnum.deleteResource)
);
authenticated.put(
"/resource/:resourceId/target",
verifyApiKeyResourceAccess,
verifyApiKeyHasAction(ActionsEnum.createTarget),
target.createTarget
target.createTarget,
logActionAudit(ActionsEnum.createTarget)
);
authenticated.get(
@@ -289,7 +304,8 @@ authenticated.put(
"/resource/:resourceId/rule",
verifyApiKeyResourceAccess,
verifyApiKeyHasAction(ActionsEnum.createResourceRule),
resource.createResourceRule
resource.createResourceRule,
logActionAudit(ActionsEnum.createResourceRule)
);
authenticated.get(
@@ -303,14 +319,16 @@ authenticated.post(
"/resource/:resourceId/rule/:ruleId",
verifyApiKeyResourceAccess,
verifyApiKeyHasAction(ActionsEnum.updateResourceRule),
resource.updateResourceRule
resource.updateResourceRule,
logActionAudit(ActionsEnum.updateResourceRule)
);
authenticated.delete(
"/resource/:resourceId/rule/:ruleId",
verifyApiKeyResourceAccess,
verifyApiKeyHasAction(ActionsEnum.deleteResourceRule),
resource.deleteResourceRule
resource.deleteResourceRule,
logActionAudit(ActionsEnum.deleteResourceRule)
);
authenticated.get(
@@ -324,21 +342,24 @@ authenticated.post(
"/target/:targetId",
verifyApiKeyTargetAccess,
verifyApiKeyHasAction(ActionsEnum.updateTarget),
target.updateTarget
target.updateTarget,
logActionAudit(ActionsEnum.updateTarget)
);
authenticated.delete(
"/target/:targetId",
verifyApiKeyTargetAccess,
verifyApiKeyHasAction(ActionsEnum.deleteTarget),
target.deleteTarget
target.deleteTarget,
logActionAudit(ActionsEnum.deleteTarget)
);
authenticated.put(
"/org/:orgId/role",
verifyApiKeyOrgAccess,
verifyApiKeyHasAction(ActionsEnum.createRole),
role.createRole
role.createRole,
logActionAudit(ActionsEnum.createRole)
);
authenticated.get(
@@ -352,7 +373,8 @@ authenticated.delete(
"/role/:roleId",
verifyApiKeyRoleAccess,
verifyApiKeyHasAction(ActionsEnum.deleteRole),
role.deleteRole
role.deleteRole,
logActionAudit(ActionsEnum.deleteRole)
);
authenticated.get(
@@ -367,7 +389,8 @@ authenticated.post(
verifyApiKeyRoleAccess,
verifyApiKeyUserAccess,
verifyApiKeyHasAction(ActionsEnum.addUserRole),
user.addUserRole
user.addUserRole,
logActionAudit(ActionsEnum.addUserRole)
);
authenticated.post(
@@ -375,7 +398,8 @@ authenticated.post(
verifyApiKeyResourceAccess,
verifyApiKeyRoleAccess,
verifyApiKeyHasAction(ActionsEnum.setResourceRoles),
resource.setResourceRoles
resource.setResourceRoles,
logActionAudit(ActionsEnum.setResourceRoles)
);
authenticated.post(
@@ -383,35 +407,40 @@ authenticated.post(
verifyApiKeyResourceAccess,
verifyApiKeySetResourceUsers,
verifyApiKeyHasAction(ActionsEnum.setResourceUsers),
resource.setResourceUsers
resource.setResourceUsers,
logActionAudit(ActionsEnum.setResourceUsers)
);
authenticated.post(
`/resource/:resourceId/password`,
verifyApiKeyResourceAccess,
verifyApiKeyHasAction(ActionsEnum.setResourcePassword),
resource.setResourcePassword
resource.setResourcePassword,
logActionAudit(ActionsEnum.setResourcePassword)
);
authenticated.post(
`/resource/:resourceId/pincode`,
verifyApiKeyResourceAccess,
verifyApiKeyHasAction(ActionsEnum.setResourcePincode),
resource.setResourcePincode
resource.setResourcePincode,
logActionAudit(ActionsEnum.setResourcePincode)
);
authenticated.post(
`/resource/:resourceId/header-auth`,
verifyApiKeyResourceAccess,
verifyApiKeyHasAction(ActionsEnum.setResourceHeaderAuth),
resource.setResourceHeaderAuth
resource.setResourceHeaderAuth,
logActionAudit(ActionsEnum.setResourceHeaderAuth)
);
authenticated.post(
`/resource/:resourceId/whitelist`,
verifyApiKeyResourceAccess,
verifyApiKeyHasAction(ActionsEnum.setResourceWhitelist),
resource.setResourceWhitelist
resource.setResourceWhitelist,
logActionAudit(ActionsEnum.setResourceWhitelist)
);
authenticated.get(
@@ -439,14 +468,16 @@ authenticated.post(
`/resource/:resourceId/access-token`,
verifyApiKeyResourceAccess,
verifyApiKeyHasAction(ActionsEnum.generateAccessToken),
accessToken.generateAccessToken
accessToken.generateAccessToken,
logActionAudit(ActionsEnum.generateAccessToken)
);
authenticated.delete(
`/access-token/:accessTokenId`,
verifyApiKeyAccessTokenAccess,
verifyApiKeyHasAction(ActionsEnum.deleteAcessToken),
accessToken.deleteAccessToken
accessToken.deleteAccessToken,
logActionAudit(ActionsEnum.deleteAcessToken)
);
authenticated.get(
@@ -474,7 +505,8 @@ authenticated.post(
"/user/:userId/2fa",
verifyApiKeyIsRoot,
verifyApiKeyHasAction(ActionsEnum.updateUser),
user.updateUser2FA
user.updateUser2FA,
logActionAudit(ActionsEnum.updateUser)
);
authenticated.get(
@@ -495,7 +527,8 @@ authenticated.put(
"/org/:orgId/user",
verifyApiKeyOrgAccess,
verifyApiKeyHasAction(ActionsEnum.createOrgUser),
user.createOrgUser
user.createOrgUser,
logActionAudit(ActionsEnum.createOrgUser)
);
authenticated.post(
@@ -503,7 +536,8 @@ authenticated.post(
verifyApiKeyOrgAccess,
verifyApiKeyUserAccess,
verifyApiKeyHasAction(ActionsEnum.updateOrgUser),
user.updateOrgUser
user.updateOrgUser,
logActionAudit(ActionsEnum.updateOrgUser)
);
authenticated.delete(
@@ -511,7 +545,8 @@ authenticated.delete(
verifyApiKeyOrgAccess,
verifyApiKeyUserAccess,
verifyApiKeyHasAction(ActionsEnum.removeUser),
user.removeUserOrg
user.removeUserOrg,
logActionAudit(ActionsEnum.removeUser)
);
// authenticated.put(
@@ -531,7 +566,8 @@ authenticated.post(
`/org/:orgId/api-key/:apiKeyId/actions`,
verifyApiKeyIsRoot,
verifyApiKeyHasAction(ActionsEnum.setApiKeyActions),
apiKeys.setApiKeyActions
apiKeys.setApiKeyActions,
logActionAudit(ActionsEnum.setApiKeyActions)
);
authenticated.get(
@@ -545,28 +581,32 @@ authenticated.put(
`/org/:orgId/api-key`,
verifyApiKeyIsRoot,
verifyApiKeyHasAction(ActionsEnum.createApiKey),
apiKeys.createOrgApiKey
apiKeys.createOrgApiKey,
logActionAudit(ActionsEnum.createApiKey)
);
authenticated.delete(
`/org/:orgId/api-key/:apiKeyId`,
verifyApiKeyIsRoot,
verifyApiKeyHasAction(ActionsEnum.deleteApiKey),
apiKeys.deleteApiKey
apiKeys.deleteApiKey,
logActionAudit(ActionsEnum.deleteApiKey)
);
authenticated.put(
"/idp/oidc",
verifyApiKeyIsRoot,
verifyApiKeyHasAction(ActionsEnum.createIdp),
idp.createOidcIdp
idp.createOidcIdp,
logActionAudit(ActionsEnum.createIdp)
);
authenticated.post(
"/idp/:idpId/oidc",
verifyApiKeyIsRoot,
verifyApiKeyHasAction(ActionsEnum.updateIdp),
idp.updateOidcIdp
idp.updateOidcIdp,
logActionAudit(ActionsEnum.updateIdp)
);
authenticated.get(
@@ -587,21 +627,24 @@ authenticated.put(
"/idp/:idpId/org/:orgId",
verifyApiKeyIsRoot,
verifyApiKeyHasAction(ActionsEnum.createIdpOrg),
idp.createIdpOrgPolicy
idp.createIdpOrgPolicy,
logActionAudit(ActionsEnum.createIdpOrg)
);
authenticated.post(
"/idp/:idpId/org/:orgId",
verifyApiKeyIsRoot,
verifyApiKeyHasAction(ActionsEnum.updateIdpOrg),
idp.updateIdpOrgPolicy
idp.updateIdpOrgPolicy,
logActionAudit(ActionsEnum.updateIdpOrg)
);
authenticated.delete(
"/idp/:idpId/org/:orgId",
verifyApiKeyIsRoot,
verifyApiKeyHasAction(ActionsEnum.deleteIdpOrg),
idp.deleteIdpOrgPolicy
idp.deleteIdpOrgPolicy,
logActionAudit(ActionsEnum.deleteIdpOrg)
);
authenticated.get(
@@ -640,7 +683,8 @@ authenticated.put(
verifyClientsEnabled,
verifyApiKeyOrgAccess,
verifyApiKeyHasAction(ActionsEnum.createClient),
client.createClient
client.createClient,
logActionAudit(ActionsEnum.createClient)
);
authenticated.delete(
@@ -648,7 +692,8 @@ authenticated.delete(
verifyClientsEnabled,
verifyApiKeyClientAccess,
verifyApiKeyHasAction(ActionsEnum.deleteClient),
client.deleteClient
client.deleteClient,
logActionAudit(ActionsEnum.deleteClient)
);
authenticated.post(
@@ -656,12 +701,14 @@ authenticated.post(
verifyClientsEnabled,
verifyApiKeyClientAccess,
verifyApiKeyHasAction(ActionsEnum.updateClient),
client.updateClient
client.updateClient,
logActionAudit(ActionsEnum.updateClient)
);
authenticated.put(
"/org/:orgId/blueprint",
verifyApiKeyOrgAccess,
verifyApiKeyHasAction(ActionsEnum.applyBlueprint),
org.applyBlueprint
org.applyBlueprint,
logActionAudit(ActionsEnum.applyBlueprint)
);