diff --git a/sysom_web/config/defaultSettings.js b/sysom_web/config/defaultSettings.js
index fe5df0f9252b9b12f494093b997af9038d00418f..14dbf778d6792271106fb5c6dd64c57ef70397dd 100644
--- a/sysom_web/config/defaultSettings.js
+++ b/sysom_web/config/defaultSettings.js
@@ -5,7 +5,7 @@ const Settings = {
contentWidth: 'Fluid',
fixedHeader: true,
fixSiderbar: true,
- title: '系统运维平台',
- logo: null,
+ title: '统信有幄UMOP',
+ logo: '/logo.png',
};
-export default Settings;
\ No newline at end of file
+export default Settings;
diff --git a/sysom_web/package.json b/sysom_web/package.json
index 68a95463998d6b818806d614927d56cb19aa00b6..7b85834d827db61c760bd0a7025436d6be4476f5 100644
--- a/sysom_web/package.json
+++ b/sysom_web/package.json
@@ -57,6 +57,8 @@
"@umijs/route-utils": "^2.0.3",
"antd": "4.17.0",
"axios": "^0.26.1",
+ "browserslist": "^4.20.2",
+ "caniuse-lite": "^1.0.30001320",
"classnames": "^2.2.6",
"lodash": "^4.17.11",
"moment": "^2.25.3",
diff --git a/sysom_web/public/logo.png b/sysom_web/public/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..ef27172d4cf33aaea317029595a55f7703ad1eff
Binary files /dev/null and b/sysom_web/public/logo.png differ
diff --git a/sysom_web/src/global.less b/sysom_web/src/global.less
index a58f01c7be4044f080e5051a507d33bc21194654..884dd5f96a050b4f1ee290c172bf4ca6bcd8721f 100644
--- a/sysom_web/src/global.less
+++ b/sysom_web/src/global.less
@@ -24,7 +24,20 @@ body,
.ant-pro-global-footer-links{
margin: 0;
}
-
+
+.ant-pro-top-nav-header-logo h1{
+ color: rgba(255, 255, 255, 0.65);
+ line-height: 48px;
+ font-size: 15px;
+ font-weight: bold;
+}
+
+.ant-pro-top-nav-header-logo img{
+ padding-right:20px;
+ height:15px;
+ vertical-align: text-top;
+ border-right: 1px solid rgba(255, 255, 255, 0.65);
+}
canvas {
display: block;
@@ -66,4 +79,4 @@ ol {
}
.ant-carousel .slick-dots li button{background: #fff !important;}
-.ant-carousel .slick-dots li.slick-active button{background: #fff !important;}
\ No newline at end of file
+.ant-carousel .slick-dots li.slick-active button{background: #fff !important;}
diff --git a/sysom_web/src/locales/zh-CN/component.js b/sysom_web/src/locales/zh-CN/component.js
index 1f1feadbf6f1494e8da6a1e781a87399f1c46a8a..d67dbf10ae4148c68e6e235e250c46b395958d60 100644
--- a/sysom_web/src/locales/zh-CN/component.js
+++ b/sysom_web/src/locales/zh-CN/component.js
@@ -2,4 +2,14 @@ export default {
'component.tagSelect.expand': '展开',
'component.tagSelect.collapse': '收起',
'component.tagSelect.all': '全部',
+ 'component.ListCard.needed_to_repair': '需要修复的漏洞(CVE)',
+ 'component.ListCard.high_needed_to_repair': '需要修复的高危漏洞(CVE)',
+ 'component.ListCard.hosts_with_vul': '存在漏洞的主机',
+ 'component.ListCard.today_repaired': '今日已修复漏洞',
+ 'component.ListCard.cumulate_repaired': '累计已修复漏洞',
+ 'component.ListCard.latest_scan_time': '最新扫描时间',
+ 'component.ListCard.scan': '一键扫描',
+ 'component.ListCard.scanning': '扫描中',
+ 'component.ListCard.success': '扫描成功',
+ 'component.ListCard.failed': '扫描失败'
};
diff --git a/sysom_web/src/locales/zh-CN/pages.js b/sysom_web/src/locales/zh-CN/pages.js
index f1b60c96137e5db93ac37fafebce74f99d38e4c5..e5ac9e06726b536d84542463aaca8a20f16a26b5 100644
--- a/sysom_web/src/locales/zh-CN/pages.js
+++ b/sysom_web/src/locales/zh-CN/pages.js
@@ -71,5 +71,47 @@ export default {
'pages.journal.task.params': '参数列表',
'pages.journal.task.success': '成功',
'pages.journal.task.fail': '失败',
-
-};
+ 'pages.security.list.index':'序号',
+ 'pages.security.list.cve_id':'编号',
+ 'pages.security.list.pub_time':'发布时间',
+ 'pages.security.list.vul_level':'漏洞等级',
+ 'pages.security.list.hosts':'涉及主机',
+ 'pages.security.list.operation':'操作',
+ 'pages.security.list.high':'高危',
+ 'pages.security.list.medium':'中危',
+ 'pages.security.list.critical':'严重',
+ 'pages.security.list.low':'低危',
+ 'pages.security.list.repair':'修复',
+ 'pages.security.list.confirm':'确认修复吗',
+ 'pages.security.list.re':'正在修复中...',
+ 'pages.security.list.error':'修复出错了,',
+ 'pages.security.list.details':'查看详情,',
+ 'pages.security.Homelist.name':'软件名称',
+ 'pages.security.Homelist.vul_level':'严重程度',
+ 'pages.security.Homelist.fixed_version':'修复版本',
+ 'pages.security.Homelist.hostname':'主机名称',
+ 'pages.security.Homelist.ip':'IP地址',
+ 'pages.security.Homelist.created_by':'用户',
+ 'pages.security.Homelist.created_at':'创建时间',
+ 'pages.security.Homelist.status':'主机状态',
+ 'pages.security.Homelist.re':'修复中',
+ 'pages.security.Historical.title': '历史修复漏洞信息',
+ 'pages.security.Historical.id': '序号',
+ 'pages.security.Historical.cve_id': 'cve编号',
+ 'pages.security.Historical.fixed_time': '修复时间',
+ 'pages.security.Historical.fix_user': '修复者',
+ 'pages.security.Historical.vul_level': '漏洞等级',
+ 'pages.security.Historical.severe_risk': '严重',
+ 'pages.security.Historical.high_risk': '高危',
+ 'pages.security.Historical.medium_risk': '中危',
+ 'pages.security.Historical.low_risk': '低危',
+ 'pages.security.Historical.fix_status': 'cve修复状态',
+ 'pages.security.Historical.details': '查看详情',
+ 'pages.security.Historical.back': '返回',
+ 'pages.security.Historical.created_at': '创建时间',
+ 'pages.security.Historical.success': '成功',
+ 'pages.security.Historical.fail': '失败',
+ 'pages.security.Historical.fix_details': 'CVE修复详情',
+ 'pages.security.Historical.fix_success': 'CVE修复成功',
+ 'pages.security.Historical.fix_fail': 'CVE修复失败,失败原因:'
+};
\ No newline at end of file
diff --git a/sysom_web/src/pages/security/Historical/index.jsx b/sysom_web/src/pages/security/Historical/index.jsx
index 209b4b5b6b6c5cc7cd54e8fd49faa02bc3e7429b..66aeb052cd65c95833f0a1720eaccbe9723932fa 100644
--- a/sysom_web/src/pages/security/Historical/index.jsx
+++ b/sysom_web/src/pages/security/Historical/index.jsx
@@ -1,117 +1,112 @@
-import React ,{useState,useEffect}from 'react';
-import {Button,Card,Table,Col,Row} from 'antd'
+import { useState, useEffect } from 'react';
+import { useIntl, FormattedMessage } from 'umi';
+import { Button, Col, Row } from 'antd'
import './hist.less'
-import {histApi} from '../service'
+import { histApi } from '../service'
import { PageContainer } from '@ant-design/pro-layout';
-
+import ProTable from '@ant-design/pro-table';
+
function index(props) {
- const [dataSource,setdataSource]=useState([])
- const [total,setTotal]=useState(0)
- useEffect(async() => {
- const msg=await histApi()
- setdataSource(msg.data)
- }, []);
- const columns=[
-
- {
- title: "序号",
- key: "id",
- width: 80,
- align: "center",
- render: (txt, record, index) => index + 1,
- },
+ const intl = useIntl();
+ const columns = [
+ {
+ title: ,
+ key: "id",
+ width: 80,
+ align: "center",
+ render: (txt, record, index) => index + 1,
+ },
{
- title:"cve编号",
- dataIndex:'cve_id',
- key:'cve_id',
+ title: ,
+ dataIndex: 'cve_id',
+ key: 'cve_id',
align: "center",
},
{
- title:"修复时间",
- dataIndex:"fixed_time",
- key:"fixed_time",
+ title: ,
+ dataIndex: "fixed_time",
+ key: "fixed_time",
align: "center",
},
{
- title:"修复者",
- dataIndex:"fix_user",
- key:"fix_user",
+ title: ,
+ dataIndex: "fix_user",
+ key: "fix_user",
align: "center",
},
{
- title:"漏洞等级",
- dataIndex:"vul_level",
- key:"vul_level",
+ title: ,
+ dataIndex: "vul_level",
+ key: "vul_level",
align: "center",
- render:(txt,record)=>{
-
- if(record.vul_level=="high"){
- return
高危
- }else if(record.vul_level=="medium"){
- return 中危
- }else if(record.vul_level=="critical"){
- return 严重
- }else if (record.vul_level == "low") {
- return 低危
;
+ render: (txt, record) => {
+ if (record.vul_level == "high") {
+ return
+ } else if (record.vul_level == "medium") {
+ return
+ } else if (record.vul_level == "critical") {
+ return
+ } else if (record.vul_level == "low") {
+ return
;
} else if (record.vul_level == "") {
return ;
}
- },
- },{
- title:"CVE修复状态",
- dataIndex:"status",
- key:"status",
+ },
+ }, {
+ title: ,
+ dataIndex: "status",
+ key: "status",
align: "center",
width: 150,
- render:(txt,record)=>{
- if(record.status=="success"){
- return
- }else{
- return
- }
+ render: (txt, record) => {
+ if (record.status == "success") {
+ return
+ } else {
+ return
+ }
},
-
},
{
- title:"操作",
+ title: ,
align: "center",
- render:(txt,record,index)=>{
+ render: (txt, record, index) => {
return (
-
-
+
)
}
}
-
]
- const paginationProps = {
- showSizeChanger: true,
- showQuickJumper: true,
- total: total, // 数据总数
- pageSizeOptions: [10,20,50,100] ,
- defaultPageSize:20,
- // current: pageNum, // 当前页码
- showTotal: ((total,ranage) => `共 ${total} 条`),
- position:["bottomRight"],
- // size:"small"
- };
return (
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
);
}
-export default index;
+export default index;
\ No newline at end of file
diff --git a/sysom_web/src/pages/security/Historicalist/historicalist.less b/sysom_web/src/pages/security/Historicalist/historicalist.less
index 1468f007f70c37113993844f2325caadfb97880c..f11511a92d1541746d89cb909e5eee523c490c1d 100644
--- a/sysom_web/src/pages/security/Historicalist/historicalist.less
+++ b/sysom_web/src/pages/security/Historicalist/historicalist.less
@@ -13,7 +13,7 @@ margin-left: 55px;
border-radius: 50%;
margin-left: 55px;
}
-.list-table{
+.hisTable{
margin-top: 20px;
}
.ant-table-pagination.ant-pagination{
diff --git a/sysom_web/src/pages/security/Historicalist/index.jsx b/sysom_web/src/pages/security/Historicalist/index.jsx
index 82b8636d1c50175a818110cc81ef5abef71baf80..9b852c9b28de53a40ff3553102376d919c55cb76 100644
--- a/sysom_web/src/pages/security/Historicalist/index.jsx
+++ b/sysom_web/src/pages/security/Historicalist/index.jsx
@@ -1,134 +1,135 @@
-import React,{useEffect,useState} from 'react';
-import {Button,Card,Table,Row,Col} from 'antd'
+import { useState } from 'react';
+import { FormattedMessage, } from 'umi';
+import { Button, Row, Col } from 'antd'
import './historicalist.less'
import { PageContainer } from '@ant-design/pro-layout';
-import {histidApi,} from '../service'
-import Headcard from "../components/Headcard";
-
+import { histidApi, } from '../service'
+import ProTable from '@ant-design/pro-table';
function index(props) {
- const [dataSource,setdataSource]=useState([])
- const [total,setTotal]=useState(0)
- const [title,setTitle]=useState("")
- useEffect( async()=>{
- const msg=await histidApi(props.match.params.id)
- setdataSource(msg.setdatasource)
- setTitle(msg.title)
-
- },[])
- const fn = () => {
- props.history.push("/security/historical");
- };
-
-
+ const [cveId, setCveId] = useState('cve');
+ const getHist = async () => {
+ const res = await histidApi(props.match.params.id);
+ setCveId(res.cve_id);
+ return res;
+ }
- const paginationProps = {
- showSizeChanger: true,
- showQuickJumper: true,
- total: total, // 数据总数
- pageSizeOptions: [10,20,50,100],
- defaultPageSize:20,
- // current: pageNum, // 当前页码
- showTotal: ((total,ranage) => `共 ${total} 条`),
- position:["bottomRight"],
- // size:"small"
- };
- const columns=[
-
+ const columns = [
{
- title: "序号",
+ title: ,
key: "id",
width: 80,
align: "center",
- render: (txt, record, index) => index + 1,
+ render: (txt, record, index) => index + 1,
},
- {
- title:"主机名称",
- dataIndex:'hostname',
- key:'hostname',
- align: "center",
- },
- {
- title:"IP地址",
- dataIndex:"ip",
- key:"ip",
- align: "center",
- },
- {
- title:"用户",
- dataIndex:"created_by",
- key:"created_by",
- align: "center",
- },
- {
- title:"创建时间",
- dataIndex:"created_at",
- key:"created_at",
- align: "center",
- },
- {
- title:"主机状态",
- dataIndex:"host_status",
- key:"host_status",
- align: "center",
- render:(txt,record)=>{
- if(record.host_status==="running"){
- return 运行中
- }else{
- return 离线
+ {
+ title: ,
+ dataIndex: 'hostname',
+ key: 'hostname',
+ align: "center",
+ },
+ {
+ title: ,
+ dataIndex: "ip",
+ key: "ip",
+ align: "center",
+ },
+ {
+ title: ,
+ dataIndex: "created_by",
+ key: "created_by",
+ align: "center",
+ },
+ {
+ title: ,
+ dataIndex: "created_at",
+ key: "created_at",
+ align: "center",
+ },
+ {
+ title: ,
+ dataIndex: "host_status",
+ key: "host_status",
+ align: "center",
+ render: (txt, record) => {
+ if (record.host_status === "running") {
+ return
+
+
+ } else {
+ return
+
+
+ }
}
- }
- },{
- title:"CVE修复状态",
- dataIndex:"status",
- key:"status",
- align: "center",
- width: 150,
- render:(txt,record)=>{
-
- if(record.status=="success"){
- return
- }else{
- return
- }
+ }, {
+ title: ,
+ dataIndex: "status",
+ key: "status",
+ align: "center",
+ width: 150,
+ render: (txt, record) => {
+
+ if (record.status == "success") {
+ return
+ } else {
+ return
+ }
+ },
+ filters: [
+ {
+ text:
+
+ , value: 'success'
+ },
+ {
+ text:
+
+ , value: 'fail'
+ },
+
+ ],
+ onFilter: (value, record) => record.status.includes(value),
},
- filters: [
- { text: '成功', value: 'success' },
- { text: '失败', value: 'fail' },
-
- ],
- onFilter: (value, record) => record.status.includes(value),
- },
- {
- title:"CVE修复详情",
- align: "center",
- render:(txt,record,index)=>{
- return (
-
-
-
-
- )
+ {
+ title: ,
+ align: "center",
+ render: (txt, record, index) => {
+ return (
+
+
+
+ )
+ }
}
- }
-
-]
+ ]
return (
-
-
-
-
-
-
-
-
-
+
+
|
+
+
+
+
+
+
);
}
-export default index;
+export default index;
\ No newline at end of file
diff --git a/sysom_web/src/pages/security/Homelist/Cvetable.jsx b/sysom_web/src/pages/security/Homelist/Cvetable.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..1294aafef29d8dd294bbfa1850e55046199d52c3
--- /dev/null
+++ b/sysom_web/src/pages/security/Homelist/Cvetable.jsx
@@ -0,0 +1,177 @@
+import { useRef ,useState} from 'react';
+import { useIntl, FormattedMessage ,history} from 'umi';
+import { Button,Modal,Progress,Card,Row,Col} from 'antd';
+import ProCard from '@ant-design/pro-card';
+import ProTable from '@ant-design/pro-table';
+import "./homelist.less";
+import {getOneById,manyApi} from '../service'
+const Cvetable=(params)=> {
+ const request=async()=>{
+ const msg=await getOneById(params.id);
+ msg.data = [...msg.setlovodata]
+ return msg
+ }
+ const [succesvisible, setsuccesvisible] = useState(false);
+ const [errvisible, seterrvisible] = useState(false);
+ const [vlue,setCount]=useState(0)
+ const [selectedRowKeys, setselectedRowKeys] = useState(0);
+ const [selectedRows,setselectedRows]=useState(0)
+ const rowSelection = {
+ onChange: (selectedRowKeys,selectedRows) => {
+ setselectedRowKeys(selectedRowKeys)
+ setselectedRows(selectedRows)
+ },
+ };
+ const columns=[
+ {
+ title: ,
+ dataIndex: 'index',
+ align: "center",
+ hideInSearch: true,
+ render: (txt, record, index) => index + 1,
+ },
+ {
+ title:,
+ dataIndex:'hostname',
+ },
+ {
+ title:,
+ dataIndex:"ip",
+ },
+ {
+ title:,
+ dataIndex:"created_by",
+ },
+ {
+ title:,
+ dataIndex:"created_at",
+ },
+ {
+ title:,
+ dataIndex:"status",
+ align: "center",
+ render: (txt, record) => {
+ if (record.status === "running") {
+ return
+
+
+ } else if(record.status === "offline"){
+ return
+
+
+ }else{
+ return
+
+
+ }
+ }
+ },
+ {
+ title: ,
+ dataIndex: "option",
+ align: "center",
+ valueType: "option",
+ render: (_, record) => [
+ {
+ setsuccesvisible(true)
+ seterrvisible(false)
+ const time =setInterval(()=>{
+ setCount(vlue=>vlue+1);
+ },2500)
+ const arry=[];
+ const id=params.id
+ arry.push({"cve_id":id, "hostname":[record.hostname ]})
+ const msg=await manyApi({cve_id_list:arry});
+ if(msg){
+ setsuccesvisible(true)
+ setCount(99);
+ clearInterval(time)
+ if(msg.message=="fix cve failed"){
+ seterrvisible(true)
+ setsuccesvisible(false);
+ setCount(0);
+ }else{
+ setTimeout(() => {
+ history.push("/security/list")
+ }, 1000);
+
+ }
+ }
+ }}>
+ {}
+ ,
+ ],
+ },
+]
+ const repair=async()=>{
+ const arry=[];
+ const leght =selectedRows.length;
+
+ if(leght>0){
+ setsuccesvisible(true)
+ seterrvisible(false)
+ const time =setInterval(()=>{
+ setCount(vlue=>vlue+1);
+
+ },2500)
+ const id=params.id
+ for(let i = 0; i < leght; i++){
+ arry.push({"cve_id":id, "hostname":[selectedRows[i].hostname ]})
+ }
+ const msg=await manyApi({cve_id_list:arry});
+ if(msg){
+ setsuccesvisible(true)
+ setCount(99);
+ clearInterval(time)
+ if(msg.message=="fix cve failed"){
+ seterrvisible(true)
+ setsuccesvisible(false);
+ setCount(0);
+ }else{
+ setTimeout(() => {
+ history.push("/security/list")
+ }, 1000);
+
+ }
+ }
+ }
+
+
+ }
+ const [flags,setflags]=useState(false)
+ const cancel=()=>{
+ if(succesvisible==true){
+ setflags(true)
+ }else{
+ history.push("/security/list")
+ }
+ }
+ return (
+ <>
+
+
+
+
+ {succesvisible?( 修复中< Progress width={40} percent={vlue} size="small" />
):null}
+ {errvisible?(修复出错了,
):null}
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
+
+export default Cvetable;
diff --git a/sysom_web/src/pages/security/Homelist/Toptable.jsx b/sysom_web/src/pages/security/Homelist/Toptable.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..8e09ac7d3996e2cc2904c57cbf009125b5ac3baf
--- /dev/null
+++ b/sysom_web/src/pages/security/Homelist/Toptable.jsx
@@ -0,0 +1,51 @@
+import { useRef, useState } from "react";
+import { useIntl, FormattedMessage } from "umi";
+import ProTable from "@ant-design/pro-table";
+import {getOneById} from '../service'
+import "./homelist.less";
+
+
+const Toptable = (params) => {
+ console.log(params.id)
+
+const request=async()=>{
+ const msg=await getOneById(params.id);
+ msg.data = [...msg.setdata]
+ return msg
+}
+
+ const columns=[
+
+ {
+ title:,
+ dataIndex:'name',
+ align: "center",
+ },
+ {
+ title:,
+ dataIndex:"vul_level",
+ key:"vul_level",
+
+ },
+ {
+ title:,
+ dataIndex:"fixed_version",
+ key:"fixed_version",
+ }
+ ]
+ return (
+
+ );
+};
+
+export default Toptable;
diff --git a/sysom_web/src/pages/security/Homelist/homelist.less b/sysom_web/src/pages/security/Homelist/homelist.less
index 54dce3cfb48cfc3bffa1ad8887c15eac7d29bae2..bc265e8e5b8d83d08ee68d3ad27175550a861761 100644
--- a/sysom_web/src/pages/security/Homelist/homelist.less
+++ b/sysom_web/src/pages/security/Homelist/homelist.less
@@ -3,10 +3,18 @@
margin-bottom: 20px;
}
-// .numbersuccess{
-// color: palegreen;
-// }
-// .numbererr{
-// color: red
-// }
+.numbersuccess{
+ color: palegreen;
+}
+.numbererr{
+ color: red
+}
+.ant-card-body{
+ padding-bottom: 0px;
+}
+.allbtn{
+ display:flex;
+ flex-direction:row-reverse;
+ align-items: center;
+}
\ No newline at end of file
diff --git a/sysom_web/src/pages/security/Homelist/index.jsx b/sysom_web/src/pages/security/Homelist/index.jsx
index d8a7112db2bc0d51b38d34db0898ee14526e10a0..51ca5090f7953b181a70c83293f23ae05174633b 100644
--- a/sysom_web/src/pages/security/Homelist/index.jsx
+++ b/sysom_web/src/pages/security/Homelist/index.jsx
@@ -1,204 +1,22 @@
-import React ,{useState,useEffect}from 'react';
-import { Card, Table, Button,Progress,Row, Col} from "antd";
-import './homelist.less'
+import { useRef ,useState} from 'react';
+import { useIntl, FormattedMessage } from 'umi';
+import ProCard from '@ant-design/pro-card';
import { PageContainer } from '@ant-design/pro-layout';
+import Toptable from './Toptable'
+import Cvetable from './Cvetable'
+import './homelist.less'
-import {getOneById,manyApi} from '../service'
-import Headcard from "../components/Headcard";
-function index(props) {
- const [data,setdata]=useState([])
- const [lovodata,setlovodata]=useState([])
- const [total,setTotal]=useState(0)
- const [selectedRowKeys, setselectedRowKeys] = useState([]);
- const [selectedRows, setselectedRows] = useState([]);
- const [title,settitle]=useState("")
- const [vlue,setCount]=useState(0)
-
- useEffect(async()=>{
- const msg=await getOneById(props.match.params.id);
- setlovodata(msg.setlovodata)
- setdata(msg.setdata)
- settitle(msg.title)
- },[])
- const[succesvisible,setsuccesvisible]=useState(false);
- const [errvisible,seterrvisible]=useState(false)
-
- const fn = () => {
- props.history.push("/security/historical");
- };
- const rowSelection = {
- selectedRowKeys,
- onChange: (selectedRowKeys, selectedRows) => {
- setselectedRowKeys(selectedRowKeys);
- setselectedRows(selectedRows);
- },
- };
- const columns=[
-
- {
- title:"软件名称",
- dataIndex:'name',
- key:'name'
- },
- {
- title:"严重程度",
- dataIndex:"vul_level",
- key:"vul_level",
-
- },
- {
- title:"修复版本",
- dataIndex:"fixed_version",
- key:"fixed_version",
- }
- ]
- const lnvohost=[
- {
- title: "序号",
- key: "id",
- width: 80,
- align: "center",
- render: (txt, record, index) => index + 1,
- },
- {
- title:"主机名称",
- dataIndex:'hostname',
- key:'hostname'
- },
- {
- title:"IP地址",
- dataIndex:"ip",
- key:"ip",
- },
- {
- title:"用户",
- dataIndex:"created_by",
- key:"created_by",
- },
- {
- title:"创建时间",
- dataIndex:"created_at",
- key:"created_at",
- },
- {
- title:"主机状态",
- dataIndex:"status",
- key:"status",
- render:(txt,record)=>{
- if(record.status==="running"){
- return 运行中
- }else{
- return 离线
- }
- }
- },{
- title:"操作",
- render:(txt,record,index)=>{
- return (
-
-
-
-
- )
- }
- }
- ]
-
-const repair=async()=>{
- const arry=[];
- const leght =selectedRows.length;
-
- if(leght>0){
- setsuccesvisible(true)
- seterrvisible(false)
- const time =setInterval(()=>{
- setCount(vlue=>vlue+1);
-
- },2500)
- const id=props.match.params.id
- for(let i = 0; i < leght; i++){
- arry.push({"cve_id":id, "hostname":[selectedRows[i].hostname ]})
- }
- const msg=await manyApi({cve_id_list:arry});
- if(msg){
- setsuccesvisible(true)
- setCount(99);
- clearInterval(time)
- if(msg.message=="fix cve failed"){
- seterrvisible(true)
- setsuccesvisible(false);
- setCount(0);
- }else{
- setTimeout(() => {
- props.history.push("/security/list")
- }, 1000);
-
- }
- }
- }
-
-
-}
- const paginationProps = {
- showSizeChanger: true,
- showQuickJumper: true,
- total: total, // 数据总数
- pageSizeOptions: [10,20,50,100] ,
- defaultPageSize:20,
- // current: pageNum, // 当前页码
- showTotal: ((total,ranage) => `共 ${total} 条`),
- position:["bottomRight"],
- // size:"small"
- };
- return (
-
-
-
-
-
-
-
-
-
-
-
-
- {succesvisible?( 修复中< Progress width={40} percent={vlue} size="small" />
):null}
- {errvisible?(恢复出错了,
):null}
-
-
- { props.history.push("/security/list") }}>
-
-
-
-
-
+const { Divider } = ProCard;
+const Homelist=(props)=> {
+ const id=props.match.params.id
+ return (
+
+
+
+
+
+
);
}
-export default index;
+export default Homelist;
diff --git a/sysom_web/src/pages/security/List/index.jsx b/sysom_web/src/pages/security/List/index.jsx
index 4cc4f8983abf8e48cd7231b94fb3d32bda65a519..7b3473af3cd58e80e7d219cf53633691750f197d 100644
--- a/sysom_web/src/pages/security/List/index.jsx
+++ b/sysom_web/src/pages/security/List/index.jsx
@@ -1,39 +1,46 @@
-import React, { useState, useEffect, useRef } from "react";
-import { Card, Table, Button, Progress, Modal, Tooltip, message, } from "antd";
+import { useRef ,useState} from 'react';
+import { useIntl, FormattedMessage } from 'umi';
+import ProCard from '@ant-design/pro-card';
+import { PageContainer } from '@ant-design/pro-layout';
+import { Button,Modal,Progress} from 'antd';
+import ProTable from '@ant-design/pro-table';
+import Restoration from "../components/restoration"
+import ListCard from '../components/ListCard'
import "./list.less";
-import { listApi, manyApi, updataApi } from "../service";
-import { PageContainer } from "@ant-design/pro-layout";
-import Headcard from "../components/Headcard";
+import { listApi, manyApi } from "../service";
-function List(props) {
- // console.log(props)
- const [data, setdata] = useState([]);
-
- useEffect(async () => {
- const msg = await listApi();
-
- setdata(msg.data);
- }, []);
+const { Divider } = ProCard;
+const List=(props)=> {
+ const actionRef = useRef();
+ const intl = useIntl();
const fn = () => {
props.history.push("/security/historical");
};
+ const [selectedRowKeys, setselectedRowKeys] = useState(0);
+ const [selectedRows,setselectedRows]=useState(0)
+ const rowSelection = {
+ onChange: (selectedRowKeys,selectedRows) => {
+ setselectedRowKeys(selectedRowKeys)
+ setselectedRows(selectedRows)
+ },
+ };
const [isModalVisible, setIsModalVisible] = useState(false);
const [succesvisible, setsuccesvisible] = useState(false);
const [errvisible, seterrvisible] = useState(false);
const [vlue, setCount] = useState(0);
- const [huan,sethuan]=useState(false)
+
const showModal = () => {
- const leght = selectedRows.length;
- if (leght > 0) {
+ const leght = selectedRows.length;
+ if (leght > 0) {
setIsModalVisible(true);
}
};
const handleOk = async () => {
const time = setInterval(() => {
setCount((vlue) => vlue + 1);
- }, 2500);
+ }, 4500);
setIsModalVisible(false);
setsuccesvisible(true);
const arry = [];
@@ -44,7 +51,7 @@ function List(props) {
hostname: selectedRows[i].hosts,
});
}
- const msg = await manyApi({ cve_id_list: arry });
+ const msg = await manyApi({ cve_id_list: arry });
if (msg) {
setIsModalVisible(false);
setsuccesvisible(true);
@@ -63,73 +70,67 @@ function List(props) {
const handleCancel = () => {
setIsModalVisible(false);
};
- const geng=async()=>{
- sethuan(true)
- const msg = await updataApi();
- console.log(msg)
- if(msg.message=="success"){
- sethuan(false)
- props.history.push("/security");
- }else if(msg.message=="forbidden"){
- sethuan(false)
- message.warning('操作频率过快,请稍后再试!');
-}
- }
-
+
const columns = [
{
- title: "序号",
- key: "index",
- width: 80,
+ title: ,
+ dataIndex: 'index',
align: "center",
-
+ hideInSearch: true,
render: (txt, record, index) => index + 1,
},
{
- title: "编号",
- dataIndex: "cve_id",
- key: "cve_id",
+ title: ,
+ dataIndex: 'cve_id',
align: "center",
+ hideInSearch: true
},
{
- title: "发布时间",
- dataIndex: "pub_time",
- key: "pub_time",
+ title: ,
+ dataIndex: 'pub_time',
+ valueType: 'dateTime',
align: "center",
- sorter: (a, b) => a.pub_time.length - b.pub_time.length,
+ hideInSearch: true,
+ sorter: (a, b) => a.pub_time - b.pub_time,
},
{
- title: "漏洞等级",
- dataIndex: "vul_level",
- key: "vul_level",
+ title: ,
+ dataIndex: 'vul_level',
align: "center",
- render: (txt, record) => {
- if (record.vul_level == "high") {
- return 高危
;
- } else if (record.vul_level == "medium") {
- return 中危
;
- } else if (record.vul_level == "critical") {
- return 严重
;
- } else if (record.vul_level == "low") {
- return 低危
;
- } else if (record.vul_level == "") {
- return ;
- }
+ filters: true,
+ onFilter: true,
+ hideInSearch: true,
+ valueEnum: {
+ high: {
+ text: (
+
+ ),
+ },
+ medium: {
+ text: (
+
+ ),
+ },
+ critical: {
+ text: (
+
+ ),
+ },
+ low: {
+ text: (
+
+ ),
+ },
},
- filters: [
- { text: "严重", value: "critical" },
- { text: "高危", value: "high" },
- { text: "中危", value: "medium" },
- { text: "低危", value: "low" },
- ],
- onFilter: (value, record) => record.vul_level.includes(value),
},
+
{
+ title: ,
+ dataIndex: 'hosts',
width: "20%",
- title: "涉及主机",
align: "center",
- dataIndex: "hosts",
- key: "hosts",
+ valueType: 'select',
+ hideInSearch: true,
onCell: () => {
return {
style: {
@@ -141,105 +142,62 @@ function List(props) {
},
};
},
- render: (text) => (
-
- {text.toString()}
+ render: (_,record,text) => (
+
+ {record.hosts.toString()}
),
},
{
- title: "操作",
+ title: ,
+ dataIndex: "option",
align: "center",
- render: (txt, record, index) => {
- return (
-
-
-
- );
- },
+ valueType: "option",
+ render: (_, record) => [
+
+ {}
+ ,
+ ],
},
+
+
];
- const [selectedRowKeys, setselectedRowKeys] = useState(0);
- const [selectedRows, setselectedRows] = useState(0);
- const [total, setTotal] = useState(0);
- const rowSelection = {
- selectedRowKeys,
- onChange: (selectedRowKeys, selectedRows) => {
- setselectedRowKeys(selectedRowKeys);
- setselectedRows(selectedRows);
- },
- };
- const paginationProps = {
- showSizeChanger: true,
- showQuickJumper: true,
- total: total, // 数据总数
- pageSizeOptions: [10, 20, 50, 100],
- defaultPageSize: 20,
- // current: pageNum, // 当前页码
- showTotal: (total, ranage) => `共 ${total} 条`,
- position: ["bottomRight"],
- // size:"small"
- };
return (
-
-
-
-
- 修复
-
- }
- >
-
-
- 确定修复吗
+
+
+
+
+ [
+ ,
+
+ ]}
+ rowSelection={rowSelection}
+ />
+
+
+
+ {}
+
-
- 正在修复中...
+ {}
-
- 恢复出错了,
-
-
-
+
+
);
}
diff --git a/sysom_web/src/pages/security/List/list.less b/sysom_web/src/pages/security/List/list.less
index 3ee14fb023fac7f2717f973c13f9fde3055ed071..43d63a63c2936f71e81ac27d1949b230c8c823fa 100644
--- a/sysom_web/src/pages/security/List/list.less
+++ b/sysom_web/src/pages/security/List/list.less
@@ -4,6 +4,7 @@
.blue{
width: 20px;
height: 20px;
+background: blue;
}
.tan{
position: relative;
@@ -11,6 +12,13 @@ height: 20px;
width: 200px;
}
+// .waring{
+// width: 25px;
+// height: 25px;
+// background-image: url(../../../../public/icons/waring.png);
+// background-repeat:no-repeat;
+
+// }
.ant-modal-body{
p{
@@ -21,9 +29,4 @@ height: 20px;
}
-}
-.Ooylined{
- float:right;
-
-
}
\ No newline at end of file
diff --git a/sysom_web/src/pages/security/Viewdetails/Viewdetails.less b/sysom_web/src/pages/security/Viewdetails/Viewdetails.less
index 5a7ed88e7426f5fd34c29c2c640e19b9e5b82fee..e42d5d7f3defb82cd7c4ffed4c1896f3b44139e0 100644
--- a/sysom_web/src/pages/security/Viewdetails/Viewdetails.less
+++ b/sysom_web/src/pages/security/Viewdetails/Viewdetails.less
@@ -1,6 +1,5 @@
-.card_succ{
+.card_result{
margin-top: 15px;
-
font-size: 16px;
h3{
margin-bottom: 12px;
@@ -17,29 +16,12 @@
span{
margin-left: 5px;
}
- }
-}
-.card_err{
- margin-top: 15px;
- font-size: 16px;
- h3{
- margin-bottom: 12px;
- span{
- margin-right: 12px;
+ &.card_err{
+ color: red;
}
- }
- h5{
- font-size: 18px;
-
- }
- p{
- font-size: 14px;
- color: red;
- span{
- margin-left: 6px;
}
}
-}
+
.err_Button{
margin-left: 92%;
margin-top: 20px;
diff --git a/sysom_web/src/pages/security/Viewdetails/index.jsx b/sysom_web/src/pages/security/Viewdetails/index.jsx
index c48b35349c03712c5e531eaff49bc5bb6b8e7df4..7ebb3d0628cbaeb408b09510f32984cb8b1d9ecb 100644
--- a/sysom_web/src/pages/security/Viewdetails/index.jsx
+++ b/sysom_web/src/pages/security/Viewdetails/index.jsx
@@ -1,28 +1,26 @@
-import React, { useState, useEffect } from "react";
-import { Card, Table, Button, Progress, Modal, Row, Col } from "antd";
+import { useState, useEffect } from "react";
+import { FormattedMessage } from 'umi';
+import { Button, Row, Col } from "antd";
import "./Viewdetails.less";
import { viewApi, summaryApi } from "../service";
import { PageContainer } from "@ant-design/pro-layout";
-import Headcard from "../components/Headcard";
+import ProCard from "@ant-design/pro-card";
function index(props) {
const [home, sethome] = useState("");
const [reason, setreason] = useState("");
const [Svisible, setSvisible] = useState(false);
- const [errvisible, seterrvisible] = useState(false);
useEffect(async () => {
const msg = await viewApi(
props.match.params.id,
props.match.params.homename
);
-
+ sethome(msg.data.hostname);
if (msg.data.status == "fail") {
- seterrvisible(true);
- sethome(msg.data.hostname);
+ setSvisible(false);
setreason(msg.data.details);
} else {
setSvisible(true);
- sethome(msg.data.hostname);
}
}, []);
const fn = () => {
@@ -31,35 +29,23 @@ function index(props) {
return (
-
-
- {Svisible ? (
- 主机名称 {home}
- CVE修复成功.
-
- ) : null}
- {errvisible ? (
-
-
- 主机名称
- {home}
-
-
- CVE修复失败,失败原因:{reason}
-
- ) : null}
-
+
+
+
+ {home}
+ {Svisible ?
+ .
+ : {reason}
}
+
+
-
-
- {" "}
+
{
props.history.go(-1);
- }}
- >
- 返回
+ }}>
+
@@ -68,4 +54,4 @@ function index(props) {
);
}
-export default index;
+export default index;
\ No newline at end of file
diff --git a/sysom_web/src/pages/security/components/Headcard.jsx b/sysom_web/src/pages/security/components/Headcard.jsx
deleted file mode 100644
index 05b914fc82d4f890879660166118785bb0c66761..0000000000000000000000000000000000000000
--- a/sysom_web/src/pages/security/components/Headcard.jsx
+++ /dev/null
@@ -1,40 +0,0 @@
-import React,{useState,useEffect} from 'react';
-import { Card, Button,Row,Col} from "antd";
-import {summaryApi} from '../service'
-import {SyncOutlined} from '@ant-design/icons';
-import '../List/list.less'
-
-function Headcard(param) {
- const [affectcount,setaffectcount]=useState(0);
- const [cvecount,setcvecount]=useState(0);
- const [higtcount,sethigtcount]=useState(0)
-
- useEffect(async() => {
- const msg=await summaryApi();
- setaffectcount(msg.affect)
- setcvecount(msg.cvecount)
- sethigtcount(msg.highcount)
- }, []);
-
-
-
-
- return (
-
-
-
-
- {affectcount}台主机存在被攻击风险,涉及CVE漏洞{cvecount}个,其中高危漏洞{higtcount}个,请尽快修复。
- {param.isShow?(历史修复):""}
- {param.upData?(更新):""}
-
-
- {param.quan?( < SyncOutlined className="Ooylined" style={{fontSize:'22px',}} spin />):""}
-
-
-
-
- );
-}
-
-export default Headcard;
\ No newline at end of file
diff --git a/sysom_web/src/pages/security/components/ListCard.jsx b/sysom_web/src/pages/security/components/ListCard.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..4c65ce41bbc00fc64b38adc69df4df7a98d5094f
--- /dev/null
+++ b/sysom_web/src/pages/security/components/ListCard.jsx
@@ -0,0 +1,99 @@
+import { Statistic ,Button, message} from 'antd';
+import { useState, useEffect } from 'react';
+import { useIntl, FormattedMessage } from 'umi';
+import ProCard from '@ant-design/pro-card';
+import RcResizeObserver from 'rc-resize-observer';
+import {summaryApi,updataApi} from '../service'
+const { Divider } = ProCard;
+import '../List/list.less'
+import { size } from 'lodash-es';
+
+
+const ListCard=(props)=> {
+ const intl = useIntl();
+ const [responsive, setResponsive] = useState(false);
+ const [complete, setComplete] = useState(false);
+ const [StatisticList, setStatisticList] = useState()
+ const getSummary = async() => {
+ setComplete(true);
+ let msg=await summaryApi();
+ if(msg){
+ setComplete(false);
+ if(msg.success){
+ message.success(intl.formatMessage({id:'component.ListCard.success',defaultMessage:'Scan success'}));
+ setStatisticList(msg.data.fixed_cve)
+ props.refreshTable();
+ }else{
+ message.error(intl.formatMessage({id:'component.ListCard.failed',defaultMessage:'Scan failed'}));
+ }
+ }
+ }
+ useEffect(async() => {
+ let msg=await summaryApi();
+ if(msg.success)
+ setStatisticList(msg.data.fixed_cve)
+ }, []);
+
+ return (
+ {
+ setResponsive(offset.width < 596);
+ }}>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {complete ? : }
+
+
+
+ );
+}
+
+export default ListCard;
diff --git a/sysom_web/src/pages/security/components/restoration.jsx b/sysom_web/src/pages/security/components/restoration.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..7615f8f61627e4a07058cc973d4b7d8b02b258de
--- /dev/null
+++ b/sysom_web/src/pages/security/components/restoration.jsx
@@ -0,0 +1,12 @@
+import { Button, message } from "antd";
+
+const restoration=(param)=> {
+ // console.log(param)
+ return (
+
+ 历史修复
+
+ );
+}
+
+export default restoration;
diff --git a/sysom_web/src/pages/security/service.js b/sysom_web/src/pages/security/service.js
index 506fbd36f49c96f17bbbf22f3bce9701be14f226..f46ca96bac7e981208841cd31508057a2167f88f 100644
--- a/sysom_web/src/pages/security/service.js
+++ b/sysom_web/src/pages/security/service.js
@@ -18,7 +18,7 @@ const token = localStorage.getItem('token');
}
export async function summaryApi(options) {
- const msg= await request('/api/v1/vul/summary', {
+ const msg= await request('/api/v1/vul/summary/', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
@@ -27,12 +27,13 @@ const token = localStorage.getItem('token');
...(options || {}),
});
- return {
- affect:msg.data.fixed_cve.affect_host_count,
- cvecount:msg.data.fixed_cve.cve_count,
- highcount:msg.data.fixed_cve.high_cve_count
- }
+ return msg;
}
+// {
+// affect:msg.data.fixed_cve.affect_host_count,
+// cvecount:msg.data.fixed_cve.cve_count,
+// highcount:msg.data.fixed_cve.high_cve_count
+// }
@@ -58,11 +59,8 @@ const token = localStorage.getItem('token');
},
...(options || {}),
});
-
- return {
- setdatasource:msg.data.hosts_datail,
- title:msg.data.cve_id
- }
+ msg.data.data = [...msg.data.hosts_datail];
+ return msg.data;
};
@@ -124,7 +122,7 @@ const token = localStorage.getItem('token');
...(options || {}),
});
- return msg
+ return msg;
}
diff --git a/sysom_web/yarn.lock b/sysom_web/yarn.lock
index 4b4fee6ebdd2a9b79323699aabe67be6919a4beb..dbd8e70b8e158b8eef27e43fac5567c461acdf00 100644
--- a/sysom_web/yarn.lock
+++ b/sysom_web/yarn.lock
@@ -5086,6 +5086,17 @@ browserslist@^4.12.0, browserslist@^4.17.5, browserslist@^4.17.6, browserslist@^
node-releases "^2.0.1"
picocolors "^1.0.0"
+browserslist@^4.20.2:
+ version "4.20.2"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88"
+ integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==
+ dependencies:
+ caniuse-lite "^1.0.30001317"
+ electron-to-chromium "^1.4.84"
+ escalade "^3.1.1"
+ node-releases "^2.0.2"
+ picocolors "^1.0.0"
+
bser@2.1.1:
version "2.1.1"
resolved "https://registry.npm.taobao.org/bser/download/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05"
@@ -5252,10 +5263,10 @@ camelcase@^6.0.0:
resolved "https://registry.npmmirror.com/camelcase/download/camelcase-6.2.1.tgz?cache=0&sync_timestamp=1636945205805&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fcamelcase%2Fdownload%2Fcamelcase-6.2.1.tgz#250fd350cfd555d0d2160b1d51510eaf8326e86e"
integrity sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==
-caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001280:
- version "1.0.30001282"
- resolved "https://registry.npmmirror.com/caniuse-lite/download/caniuse-lite-1.0.30001282.tgz?cache=0&sync_timestamp=1637135357719&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fcaniuse-lite%2Fdownload%2Fcaniuse-lite-1.0.30001282.tgz#38c781ee0a90ccfe1fe7fefd00e43f5ffdcb96fd"
- integrity sha512-YhF/hG6nqBEllymSIjLtR2iWDDnChvhnVJqp+vloyt2tEHFG1yBR+ac2B/rOw0qOK0m0lEXU2dv4E/sMk5P9Kg==
+caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001280, caniuse-lite@^1.0.30001317, caniuse-lite@^1.0.30001320:
+ version "1.0.30001320"
+ resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001320.tgz"
+ integrity sha512-MWPzG54AGdo3nWx7zHZTefseM5Y1ccM7hlQKHRqJkPozUaw3hNbBTMmLn16GG2FUzjR13Cr3NPfhIieX5PzXDA==
capture-exit@^2.0.0:
version "2.0.0"
@@ -6773,6 +6784,11 @@ electron-to-chromium@^1.3.564, electron-to-chromium@^1.3.896:
resolved "https://registry.npmmirror.com/electron-to-chromium/download/electron-to-chromium-1.3.907.tgz#c8e155a17cb642a1023481c601aa3ad9ee61f402"
integrity sha512-xoUPSkjimw51d9ryeH38XUwmR3HmCA+eky4hk0YEgsWeBWGyhb35OCvT3lWAdmvIkcGYCRNOB8LvtO00dJQpOA==
+electron-to-chromium@^1.4.84:
+ version "1.4.91"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.91.tgz#842bbc97fd639abe7e46e7da530e3af5f6ca2831"
+ integrity sha512-Z7Jkc4+ouEg8F6RrrgLOs0kkJjI0cnyFQmnGVpln8pPifuKBNbUr37GMgJsCTSwy6Z9TK7oTwW33Oe+3aERYew==
+
element-resize-event@^3.0.3:
version "3.0.6"
resolved "https://registry.nlark.com/element-resize-event/download/element-resize-event-3.0.6.tgz#3a18efd4879ad615e979fd8bbf173b014987eb9a"
@@ -11669,6 +11685,11 @@ node-releases@^2.0.1:
resolved "https://registry.npmmirror.com/node-releases/download/node-releases-2.0.1.tgz?cache=0&sync_timestamp=1634806914912&other_urls=https%3A%2F%2Fregistry.npmmirror.com%2Fnode-releases%2Fdownload%2Fnode-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5"
integrity sha1-PR05XyBPHy8ppUNYuftnh2WtL8U=
+node-releases@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01"
+ integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==
+
normalize-package-data@^2.3.2, normalize-package-data@^2.5.0:
version "2.5.0"
resolved "https://registry.nlark.com/normalize-package-data/download/normalize-package-data-2.5.0.tgz?cache=0&sync_timestamp=1629301911873&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fnormalize-package-data%2Fdownload%2Fnormalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"