From d31c52fe57e95681308cb348566db00f53fb69a4 Mon Sep 17 00:00:00 2001 From: arteevraina Date: Wed, 7 Jun 2023 11:59:39 +0530 Subject: [PATCH 1/4] fix: added security checks for apis --- flask/namespaces.py | 34 ++++++++++++++++++++++++++++++---- flask/packages.py | 18 ++++++++++++++++-- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/flask/namespaces.py b/flask/namespaces.py index 7f66c4d8..c7ba18f9 100644 --- a/flask/namespaces.py +++ b/flask/namespaces.py @@ -183,14 +183,27 @@ def namespace_packages(namespace): 200, ) -@app.route("/namespace//admins", methods=["GET"]) -@swag_from("documentation/get_namespace_admins.yaml", methods=["GET"]) +@app.route("/namespaces//admins", methods=["POST"]) +@swag_from("documentation/get_namespace_admins.yaml", methods=["POST"]) def namespace_admins(namespace): + uuid = request.form.get("uuid") + + if not uuid: + return jsonify({"code": 401, "message": "Unauthorized"}), 401 + + user = db.users.find_one({"uuid": uuid}) + + if not user: + return jsonify({"code": 404, "message": "User not found"}), 404 + namespace_doc = db.namespaces.find_one({"namespace": namespace}) if not namespace_doc: return jsonify({"code": 404, "message": "Namespace not found"}), 404 + if not user["_id"] in namespace_doc["admins"] and not user["_id"] in namespace_doc["maintainers"]: + return jsonify({"code": 401, "message": "Unauthorized"}), 401 + admins = [] for i in namespace_doc["admins"]: @@ -202,14 +215,27 @@ def namespace_admins(namespace): return jsonify({"code": 200, "users": admins}), 200 -@app.route("/namespace//maintainers", methods=["GET"]) -@swag_from("documentation/get_namespace_maintainers.yaml", methods=["GET"]) +@app.route("/namespaces//maintainers", methods=["POST"]) +@swag_from("documentation/get_namespace_maintainers.yaml", methods=["POST"]) def namespace_maintainers(namespace): + uuid = request.form.get("uuid") + + if not uuid: + return jsonify({"code": 401, "message": "Unauthorized"}), 401 + + user = db.users.find_one({"uuid": uuid}) + + if not user: + return jsonify({"code": 404, "message": "User not found"}), 404 + namespace_doc = db.namespaces.find_one({"namespace": namespace}) if not namespace_doc: return jsonify({"code": 404, "message": "Namespace not found"}), 404 + if not user["_id"] in namespace_doc["admins"] and not user["_id"] in namespace_doc["maintainers"]: + return jsonify({"code": 401, "message": "Unauthorized"}), 401 + maintainers = [] for i in namespace_doc["maintainers"]: diff --git a/flask/packages.py b/flask/packages.py index dbd8a0e7..ee544a21 100644 --- a/flask/packages.py +++ b/flask/packages.py @@ -582,9 +582,20 @@ def create_token_upload_token_package(namespace_name, package_name): ) return jsonify({"code": 200, "message": "Upload token created successfully", "uploadToken": upload_token}), 200 -@app.route("/packages///maintainers", methods=["GET"]) -@swag_from("documentation/package_maintainers.yaml", methods=["GET"]) + +@app.route("/packages///maintainers", methods=["POST"]) +@swag_from("documentation/package_maintainers.yaml", methods=["POST"]) def package_maintainers(namespace, package): + uuid = request.form.get("uuid") + + if not uuid: + return jsonify({"code": 401, "message": "Unauthorized"}), 401 + + user = db.users.find_one({"uuid": uuid}) + + if not user: + return jsonify({"code": 401, "message": "Unauthorized"}), 401 + namespace_doc = db.namespaces.find_one({"namespace": namespace}) if not namespace_doc: @@ -595,6 +606,9 @@ def package_maintainers(namespace, package): if not package_doc: return jsonify({"message": "Package not found", "code": 404}) + if str(user["_id"]) not in [str(obj_id) for obj_id in namespace_doc["maintainers"]] and str(user["_id"]) not in [str(obj_id) for obj_id in namespace_doc["admins"]] and str(user["_id"]) not in [str(obj_id) for obj_id in package_doc["maintainers"]]: + return jsonify({"code": 401, "message": "Unauthorized"}), 401 + maintainers = [] for i in package_doc["maintainers"]: From f032f3bc504ad6983d63819b0fbd889b45a4db09 Mon Sep 17 00:00:00 2001 From: arteevraina Date: Wed, 7 Jun 2023 12:00:01 +0530 Subject: [PATCH 2/4] feat: added error handling for users list dialog --- registry/src/pages/showUserListDialog.js | 5 +++++ registry/src/store/actions/userListActions.js | 11 ++++++++--- registry/src/store/reducers/userListReducer.js | 4 ++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/registry/src/pages/showUserListDialog.js b/registry/src/pages/showUserListDialog.js index b99f29bb..0d69d758 100644 --- a/registry/src/pages/showUserListDialog.js +++ b/registry/src/pages/showUserListDialog.js @@ -6,6 +6,9 @@ import { MDBIcon } from "mdbreact"; const ShowUserListDialog = (props) => { const users = useSelector((state) => state.userList.users); + const uuid = useSelector((state) => state.auth.uuid); + const error = useSelector((state) => state.userList.error); + const dispatch = useDispatch(); useEffect(() => { @@ -20,6 +23,7 @@ const ShowUserListDialog = (props) => { packageMaintainers: props.packagemaintainers, namespace: props.namespace, packageName: props.package, + uuid: uuid, }) ); }, [props.show]); @@ -36,6 +40,7 @@ const ShowUserListDialog = (props) => { + {error ?

{error}

: null} {users && users.length === 0 ?

No users found

: null} {users && users.map((user, index) => { diff --git a/registry/src/store/actions/userListActions.js b/registry/src/store/actions/userListActions.js index c66d4356..2828d61e 100644 --- a/registry/src/store/actions/userListActions.js +++ b/registry/src/store/actions/userListActions.js @@ -10,23 +10,27 @@ export const fetchUserListData = ({ packageMaintainers = false, namespace, packageName, + uuid, }) => { return async (dispatch) => { dispatch({ type: FETCH_USERS_LIST }); let url; + let formData = new FormData(); + formData.append("uuid", uuid); if (namespaceAdmins) { - url = `${process.env.REACT_APP_REGISTRY_API_URL}/namespace/${namespace}/admins`; + url = `${process.env.REACT_APP_REGISTRY_API_URL}/namespaces/${namespace}/admins`; } else if (namespaceMaintainers) { - url = `${process.env.REACT_APP_REGISTRY_API_URL}/namespace/${namespace}/maintainers`; + url = `${process.env.REACT_APP_REGISTRY_API_URL}/namespaces/${namespace}/maintainers`; } else if (packageMaintainers) { url = `${process.env.REACT_APP_REGISTRY_API_URL}/packages/${namespace}/${packageName}/maintainers`; } try { const result = await axios({ - method: "get", + method: "post", url: url, + data: formData, }); dispatch({ @@ -36,6 +40,7 @@ export const fetchUserListData = ({ }, }); } catch (error) { + console.log(error); dispatch({ type: FETCH_USERS_LIST_ERROR, payload: { diff --git a/registry/src/store/reducers/userListReducer.js b/registry/src/store/reducers/userListReducer.js index c33f0d15..85e12a1a 100644 --- a/registry/src/store/reducers/userListReducer.js +++ b/registry/src/store/reducers/userListReducer.js @@ -7,6 +7,7 @@ import { const initialState = { users: null, isLoading: true, + error: null, }; const userListReducer = (state = initialState, action) => { @@ -15,17 +16,20 @@ const userListReducer = (state = initialState, action) => { return { ...state, isLoading: true, + error: null, }; case FETCH_USERS_LIST_SUCCESS: return { ...state, users: action.payload.users, isLoading: false, + error: null, }; case FETCH_USERS_LIST_ERROR: return { ...state, isLoading: false, + error: action.payload.message, }; default: return state; From 85c740c8b07efce9d5b37d638207908a2f4b2b07 Mon Sep 17 00:00:00 2001 From: arteevraina Date: Wed, 7 Jun 2023 12:00:44 +0530 Subject: [PATCH 3/4] tests: fix tests for the apis --- tests/test_namespaces.py | 4 ++-- tests/test_packages.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_namespaces.py b/tests/test_namespaces.py index f049deaa..b6dbae3e 100644 --- a/tests/test_namespaces.py +++ b/tests/test_namespaces.py @@ -167,7 +167,7 @@ def test_namespace_maintainers_list(self): namespace_name = TestNamespaces.test_namespace_data['namespace'] # Get the list of maintainers. - response = self.client.get(f"/namespace/{namespace_name}/maintainers") + response = self.client.post(f"/namespaces/{namespace_name}/maintainers", data={"uuid": uuid}) self.assertEqual(200, response.json["code"]) self.assertEqual(1, len(response.json["users"])) @@ -198,6 +198,6 @@ def test_namespace_admins_list(self): namespace_name = TestNamespaces.test_namespace_data['namespace'] # Get the list of admins. - response = self.client.get(f"/namespace/{namespace_name}/admins") + response = self.client.post(f"/namespaces/{namespace_name}/admins", data={"uuid": uuid}) self.assertEqual(200, response.json["code"]) self.assertEqual(1, len(response.json["users"])) \ No newline at end of file diff --git a/tests/test_packages.py b/tests/test_packages.py index 96ee171f..9b0d7c6a 100644 --- a/tests/test_packages.py +++ b/tests/test_packages.py @@ -521,5 +521,5 @@ def test_package_maintainers(self): response = self.client.post("/packages", data=TestPackages.test_package_data) self.assertEqual(200, response.json["code"]) - response = self.client.get(f"/packages/{TestPackages.test_namespace_data['namespace']}/{TestPackages.test_package_data['package_name']}/maintainers") + response = self.client.post(f"/packages/{TestPackages.test_namespace_data['namespace']}/{TestPackages.test_package_data['package_name']}/maintainers", data={"uuid": uuid}) self.assertEqual(200, response.json["code"]) \ No newline at end of file From 4ab4666b69c57dd5d98daeea7a5f2e8d6c1ad765 Mon Sep 17 00:00:00 2001 From: arteevraina Date: Wed, 7 Jun 2023 12:29:25 +0530 Subject: [PATCH 4/4] docs: updated documentation after changes in the api --- flask/documentation/get_namespace_admins.yaml | 14 ++++++++--- .../get_namespace_maintainers.yaml | 24 +++++++++++++++++-- flask/documentation/package_maintainers.yaml | 20 +++++++++++++++- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/flask/documentation/get_namespace_admins.yaml b/flask/documentation/get_namespace_admins.yaml index 57344176..4cce51f4 100644 --- a/flask/documentation/get_namespace_admins.yaml +++ b/flask/documentation/get_namespace_admins.yaml @@ -1,10 +1,18 @@ -description: Get admins of a namespace. +description: Verifies by uuid of the user and gets the namespace admins. + parameters: - name: namespace in: path description: Namespace name required: true type: string + + - name: uuid + in: formData + required: true + type: string + description: UUID of the user + responses: 200: description: Admins found @@ -12,7 +20,7 @@ responses: type: object properties: code: - type: string + type: integer description: Response status code admins: type: array @@ -32,7 +40,7 @@ responses: type: object properties: code: - type: string + type: integer description: Response status code message: type: string diff --git a/flask/documentation/get_namespace_maintainers.yaml b/flask/documentation/get_namespace_maintainers.yaml index 014fbfb7..152c9255 100644 --- a/flask/documentation/get_namespace_maintainers.yaml +++ b/flask/documentation/get_namespace_maintainers.yaml @@ -1,10 +1,18 @@ -description: Get maintainers of a namespace. +description: Verifies using uuid of the user and gets the namespace maintainers. + parameters: - name: namespace in: path description: Namespace name required: true type: string + + - name: uuid + in: formData + description: UUID of the user + required: true + type: string + responses: 200: description: Maintainers found @@ -32,8 +40,20 @@ responses: type: object properties: code: - type: string + type: integer description: Response status code message: type: string description: Error message + + 401: + description: Unauthorized access + schema: + type: object + properties: + code: + type: integer + description: Response status code + message: + type: string + description: Unauthorized access diff --git a/flask/documentation/package_maintainers.yaml b/flask/documentation/package_maintainers.yaml index 2fa87836..2565d3a8 100644 --- a/flask/documentation/package_maintainers.yaml +++ b/flask/documentation/package_maintainers.yaml @@ -1,4 +1,4 @@ -description: Gets package maintainers of a package. +description: Verifies by uuid and gets the package maintainers. parameters: - name: namespace @@ -13,6 +13,12 @@ parameters: required: true type: string + - name: uuid + in: formData + required: true + type: string + description: UUID of the user + responses: 200: description: Package Found. @@ -46,3 +52,15 @@ responses: message: type: string description: Package or Namespace not found. + + 401: + description: Unauthorized access + schema: + type: object + properties: + code: + type: integer + description: response status code + message: + type: string + description: Unauthorized access