Skip to content

Commit ec094cd

Browse files
committed
refactor imports to use api
1 parent 04a89b2 commit ec094cd

File tree

83 files changed

+2767
-1796
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+2767
-1796
lines changed

package-lock.json

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/api/src/authz/service.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ import {
66
} from "@common/db/schema/enterprise/organization";
77
import { project, userProject } from "@common/db/schema/project";
88
import { ApiError } from "../types";
9+
import {
10+
verifyAgsImportOwnership,
11+
verifyExcelImportOwnership,
12+
verifyAgsFileUploadOwnership,
13+
verifyExcelImportFileOwnership,
14+
} from "../services/db/imports";
915

1016
export type ProjectVisibility = "internal" | "private";
1117

@@ -200,6 +206,38 @@ export class AuthorizationService {
200206
}
201207
}
202208

209+
/**
210+
* Verify that an entity belongs to a specific project
211+
*/
212+
async verifyEntityOwnership(
213+
entityType:
214+
| "agsImport"
215+
| "excelImport"
216+
| "agsFileUpload"
217+
| "excelImportFile",
218+
entityId: string,
219+
projectId: string,
220+
): Promise<boolean> {
221+
try {
222+
switch (entityType) {
223+
case "agsImport":
224+
return await verifyAgsImportOwnership(entityId, projectId);
225+
case "excelImport":
226+
return await verifyExcelImportOwnership(entityId, projectId);
227+
case "agsFileUpload":
228+
return await verifyAgsFileUploadOwnership(entityId, projectId);
229+
case "excelImportFile":
230+
return await verifyExcelImportFileOwnership(entityId, projectId);
231+
default:
232+
console.error(`Unknown entity type: ${entityType}`);
233+
return false;
234+
}
235+
} catch (error) {
236+
console.error(`Error verifying ${entityType} ownership:`, error);
237+
return false;
238+
}
239+
}
240+
203241
/**
204242
* Check if user can access organization with specific action
205243
*/

packages/api/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,12 @@ app.get("/health", (req, res) => {
5555
import projectsRouter from "./routes/projects";
5656
import organizationsRouter from "./routes/organizations";
5757
import notificationsRouter from "./routes/notifications";
58+
import importsRouter from "./routes/imports";
5859

5960
// API routes with nested organization structure
6061
app.use("/api/orgs", organizationsRouter);
6162
app.use("/api/orgs/:organizationId/projects", projectsRouter);
63+
app.use("/api/orgs", importsRouter);
6264
app.use("/api/notifications", notificationsRouter);
6365

6466
app.get("/api", (req, res) => {

packages/api/src/middleware/authorization.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,53 @@ export function requireProjectView() {
125125
return requireProjectAccess("read");
126126
}
127127

128+
/**
129+
* Middleware to require entity ownership validation
130+
* This ensures that the requested entity actually belongs to the specified project
131+
*/
132+
export function requireEntityOwnership(
133+
entityType: "agsImport" | "excelImport" | "agsFileUpload" | "excelImportFile",
134+
getEntityId: (_req: AuthenticatedRequest) => string,
135+
) {
136+
return async (
137+
req: AuthenticatedRequest,
138+
_res: Response,
139+
next: NextFunction,
140+
): Promise<void> => {
141+
try {
142+
if (!req.user) {
143+
throw new ApiError("Authentication required", 401);
144+
}
145+
146+
const projectId = req.params.projectId as string;
147+
const entityId = getEntityId(req);
148+
149+
if (!projectId || !entityId) {
150+
throw new ApiError("Missing required parameters", 400);
151+
}
152+
153+
// Verify entity belongs to project
154+
const belongsToProject = await authzService.verifyEntityOwnership(
155+
entityType,
156+
entityId,
157+
projectId,
158+
);
159+
160+
if (!belongsToProject) {
161+
throw new ApiError("Entity not found or access denied", 404);
162+
}
163+
164+
next();
165+
} catch (error) {
166+
if (error instanceof ApiError) {
167+
next(error);
168+
} else {
169+
next(new ApiError("Entity ownership validation failed", 500));
170+
}
171+
}
172+
};
173+
}
174+
128175
/**
129176
* Middleware to extract organization context from request
130177
*/

0 commit comments

Comments
 (0)