Skip to content

Commit abb019d

Browse files
authored
Merge pull request #44 from SoftwareBrothers/fix/do-not-protect-non-admin-routes
fix: Do not protect non-admin routes
2 parents eb17e5a + 1931b69 commit abb019d

File tree

6 files changed

+70
-3
lines changed

6 files changed

+70
-3
lines changed

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,5 +77,8 @@
7777
"ts-jest": "^26.4.4",
7878
"ts-node": "^9.0.0",
7979
"typescript": "^4.1.2"
80+
},
81+
"dependencies": {
82+
"path-to-regexp": "^6.2.0"
8083
}
8184
}
Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import AdminJS, { Router as AdminRouter } from "adminjs";
22
import { Router } from "express";
3+
import { convertToExpressRoute } from "../convertRoutes";
4+
import { pathToRegexp } from "path-to-regexp";
35

46
export const withProtectedRoutesHandler = (
57
router: Router,
@@ -8,7 +10,7 @@ export const withProtectedRoutesHandler = (
810
const { rootPath } = admin.options;
911

1012
router.use((req, res, next) => {
11-
if (AdminRouter.assets.find((asset) => req.originalUrl.match(asset.path))) {
13+
if (isAdminAsset(req.originalUrl)) {
1214
next();
1315
} else if (
1416
req.session.adminUser ||
@@ -17,18 +19,36 @@ export const withProtectedRoutesHandler = (
1719
req.originalUrl.startsWith(admin.options.logoutPath)
1820
) {
1921
next();
20-
} else {
22+
} else if (isAdminRoute(req.originalUrl, rootPath)) {
2123
// If the redirection is caused by API call to some action just redirect to resource
2224
const [redirectTo] = req.originalUrl.split("/actions");
2325
req.session.redirectTo = redirectTo.includes(`${rootPath}/api`)
2426
? rootPath
2527
: redirectTo;
28+
2629
req.session.save((err) => {
2730
if (err) {
2831
next(err);
2932
}
3033
res.redirect(admin.options.loginPath);
3134
});
35+
} else {
36+
next();
3237
}
3338
});
3439
};
40+
41+
export const isAdminRoute = (url: string, adminRootUrl: string): boolean => {
42+
const adminRoutes = AdminRouter.routes
43+
.map((route) => convertToExpressRoute(route.path))
44+
.filter((route) => route !== "");
45+
const isAdminRootUrl = url === adminRootUrl;
46+
47+
return (
48+
isAdminRootUrl ||
49+
!!adminRoutes.find((route) => pathToRegexp(route).test(url))
50+
);
51+
};
52+
53+
const isAdminAsset = (url: string) =>
54+
AdminRouter.assets.find((asset) => url.match(asset.path));

src/buildRouter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import path from "path";
55
import { WrongArgumentError } from "./errors";
66
import { log } from "./logger";
77
import { FormidableOptions } from "./types";
8+
import { convertToExpressRoute } from "./convertRoutes";
89

910
const INVALID_ADMINJS_INSTANCE =
1011
"You have to pass an instance of AdminJS to the buildRouter() function";
@@ -28,7 +29,7 @@ export const buildRouter = (
2829

2930
routes.forEach((route) => {
3031
// we have to change routes defined in AdminJS from {recordId} to :recordId
31-
const expressPath = route.path.replace(/{/g, ":").replace(/}/g, "");
32+
const expressPath = convertToExpressRoute(route.path);
3233

3334
const handler: RequestHandler = async (req, res, next) => {
3435
try {

src/convertRoutes.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const convertToExpressRoute = (adminRoute: string): string =>
2+
adminRoute.replace(/{/g, ":").replace(/}/g, "");

test/protected-routes.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { isAdminRoute } from "../src/authentication/protected-routes.handler";
2+
3+
describe("Protected routes", () => {
4+
describe("#isAdminRoute", () => {
5+
it("should detect admin routes", () => {
6+
const adminRoutes = [
7+
"/",
8+
"/resources/someResource",
9+
"/api/resources/someResource/search/searchQuery",
10+
"/resources/someResource/actions/someAction",
11+
"/api/resources/someResource/actions/someAction",
12+
"/api/resources/someResource/actions/someAction/searchQuery",
13+
"/api/resources/someResource/actions/someAction",
14+
"/resources/someResource/records/someRecordId/someAction",
15+
"/api/resources/someResource/records/someRecordId/someAction",
16+
"/api/resources/someResource/records/someRecordId/someAction",
17+
"/resources/someResource/bulk/someAction",
18+
"/api/resources/someResource/bulk/someAction",
19+
"/api/resources/someResource/bulk/someAction",
20+
"/api/resources/someResource/search/",
21+
"/api/dashboard",
22+
"/pages/somePage",
23+
"/api/pages/somePage",
24+
"/api/pages/somePage",
25+
];
26+
27+
adminRoutes.forEach((route) => {
28+
expect(isAdminRoute(route, "/")).toBeTruthy();
29+
});
30+
});
31+
32+
it("should detect non-admin routes", () => {
33+
expect(isAdminRoute("/api/my-endpoint", "/")).toBeFalsy();
34+
});
35+
});
36+
});

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8431,6 +8431,11 @@ path-to-regexp@^1.7.0:
84318431
dependencies:
84328432
isarray "0.0.1"
84338433

8434+
path-to-regexp@^6.2.0:
8435+
version "6.2.0"
8436+
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.0.tgz#f7b3803336104c346889adece614669230645f38"
8437+
integrity sha512-f66KywYG6+43afgE/8j/GoiNyygk/bnoCbps++3ErRKsIYkGGupyv07R2Ok5m9i67Iqc+T2g1eAUGUPzWhYTyg==
8438+
84348439
path-type@^2.0.0:
84358440
version "2.0.0"
84368441
resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73"

0 commit comments

Comments
 (0)