diff --git a/backend/packages.py b/backend/packages.py index f289761c..413d8601 100644 --- a/backend/packages.py +++ b/backend/packages.py @@ -993,12 +993,14 @@ def view_report(): if "admin" in user["roles"]: non_viewed_reports = list() - malicious_reports = db.packages.find({"malicious_reports.isViewed": False}) + malicious_reports = db.packages.find({"malicious_report.isViewed": False}) for package in list(malicious_reports): for user_id, report in package.get("malicious_report", {}).get("users", {}).items(): if not report.get("isViewed", False): report['name'] = db.users.find_one({"_id": ObjectId(user_id)}, {"username": 1})["username"] del report["isViewed"] + report["package"] = package["name"] + report["namespace"] = db.namespaces.find_one({"_id": package["namespace"]}, {"namespace": 1})["namespace"] non_viewed_reports.append(report) return jsonify({"message": "Malicious Reports fetched Successfully", "code": 200, "reports": non_viewed_reports}), 200 diff --git a/backend/user.py b/backend/user.py index 2acff09f..4bf7e027 100644 --- a/backend/user.py +++ b/backend/user.py @@ -7,6 +7,7 @@ from app import swagger from flasgger.utils import swag_from from auth import forgot_password +from flask_jwt_extended import jwt_required, get_jwt_identity load_dotenv() @@ -194,8 +195,10 @@ def account(): @app.route("/users/admin", methods=["POST"]) @swag_from("documentation/check_admin_user.yaml", methods=["POST"]) +@jwt_required() def admin(): - uuid = request.form.get("uuid") + uuid = get_jwt_identity() + if not uuid: return jsonify({"message": "Unauthorized", "code": 401}), 401 else: diff --git a/frontend/src/pages/admin.js b/frontend/src/pages/admin.js index b401339a..446f796f 100644 --- a/frontend/src/pages/admin.js +++ b/frontend/src/pages/admin.js @@ -20,18 +20,26 @@ import { deleteRelease, deprecatePackage, } from "../store/actions/adminActions"; +import ViewMalicousReports from "./viewMalicousReports"; import NoPage from "./404"; const AdminSection = () => { const uuid = useSelector((state) => state.auth.uuid); + const accessToken = useSelector((state) => state.auth.accessToken); const dispatch = useDispatch(); const message = useSelector((state) => state.admin.message); const statuscode = useSelector((state) => state.admin.statuscode); const isAuthenticated = useSelector((state) => state.auth.isAuthenticated); const isAdmin = useSelector((state) => state.admin.isAdmin); + const [showReports, setShowReports] = useState(false); + + const handleShowReports = (value) => { + setShowReports(value); + }; + useEffect(() => { - dispatch(adminAuth(uuid)); + dispatch(adminAuth(accessToken)); }, [isAuthenticated, uuid]); useEffect(() => { @@ -207,10 +215,18 @@ const AdminSection = () => { // }); // }; - return isAdmin? ( + return isAdmin ? ( -

Admin Settings

+
+

View Malicious Reports

+ +

Delete package

@@ -361,6 +377,10 @@ const AdminSection = () => { Change Password

*/} + handleShowReports(false)} + /> @@ -386,7 +406,9 @@ const AdminSection = () => {
- ):(); + ) : ( + + ); }; export default AdminSection; diff --git a/frontend/src/pages/viewMalicousReports.js b/frontend/src/pages/viewMalicousReports.js new file mode 100644 index 00000000..8a728706 --- /dev/null +++ b/frontend/src/pages/viewMalicousReports.js @@ -0,0 +1,60 @@ +import { useState, useEffect } from "react"; +import { useDispatch, useSelector } from "react-redux"; +import { Card, Container, Modal, Spinner } from "react-bootstrap"; +import { + fetchMalicousReports, + resetData, +} from "../store/actions/viewMalicousReportActions"; + +const ViewMalicousReports = (props) => { + const accessToken = useSelector((state) => state.auth.accessToken); + const reports = useSelector((state) => state.malicousReport.reports); + const loading = useSelector((state) => state.malicousReport.isLoading); + const dispatch = useDispatch(); + + useEffect(() => { + if (!props.show) { + return; + } + + dispatch(fetchMalicousReports(accessToken)); + }, [props.show]); + + const onExit = () => { + dispatch(resetData()); + }; + + return ( + + + View Malicious Reports + + + {loading && ( +
+ + Loading... + +
+ )} + {reports.map((report, index) => { + return ( + + +
Namespace - {report.namespace}
+
Package - {report.package}
+

{report.reason}

+
+
+ ); + })} +
+
+ ); +}; + +export default ViewMalicousReports; diff --git a/frontend/src/store/actions/adminActions.js b/frontend/src/store/actions/adminActions.js index f95843f6..9fd6b62a 100644 --- a/frontend/src/store/actions/adminActions.js +++ b/frontend/src/store/actions/adminActions.js @@ -18,10 +18,9 @@ export const ADMIN_AUTH_SUCCESS = "ADMIN_AUTH_SUCCESS"; export const DELETE_PACKAGE_SUCCESS = "DELETE_PACKAGE_SUCCESS"; export const DELETE_PACKAGE_ERROR = "DELETE_PACKAGE_ERROR"; -export const adminAuth = (uuid) => async (dispatch) => { +export const adminAuth = (accessToken) => async (dispatch) => { // Make an api call to authenticate admin let formData = new FormData(); - formData.append("uuid", uuid); try { let result = await axios({ @@ -30,6 +29,7 @@ export const adminAuth = (uuid) => async (dispatch) => { data: formData, headers: { "Content-Type": "multipart/form-data", + Authorization: `Bearer ${accessToken}`, }, }); @@ -157,7 +157,7 @@ export const deleteNamespace = (namespace, uuid) => async (dispatch) => { export const deletePackage = (namespacename, packagename, uuid) => async (dispatch) => { - // Make an api call to delete package + // Make an api call to delete package let formData = new FormData(); formData.append("uuid", uuid); @@ -204,7 +204,7 @@ export const deletePackage = export const deleteRelease = (namespace_name, package_name, version, uuid) => async (dispatch) => { - // Make an api call to delete package release + // Make an api call to delete package release let formData = new FormData(); formData.append("uuid", uuid); diff --git a/frontend/src/store/actions/viewMalicousReportActions.js b/frontend/src/store/actions/viewMalicousReportActions.js new file mode 100644 index 00000000..a5905546 --- /dev/null +++ b/frontend/src/store/actions/viewMalicousReportActions.js @@ -0,0 +1,43 @@ +import axios from "axios"; + +export const FETCH_MALICIOUS_REPORTS = "FETCH_MALICIOUS_REPORTS"; +export const FETCH_MALICIOUS_REPORTS_SUCCESS = + "FETCH_MALICIOUS_REPORTS_SUCCESS"; +export const FETCH_MALICIOUS_REPORTS_ERROR = "FETCH_MALICIOUS_REPORTS_ERROR"; +export const RESET_DATA = "RESET_DATA"; + +export const fetchMalicousReports = (accessToken) => { + return async (dispatch) => { + dispatch({ type: FETCH_MALICIOUS_REPORTS }); + try { + const result = await axios({ + method: "get", + url: `${process.env.REACT_APP_REGISTRY_API_URL}/report/view`, + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }); + + dispatch({ + type: FETCH_MALICIOUS_REPORTS_SUCCESS, + payload: { + reports: result.data.reports, + }, + }); + } catch (error) { + dispatch({ + type: FETCH_MALICIOUS_REPORTS_ERROR, + payload: { + statuscode: error.response.data.code, + message: error.response.data.message, + }, + }); + } + }; +}; + +export const resetData = () => (dispatch) => { + dispatch({ + type: RESET_DATA, + }); +}; diff --git a/frontend/src/store/reducers/rootReducer.js b/frontend/src/store/reducers/rootReducer.js index 4865194b..5d8f1858 100644 --- a/frontend/src/store/reducers/rootReducer.js +++ b/frontend/src/store/reducers/rootReducer.js @@ -18,6 +18,7 @@ import addRemoveNamespaceAdminReducer from "./namespaceAdminReducer"; import verifyEmailReducer from "./verifyEmailReducer"; import userListReducer from "./userListReducer"; import reportPackageReducer from "./reportPackageReducer"; +import viewMalicousReportsReducer from "./viewMalicousReportsReducer"; const rootReducer = combineReducers({ auth: authReducer, @@ -39,6 +40,7 @@ const rootReducer = combineReducers({ userList: userListReducer, archives: archivesReducer, reportPackage: reportPackageReducer, + malicousReport: viewMalicousReportsReducer, }); export default rootReducer; diff --git a/frontend/src/store/reducers/viewMalicousReportsReducer.js b/frontend/src/store/reducers/viewMalicousReportsReducer.js new file mode 100644 index 00000000..8afed31a --- /dev/null +++ b/frontend/src/store/reducers/viewMalicousReportsReducer.js @@ -0,0 +1,46 @@ +import { + FETCH_MALICIOUS_REPORTS, + FETCH_MALICIOUS_REPORTS_SUCCESS, + FETCH_MALICIOUS_REPORTS_ERROR, + RESET_DATA, +} from "../actions/viewMalicousReportActions"; + +const initialState = { + reports: [], + isLoading: false, + error: null, +}; + +const viewMalicousReportsReducer = (state = initialState, action) => { + switch (action.type) { + case FETCH_MALICIOUS_REPORTS: + return { + ...state, + isLoading: true, + error: null, + }; + case FETCH_MALICIOUS_REPORTS_SUCCESS: + return { + ...state, + reports: action.payload.reports, + isLoading: false, + error: null, + }; + case FETCH_MALICIOUS_REPORTS_ERROR: + return { + ...state, + isLoading: false, + error: action.payload.message, + }; + case RESET_DATA: + return { + reports: [], + isLoading: false, + error: null, + }; + default: + return state; + } +}; + +export default viewMalicousReportsReducer;