Skip to content

Commit d8b3874

Browse files
authored
Enable/Disable upload file and folder button for bucket (#1486)
1 parent 2e9a423 commit d8b3874

File tree

3 files changed

+117
-65
lines changed

3 files changed

+117
-65
lines changed

portal-ui/src/common/SecureComponent/SecureComponent.tsx

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ import { hasAccessToResource } from "./permissions";
2121
export const hasPermission = (
2222
resource: string | undefined,
2323
scopes: string[],
24-
matchAll?: boolean
24+
matchAll?: boolean,
25+
containsResource?: boolean
2526
) => {
2627
if (!resource) {
2728
return false;
@@ -33,8 +34,17 @@ export const hasPermission = (
3334
sessionGrants[`arn:aws:s3:::${resource}/*`] ||
3435
[];
3536
const globalGrants = sessionGrants["arn:aws:s3:::*"] || [];
37+
let containsResourceGrants: string[] = [];
38+
if (containsResource) {
39+
const matchResource = `arn:aws:s3:::${resource}`;
40+
for (const [key, value] of Object.entries(sessionGrants)) {
41+
if (key.includes(matchResource)) {
42+
containsResourceGrants = containsResourceGrants.concat(value);
43+
}
44+
}
45+
}
3646
return hasAccessToResource(
37-
[...resourceGrants, ...globalGrants],
47+
[...resourceGrants, ...globalGrants, ...containsResourceGrants],
3848
scopes,
3949
matchAll
4050
);
@@ -47,6 +57,7 @@ interface ISecureComponentProps {
4757
children: any;
4858
scopes: string[];
4959
resource: string;
60+
containsResource?: boolean;
5061
}
5162

5263
const SecureComponent = ({
@@ -56,8 +67,14 @@ const SecureComponent = ({
5667
matchAll = false,
5768
scopes = [],
5869
resource,
70+
containsResource = false,
5971
}: ISecureComponentProps) => {
60-
const permissionGranted = hasPermission(resource, scopes, matchAll);
72+
const permissionGranted = hasPermission(
73+
resource,
74+
scopes,
75+
matchAll,
76+
containsResource
77+
);
6178
if (!permissionGranted && !errorProps) return <RenderError />;
6279
if (!permissionGranted && errorProps) {
6380
return Array.isArray(children) ? (

portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ListObjects.tsx

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ const styles = (theme: Theme) =>
142142
right: 1,
143143
width: 5,
144144
height: 5,
145-
minWidth: 5
145+
minWidth: 5,
146146
},
147147
},
148148
screenTitle: {
@@ -764,7 +764,12 @@ const ListObjects = ({
764764
xhr.status === 400 ||
765765
xhr.status === 500
766766
) {
767-
setSnackBarMessage(errorMessage);
767+
if (xhr.response) {
768+
const err = JSON.parse(xhr.response);
769+
setSnackBarMessage(err.detailedMessage);
770+
} else {
771+
setSnackBarMessage(errorMessage);
772+
}
768773
}
769774
if (xhr.status === 413) {
770775
setSnackBarMessage("Error - File size too large");
@@ -1061,7 +1066,10 @@ const ListObjects = ({
10611066
});
10621067
}
10631068
};
1064-
1069+
let uploadPath = [bucketName];
1070+
if (currentPath.length > 0) {
1071+
uploadPath = uploadPath.concat(currentPath);
1072+
}
10651073
return (
10661074
<React.Fragment>
10671075
{shareFileModalOpen && selectedPreview && (
@@ -1131,42 +1139,36 @@ const ListObjects = ({
11311139
}
11321140
actions={
11331141
<Fragment>
1134-
<SecureComponent
1135-
resource={bucketName}
1136-
scopes={[IAM_SCOPES.S3_PUT_OBJECT]}
1137-
errorProps={{ disabled: true }}
1138-
>
1139-
<Fragment>
1140-
<UploadFilesButton
1141-
uploadFileFunction={(closeMenu) => {
1142-
if (fileUpload && fileUpload.current) {
1143-
fileUpload.current.click();
1144-
}
1145-
closeMenu();
1146-
}}
1147-
uploadFolderFunction={(closeMenu) => {
1148-
if (folderUpload && folderUpload.current) {
1149-
folderUpload.current.click();
1150-
}
1151-
closeMenu();
1152-
}}
1153-
/>
1154-
<input
1155-
type="file"
1156-
multiple
1157-
onChange={handleUploadButton}
1158-
style={{ display: "none" }}
1159-
ref={fileUpload}
1160-
/>
1161-
<input
1162-
type="file"
1163-
multiple
1164-
onChange={handleUploadButton}
1165-
style={{ display: "none" }}
1166-
ref={folderUpload}
1167-
/>
1168-
</Fragment>
1169-
</SecureComponent>
1142+
<input
1143+
type="file"
1144+
multiple
1145+
onChange={handleUploadButton}
1146+
style={{ display: "none" }}
1147+
ref={fileUpload}
1148+
/>
1149+
<input
1150+
type="file"
1151+
multiple
1152+
onChange={handleUploadButton}
1153+
style={{ display: "none" }}
1154+
ref={folderUpload}
1155+
/>
1156+
<UploadFilesButton
1157+
bucketName={bucketName}
1158+
uploadPath={uploadPath.join("/")}
1159+
uploadFileFunction={(closeMenu) => {
1160+
if (fileUpload && fileUpload.current) {
1161+
fileUpload.current.click();
1162+
}
1163+
closeMenu();
1164+
}}
1165+
uploadFolderFunction={(closeMenu) => {
1166+
if (folderUpload && folderUpload.current) {
1167+
folderUpload.current.click();
1168+
}
1169+
closeMenu();
1170+
}}
1171+
/>
11701172
</Fragment>
11711173
}
11721174
/>

portal-ui/src/screens/Console/Buckets/ListBuckets/UploadFilesButton.tsx

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,15 @@ import ListItemText from "@mui/material/ListItemText";
2323
import ListItemIcon from "@mui/material/ListItemIcon";
2424
import { UploadFolderIcon, UploadIcon } from "../../../../icons";
2525
import RBIconButton from "../BucketDetails/SummaryItems/RBIconButton";
26+
import { IAM_SCOPES } from "../../../../common/SecureComponent/permissions";
27+
import SecureComponent, {
28+
hasPermission,
29+
} from "../../../../common/SecureComponent/SecureComponent";
2630

2731
interface IUploadFilesButton {
28-
buttonDisabled?: boolean;
32+
uploadPath: string;
33+
bucketName: string;
34+
forceDisable?: boolean;
2935
uploadFileFunction: (closeFunction: () => void) => void;
3036
uploadFolderFunction: (closeFunction: () => void) => void;
3137
classes: any;
@@ -43,7 +49,9 @@ const styles = (theme: Theme) =>
4349
});
4450

4551
const UploadFilesButton = ({
46-
buttonDisabled = false,
52+
uploadPath,
53+
bucketName,
54+
forceDisable = false,
4755
uploadFileFunction,
4856
uploadFolderFunction,
4957
classes,
@@ -57,6 +65,18 @@ const UploadFilesButton = ({
5765
setAnchorEl(null);
5866
};
5967

68+
const uploadObjectAllowed = hasPermission(uploadPath, [
69+
IAM_SCOPES.S3_PUT_OBJECT,
70+
]);
71+
const uploadFolderAllowed = hasPermission(
72+
bucketName,
73+
[IAM_SCOPES.S3_PUT_OBJECT],
74+
false,
75+
true
76+
);
77+
78+
const uploadEnabled: boolean = uploadObjectAllowed || uploadFolderAllowed;
79+
6080
return (
6181
<Fragment>
6282
<RBIconButton
@@ -70,7 +90,7 @@ const UploadFilesButton = ({
7090
icon={<UploadIcon />}
7191
color="primary"
7292
variant={"contained"}
73-
disabled={buttonDisabled}
93+
disabled={forceDisable || !uploadEnabled}
7494
/>
7595
<Menu
7696
id={`upload-main-menu`}
@@ -89,28 +109,41 @@ const UploadFilesButton = ({
89109
horizontal: "center",
90110
}}
91111
>
92-
<MenuItem
93-
onClick={() => {
94-
uploadFileFunction(handleCloseUpload);
95-
}}
96-
disabled={buttonDisabled}
112+
<SecureComponent
113+
resource={uploadPath}
114+
scopes={[IAM_SCOPES.S3_PUT_OBJECT]}
115+
errorProps={{ disabled: true }}
97116
>
98-
<ListItemIcon className={classes.listUploadIcons}>
99-
<UploadIcon />
100-
</ListItemIcon>{" "}
101-
<ListItemText>Upload File</ListItemText>
102-
</MenuItem>
103-
<MenuItem
104-
onClick={() => {
105-
uploadFolderFunction(handleCloseUpload);
106-
}}
107-
disabled={buttonDisabled}
117+
<MenuItem
118+
onClick={() => {
119+
uploadFileFunction(handleCloseUpload);
120+
}}
121+
disabled={forceDisable}
122+
>
123+
<ListItemIcon className={classes.listUploadIcons}>
124+
<UploadIcon />
125+
</ListItemIcon>
126+
<ListItemText>Upload File</ListItemText>
127+
</MenuItem>
128+
</SecureComponent>
129+
<SecureComponent
130+
resource={bucketName}
131+
containsResource
132+
scopes={[IAM_SCOPES.S3_PUT_OBJECT]}
133+
errorProps={{ disabled: true }}
108134
>
109-
<ListItemIcon className={classes.listUploadIcons}>
110-
<UploadFolderIcon />
111-
</ListItemIcon>{" "}
112-
<ListItemText>Upload Folder</ListItemText>
113-
</MenuItem>
135+
<MenuItem
136+
onClick={() => {
137+
uploadFolderFunction(handleCloseUpload);
138+
}}
139+
disabled={forceDisable}
140+
>
141+
<ListItemIcon className={classes.listUploadIcons}>
142+
<UploadFolderIcon />
143+
</ListItemIcon>
144+
<ListItemText>Upload Folder</ListItemText>
145+
</MenuItem>
146+
</SecureComponent>
114147
</Menu>
115148
</Fragment>
116149
);

0 commit comments

Comments
 (0)