Fix confusing 404 for unauthorized requests
This commit is contained in:
1 parent
c52ff6f6ec
commit
36798cfb5f
2 files changed
+33
-29
No files matched your search
+29
-29
@@ -86,7 +86,7 @@ router.get(`/devices/:id.csv`, async (ctx) => {
|
|||||||
|
|
||||||
if (!authorizer.hasAccess("devices", 2)) {
|
if (!authorizer.hasAccess("devices", 2)) {
|
||||||
logUnauthorizedWarning(log);
|
logUnauthorizedWarning(log);
|
||||||
return void (ctx.status = 404);
|
return void (ctx.status = 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await db.query("devices", filter);
|
const res = await db.query("devices", filter);
|
||||||
@@ -127,7 +127,7 @@ router.get(`/devices/:id.csv`, async (ctx) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
for (const [resource, flags] of Object.entries(resources)) {
|
for (const [resource, flags] of Object.entries(resources)) {
|
||||||
router.head(`/${resource}`, async (ctx, next) => {
|
router.head(`/${resource}`, async (ctx) => {
|
||||||
const authorizer: Authorizer = ctx.state.authorizer;
|
const authorizer: Authorizer = ctx.state.authorizer;
|
||||||
let filter: Expression = authorizer.getFilter(resource, 1);
|
let filter: Expression = authorizer.getFilter(resource, 1);
|
||||||
if (ctx.request.query.filter)
|
if (ctx.request.query.filter)
|
||||||
@@ -142,7 +142,7 @@ for (const [resource, flags] of Object.entries(resources)) {
|
|||||||
|
|
||||||
if (!authorizer.hasAccess(resource, 1)) {
|
if (!authorizer.hasAccess(resource, 1)) {
|
||||||
logUnauthorizedWarning(log);
|
logUnauthorizedWarning(log);
|
||||||
return void next();
|
return void (ctx.status = 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exclude temporary tasks and faults
|
// Exclude temporary tasks and faults
|
||||||
@@ -163,7 +163,7 @@ for (const [resource, flags] of Object.entries(resources)) {
|
|||||||
logger.accessInfo(log);
|
logger.accessInfo(log);
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get(`/${resource}`, async (ctx, next) => {
|
router.get(`/${resource}`, async (ctx) => {
|
||||||
const authorizer: Authorizer = ctx.state.authorizer;
|
const authorizer: Authorizer = ctx.state.authorizer;
|
||||||
const options: QueryOptions = {};
|
const options: QueryOptions = {};
|
||||||
let filter: Expression = authorizer.getFilter(resource, 2);
|
let filter: Expression = authorizer.getFilter(resource, 2);
|
||||||
@@ -191,7 +191,7 @@ for (const [resource, flags] of Object.entries(resources)) {
|
|||||||
|
|
||||||
if (!authorizer.hasAccess(resource, 2)) {
|
if (!authorizer.hasAccess(resource, 2)) {
|
||||||
logUnauthorizedWarning(log);
|
logUnauthorizedWarning(log);
|
||||||
return void next();
|
return void (ctx.status = 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exclude temporary tasks and faults
|
// Exclude temporary tasks and faults
|
||||||
@@ -217,7 +217,7 @@ for (const [resource, flags] of Object.entries(resources)) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// CSV download
|
// CSV download
|
||||||
router.get(`/${resource}.csv`, async (ctx, next) => {
|
router.get(`/${resource}.csv`, async (ctx) => {
|
||||||
const authorizer: Authorizer = ctx.state.authorizer;
|
const authorizer: Authorizer = ctx.state.authorizer;
|
||||||
const options: QueryOptions = { projection: {} };
|
const options: QueryOptions = { projection: {} };
|
||||||
let filter: Expression = authorizer.getFilter(resource, 2);
|
let filter: Expression = authorizer.getFilter(resource, 2);
|
||||||
@@ -239,7 +239,7 @@ for (const [resource, flags] of Object.entries(resources)) {
|
|||||||
|
|
||||||
if (!authorizer.hasAccess(resource, 2)) {
|
if (!authorizer.hasAccess(resource, 2)) {
|
||||||
logUnauthorizedWarning(log);
|
logUnauthorizedWarning(log);
|
||||||
return void next();
|
return void (ctx.status = 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
const columns: Record<string, Expression> = JSON.parse(
|
const columns: Record<string, Expression> = JSON.parse(
|
||||||
@@ -308,7 +308,7 @@ for (const [resource, flags] of Object.entries(resources)) {
|
|||||||
logger.accessInfo(log);
|
logger.accessInfo(log);
|
||||||
});
|
});
|
||||||
|
|
||||||
router.head(`/${resource}/:id`, async (ctx, next) => {
|
router.head(`/${resource}/:id`, async (ctx) => {
|
||||||
const authorizer: Authorizer = ctx.state.authorizer;
|
const authorizer: Authorizer = ctx.state.authorizer;
|
||||||
const log = {
|
const log = {
|
||||||
message: `Count ${resource}`,
|
message: `Count ${resource}`,
|
||||||
@@ -323,18 +323,18 @@ for (const [resource, flags] of Object.entries(resources)) {
|
|||||||
]);
|
]);
|
||||||
if (!authorizer.hasAccess(resource, 2)) {
|
if (!authorizer.hasAccess(resource, 2)) {
|
||||||
logUnauthorizedWarning(log);
|
logUnauthorizedWarning(log);
|
||||||
return void next();
|
return void (ctx.status = 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await db.query(resource, filter);
|
const res = await db.query(resource, filter);
|
||||||
|
|
||||||
if (!res.length) return void next();
|
if (!res.length) return void (ctx.status = 404);
|
||||||
|
|
||||||
logger.accessInfo(log);
|
logger.accessInfo(log);
|
||||||
ctx.body = "";
|
ctx.body = "";
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get(`/${resource}/:id`, async (ctx, next) => {
|
router.get(`/${resource}/:id`, async (ctx) => {
|
||||||
const authorizer: Authorizer = ctx.state.authorizer;
|
const authorizer: Authorizer = ctx.state.authorizer;
|
||||||
const log = {
|
const log = {
|
||||||
message: `Query ${resource}`,
|
message: `Query ${resource}`,
|
||||||
@@ -349,19 +349,19 @@ for (const [resource, flags] of Object.entries(resources)) {
|
|||||||
]);
|
]);
|
||||||
if (!authorizer.hasAccess(resource, 2)) {
|
if (!authorizer.hasAccess(resource, 2)) {
|
||||||
logUnauthorizedWarning(log);
|
logUnauthorizedWarning(log);
|
||||||
return void next();
|
return void (ctx.status = 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await db.query(resource, filter);
|
const res = await db.query(resource, filter);
|
||||||
|
|
||||||
if (!res.length) return void next();
|
if (!res.length) return void (ctx.status = 404);
|
||||||
|
|
||||||
logger.accessInfo(log);
|
logger.accessInfo(log);
|
||||||
ctx.body = res[0];
|
ctx.body = res[0];
|
||||||
});
|
});
|
||||||
|
|
||||||
if (flags & RESOURCE_DELETE) {
|
if (flags & RESOURCE_DELETE) {
|
||||||
router.delete(`/${resource}/:id`, async (ctx, next) => {
|
router.delete(`/${resource}/:id`, async (ctx) => {
|
||||||
const authorizer: Authorizer = ctx.state.authorizer;
|
const authorizer: Authorizer = ctx.state.authorizer;
|
||||||
const log = {
|
const log = {
|
||||||
message: `Delete ${resource}`,
|
message: `Delete ${resource}`,
|
||||||
@@ -376,10 +376,10 @@ for (const [resource, flags] of Object.entries(resources)) {
|
|||||||
]);
|
]);
|
||||||
if (!authorizer.hasAccess(resource, 3)) {
|
if (!authorizer.hasAccess(resource, 3)) {
|
||||||
logUnauthorizedWarning(log);
|
logUnauthorizedWarning(log);
|
||||||
return void next();
|
return void (ctx.status = 403);
|
||||||
}
|
}
|
||||||
const res = await db.query(resource, filter);
|
const res = await db.query(resource, filter);
|
||||||
if (!res.length) return void next();
|
if (!res.length) return void (ctx.status = 404);
|
||||||
|
|
||||||
const validate = authorizer.getValidator(resource, res[0]);
|
const validate = authorizer.getValidator(resource, res[0]);
|
||||||
if (!validate("delete")) {
|
if (!validate("delete")) {
|
||||||
@@ -396,7 +396,7 @@ for (const [resource, flags] of Object.entries(resources)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (flags & RESOURCE_PUT) {
|
if (flags & RESOURCE_PUT) {
|
||||||
router.put(`/${resource}/:id`, async (ctx, next) => {
|
router.put(`/${resource}/:id`, async (ctx) => {
|
||||||
const authorizer: Authorizer = ctx.state.authorizer;
|
const authorizer: Authorizer = ctx.state.authorizer;
|
||||||
const id = ctx.params.id;
|
const id = ctx.params.id;
|
||||||
|
|
||||||
@@ -408,7 +408,7 @@ for (const [resource, flags] of Object.entries(resources)) {
|
|||||||
|
|
||||||
if (!authorizer.hasAccess(resource, 3)) {
|
if (!authorizer.hasAccess(resource, 3)) {
|
||||||
logUnauthorizedWarning(log);
|
logUnauthorizedWarning(log);
|
||||||
return void next();
|
return void (ctx.status = 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
const obj = ctx.request.body;
|
const obj = ctx.request.body;
|
||||||
@@ -435,7 +435,7 @@ for (const [resource, flags] of Object.entries(resources)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
router.put("/files/:id", async (ctx, next) => {
|
router.put("/files/:id", async (ctx) => {
|
||||||
const authorizer: Authorizer = ctx.state.authorizer;
|
const authorizer: Authorizer = ctx.state.authorizer;
|
||||||
const resource = "files";
|
const resource = "files";
|
||||||
const id = ctx.params.id;
|
const id = ctx.params.id;
|
||||||
@@ -449,7 +449,7 @@ router.put("/files/:id", async (ctx, next) => {
|
|||||||
|
|
||||||
if (!authorizer.hasAccess(resource, 3)) {
|
if (!authorizer.hasAccess(resource, 3)) {
|
||||||
logUnauthorizedWarning(log);
|
logUnauthorizedWarning(log);
|
||||||
return void next();
|
return void (ctx.status = 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
const metadata = {
|
const metadata = {
|
||||||
@@ -478,7 +478,7 @@ router.put("/files/:id", async (ctx, next) => {
|
|||||||
ctx.body = "";
|
ctx.body = "";
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post("/devices/:id/tasks", async (ctx, next) => {
|
router.post("/devices/:id/tasks", async (ctx) => {
|
||||||
const authorizer: Authorizer = ctx.state.authorizer;
|
const authorizer: Authorizer = ctx.state.authorizer;
|
||||||
const log = {
|
const log = {
|
||||||
message: "Commit tasks",
|
message: "Commit tasks",
|
||||||
@@ -494,10 +494,10 @@ router.post("/devices/:id/tasks", async (ctx, next) => {
|
|||||||
]);
|
]);
|
||||||
if (!authorizer.hasAccess("devices", 3)) {
|
if (!authorizer.hasAccess("devices", 3)) {
|
||||||
logUnauthorizedWarning(log);
|
logUnauthorizedWarning(log);
|
||||||
return void next();
|
return void (ctx.status = 403);
|
||||||
}
|
}
|
||||||
const devices = await db.query("devices", filter);
|
const devices = await db.query("devices", filter);
|
||||||
if (!devices.length) return void next();
|
if (!devices.length) return void (ctx.status = 404);
|
||||||
const device = devices[0];
|
const device = devices[0];
|
||||||
|
|
||||||
const validate = authorizer.getValidator("devices", device);
|
const validate = authorizer.getValidator("devices", device);
|
||||||
@@ -546,7 +546,7 @@ router.post("/devices/:id/tasks", async (ctx, next) => {
|
|||||||
ctx.body = res.tasks;
|
ctx.body = res.tasks;
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post("/devices/:id/tags", async (ctx, next) => {
|
router.post("/devices/:id/tags", async (ctx) => {
|
||||||
const authorizer: Authorizer = ctx.state.authorizer;
|
const authorizer: Authorizer = ctx.state.authorizer;
|
||||||
const log = {
|
const log = {
|
||||||
message: "Update tags",
|
message: "Update tags",
|
||||||
@@ -562,10 +562,10 @@ router.post("/devices/:id/tags", async (ctx, next) => {
|
|||||||
]);
|
]);
|
||||||
if (!authorizer.hasAccess("devices", 3)) {
|
if (!authorizer.hasAccess("devices", 3)) {
|
||||||
logUnauthorizedWarning(log);
|
logUnauthorizedWarning(log);
|
||||||
return void next();
|
return void (ctx.status = 403);
|
||||||
}
|
}
|
||||||
const res = await db.query("devices", filter);
|
const res = await db.query("devices", filter);
|
||||||
if (!res.length) return void next();
|
if (!res.length) return void (ctx.status = 404);
|
||||||
|
|
||||||
const validate = authorizer.getValidator("devices", res[0]);
|
const validate = authorizer.getValidator("devices", res[0]);
|
||||||
if (!validate("tags", ctx.request.body)) {
|
if (!validate("tags", ctx.request.body)) {
|
||||||
@@ -601,7 +601,7 @@ router.get("/ping/:host", async (ctx) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.put("/users/:id/password", async (ctx, next) => {
|
router.put("/users/:id/password", async (ctx) => {
|
||||||
const authorizer: Authorizer = ctx.state.authorizer;
|
const authorizer: Authorizer = ctx.state.authorizer;
|
||||||
const username = ctx.params.id;
|
const username = ctx.params.id;
|
||||||
const log = {
|
const log = {
|
||||||
@@ -626,7 +626,7 @@ router.put("/users/:id/password", async (ctx, next) => {
|
|||||||
}
|
}
|
||||||
} else if (!authorizer.hasAccess("users", 3)) {
|
} else if (!authorizer.hasAccess("users", 3)) {
|
||||||
logUnauthorizedWarning(log);
|
logUnauthorizedWarning(log);
|
||||||
return void next();
|
return void (ctx.status = 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
const filter = and(authorizer.getFilter("users", 3), [
|
const filter = and(authorizer.getFilter("users", 3), [
|
||||||
@@ -635,7 +635,7 @@ router.put("/users/:id/password", async (ctx, next) => {
|
|||||||
username,
|
username,
|
||||||
]);
|
]);
|
||||||
const res = await db.query("users", filter);
|
const res = await db.query("users", filter);
|
||||||
if (!res.length) return void next();
|
if (!res.length) return void (ctx.status = 404);
|
||||||
|
|
||||||
const newPassword = ctx.request.body.newPassword;
|
const newPassword = ctx.request.body.newPassword;
|
||||||
if (ctx.state.user) {
|
if (ctx.state.user) {
|
||||||
|
|||||||
@@ -173,6 +173,7 @@ export async function xhrRequest(
|
|||||||
|
|
||||||
// https://mithril.js.org/request.html#error-handling
|
// https://mithril.js.org/request.html#error-handling
|
||||||
if (xhr.status !== 304 && Math.floor(xhr.status / 100) !== 2) {
|
if (xhr.status !== 304 && Math.floor(xhr.status / 100) !== 2) {
|
||||||
|
if (xhr.status === 403) throw new Error("Not authorized");
|
||||||
const err = new Error();
|
const err = new Error();
|
||||||
err["message"] =
|
err["message"] =
|
||||||
xhr.status === 0
|
xhr.status === 0
|
||||||
@@ -385,6 +386,7 @@ function _fulfill(
|
|||||||
filter: memoizedStringify(filter),
|
filter: memoizedStringify(filter),
|
||||||
}),
|
}),
|
||||||
extract: (xhr) => {
|
extract: (xhr) => {
|
||||||
|
if (xhr.status === 403) throw new Error("Not authorized");
|
||||||
if (!xhr.status) {
|
if (!xhr.status) {
|
||||||
throw new Error("Server is unrachable");
|
throw new Error("Server is unrachable");
|
||||||
} else if (xhr.status !== 200) {
|
} else if (xhr.status !== 200) {
|
||||||
@@ -605,6 +607,7 @@ export function postTasks(
|
|||||||
url: `api/devices/${encodeURIComponent(deviceId)}/tasks`,
|
url: `api/devices/${encodeURIComponent(deviceId)}/tasks`,
|
||||||
body: tasks,
|
body: tasks,
|
||||||
extract: (xhr) => {
|
extract: (xhr) => {
|
||||||
|
if (xhr.status === 403) throw new Error("Not authorized");
|
||||||
if (xhr.status !== 200) throw new Error(xhr.response);
|
if (xhr.status !== 200) throw new Error(xhr.response);
|
||||||
const connectionRequestStatus = xhr.getResponseHeader(
|
const connectionRequestStatus = xhr.getResponseHeader(
|
||||||
"Connection-Request"
|
"Connection-Request"
|
||||||
@@ -675,6 +678,7 @@ export function resourceExists(resource: string, id: string): Promise<number> {
|
|||||||
filter: memoizedStringify(filter),
|
filter: memoizedStringify(filter),
|
||||||
}),
|
}),
|
||||||
extract: (xhr) => {
|
extract: (xhr) => {
|
||||||
|
if (xhr.status === 403) throw new Error("Not authorized");
|
||||||
if (!xhr.status) throw new Error("Server is unrachable");
|
if (!xhr.status) throw new Error("Server is unrachable");
|
||||||
else if (xhr.status !== 200)
|
else if (xhr.status !== 200)
|
||||||
throw new Error(`Unexpected response status code ${xhr.status}`);
|
throw new Error(`Unexpected response status code ${xhr.status}`);
|
||||||
|
|||||||
Reference in new issue
Block a user