mirror of
https://github.com/fosrl/pangolin.git
synced 2026-01-28 22:00:51 +00:00
@@ -1052,6 +1052,11 @@
|
||||
"actionUpdateClient": "Update Client",
|
||||
"actionListClients": "List Clients",
|
||||
"actionGetClient": "Get Client",
|
||||
"actionCreateSiteResource": "Create Site Resource",
|
||||
"actionDeleteSiteResource": "Delete Site Resource",
|
||||
"actionGetSiteResource": "Get Site Resource",
|
||||
"actionListSiteResources": "List Site Resources",
|
||||
"actionUpdateSiteResource": "Update Site Resource",
|
||||
"noneSelected": "None selected",
|
||||
"orgNotFound2": "No organizations found.",
|
||||
"searchProgress": "Search...",
|
||||
|
||||
@@ -11,3 +11,4 @@ export * from "./verifyAccessTokenAccess";
|
||||
export * from "./verifyApiKeyIsRoot";
|
||||
export * from "./verifyApiKeyApiKeyAccess";
|
||||
export * from "./verifyApiKeyClientAccess";
|
||||
export * from "./verifyApiKeySiteResourceAccess";
|
||||
@@ -0,0 +1,97 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { db } from "@server/db";
|
||||
import { siteResources, apiKeyOrg } from "@server/db";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import createHttpError from "http-errors";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
|
||||
export async function verifyApiKeySiteResourceAccess(
|
||||
req: Request,
|
||||
res: Response,
|
||||
next: NextFunction
|
||||
) {
|
||||
try {
|
||||
const apiKey = req.apiKey;
|
||||
const siteResourceId = parseInt(req.params.siteResourceId);
|
||||
const siteId = parseInt(req.params.siteId);
|
||||
const orgId = req.params.orgId;
|
||||
|
||||
if (!apiKey) {
|
||||
return next(
|
||||
createHttpError(HttpCode.UNAUTHORIZED, "Key not authenticated")
|
||||
);
|
||||
}
|
||||
|
||||
if (!siteResourceId || !siteId || !orgId) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.BAD_REQUEST,
|
||||
"Missing required parameters"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (apiKey.isRoot) {
|
||||
// Root keys can access any resource in any org
|
||||
return next();
|
||||
}
|
||||
|
||||
// Check if the site resource exists and belongs to the specified site and org
|
||||
const [siteResource] = await db
|
||||
.select()
|
||||
.from(siteResources)
|
||||
.where(and(
|
||||
eq(siteResources.siteResourceId, siteResourceId),
|
||||
eq(siteResources.siteId, siteId),
|
||||
eq(siteResources.orgId, orgId)
|
||||
))
|
||||
.limit(1);
|
||||
|
||||
if (!siteResource) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.NOT_FOUND,
|
||||
"Site resource not found"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Verify that the API key has access to the organization
|
||||
if (!req.apiKeyOrg) {
|
||||
const apiKeyOrgRes = await db
|
||||
.select()
|
||||
.from(apiKeyOrg)
|
||||
.where(
|
||||
and(
|
||||
eq(apiKeyOrg.apiKeyId, apiKey.apiKeyId),
|
||||
eq(apiKeyOrg.orgId, orgId)
|
||||
)
|
||||
)
|
||||
.limit(1);
|
||||
|
||||
if (apiKeyOrgRes.length === 0) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.FORBIDDEN,
|
||||
"Key does not have access to this organization"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
req.apiKeyOrg = apiKeyOrgRes[0];
|
||||
}
|
||||
|
||||
// Attach the siteResource to the request for use in the next middleware/route
|
||||
// @ts-ignore - Extending Request type
|
||||
req.siteResource = siteResource;
|
||||
|
||||
return next();
|
||||
} catch (error) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.INTERNAL_SERVER_ERROR,
|
||||
"Error verifying site resource access"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import * as client from "./client";
|
||||
import * as accessToken from "./accessToken";
|
||||
import * as apiKeys from "./apiKeys";
|
||||
import * as idp from "./idp";
|
||||
import * as siteResource from "./siteResource";
|
||||
import {
|
||||
verifyApiKey,
|
||||
verifyApiKeyOrgAccess,
|
||||
@@ -22,7 +23,8 @@ import {
|
||||
verifyApiKeyAccessTokenAccess,
|
||||
verifyApiKeyIsRoot,
|
||||
verifyApiKeyClientAccess,
|
||||
verifyClientsEnabled
|
||||
verifyClientsEnabled,
|
||||
verifyApiKeySiteResourceAccess
|
||||
} from "@server/middlewares";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import { Router } from "express";
|
||||
@@ -128,6 +130,69 @@ authenticated.delete(
|
||||
site.deleteSite
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/user-resources",
|
||||
verifyApiKeyOrgAccess,
|
||||
resource.getUserResources
|
||||
);
|
||||
// Site Resource endpoints
|
||||
authenticated.put(
|
||||
"/org/:orgId/site/:siteId/resource",
|
||||
verifyApiKeyOrgAccess,
|
||||
verifyApiKeySiteAccess,
|
||||
verifyApiKeyHasAction(ActionsEnum.createSiteResource),
|
||||
siteResource.createSiteResource
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/site/:siteId/resources",
|
||||
verifyApiKeyOrgAccess,
|
||||
verifyApiKeySiteAccess,
|
||||
verifyApiKeyHasAction(ActionsEnum.listSiteResources),
|
||||
siteResource.listSiteResources
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/site-resources",
|
||||
verifyApiKeyOrgAccess,
|
||||
verifyApiKeyHasAction(ActionsEnum.listSiteResources),
|
||||
siteResource.listAllSiteResourcesByOrg
|
||||
);
|
||||
|
||||
authenticated.get(
|
||||
"/org/:orgId/site/:siteId/resource/:siteResourceId",
|
||||
verifyApiKeyOrgAccess,
|
||||
verifyApiKeySiteAccess,
|
||||
verifyApiKeySiteResourceAccess,
|
||||
verifyApiKeyHasAction(ActionsEnum.getSiteResource),
|
||||
siteResource.getSiteResource
|
||||
);
|
||||
|
||||
authenticated.post(
|
||||
"/org/:orgId/site/:siteId/resource/:siteResourceId",
|
||||
verifyApiKeyOrgAccess,
|
||||
verifyApiKeySiteAccess,
|
||||
verifyApiKeySiteResourceAccess,
|
||||
verifyApiKeyHasAction(ActionsEnum.updateSiteResource),
|
||||
siteResource.updateSiteResource
|
||||
);
|
||||
|
||||
authenticated.delete(
|
||||
"/org/:orgId/site/:siteId/resource/:siteResourceId",
|
||||
verifyApiKeyOrgAccess,
|
||||
verifyApiKeySiteAccess,
|
||||
verifyApiKeySiteResourceAccess,
|
||||
verifyApiKeyHasAction(ActionsEnum.deleteSiteResource),
|
||||
siteResource.deleteSiteResource
|
||||
);
|
||||
|
||||
authenticated.put(
|
||||
"/org/:orgId/resource",
|
||||
verifyApiKeyOrgAccess,
|
||||
verifyApiKeyHasAction(ActionsEnum.createResource),
|
||||
resource.createResource
|
||||
);
|
||||
|
||||
authenticated.put(
|
||||
"/org/:orgId/site/:siteId/resource",
|
||||
verifyApiKeyOrgAccess,
|
||||
|
||||
@@ -51,7 +51,12 @@ function getActionsCategories(root: boolean) {
|
||||
[t('actionSetResourcePassword')]: "setResourcePassword",
|
||||
[t('actionSetResourcePincode')]: "setResourcePincode",
|
||||
[t('actionSetResourceEmailWhitelist')]: "setResourceWhitelist",
|
||||
[t('actionGetResourceEmailWhitelist')]: "getResourceWhitelist"
|
||||
[t('actionGetResourceEmailWhitelist')]: "getResourceWhitelist",
|
||||
[t('actionCreateSiteResource')]: "createSiteResource",
|
||||
[t('actionDeleteSiteResource')]: "deleteSiteResource",
|
||||
[t('actionGetSiteResource')]: "getSiteResource",
|
||||
[t('actionListSiteResources')]: "listSiteResources",
|
||||
[t('actionUpdateSiteResource')]: "updateSiteResource"
|
||||
},
|
||||
|
||||
Target: {
|
||||
|
||||
Reference in New Issue
Block a user