From 95f622a597f57eabfeccf2a98f4759bbbee367db Mon Sep 17 00:00:00 2001 From: Lenin Alevski Date: Tue, 19 Oct 2021 17:42:59 -0700 Subject: [PATCH] fix: more fixes related to object name encoding (#1128) - removing limitation of characters for paths/folders - fixed object names with international characters inside paths Signed-off-by: Lenin Alevski --- portal-ui/src/common/utils.ts | 12 ++++++++++-- .../Objects/ListObjects/CreateFolderModal.tsx | 16 +--------------- .../Objects/ListObjects/DeleteObject.tsx | 13 +++++-------- .../Objects/ListObjects/ListObjects.tsx | 8 ++------ .../Objects/ObjectDetails/ObjectDetails.tsx | 6 ++++-- restapi/user_objects.go | 13 +++++++++++-- 6 files changed, 33 insertions(+), 35 deletions(-) diff --git a/portal-ui/src/common/utils.ts b/portal-ui/src/common/utils.ts index 480da889b..8a7c884ca 100644 --- a/portal-ui/src/common/utils.ts +++ b/portal-ui/src/common/utils.ts @@ -584,9 +584,17 @@ export const representationNumber = (number: number | undefined) => { }; export const encodeFileName = (name: string) => { - return btoa(unescape(encodeURIComponent(name))); + try { + return btoa(unescape(encodeURIComponent(name))); + } catch (err) { + return ""; + } }; export const decodeFileName = (text: string) => { - return decodeURIComponent(escape(window.atob(text))); + try { + return decodeURIComponent(escape(window.atob(text))); + } catch (err) { + return text; + } }; diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/CreateFolderModal.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/CreateFolderModal.tsx index bb6dc8667..c680b5bcd 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/CreateFolderModal.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/CreateFolderModal.tsx @@ -55,7 +55,6 @@ const CreateFolderModal = ({ classes, }: ICreateFolder) => { const [pathUrl, setPathUrl] = useState(""); - const [nameInputError, setNameInputError] = useState(""); const [isFormValid, setIsFormValid] = useState(false); const currentPath = `${bucketName}/${decodeFileName(folderName)}`; @@ -80,21 +79,9 @@ const CreateFolderModal = ({ onClose(); }; - const validPathURL = useCallback(() => { - const patternAgainst = /^[a-zA-Z0-9*'#-\[\]_/&.@\s()]+$/; // Only allow uppercase, numbers, dashes and underscores - if (patternAgainst.test(pathUrl)) { - setNameInputError(""); - return true; - } - setNameInputError( - "Please verify the folder path contains valid characters only (letters, numbers and some special characters)." - ); - return false; - }, [pathUrl]); - useEffect(() => { let valid = true; - if (pathUrl.trim().length === 0 || !validPathURL()) { + if (pathUrl.trim().length === 0) { valid = false; } setIsFormValid(valid); @@ -120,7 +107,6 @@ const CreateFolderModal = ({ setPathUrl(e.target.value); }} required - error={nameInputError} /> diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteObject.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteObject.tsx index 6d660fb07..44da42008 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteObject.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/DeleteObject.tsx @@ -28,6 +28,7 @@ import { import { setErrorSnackMessage } from "../../../../../../actions"; import { ErrorResponseHandler } from "../../../../../../common/types"; import api from "../../../../../../common/api"; +import { decodeFileName } from "../../../../../../common/utils"; interface IDeleteObjectProps { closeDeleteModalAndRefresh: (refresh: boolean) => void; @@ -50,13 +51,8 @@ const DeleteObject = ({ if (deleteLoading) { return; } - let recursive = false; - if (selectedObject.endsWith("/")) { - recursive = true; - } - // Escape object name - selectedObject = encodeURIComponent(selectedObject); - + const decodedSelectedObject = decodeFileName(selectedObject); + const recursive = decodedSelectedObject.endsWith("/"); api .invoke( "DELETE", @@ -85,7 +81,8 @@ const DeleteObject = ({ {deleteLoading && } - Are you sure you want to delete: {selectedObject}?{" "} + Are you sure you want to delete:{" "} + {decodeFileName(selectedObject)}?{" "} diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ListObjects.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ListObjects.tsx index 5ae01cab4..7110f7da5 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ListObjects.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ListObjects/ListObjects.tsx @@ -897,12 +897,8 @@ const ListObjects = ({ }, ]; - const ccPath = internalPaths.split("/").pop(); - - const pageTitle = ccPath !== "" ? decodeFileName(ccPath) : "/"; - // console.log("pageTitle", pageTitle); + const pageTitle = decodeFileName(internalPaths); const currentPath = pageTitle.split("/").filter((i: string) => i !== ""); - // console.log("currentPath", currentPath); return ( @@ -922,7 +918,7 @@ const ListObjects = ({ )} diff --git a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/ObjectDetails.tsx b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/ObjectDetails.tsx index 3b2a972fa..9dc70fef7 100644 --- a/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/ObjectDetails.tsx +++ b/portal-ui/src/screens/Console/Buckets/ListBuckets/Objects/ObjectDetails/ObjectDetails.tsx @@ -77,7 +77,7 @@ import EditIcon from "../../../../../../icons/EditIcon"; import SearchIcon from "../../../../../../icons/SearchIcon"; import ObjectBrowserIcon from "../../../../../../icons/ObjectBrowserIcon"; import PreviewFileContent from "../Preview/PreviewFileContent"; -import { decodeFileName } from "../../../../../../common/utils"; +import { decodeFileName, encodeFileName } from "../../../../../../common/utils"; const styles = (theme: Theme) => createStyles({ @@ -420,7 +420,9 @@ const ObjectDetails = ({ if (redirectBack) { const newPath = allPathData.join("/"); history.push( - `/buckets/${bucketName}/browse${newPath === "" ? "" : `/${newPath}`}` + `/buckets/${bucketName}/browse${ + newPath === "" ? "" : `/${encodeFileName(newPath)}` + }` ); } }; diff --git a/restapi/user_objects.go b/restapi/user_objects.go index be1cf9d44..02952c17f 100644 --- a/restapi/user_objects.go +++ b/restapi/user_objects.go @@ -328,7 +328,16 @@ func downloadObject(ctx context.Context, client MCClient, versionID *string) (io // getDeleteObjectResponse returns whether there was an error on deletion of object func getDeleteObjectResponse(session *models.Principal, params user_api.DeleteObjectParams) *models.Error { ctx := context.Background() - s3Client, err := newS3BucketClient(session, params.BucketName, params.Path) + var prefix string + if params.Path != "" { + encodedPrefix := SanitizeEncodedPrefix(params.Path) + decodedPrefix, err := base64.StdEncoding.DecodeString(encodedPrefix) + if err != nil { + return prepareError(err) + } + prefix = string(decodedPrefix) + } + s3Client, err := newS3BucketClient(session, params.BucketName, prefix) if err != nil { return prepareError(err) } @@ -343,7 +352,7 @@ func getDeleteObjectResponse(session *models.Principal, params user_api.DeleteOb if params.VersionID != nil { version = *params.VersionID } - err = deleteObjects(ctx, mcClient, params.BucketName, params.Path, version, rec) + err = deleteObjects(ctx, mcClient, params.BucketName, prefix, version, rec) if err != nil { return prepareError(err) }