fix(security): enforce ownership on private draft blob deletion
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
import { deleteBlob } from "../../../actions/azurestorage";
|
||||
import { respondError, respondSuccess } from "../middleware/apiResponse";
|
||||
import { getServerSession } from "next-auth/next";
|
||||
import { authOptions } from "../auth/[...nextauth]";
|
||||
|
||||
import nextConnect from "next-connect";
|
||||
import middleware from "../middleware/middleware";
|
||||
@@ -8,6 +10,22 @@ import middleware from "../middleware/middleware";
|
||||
const ApiProxy = nextConnect();
|
||||
ApiProxy.use(middleware);
|
||||
|
||||
const forbidden = (res) =>
|
||||
respondError(res, {
|
||||
status: 403,
|
||||
code: "FORBIDDEN",
|
||||
message: "Request not permitted"
|
||||
});
|
||||
|
||||
const hasValue = (value) =>
|
||||
typeof value === "string" && value.trim().length > 0;
|
||||
|
||||
const isValidContainer = (value) =>
|
||||
typeof value === "string" &&
|
||||
value.length >= 3 &&
|
||||
value.length <= 63 &&
|
||||
/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(value);
|
||||
|
||||
ApiProxy.get(async (req, res) => {
|
||||
const containerName = req.query.container;
|
||||
const casefolderID = req.query.casefolderID;
|
||||
@@ -15,14 +33,10 @@ ApiProxy.get(async (req, res) => {
|
||||
const checkHash = req.query.hash;
|
||||
|
||||
if (
|
||||
typeof containerName === "undefined" ||
|
||||
containerName.length === 0 ||
|
||||
typeof casefolderID === "undefined" ||
|
||||
casefolderID.length === 0 ||
|
||||
typeof blobName === "undefined" ||
|
||||
blobName.length === 0 ||
|
||||
typeof checkHash === "undefined" ||
|
||||
checkHash.length === 0
|
||||
!hasValue(containerName) ||
|
||||
!hasValue(casefolderID) ||
|
||||
!hasValue(blobName) ||
|
||||
!hasValue(checkHash)
|
||||
) {
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
@@ -34,6 +48,23 @@ ApiProxy.get(async (req, res) => {
|
||||
const casefolderIDTrimmed = casefolderID.trim();
|
||||
const blobNameTrimmed = blobName.trim();
|
||||
|
||||
if (!isValidContainer(containerName)) {
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "INVALID_REQUEST",
|
||||
message: "Invalid request"
|
||||
});
|
||||
}
|
||||
|
||||
const session = await getServerSession(req, res, authOptions(req, res));
|
||||
if (
|
||||
typeof session?.user?.id !== "string" ||
|
||||
session.user.id.length === 0 ||
|
||||
session.user.id !== containerName
|
||||
) {
|
||||
return forbidden(res);
|
||||
}
|
||||
|
||||
const hashCandidatePaths = [
|
||||
"/api/file/deleteawaitingsubmissionfromblob?container=" +
|
||||
containerName +
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
import { deleteBlob } from "../../../actions/azurestorage";
|
||||
import { respondError, respondSuccess } from "../middleware/apiResponse";
|
||||
import { getServerSession } from "next-auth/next";
|
||||
import { authOptions } from "../auth/[...nextauth]";
|
||||
|
||||
import nextConnect from "next-connect";
|
||||
import middleware from "../middleware/middleware";
|
||||
@@ -8,6 +10,22 @@ import middleware from "../middleware/middleware";
|
||||
const ApiProxy = nextConnect();
|
||||
ApiProxy.use(middleware);
|
||||
|
||||
const forbidden = (res) =>
|
||||
respondError(res, {
|
||||
status: 403,
|
||||
code: "FORBIDDEN",
|
||||
message: "Request not permitted"
|
||||
});
|
||||
|
||||
const hasValue = (value) =>
|
||||
typeof value === "string" && value.trim().length > 0;
|
||||
|
||||
const isValidContainer = (value) =>
|
||||
typeof value === "string" &&
|
||||
value.length >= 3 &&
|
||||
value.length <= 63 &&
|
||||
/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(value);
|
||||
|
||||
ApiProxy.get(async (req, res) => {
|
||||
const containerName = req.query.container;
|
||||
const casefolderID = req.query.casefolderID;
|
||||
@@ -15,14 +33,10 @@ ApiProxy.get(async (req, res) => {
|
||||
const checkHash = req.query.hash;
|
||||
|
||||
if (
|
||||
typeof containerName === "undefined" ||
|
||||
containerName.length === 0 ||
|
||||
typeof casefolderID === "undefined" ||
|
||||
casefolderID.length === 0 ||
|
||||
typeof blobName === "undefined" ||
|
||||
blobName.length === 0 ||
|
||||
typeof checkHash === "undefined" ||
|
||||
checkHash.length === 0
|
||||
!hasValue(containerName) ||
|
||||
!hasValue(casefolderID) ||
|
||||
!hasValue(blobName) ||
|
||||
!hasValue(checkHash)
|
||||
) {
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
@@ -34,6 +48,23 @@ ApiProxy.get(async (req, res) => {
|
||||
const casefolderIDTrimmed = casefolderID.trim();
|
||||
const blobNameTrimmed = blobName.trim();
|
||||
|
||||
if (!isValidContainer(containerName)) {
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "INVALID_REQUEST",
|
||||
message: "Invalid request"
|
||||
});
|
||||
}
|
||||
|
||||
const session = await getServerSession(req, res, authOptions(req, res));
|
||||
if (
|
||||
typeof session?.user?.id !== "string" ||
|
||||
session.user.id.length === 0 ||
|
||||
session.user.id !== containerName
|
||||
) {
|
||||
return forbidden(res);
|
||||
}
|
||||
|
||||
const hashCandidatePaths = [
|
||||
"/api/file/deleteblob?container=" +
|
||||
containerName +
|
||||
|
||||
Reference in New Issue
Block a user