diff --git a/app/renderer/src/main/src/assets/icon/outline.tsx b/app/renderer/src/main/src/assets/icon/outline.tsx index abe5cbdc91..20a49c0cf2 100644 --- a/app/renderer/src/main/src/assets/icon/outline.tsx +++ b/app/renderer/src/main/src/assets/icon/outline.tsx @@ -5332,3 +5332,42 @@ const OutlineTrashSecond = () => ( export const OutlineTrashSecondIcon = (props: Partial) => { return } + +/** + * @description UI Kit/Icon/Outline/端口资产 + */ +const OutlineModScanPortData = () => ( + + + + + + + + + + + + + + + +) +export const OutlineModScanPortDataIcon = (props: Partial) => { + return +} diff --git a/app/renderer/src/main/src/assets/icon/solid.tsx b/app/renderer/src/main/src/assets/icon/solid.tsx index c011af0914..cff3990ded 100644 --- a/app/renderer/src/main/src/assets/icon/solid.tsx +++ b/app/renderer/src/main/src/assets/icon/solid.tsx @@ -1715,13 +1715,16 @@ export const SolidDocumentsearchIcon = (props: Partial) => { } const SolidDocumenttext = () => ( - + + + ) /** diff --git a/app/renderer/src/main/src/assets/mitm-bg.png b/app/renderer/src/main/src/assets/mitm-bg.png new file mode 100644 index 0000000000..5d7bdc1744 Binary files /dev/null and b/app/renderer/src/main/src/assets/mitm-bg.png differ diff --git a/app/renderer/src/main/src/components/HTTPHistory.module.scss b/app/renderer/src/main/src/components/HTTPHistory.module.scss index 3da5f0e04b..5cd3348c2b 100644 --- a/app/renderer/src/main/src/components/HTTPHistory.module.scss +++ b/app/renderer/src/main/src/components/HTTPHistory.module.scss @@ -24,6 +24,7 @@ text-orientation: sideways-right; writing-mode: vertical-rl; + border-top: 1px solid #fff; svg { width: 16px; height: 16px; diff --git a/app/renderer/src/main/src/components/layout/FuncDomain.tsx b/app/renderer/src/main/src/components/layout/FuncDomain.tsx index 6331817eaa..7c9f1c33f2 100644 --- a/app/renderer/src/main/src/components/layout/FuncDomain.tsx +++ b/app/renderer/src/main/src/components/layout/FuncDomain.tsx @@ -1165,7 +1165,7 @@ const UIOpUpdateYakit: React.FC = React.memo((props) => {
- +
{/* 等使用更新内容时,下面"当前版本"-div需要被删除 */}
diff --git a/app/renderer/src/main/src/components/layout/UILayout.tsx b/app/renderer/src/main/src/components/layout/UILayout.tsx index ed0bc2cfd0..cf4866b147 100644 --- a/app/renderer/src/main/src/components/layout/UILayout.tsx +++ b/app/renderer/src/main/src/components/layout/UILayout.tsx @@ -1233,11 +1233,13 @@ const UILayout: React.FC = (props) => { > {performanceSamplingInfo.log.map((item, index) => (
- + { ipcRenderer .invoke("is-file-exists", item.path) @@ -1251,7 +1253,12 @@ const UILayout: React.FC = (props) => { .catch(() => {}) }} > - {item.path.substring(item.path.lastIndexOf("\\") + 1)} + {item.path.substring( + Math.max( + item.path.lastIndexOf("/"), + item.path.lastIndexOf("\\") + ) + 1 + )} @@ -1288,18 +1295,20 @@ const UILayout: React.FC = (props) => { if (!visible) setIsShowSamplingInfo(false) }} > - setIsShowSamplingInfo(true)} - > -
- -
- 采样完成 -
+ + setIsShowSamplingInfo(true)} + > +
+ +
+ 采样完成 +
+
) : ( <> diff --git a/app/renderer/src/main/src/components/layout/uiLayout.module.scss b/app/renderer/src/main/src/components/layout/uiLayout.module.scss index 8d0eeb77f8..f3c5332740 100644 --- a/app/renderer/src/main/src/components/layout/uiLayout.module.scss +++ b/app/renderer/src/main/src/components/layout/uiLayout.module.scss @@ -247,7 +247,7 @@ .sampling-popover { width: 272px; - padding-top: 3px; + padding-top: 10px; border-radius: 4px; overflow: hidden; border: 1px solid var(--yakit-border-color); diff --git a/app/renderer/src/main/src/pages/assetViewer/EnterpriseReportViewer.module.scss b/app/renderer/src/main/src/pages/assetViewer/EnterpriseReportViewer.module.scss index 85c011421c..d24ccc3e65 100644 --- a/app/renderer/src/main/src/pages/assetViewer/EnterpriseReportViewer.module.scss +++ b/app/renderer/src/main/src/pages/assetViewer/EnterpriseReportViewer.module.scss @@ -1,3 +1,3 @@ -.enterprise-report-viewer{ +.enterprise-report-viewer { height: 100%; } \ No newline at end of file diff --git a/app/renderer/src/main/src/pages/fuzzer/FuzzerSequence/FuzzerSequence.tsx b/app/renderer/src/main/src/pages/fuzzer/FuzzerSequence/FuzzerSequence.tsx index fe540f7255..9716468235 100644 --- a/app/renderer/src/main/src/pages/fuzzer/FuzzerSequence/FuzzerSequence.tsx +++ b/app/renderer/src/main/src/pages/fuzzer/FuzzerSequence/FuzzerSequence.tsx @@ -2079,7 +2079,7 @@ const SequenceResponse: React.FC = React.memo( // 序列动画演示 interface SequenceAnimationAemonstrationProps {} -const SequenceAnimationAemonstration: React.FC = React.memo((props) => { +export const SequenceAnimationAemonstration: React.FC = React.memo((props) => { return (
diff --git a/app/renderer/src/main/src/pages/fuzzer/HTTPFuzzerPage.module.scss b/app/renderer/src/main/src/pages/fuzzer/HTTPFuzzerPage.module.scss index 9fc4729ca0..64c753b276 100644 --- a/app/renderer/src/main/src/pages/fuzzer/HTTPFuzzerPage.module.scss +++ b/app/renderer/src/main/src/pages/fuzzer/HTTPFuzzerPage.module.scss @@ -363,10 +363,10 @@ .blasting-animation-aemonstration { padding: 16px; + padding-top: 0; .animation-cont-wrap { margin-top: 16px; width: 100%; - height: 310px; border-radius: 10px; border: 1px solid var(--yakit-border-color); overflow: hidden; diff --git a/app/renderer/src/main/src/pages/fuzzer/HTTPFuzzerPage.tsx b/app/renderer/src/main/src/pages/fuzzer/HTTPFuzzerPage.tsx index ec8059893a..7afaa61313 100644 --- a/app/renderer/src/main/src/pages/fuzzer/HTTPFuzzerPage.tsx +++ b/app/renderer/src/main/src/pages/fuzzer/HTTPFuzzerPage.tsx @@ -1,4 +1,4 @@ -import React, {useEffect, useMemo, useRef, useState} from "react" +import React, {CSSProperties, useEffect, useMemo, useRef, useState} from "react" import {Form, Modal, Result, Space, Popover, Tooltip, Divider, Descriptions} from "antd" import { IMonacoEditor, @@ -3128,9 +3128,12 @@ const ResponseViewerSecondNode: React.FC = React. }) // 爆破动画演示 -interface BlastingAnimationAemonstrationProps {} -const BlastingAnimationAemonstration: React.FC = React.memo((props) => { - const [animationType, setAnimationType] = useState("id") +interface BlastingAnimationAemonstrationProps { + animationType?: string + videoStyle?: CSSProperties +} +export const BlastingAnimationAemonstration: React.FC = React.memo((props) => { + const [animationType, setAnimationType] = useState(props.animationType || "id") const [animationResources, setAnimationResources] = useState(blastingIdmp4) @@ -3146,28 +3149,31 @@ const BlastingAnimationAemonstration: React.FC - setAnimationType(e.target.value)} - /> + {!props.animationType && ( + setAnimationType(e.target.value)} + /> + )} +
- +
) diff --git a/app/renderer/src/main/src/pages/fuzzer/WebFuzzerPage/WebFuzzerPage.module.scss b/app/renderer/src/main/src/pages/fuzzer/WebFuzzerPage/WebFuzzerPage.module.scss index d9c978856b..2b4c5b89cb 100644 --- a/app/renderer/src/main/src/pages/fuzzer/WebFuzzerPage/WebFuzzerPage.module.scss +++ b/app/renderer/src/main/src/pages/fuzzer/WebFuzzerPage/WebFuzzerPage.module.scss @@ -22,6 +22,7 @@ color: var(--yakit-header-color); cursor: pointer; background-color: #f0f1f3; + border-bottom: 1px solid #fff; &:hover { background-color: rgba(204, 210, 222, 0.5); } diff --git a/app/renderer/src/main/src/pages/home/Home.tsx b/app/renderer/src/main/src/pages/home/Home.tsx new file mode 100644 index 0000000000..6cea6b0c4f --- /dev/null +++ b/app/renderer/src/main/src/pages/home/Home.tsx @@ -0,0 +1,1296 @@ +import React, {useEffect, useMemo, useRef, useState, ReactElement, CSSProperties} from "react" +import classNames from "classnames" +import styles from "./home.module.scss" +import { + PublicBlastingIcon, + PublicBruteIcon, + PublicCodecIcon, + PublicDNSLogIcon, + PublicDirectoryScanningIcon, + PublicMitmIcon, + PublicPayloadGeneraterIcon, + PublicPublicToolLightbulbIcon, + PublicScanPortIcon, + PublicSequenceAnimationIcon, + PublicToolBasicCrawlerIcon, + PublicToolCVEIcon, + PublicToolDBDomainIcon, + PublicToolDBHTTPHistoryIcon, + PublicToolDBReportIcon, + PublicToolDBRiskIcon, + PublicToolDataCompareIcon, + PublicToolICMPSizeLogIcon, + PublicToolModScanPortIcon, + PublicToolPayloadIcon, + PublicToolPluginHubIcon, + PublicToolReverseServerIcon, + PublicToolScreenRecorderPageIcon, + PublicToolScreenRecordingIcon, + PublicToolScreenshotIcon, + PublicToolShellReceiverIcon, + PublicToolSpaceEngineIcon, + PublicToolSubDomainCollectionIcon, + PublicToolTCPPortLogIcon, + PublicToolVulinboxIcon, + PublicToolWebsocketFuzzerIcon, + PublicToolYakScriptIcon, + PublicWebFuzzerIcon +} from "@/routes/publicIcon" +import {YakitButton} from "@/components/yakitUI/YakitButton/YakitButton" +import {SolidCheckIcon, SolidDocumenttextIcon, SolidExclamationIcon, SolidPlayIcon} from "@/assets/icon/solid" +import {showYakitModal} from "@/components/yakitUI/YakitModal/YakitModalConfirm" +import {BlastingAnimationAemonstration} from "../fuzzer/HTTPFuzzerPage" +import { + OutlineArrowrightIcon, + OutlineBugIcon, + OutlineChartbarIcon, + OutlineChevronupIcon, + OutlineDatabaseIcon, + OutlineDesktopcomputerIcon, + OutlineModScanPortDataIcon, + OutlineQuestionmarkcircleIcon +} from "@/assets/icon/outline" +import {SequenceAnimationAemonstration} from "../fuzzer/FuzzerSequence/FuzzerSequence" +import {YakitRoute} from "@/enums/yakitRoute" +import emiter from "@/utils/eventBus/eventBus" +import {RouteToPageProps} from "../layout/publicMenu/PublicMenu" +import {usePluginToId} from "@/store/publicMenu" +import {ResidentPluginName} from "@/routes/newRoute" +import {Form, Tooltip} from "antd" +import {useDebounceEffect, useDebounceFn, useGetState, useInViewport, useMemoizedFn, useThrottleFn} from "ahooks" +import {YakitInput} from "@/components/yakitUI/YakitInput/YakitInput" +import {YakitSwitch} from "@/components/yakitUI/YakitSwitch/YakitSwitch" +import {getRemoteValue, setRemoteValue} from "@/utils/kv" +import {MITMConsts} from "../mitm/MITMConsts" +import {CacheDropDownGV, RemoteGV} from "@/yakitGV" +import {openABSFileLocated} from "@/utils/openWebsite" +import {yakitNotify} from "@/utils/notification" +import {YakitSystem} from "@/yakitGVDefine" +import {YakitHint} from "@/components/yakitUI/YakitHint/YakitHint" +import {ShieldCheckIcon as AllShieldCheckIcon} from "@/components/layout/globalStateIcon" +import {useScreenRecorder} from "@/store/screenRecorder" +import numeral from "numeral" +import {CloudDownloadIcon} from "@/assets/newIcon" +import {ProjectDescription} from "../softwareSettings/ProjectManage" +import {YakQueryHTTPFlowResponse} from "@/components/HTTPFlowTable/HTTPFlowTable" +import {FieldName, Fields} from "../risks/RiskTable" +import {apiQueryYakScriptTotal} from "../plugins/utils" +import {YakitGetOnlinePlugin} from "../mitm/MITMServerHijacking/MITMPluginLocalList" +import {apiQueryPortsBase} from "../assetViewer/PortTable/utils" +import {QueryPortsRequest} from "../assetViewer/PortAssetPage" +import mitmBg from "../../assets/mitm-bg.png" +import {getReleaseEditionName, isEnpriTraceAgent} from "@/utils/envfile" +import {YakitEmpty} from "@/components/yakitUI/YakitEmpty/YakitEmpty" +import {YakitResizeBox} from "@/components/yakitUI/YakitResizeBox/YakitResizeBox" +import ReactResizeDetector from "react-resize-detector" +const {ipcRenderer} = window.require("electron") + +interface ToolInfo { + label: string + icon: ReactElement + iconStyle?: CSSProperties + desc: string + rightIcon: ReactElement + onClick: () => void +} + +export interface HomeProp {} +const Home: React.FC = (props) => { + const homeRef = useRef(null) + const [inViewport] = useInViewport(homeRef) + const {pluginToId} = usePluginToId() + const isRunRef = useRef(false) + const [timeInterval, setTimeInterval, getTimeInterval] = useGetState(5) + const timeRef = useRef(null) + const [showMitmDropdown, setShowMitmDropdown] = useState(false) + const showMitmDropdownRef = useRef(showMitmDropdown) + const mitmDropdownRef = useRef(null) + const [showMITMCertWarn, setShowMITMCertWarn] = useState(false) + const [form] = Form.useForm() + const hostWatch = Form.useWatch("host", form) + const portWatch = Form.useWatch("port", form) + const [scanningCheck, setScanningCheck] = useState("specialVulnerabilityDetection") + const [showScanningDropdown, setShowScanningDropdown] = useState(false) + const scanningdropdownRef = useRef(null) + const [pcap, setPcap] = useState<{ + IsPrivileged: boolean + Advice: string + AdviceVerbose: string + }>({Advice: "unknown", AdviceVerbose: "无法获取 PCAP 支持信息", IsPrivileged: false}) + const [system, setSystem] = useState("Darwin") + const [pcapHintShow, setPcapHintShow] = useState(false) + const [pcapResult, setPcapResult] = useState(false) + const [pcapHintLoading, setPcapHintLoading] = useState(false) + const {screenRecorderInfo} = useScreenRecorder() + const [searchToolVal, setSearchToolVal] = useState("") + const toolsList = useMemo(() => { + return [ + { + label: "YakRunner", + icon: , + iconStyle: {backgroundColor: "#8863f7", padding: 1}, + desc: "Yak语言编辑器", + rightIcon: , + onClick: () => onMenu({route: YakitRoute.YakScript}) + }, + { + label: "靶场 Vulinbox", + icon: , + desc: "Yak自带靶场", + rightIcon: , + onClick: () => onMenu({route: YakitRoute.Beta_VulinboxManager}) + }, + { + label: "Payload", + icon: , + desc: "Payload字典管理", + rightIcon: , + onClick: () => onMenu({route: YakitRoute.PayloadManager}) + }, + { + label: "数据对比", + icon: , + desc: "快速识别不同数据", + rightIcon: , + onClick: () => onMenu({route: YakitRoute.DataCompare}) + }, + { + label: "CVE 管理", + icon: , + desc: "搜索查询CVE数据", + rightIcon: , + onClick: () => onMenu({route: YakitRoute.DB_CVE}) + }, + { + label: "插件仓库", + icon: , + iconStyle: {backgroundColor: "#F4736B", padding: 1}, + desc: "海量Yakit插件一键下载", + rightIcon: , + onClick: () => onMenu({route: YakitRoute.Plugin_Hub}) + }, + { + label: "端口监听器", + icon: , + desc: "监听端口并进行交互", + rightIcon: , + onClick: () => onMenu({route: YakitRoute.ShellReceiver}) + }, + { + label: "Websocket Fuzzer", + icon: , + desc: "对Websocket数据包进行模糊测试", + rightIcon: , + onClick: () => onMenu({route: YakitRoute.WebsocketFuzzer}) + }, + { + label: "子域名收集", + icon: , + desc: "收集目标资产关联的子域名", + rightIcon: , + onClick: () => + onMenu({ + route: YakitRoute.Plugin_OP, + pluginId: pluginToId[ResidentPluginName.SubDomainCollection], + pluginName: ResidentPluginName.SubDomainCollection + }) + }, + { + label: "基础爬虫", + icon: , + desc: "收集目标资产的所有页面信息", + rightIcon: , + onClick: () => + onMenu({ + route: YakitRoute.Plugin_OP, + pluginId: pluginToId[ResidentPluginName.BasicCrawler], + pluginName: ResidentPluginName.BasicCrawler + }) + }, + { + label: "空间引擎", + icon: , + desc: "集合多种引擎,一键收集资产信息", + rightIcon: , + onClick: () => onMenu({route: YakitRoute.Space_Engine}) + }, + { + label: "ICMP-SizeLog", + icon: , + desc: "使用 ping 携带特定长度数据包判定 ICMP反连", + rightIcon: , + onClick: () => onMenu({route: YakitRoute.ICMPSizeLog}) + }, + { + label: "TCP-PortLog", + icon: , + desc: "使用未开放的随机端口来判定 TCP 反连", + rightIcon: , + onClick: () => onMenu({route: YakitRoute.TCPPortLog}) + }, + { + label: "反连服务器", + icon: , + desc: "同时在一个端口同时实现 HTTP / RMI / HTTPS 等协议的反连", + rightIcon: , + onClick: () => onMenu({route: YakitRoute.ReverseServer_New}) + }, + { + label: "History", + icon: , + desc: "查看并操作所有劫持、插件、Fuzz发出的所有历史流量", + rightIcon: , + onClick: () => onMenu({route: YakitRoute.DB_HTTPHistory}) + }, + { + label: "报告", + icon: , + desc: "查看并管理扫描时生成的报告", + rightIcon: , + onClick: () => onMenu({route: YakitRoute.DB_Report}) + }, + { + label: "漏洞与风险统计", + icon: , + desc: "管理扫描出的所有漏洞和风险信息", + rightIcon: , + onClick: () => onMenu({route: YakitRoute.DB_Risk}) + }, + { + label: "端口资产", + icon: , + desc: "管理扫描出的所有端口资产", + rightIcon: , + onClick: () => onMenu({route: YakitRoute.Mod_ScanPort}) + }, + { + label: "域名资产", + icon: , + desc: "管理扫描出的所有域名资产", + rightIcon: , + onClick: () => onMenu({route: YakitRoute.DB_Domain}) + }, + { + label: "录屏", + icon: , + desc: "录制屏幕操作", + rightIcon: , + onClick: () => !screenRecorderInfo.isRecording && ipcRenderer.invoke("send-open-screenCap-modal") + }, + { + label: "截屏", + icon: , + desc: "截取屏幕信息形成图片", + rightIcon: , + onClick: () => ipcRenderer.invoke("activate-screenshot") + }, + { + label: "录屏管理", + icon: , + desc: "管理录屏形成的所有视频文件", + rightIcon: , + onClick: () => onMenu({route: YakitRoute.ScreenRecorderPage}) + } + ] as ToolInfo[] + }, [screenRecorderInfo]) + const [curProjectInfo, setCurProjectInfo] = useState() + const [historyData, setHistoryData] = useState(0) + const [riskLevelData, setRiskLevelData] = useState([]) + const [portTotal, setPortTotal] = useState(0) + const [localPluginTotal, setLocalPluginTotal] = useState(0) + const [visibleOnline, setVisibleOnline] = useState(false) + + useEffect(() => { + showMitmDropdownRef.current = showMitmDropdown + }, [showMitmDropdown]) + + useEffect(() => { + let timer: any = null + getRemoteValue(RemoteGV.GlobalStateTimeInterval).then((time: any) => { + setTimeInterval(+time || 5) + if ((+time || 5) > 5) updateAllInfo() + if (timer) clearInterval(timer) + timer = setInterval(() => { + setRemoteValue(RemoteGV.GlobalStateTimeInterval, `${getTimeInterval()}`) + }, 20000) + }) + + getRemoteValue(MITMConsts.MITMDefaultPort).then((e) => { + if (!!e) { + form.setFieldsValue({port: e}) + } else { + form.setFieldsValue({port: "8083"}) + } + }) + + getRemoteValue(CacheDropDownGV.MITMDefaultHostHistoryList).then((e) => { + if (!!e) { + try { + const obj = JSON.parse(e) || {} + form.setFieldsValue({host: obj.defaultValue}) + } catch (error) { + form.setFieldsValue({host: "127.0.0.1"}) + } + } else { + form.setFieldsValue({port: "127.0.0.1"}) + } + }) + + getRemoteValue(RemoteGV.HomeStartScanning).then((e) => { + if (!!e) { + setScanningCheck(e) + } else { + setScanningCheck("specialVulnerabilityDetection") + } + }) + + // 获取系统 + ipcRenderer.invoke("fetch-system-name").then((systemName) => { + setSystem(systemName) + }) + + // dropdown 点击外部关闭 + const handleClickOutside = (event) => { + if (scanningdropdownRef.current && !scanningdropdownRef.current.contains(event.target)) { + setShowScanningDropdown(false) + } + if (mitmDropdownRef.current && !mitmDropdownRef.current.contains(event.target)) { + setTimeout(() => { + setShowMitmDropdown(false) + }, 150) + } + } + document.addEventListener("mousedown", handleClickOutside) + return () => { + document.removeEventListener("mousedown", handleClickOutside) + } + }, []) + + useDebounceEffect( + () => { + getRemoteValue(CacheDropDownGV.MITMDefaultHostHistoryList).then((e) => { + if (!!e) { + try { + const obj = JSON.parse(e) || {} + form.setFieldsValue({host: obj.defaultValue}) + } catch (error) { + form.setFieldsValue({host: "127.0.0.1"}) + } + } else { + form.setFieldsValue({port: "127.0.0.1"}) + } + }) + updateProjectDbSize() + undateHistoryData() + undateRiskLevel() + updatePortTotal() + updateLocalPluginTotal() + }, + [inViewport], + {wait: 200} + ) + + // 修改查询间隔时间后 + useDebounceEffect( + () => { + if (timeRef.current) clearInterval(timeRef.current) + timeRef.current = setInterval(updateAllInfo, timeInterval * 1000) + + return () => { + isRunRef.current = false + if (timeRef.current) clearInterval(timeRef.current) + timeRef.current = null + } + }, + [timeInterval], + {wait: 300} + ) + + const updateAllInfo = useMemoizedFn(() => { + if (isRunRef.current) return + isRunRef.current = true + Promise.allSettled([updateMITMCert(), updatePcap()]) + .then((values) => { + isRunRef.current = false + }) + .catch(() => {}) + }) + + // 打开页面 + const onMenu = (info: RouteToPageProps) => { + if (!info.route) return + emiter.emit("menuOpenPage", JSON.stringify(info)) + } + + // 获取是否安装MITM证书 + const updateMITMCert = useMemoizedFn(() => { + return new Promise((resolve, reject) => { + ipcRenderer + .invoke("VerifySystemCertificate") + .then((res) => { + if (res.valid) { + setShowMITMCertWarn(false) + } else { + setShowMITMCertWarn(true) + } + if (res.Reason != "") { + reject(`error-mitm-cert ${res.Reason}`) + } + }) + .catch((e) => reject(`error-mitm-cert ${e}`)) + .finally(() => { + resolve("mitm-cert") + }) + }) + }) + + // 下载安装MITM证书 + const handleDownMitmCert = (e) => { + e.stopPropagation() + const m = showYakitModal({ + title: "生成自动安装脚本", + width: "600px", + centered: true, + content: ( +
+ 请按照以下步骤进行操作: +
+
+ 1. 点击确定后将会打开脚本存放的目录。 +
+ 2. 双击打开 "auto-install-cert.bat/auto-install-cert.sh" 的文件执行安装。 +
+ 3. 如果安装成功,您将看到“Certificate successfully installed.”的提示。 +
+
+ 请确保在运行脚本之前关闭任何可能会阻止安装的应用程序。 +
+ 安装完成后,您将能够顺利使用 MITM。 +
+
+ 如有任何疑问或需要进一步帮助,请随时联系我们。 +
+ ), + onOk: () => { + ipcRenderer + .invoke("generate-install-script", {}) + .then((p: string) => { + if (p) { + openABSFileLocated(p) + } else { + yakitNotify("error", "生成失败") + } + }) + .catch(() => {}) + m.destroy() + } + }) + } + + // 爆破示例 + const handleBlastingExample = (animationType: string) => { + const m = showYakitModal({ + type: "white", + title: "WebFuzzer 爆破动画演示", + width: 650, + content: ( + + ), + footer: null, + centered: true, + destroyOnClose: true, + maskClosable: false + }) + } + + // 演示动画 + const handleSequenceAnimation = (e) => { + e.stopPropagation() + const m = showYakitModal({ + type: "white", + title: ( +
+ WebFuzzer 序列动画演示 +
+ ipcRenderer.invoke( + "open-url", + "https://www.yaklang.com/products/Web%20Fuzzer/fuzz-sequence" + ) + } + > + 官方帮助文档 + +
+
+ ), + width: 650, + content: , + footer: null, + centered: true, + destroyOnClose: true, + maskClosable: false + }) + } + + // 获取网卡操作权限 + const updatePcap = useMemoizedFn(() => { + return new Promise((resolve, reject) => { + ipcRenderer + .invoke("IsPrivilegedForNetRaw", {}) + .then((res) => { + setPcap(res) + resolve("pcap") + }) + .catch((e) => reject(`error-pcap ${e}`)) + }) + }) + + // 开启PCAP权限 + const openPcapPower = useMemoizedFn(() => { + setPcapHintLoading(true) + ipcRenderer + .invoke(`PromotePermissionForUserPcap`, {}) + .then(() => { + setPcapResult(true) + }) + .catch((e) => { + yakitNotify("error", `提升 Pcap 用户权限失败:${e}`) + }) + .finally(() => setPcapHintLoading(false)) + }) + + // 开始扫描 + const handleOpenScanning = useMemoizedFn(() => { + if (scanningCheck === "specialVulnerabilityDetection") { + onMenu({route: YakitRoute.PoC}) + } else if (scanningCheck === "customDetection") { + onMenu({route: YakitRoute.BatchExecutorPage}) + } + setRemoteValue(RemoteGV.HomeStartScanning, scanningCheck) + }) + + // 工具箱渲染列表 + const renderToolsList = useMemo(() => { + return searchToolVal + ? toolsList.filter((v) => v.label.toLocaleLowerCase().includes(searchToolVal.toLocaleLowerCase())) + : toolsList + }, [searchToolVal, toolsList]) + + // 项目名称 + const projectName = useMemo(() => { + if (isEnpriTraceAgent()) return getReleaseEditionName() + if (curProjectInfo?.ProjectName === "[temporary]") { + return "临时项目" + } else { + return curProjectInfo?.ProjectName + ? curProjectInfo?.ProjectName.substring(1, curProjectInfo?.ProjectName.length - 1) + : getReleaseEditionName() + } + }, [curProjectInfo]) + + // 更新项目数据库大小 + const updateProjectDbSize = async () => { + ipcRenderer.invoke("GetCurrentProject").then((res: ProjectDescription) => { + setCurProjectInfo(res) + }) + } + const convertToBytes = (size: number, unit: string) => { + const units = { + B: 1, + KB: 1024, + MB: 1024 ** 2, + GB: 1024 ** 3, + TB: 1024 ** 4 + } + return size * (units[unit.toUpperCase()] || 1) + } + const judgeMoreTenGB = useMemo(() => { + const arr: string[] = curProjectInfo?.FileSize.split(" ") || [] + if (arr[0] && arr[1]) { + return convertToBytes(+arr[0], arr[1]) > convertToBytes(10, "GB") + } else { + return false + } + }, [curProjectInfo?.FileSize]) + + // 更新流量数据 + const undateHistoryData = () => { + const params = { + SourceType: "mitm,scan,basic-crawler", + WithPayload: false, + Pagination: { + Page: 1, + Limit: 10, + Order: "desc", + OrderBy: "Id" + } + } + ipcRenderer.invoke("QueryHTTPFlows", params).then((rsp: YakQueryHTTPFlowResponse) => { + setHistoryData(rsp.Total) + }) + } + + // 更新漏洞数据 + const undateRiskLevel = () => { + ipcRenderer.invoke("QueryAvailableRiskLevel", {}).then((i: Fields) => { + setRiskLevelData(i.Values) + }) + } + const riskLevelTotal = (verbose: string) => { + return riskLevelData.find((item) => item.Verbose === verbose)?.Total || 0 + } + + // 更新端口数据 + const updatePortTotal = () => { + const params: QueryPortsRequest = { + Hosts: "", + Ports: "", + State: "open", + Service: "", + Title: "", + TitleEffective: false, + Keywords: "", + ComplexSelect: "", + RuntimeId: "", + Pagination: { + Limit: 20, + Page: 1, + OrderBy: "id", + Order: "desc" + }, + All: true, + Order: "desc", + OrderBy: "id" + } + apiQueryPortsBase(params).then((allRes) => { + setPortTotal(Number(allRes.Total)) + }) + } + + // 更新本地插件 + const updateLocalPluginTotal = () => { + apiQueryYakScriptTotal().then((res) => { + setLocalPluginTotal(+res.Total) + }) + } + + // 计算各个块的高度 + const mitmRef = useRef(null) + const webFuzzerRef = useRef(null) + const signlejumpRef = useRef(null) + const vulnerabilityRef = useRef(null) + const [watchWidth, setWatchWidth] = useState(0) + const adjustHeight = (container, wRadio: number, hRadio: number, minHeight: number, maxHeight: number) => { + if (!container) return + const width = container.clientWidth + const height = (width * hRadio) / wRadio + if (height > maxHeight) { + container.style.height = maxHeight + "px" + return + } + if (height < minHeight) { + container.style.height = minHeight + "px" + return + } + container.style.height = height + "px" + } + const calcMitmAndwebFuzzerMinWidth = () => { + const screenWidth = window.innerWidth + if (screenWidth <= 1220) return 320 + if (screenWidth > 1221 && screenWidth <= 1920) return 400 + return 450 + } + const calcSignlejumpAndVulnerabilityMinWidth = () => { + const screenWidth = window.innerWidth + if (screenWidth <= 1220) return 250 + if (screenWidth > 1221 && screenWidth <= 1920) return 300 + return 320 + } + const resizeAdjustHeight = useThrottleFn( + () => { + adjustHeight(mitmRef.current, 16, 9, calcMitmAndwebFuzzerMinWidth(), 650) + adjustHeight(webFuzzerRef.current, 16, 9, calcMitmAndwebFuzzerMinWidth(), 650) + adjustHeight(signlejumpRef.current, 16, 9, calcSignlejumpAndVulnerabilityMinWidth(), 450) + adjustHeight(vulnerabilityRef.current, 16, 9, calcSignlejumpAndVulnerabilityMinWidth(), 450) + }, + {wait: 300} + ).run + useEffect(() => { + resizeAdjustHeight() + }, [watchWidth]) + + return ( +
+ + { + if (!w || !h) { + return + } + setWatchWidth(w) + }} + handleHeight={true} + /> +
+
{ + if (showMitmDropdown) return + onMenu({route: YakitRoute.HTTPHacker}) + }} + > +
+
+ + MITM 交互式劫持 +
+
+ 安装 SSL/TLS + 证书,劫持浏览器所有流量请求、响应数据包,提供手动劫持与被动扫描两种模式 +
+
+ {showMITMCertWarn && ( +
+
+ + 检测到证书未配置 +
+ + 下载安装 + +
+ )} +
+
+
+
+
+
+
+
{ + e.stopPropagation() + onMenu({route: YakitRoute.HTTPHacker}) + setTimeout(() => { + emiter.emit( + "onHomeExecStartMITM", + JSON.stringify({ + host: hostWatch, + port: portWatch, + enableInitialPlugin: + form.getFieldValue( + "enableInitialPlugin" + ) === true + }) + ) + }, 500) + }} + > + + 启动劫持 +
+
{ + e.stopPropagation() + setShowMitmDropdown(!showMitmDropdown) + }} + > + +
+
e.stopPropagation()} + > +
+ + + + + + + + + +
+
+
+
+
+
+
+
+
+
+
onMenu({route: YakitRoute.HTTPFuzzer})} + > +
+
+ + WebFuzzer +
+
+ 通过核心模糊测试标签语法,实现了对 Burpsuite 的 Repeater 和 Intruder 的完美整合 +
+
+
+
+ + 爆破示例 +
+
+
{ + e.stopPropagation() + handleBlastingExample("id") + }} + > + 爆破 ID +
+
{ + e.stopPropagation() + handleBlastingExample("pwd") + }} + > + 爆破密码 +
+
{ + e.stopPropagation() + handleBlastingExample("count") + }} + > + 爆破账户 +
+
+
+
+
+ + Fuzz 序列动画演示 +
+
+ 将多个 Web Fuzzer 节点串联起来,实现更复杂的逻辑与功能 +
+
+ } + className={styles["animation-btn"]} + type='outline1' + onClick={handleSequenceAnimation} + > + 演示动画 + +
+
+
+
+
+
+
onMenu({route: YakitRoute.PayloadGenerater_New})} + > +
+ +
+
Yso-Java Hack
+
+ 配置序列化 Payload 或恶意类,测试反序列化、类加载、JNDI 漏洞利用等 +
+
+
+
+
onMenu({route: YakitRoute.DNSLog})} + > +
+ +
+
DNSLog
+
+ 自动生成一个子域名,任何查询到这个子域名的 IP 被集合展示在列表中 +
+
+
+
+
onMenu({route: YakitRoute.Codec})} + > +
+ +
+
Codec
+
+ 加解密与编码,可通过插件自定义数据处理方法 +
+
+
+
+
+
+
+
+ + 漏洞扫描 +
+
+ 可自由选择需要的 POC 进行批量漏洞检测,或选择设置好的分组进行专项漏洞扫描 +
+
+
+
+
+ + 开始扫描 +
+
setShowScanningDropdown(!showScanningDropdown)} + > + +
+
+ {[ + {label: "专项漏洞检测", key: "specialVulnerabilityDetection"}, + {label: "自定义检测", key: "customDetection"} + ].map((item) => ( +
{ + setScanningCheck(item.key) + setShowScanningDropdown(!showScanningDropdown) + }} + key={item.key} + > + {item.label} + {scanningCheck === item.key && ( + + )} +
+ ))} +
+
+
+ {!pcap.IsPrivileged && system !== "Windows_NT" && ( +
+
+ + 检测到网卡权限未修复 +
+ { + if (pcapHintShow) return + setPcapHintShow(true) + }} + > + 去修复 + +
+ )} + : undefined} + title={pcapResult ? "已有网卡操作权限" : "当前引擎不具有网卡操作权限"} + content={ + pcapResult + ? "网卡修复需要时间,请耐心等待" + : "Linux 与 MacOS 可通过设置权限与组为用户态赋予网卡完全权限" + } + okButtonText='开启 PCAP 权限' + cancelButtonText={pcapResult ? "知道了~" : "稍后再说"} + okButtonProps={{ + loading: pcapHintLoading, + style: pcapResult ? {display: "none"} : undefined + }} + cancelButtonProps={{loading: !pcapResult && pcapHintLoading}} + onOk={openPcapPower} + onCancel={() => { + setPcapResult(false) + setPcapHintShow(false) + }} + footerExtra={ + pcapResult ? undefined : ( + + + 手动修复 + + + ) + } + > +
+
onMenu({route: YakitRoute.Mod_ScanPort})} + > + + 端口扫描 +
+
onMenu({route: YakitRoute.Mod_Brute})} + > + + 弱口令检测 +
+
+ onMenu({ + route: YakitRoute.Plugin_OP, + pluginId: pluginToId[ResidentPluginName.DirectoryScanning], + pluginName: ResidentPluginName.DirectoryScanning + }) + } + > + + 目录爆破 +
+
+
+
+
+ } + firstRatio='50%' + firstMinSize='800px' + firstNodeStyle={{padding: 0}} + secondNode={ +
+
+
+ + 工具箱 + 可通过搜索快速查找软件功能 +
+
+ setSearchToolVal(value)} /> +
+
+ {renderToolsList.length ? ( + <> + {renderToolsList.map((item) => ( +
+
+
+ {item.icon} +
+ {item.label} +
+
{item.desc}
+
{item.rightIcon}
+
+ ))} + + ) : ( + + )} +
+
+
+
+ + {projectName} +
+
+ + 项目数据库 +
+ {!judgeMoreTenGB ? ( + + {curProjectInfo?.FileSize} + + ) : ( + <> + + {curProjectInfo?.FileSize} + + + + + + )} +
+
+
+ + 流量数据 +
+ + {numeral(historyData).format("0,0")} + +
+
+ {(riskLevelTotal("严重") || + riskLevelTotal("高危") || + riskLevelTotal("中危") || + riskLevelTotal("低危")) > 0 ? ( +
+ + 漏洞数据 +
+ {riskLevelTotal("严重") ? ( +
+
严重
+
{riskLevelTotal("严重")}
+
+ ) : null} + {riskLevelTotal("高危") ? ( +
+
高危
+
{riskLevelTotal("高危")}
+
+ ) : null} + {riskLevelTotal("中危") ? ( +
+
中危
+
{riskLevelTotal("中危")}
+
+ ) : null} + {riskLevelTotal("低危") ? ( +
+
低危
+
{riskLevelTotal("低危")}
+
+ ) : null} +
+
+ ) : null} +
+ + 端口数据 +
+ {portTotal} +
+
+
+ + 本地插件 +
+ {localPluginTotal < 30 ? ( + } + onClick={() => setVisibleOnline(true)} + style={{padding: 0}} + className={styles["download-btn"]} + > + 一键下载 + + ) : ( + {localPluginTotal} + )} +
+ {visibleOnline && ( + { + setVisibleOnline(v) + updateLocalPluginTotal() + }} + /> + )} +
+
+
+ } + secondRatio='10%' + secondMinSize='350px' + > +
+ ) +} + +export default Home diff --git a/app/renderer/src/main/src/pages/home/home.module.scss b/app/renderer/src/main/src/pages/home/home.module.scss new file mode 100644 index 0000000000..980411cbdc --- /dev/null +++ b/app/renderer/src/main/src/pages/home/home.module.scss @@ -0,0 +1,1531 @@ +// 这里的样式 字体大小 icon大小 gap大小和设备宽度大于等于1921px的样式一致 +.home-page-wrapper { + height: 100%; + padding: 14px 18px; + &-left { + display: flex; + flex-direction: column; + height: 100%; + overflow: auto; + .left-row-wrapper { + display: flex; + margin-bottom: 10px; + &:last-of-type { + margin-bottom: 0; + } + } + } + &-right { + display: flex; + overflow: hidden; + flex-direction: column; + height: 100%; + } + .home-card { + display: flex; + justify-content: space-between; + overflow: hidden; + flex-direction: column; + border-radius: 8px; + + gap: 10px; + &-header { + &-title { + display: flex; + align-items: center; + .title-icon { + svg { + width: 36px; + height: 36px; + } + } + .title-text { + margin-left: 8px; + font-size: 20px; + font-weight: 600; + } + } + &-desc { + color: #85899e; + font-size: 16px; + } + } + &-operation-btn-wrapper { + display: flex; + justify-content: center; + } + &-config-detection { + display: flex; + justify-content: space-between; + align-items: center; + height: 38px; + padding-left: 8px; + border-radius: 4px; + background-color: #eee9f1; + .exclamation-icon { + svg { + width: 18px; + height: 18px; + } + } + .config-detection-left { + display: flex; + align-items: center; + margin-right: 4px; + color: #f6544a; + font-size: 14px; + } + .config-detection-btn { + height: 38px; + font-size: 14px; + } + } + .operation-btn-wrapper { + position: relative; + display: flex; + color: #ffffff; + border-radius: 40px; + .operation-btn-left { + display: flex; + justify-content: center; + align-items: center; + padding: 8px 12px; + cursor: pointer; + border-right: 1px solid #ffffff; + background-color: var(--yakit-primary-5); + font-size: 18px; + font-weight: 600; + .open-icon { + margin-right: 4px; + svg { + width: 28px; + height: 28px; + } + } + &:hover { + background-color: var(--yakit-primary-4); + } + &:active { + background-color: var(--yakit-primary-6); + } + } + .operation-btn-right { + display: flex; + justify-content: center; + align-items: center; + padding: 8px; + cursor: pointer; + transition: transform 0.5s; + background-color: var(--yakit-primary-6); + .title-icon { + transition: transform 0.5s; + &.rotate-180 { + transform: rotate(180deg); + } + } + &:hover { + background-color: var(--yakit-primary-5); + } + } + } + } + .mitm-card { + overflow: visible; + flex: 1; + margin-right: 10px; + padding: 22px; + padding-bottom: 0px; + cursor: pointer; + border: 1px solid #b5f2f9; + background-color: #ebfcfe; + &:hover { + border: 1px solid rgba(53, 216, 238, 1); + background-color: rgba(53, 216, 238, 0.2); + } + .mitm-cont-wrapper { + flex: 1; + border-radius: 8px 8px 0 0; + background-size: cover; + .mitm-glass-effect { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + border-radius: 8px 8px 0 0; + background: rgba(255, 255, 255, 0.3); /* 半透明背景 */ + + backdrop-filter: blur(2px); + .mitm-operation { + &-border { + width: 100%; + border-radius: 40px; + } + } + } + .mitm-operation { + .operation-dropdown-wrapper { + position: absolute; + bottom: -154px; + left: 50%; + width: 300px; + margin-left: -150px; + padding: 20px 20px 10px 10px; + transition: all 0.5 ease; + border: 1px solid var(--yakit-border-color); + border-radius: 4px; + background-color: #ffffff; + :global { + .ant-form-item { + margin-bottom: 8px; + } + } + } + } + } + } + .webFuzzer-card { + flex: 1; + padding: 22px; + cursor: pointer; + border: 1px solid #c2ebd6; + background-color: #effaf4; + &:hover { + border: 1px solid #56c991; + background-color: rgba(86, 201, 145, 0.2); + } + .example-blasting-wrapper { + display: flex; + flex-direction: column; + flex: 1; + padding: 18px 22px; + border-radius: 8px; + background-color: #ffffff; + .example-blasting-title { + display: flex; + align-items: center; + margin-bottom: 8px; + span.title-text { + margin-left: 8px; + font-size: 16px; + font-weight: 600; + } + } + .example-blasting-video-wrapper { + display: flex; + justify-content: space-between; + flex: 1; + + gap: 10px; + .example-blasting-video { + display: flex; + justify-content: center; + align-items: center; + flex: 1; + cursor: pointer; + text-align: center; + color: var(--yakit-primary-5); + border-radius: 8px; + background-color: #fff8f4; + font-size: 16px; + font-weight: 600; + &:hover { + border: 1px solid var(--yakit-primary-5); + } + } + .example-blasting-title { + .example-blasting-icon { + svg { + width: 28px; + height: 28px; + } + } + span.title-text { + font-size: 16px; + } + } + } + } + .sequence-animation-wrapper { + position: relative; + flex: 1; + padding: 18px 22px; + border-radius: 8px; + background-color: #ffffff; + .sequence-animation-title { + display: flex; + align-items: center; + margin-bottom: 8px; + span.title-text { + margin-left: 8px; + font-size: 16px; + font-weight: 600; + } + .sequence-animation-icon { + svg { + width: 28px; + height: 28px; + } + } + } + .sequence-animation-desc { + margin-bottom: 10px; + color: #85899e; + font-size: 16px; + } + .sequence-animation-btn-wrapper { + text-align: center; + .animation-play-icon { + svg { + width: 24px; + height: 24px; + } + } + .animation-btn { + height: 32px; + padding: 0 14px; + font-size: 16px; + } + } + } + } + .signle-jump-wrapper { + display: flex; + flex-direction: column; + width: 50%; + height: 100%; + margin-right: 10px; + + gap: 10px; + .signle-jump-item { + display: flex; + align-items: center; + flex: 1; + padding: 0 14px; + cursor: pointer; + border: 1px solid #eaecf3; + border-radius: 8px; + &:last-of-type { + margin-bottom: 0; + } + &-cont { + display: flex; + align-items: center; + .signle-jump-item-icon { + svg { + width: 36px; + height: 36px; + } + } + &-right { + margin-left: 8px; + .single-jump-cont-title { + font-size: 18px; + font-weight: 600; + } + .single-jump-cont-desc { + color: #85899e; + font-size: 16px; + } + } + } + &:hover { + background-color: #f8f8f8; + } + } + } + .vulnerability-scanning-card { + width: 50%; + padding: 22px; + padding-bottom: 14px; + border: 1px solid #bcd8fd; + background-color: #edf5ff; + .operation-dropdown-wrapper { + position: absolute; + right: 0; + bottom: -85px; + left: 0; + padding: 8px; + transition: all 0.5 ease; + border: 1px solid var(--yakit-border-color); + border-radius: 4px; + background-color: #ffffff; + .operation-dropdown-list-item { + display: flex; + justify-content: space-between; + padding: 6px 8px; + cursor: pointer; + color: #000000; + font-size: 14px; + line-height: 20px; + &:hover { + background-color: var(--yakit-primary-1); + } + &.active { + color: var(--yakit-primary-5); + } + .check-icon { + svg { + color: var(--yakit-primary-5); + } + } + } + } + .security-tools { + display: flex; + justify-content: space-between; + flex: 1; + + gap: 10px; + &-item { + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; + flex: 1; + cursor: pointer; + border-radius: 8px; + background-color: #ffffff; + + gap: 6px; + &:hover { + border: 1px solid var(--yakit-primary-5); + } + .tools-icon { + svg { + width: 36px; + height: 36px; + } + } + .tools-text { + font-size: 16px; + font-weight: 600; + } + } + } + } + .tools-wrapper { + display: flex; + overflow: hidden; + flex-direction: column; + flex: 1; + height: 70%; + margin-bottom: 10px; + padding: 18px 14px; + border: 1px solid var(--yakit-border-color); + border-radius: 8px; + + gap: 10px; + .tools-title-wrapper { + display: flex; + align-items: center; + + gap: 10px; + .tools-title-icon { + svg { + width: 28px; + height: 28px; + } + } + .tools-title-text { + justify-content: center; + align-items: center; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + font-size: 20px; + font-weight: 600; + } + .tools-title-desc { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + color: #85899e; + font-size: 14px; + } + } + .tools-search-wrapper { + // height: 28px; + // :global { + // .search-icon { + // svg { + // width: 16px; + // height: 16px; + // } + // } + // } + } + .tools-list-wrapper { + overflow-y: overlay; + flex: 1; + .tools-list-item { + display: flex; + align-items: center; + width: 100%; + padding: 12px; + cursor: pointer; + &:not(:first-child) { + border-top: 1px solid var(--yakit-border-color); + } + &:last-child { + border-bottom: 1px solid var(--yakit-border-color); + } + .tools-item-left-wrapper { + display: flex; + align-items: center; + + gap: 8px; + .tools-item-icon { + display: flex; + justify-content: center; + align-items: center; + overflow: hidden; + margin-right: 4px; + border-radius: 6px; + svg { + width: 22px; + height: 22px; + } + } + .tools-item-label { + white-space: nowrap; + font-size: 16px; + font-weight: 600; + } + } + .tools-item-desc { + visibility: hidden; + overflow: hidden; + margin: 0 8px; + padding: 0 6px; + white-space: nowrap; + text-overflow: ellipsis; + border-radius: 4px; + background-color: #eaecf3; + font-size: 15px; + } + .tools-item-right-icon { + visibility: hidden; + flex: 1; + text-align: right; + svg { + width: 18px; + height: 18px; + color: var(--yakit-primary-5); + } + } + &:hover { + border-color: transparent; + border-radius: 8px; + background-color: #f8f8f8; + & + .tools-list-item { + border-top-color: transparent; + } + .tools-item-desc { + visibility: visible; + } + .tools-item-right-icon { + visibility: visible; + } + } + } + } + } + .data-preview-wrapper { + display: flex; + justify-content: space-between; + overflow-y: auto; + flex-direction: column; + max-height: 500px; + padding: 18px 14px; + border: 1px solid var(--yakit-border-color); + border-radius: 8px; + .data-preview-title { + display: flex; + align-items: center; + + gap: 12px; + .data-preview-title-icon { + svg { + width: 28px; + height: 28px; + color: #56c991; + path { + stroke: #31343f; + } + } + } + .data-preview-title-text { + font-size: 16px; + font-weight: 600; + } + } + .data-preview-item { + display: flex; + align-items: center; + .data-preview-item-icon { + margin-right: 10px; + svg { + width: 22px; + height: 22px; + color: #85899e; + path { + stroke-width: 1.5; + } + } + } + .data-preview-item-text { + display: inline-block; + width: 100px; + color: #85899e; + font-size: 16px; + } + .data-preview-item-cont { + display: flex; + align-items: center; + .download-btn-icon { + svg { + width: 20px; + height: 20px; + } + } + .download-btn { + font-size: 16px; + } + .data-preview-item-number { + display: inline-block; + margin-right: 4px; + color: #31343f; + } + .database-warning-icon { + svg { + width: 22px; + height: 22px; + color: #f6544a; + } + } + } + .risk-tag-wrapper { + display: flex; + align-items: center; + flex-wrap: wrap; + flex: 1; + flex: 0 0 50%; + width: 200px; + .risk-tag { + display: flex; + margin-right: 4px; + margin-bottom: 4px; + border-radius: 4px; + font-size: 14px; + + flex-shrink: 0; + .risk-text { + padding: 2px 6px; + } + .risk-num { + padding: 2px 6px; + color: #85899e; + } + } + .seriousRisk-tag { + border: 1px solid #e99a95; + .risk-text { + color: #cb2318; + border-right: 1px solid #e99a95; + background-color: rgba(203, 35, 24, 0.2); + } + } + .highRisk-tag { + border: 1px solid #f3c2bf; + .risk-text { + color: #f6544a; + border-right: 1px solid #f3c2bf; + background-color: rgba(246, 84, 74, 0.2); + } + } + .mediumRisk-tag { + border: 1px solid #fbc6a1; + .risk-text { + color: #f28b44; + border-right: 1px solid #fbc6a1; + background-color: #fbe7d9; + } + } + .lowRisk-tag { + border: 1px solid #ffe5c6; + .risk-text { + color: #ffb660; + border-right: 1px solid #ffe5c6; + background-color: rgba(255, 213, 131, 0.1); + } + } + } + } + } +} +.sequence-animation-pop-title { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + .subtitle-help-wrapper { + display: flex; + align-items: center; + cursor: pointer; + color: #b4bbca; + font-size: 14px; + font-weight: 400; + line-height: 20px; + .text-style { + text-decoration-line: underline; + } + svg { + width: 16px; + height: 16px; + } + } + .subtitle-help-wrapper:hover { + color: var(--yakit-primary-5); + } +} + +/* 适用于设备宽度小于1220px的样式 */ +@media (max-width: 1220px) { + .home-page-wrapper { + padding: 10px 14px; + &-left { + margin-right: 6px; + &-top { + margin-bottom: 6px; + } + } + .home-card { + gap: 4px; + &-header { + &-title { + .title-icon { + svg { + width: 28px; + height: 28px; + } + } + .title-text { + font-size: 16px; + } + } + &-desc { + font-size: 12px; + } + } + &-config-detection { + height: 34px; + .exclamation-icon { + svg { + width: 12px; + height: 12px; + } + } + .config-detection-left { + font-size: 10px; + } + .config-detection-btn { + height: 34px; + font-size: 10px; + } + } + .operation-btn-wrapper { + .operation-btn-left { + font-size: 14px; + .open-icon { + svg { + width: 20px; + height: 20px; + } + } + } + } + } + .mitm-card { + margin-right: 6px; + padding: 18px; + padding-bottom: 0px; + .mitm-cont-wrapper { + .mitm-operation { + .operation-dropdown-wrapper { + bottom: -145px; + padding: 18px 18px 8px 8px; + :global { + .ant-form-item { + margin-bottom: 5px; + } + } + } + } + } + } + .webFuzzer-card { + padding: 18px; + .example-blasting-wrapper { + padding: 14px 18px; + .example-blasting-title { + margin-bottom: 6px; + } + .example-blasting-video-wrapper { + gap: 4px; + .example-blasting-video { + font-size: 12px; + } + } + .example-blasting-title { + .example-blasting-icon { + svg { + width: 20px; + height: 20px; + } + } + span.title-text { + font-size: 12px; + } + } + } + .sequence-animation-wrapper { + padding: 14px 18px; + .sequence-animation-title { + margin-bottom: 4px; + .sequence-animation-icon { + svg { + width: 20px; + height: 20px; + } + } + span.title-text { + font-size: 12px; + } + } + .sequence-animation-desc { + margin-bottom: 6px; + font-size: 12px; + } + .sequence-animation-btn-wrapper { + .animation-play-icon { + svg { + width: 16px; + height: 16px; + } + } + .animation-btn { + height: 28px; + padding: 0 10px; + font-size: 12px; + } + } + } + } + .signle-jump-wrapper { + margin-right: 6px; + + gap: 4px; + .signle-jump-item { + padding: 0 10px; + &-cont { + .signle-jump-item-icon { + svg { + width: 28px; + height: 28px; + } + } + &-right { + .single-jump-cont-title { + font-size: 14px; + } + .single-jump-cont-desc { + font-size: 12px; + } + } + } + } + } + .vulnerability-scanning-card { + padding: 18px; + padding-bottom: 10px; + .security-tools { + gap: 4px; + &-item { + gap: 4px; + .tools-icon { + svg { + width: 28px; + height: 28px; + } + } + .tools-text { + font-size: 12px; + } + } + } + } + .tools-wrapper { + height: 75%; + margin-bottom: 6px; + padding: 12px 14px; + + gap: 4px; + .tools-title-wrapper { + gap: 4px; + .tools-title-icon { + svg { + width: 20px; + height: 20px; + } + } + .tools-title-text { + font-size: 16px; + } + .tools-title-desc { + font-size: 10px; + } + } + .tools-list-wrapper { + .tools-list-item { + padding: 8px; + .tools-item-left-wrapper { + gap: 2px; + .tools-item-icon { + svg { + width: 14px; + height: 14px; + } + } + .tools-item-label { + font-size: 12px; + } + } + .tools-item-desc { + margin: 0 4px; + font-size: 11px; + } + .tools-item-right-icon { + svg { + width: 10px; + height: 10px; + } + } + } + } + } + .data-preview-wrapper { + padding: 14px 10px; + .data-preview-title { + gap: 4px; + .data-preview-title-icon { + svg { + width: 20px; + height: 20px; + } + } + .data-preview-title-text { + font-size: 12px; + } + } + .data-preview-item { + .data-preview-item-icon { + margin-right: 6px; + svg { + width: 14px; + height: 14px; + } + } + .data-preview-item-text { + width: 100px; + font-size: 12px; + } + .data-preview-item-cont { + .download-btn-icon { + svg { + width: 12px; + height: 12px; + } + } + .download-btn { + font-size: 12px; + } + .data-preview-item-number { + font-size: 14px; + } + .database-warning-icon { + svg { + width: 14px; + height: 14px; + } + } + } + .risk-tag-wrapper { + width: 200px; + .risk-tag { + font-size: 10px; + } + } + } + } + } +} +/* 适用于设备宽度介于1221px和1440px之间的样式 */ +@media (min-width: 1221px) and (max-width: 1920px) { + .home-page-wrapper { + padding: 12px 16px; + &-left { + margin-right: 8px; + &-top { + margin-bottom: 8px; + } + } + .home-card { + gap: 8px; + &-header { + &-title { + .title-icon { + svg { + width: 32px; + height: 32px; + } + } + .title-text { + font-size: 18px; + } + } + &-desc { + font-size: 14px; + } + } + &-config-detection { + height: 36px; + .exclamation-icon { + svg { + width: 14px; + height: 14px; + } + } + .config-detection-left { + font-size: 12px; + } + .config-detection-btn { + height: 36px; + font-size: 12px; + } + } + .operation-btn-wrapper { + .operation-btn-left { + font-size: 16px; + .open-icon { + svg { + width: 24px; + height: 24px; + } + } + } + } + } + .mitm-card { + margin-right: 8px; + padding: 20px; + padding-bottom: 0px; + .mitm-cont-wrapper { + .mitm-operation { + .operation-dropdown-wrapper { + bottom: -154px; + padding: 20px 20px 10px 10px; + :global { + .ant-form-item { + margin-bottom: 7px; + } + } + } + } + } + } + .webFuzzer-card { + padding: 20px; + .example-blasting-wrapper { + padding: 16px 20px; + .example-blasting-title { + margin-bottom: 8px; + } + .example-blasting-video-wrapper { + gap: 8px; + .example-blasting-video { + font-size: 14px; + } + } + .example-blasting-title { + .example-blasting-icon { + svg { + width: 24px; + height: 24px; + } + } + span.title-text { + font-size: 14px; + } + } + } + .sequence-animation-wrapper { + padding: 16px 20px; + .sequence-animation-title { + margin-bottom: 6px; + .sequence-animation-icon { + svg { + width: 24px; + height: 24px; + } + } + span.title-text { + font-size: 14px; + } + } + .sequence-animation-desc { + margin-bottom: 8px; + font-size: 14px; + } + .sequence-animation-btn-wrapper { + .animation-play-icon { + svg { + width: 20px; + height: 20px; + } + } + .animation-btn { + height: 30px; + padding: 0 12px; + font-size: 14px; + } + } + } + } + .signle-jump-wrapper { + margin-right: 8px; + + gap: 8px; + .signle-jump-item { + padding: 0 12px; + &-cont { + .signle-jump-item-icon { + svg { + width: 32px; + height: 32px; + } + } + &-right { + .single-jump-cont-title { + font-size: 16px; + } + .single-jump-cont-desc { + font-size: 14px; + } + } + } + } + } + .vulnerability-scanning-card { + padding: 20px; + padding-bottom: 12px; + .security-tools { + gap: 8px; + &-item { + gap: 4px; + .tools-icon { + svg { + width: 32px; + height: 32px; + } + } + .tools-text { + font-size: 14px; + } + } + } + } + .tools-wrapper { + height: 70%; + margin-bottom: 8px; + padding: 16px 12px; + + gap: 8px; + .tools-title-wrapper { + gap: 8px; + .tools-title-icon { + svg { + width: 24px; + height: 24px; + } + } + .tools-title-text { + font-size: 18px; + } + .tools-title-desc { + font-size: 12px; + } + } + .tools-list-wrapper { + .tools-list-item { + padding: 10px; + .tools-item-left-wrapper { + gap: 4px; + .tools-item-icon { + svg { + width: 18px; + height: 18px; + } + } + .tools-item-label { + font-size: 14px; + } + } + .tools-item-desc { + margin: 0 6px; + font-size: 13px; + } + .tools-item-right-icon { + svg { + width: 14px; + height: 14px; + } + } + } + } + } + .data-preview-wrapper { + padding: 16px 12px; + .data-preview-title { + gap: 8px; + .data-preview-title-icon { + svg { + width: 24px; + height: 24px; + } + } + .data-preview-title-text { + font-size: 14px; + } + } + .data-preview-item { + .data-preview-item-icon { + margin-right: 8px; + svg { + width: 18px; + height: 18px; + } + } + .data-preview-item-text { + width: 100px; + font-size: 14px; + } + .data-preview-item-cont { + .download-btn-icon { + svg { + width: 16px; + height: 16px; + } + } + .download-btn { + font-size: 14px; + } + .data-preview-item-number { + font-size: 16px; + } + .database-warning-icon { + svg { + width: 18px; + height: 18px; + } + } + } + .risk-tag-wrapper { + width: 200px; + .risk-tag { + font-size: 12px; + } + } + } + } + } +} +/* 适用于设备宽度大于等于1921px的样式 */ +@media (min-width: 1921px) { + .home-page-wrapper { + padding: 14px 18px; + &-left { + margin-right: 10px; + &-top { + margin-bottom: 10px; + } + } + .home-card { + gap: 10px; + &-header { + &-title { + .title-icon { + svg { + width: 36px; + height: 36px; + } + } + .title-text { + font-size: 20px; + } + } + &-desc { + font-size: 16px; + } + } + &-config-detection { + height: 38px; + .exclamation-icon { + svg { + width: 18px; + height: 18px; + } + } + .config-detection-left { + font-size: 14px; + } + .config-detection-btn { + height: 38px; + font-size: 14px; + } + } + .operation-btn-wrapper { + .operation-btn-left { + font-size: 18px; + .open-icon { + svg { + width: 28px; + height: 28px; + } + } + } + } + } + .mitm-card { + margin-right: 10px; + padding: 22px; + padding-bottom: 0px; + .mitm-cont-wrapper { + .mitm-operation { + .operation-dropdown-wrapper { + bottom: -154px; + padding: 20px 20px 10px 10px; + :global { + .ant-form-item { + margin-bottom: 8px; + } + } + } + } + } + } + .webFuzzer-card { + padding: 22px; + .example-blasting-wrapper { + padding: 18px 22px; + .example-blasting-title { + margin-bottom: 8px; + } + .example-blasting-video-wrapper { + gap: 10px; + .example-blasting-video { + font-size: 16px; + } + } + .example-blasting-title { + .example-blasting-icon { + svg { + width: 28px; + height: 28px; + } + } + span.title-text { + font-size: 16px; + } + } + } + .sequence-animation-wrapper { + padding: 18px 22px; + .sequence-animation-title { + margin-bottom: 8px; + .sequence-animation-icon { + svg { + width: 28px; + height: 28px; + } + } + span.title-text { + font-size: 16px; + } + } + .sequence-animation-desc { + margin-bottom: 10px; + font-size: 16px; + } + .sequence-animation-btn-wrapper { + .animation-play-icon { + svg { + width: 24px; + height: 24px; + } + } + .animation-btn { + height: 32px; + padding: 0 14px; + font-size: 16px; + } + } + } + } + .signle-jump-wrapper { + margin-right: 10px; + + gap: 10px; + .signle-jump-item { + padding: 0 14px; + &-cont { + .signle-jump-item-icon { + svg { + width: 36px; + height: 36px; + } + } + &-right { + .single-jump-cont-title { + font-size: 18px; + } + .single-jump-cont-desc { + font-size: 16px; + } + } + } + } + } + .vulnerability-scanning-card { + padding: 22px; + padding-bottom: 14px; + .security-tools { + gap: 10px; + &-item { + gap: 6px; + .tools-icon { + svg { + width: 36px; + height: 36px; + } + } + .tools-text { + font-size: 16px; + } + } + } + } + .tools-wrapper { + height: 70%; + margin-bottom: 10px; + padding: 18px 14px; + + gap: 10px; + .tools-title-wrapper { + gap: 10px; + .tools-title-icon { + svg { + width: 28px; + height: 28px; + } + } + .tools-title-text { + font-size: 20px; + } + .tools-title-desc { + font-size: 14px; + } + } + .tools-list-wrapper { + .tools-list-item { + padding: 12px; + .tools-item-left-wrapper { + gap: 8px; + .tools-item-icon { + svg { + width: 22px; + height: 22px; + } + } + .tools-item-label { + font-size: 16px; + } + } + .tools-item-desc { + margin: 0 8px; + font-size: 15px; + } + .tools-item-right-icon { + svg { + width: 18px; + height: 18px; + } + } + } + } + } + .data-preview-wrapper { + padding: 18px 14px; + .data-preview-title { + gap: 12px; + .data-preview-title-icon { + svg { + width: 28px; + height: 28px; + } + } + .data-preview-title-text { + font-size: 16px; + } + } + .data-preview-item { + .data-preview-item-icon { + margin-right: 10px; + svg { + width: 22px; + height: 22px; + } + } + .data-preview-item-text { + width: 100px; + font-size: 16px; + } + .data-preview-item-cont { + .download-btn-icon { + svg { + width: 20px; + height: 20px; + } + } + .download-btn { + font-size: 16px; + } + .data-preview-item-number { + font-size: 18px; + } + .database-warning-icon { + svg { + width: 22px; + height: 22px; + } + } + } + .risk-tag-wrapper { + width: 200px; + .risk-tag { + font-size: 14px; + } + } + } + } + } +} diff --git a/app/renderer/src/main/src/pages/layout/publicMenu/PublicMenu.tsx b/app/renderer/src/main/src/pages/layout/publicMenu/PublicMenu.tsx index c2a617a2a6..b7ec3b08c1 100644 --- a/app/renderer/src/main/src/pages/layout/publicMenu/PublicMenu.tsx +++ b/app/renderer/src/main/src/pages/layout/publicMenu/PublicMenu.tsx @@ -41,6 +41,7 @@ import classNames from "classnames" import styles from "./PublicMenu.module.scss" import emiter from "@/utils/eventBus/eventBus" import {YakitRoute} from "@/enums/yakitRoute" +import { usePluginToId } from "@/store/publicMenu" const {ipcRenderer} = window.require("electron") @@ -79,6 +80,7 @@ const PublicMenu: React.FC = React.memo((props) => { [ResidentPluginName.BasicCrawler]: 0, [ResidentPluginName.DirectoryScanning]: 0 }) + const {setNewPluginToId} = usePluginToId() const [loading, setLoading] = useState(false) // 常用插件菜单 @@ -128,6 +130,7 @@ const PublicMenu: React.FC = React.memo((props) => { const pluginToIds: Record = {} for (let name of pluginTool) pluginToIds[name] = info[name] || 0 setPluginToId(pluginToIds) + setNewPluginToId(pluginToIds) }) .catch((err) => {}) }) @@ -325,6 +328,7 @@ const PublicMenu: React.FC = React.memo((props) => { const data = {...pluginToId} data[info.pluginName as any] = info.pluginId setPluginToId(data) + setNewPluginToId(data) } else { const menus = [...pluginMenu] menus.forEach((item) => { diff --git a/app/renderer/src/main/src/pages/mitm/MITMPage.tsx b/app/renderer/src/main/src/pages/mitm/MITMPage.tsx index 4da813e7c4..4d282cc7bc 100644 --- a/app/renderer/src/main/src/pages/mitm/MITMPage.tsx +++ b/app/renderer/src/main/src/pages/mitm/MITMPage.tsx @@ -285,6 +285,17 @@ export const MITMPage: React.FC = (props) => { setTip(tip) } ) + const beforeOnHomeExecStartMITM = (values: string) => { + if (status === "idle") { + emiter.emit("onExecStartMITM", values) + } + } + useEffect(() => { + emiter.on("onHomeExecStartMITM", beforeOnHomeExecStartMITM) + return () => { + emiter.off("onHomeExecStartMITM", beforeOnHomeExecStartMITM) + } + }, []) const [visible, setVisible] = useState(false) const mitmPageRef = useRef() diff --git a/app/renderer/src/main/src/pages/mitm/MITMServerHijacking/MITMServerHijacking.module.scss b/app/renderer/src/main/src/pages/mitm/MITMServerHijacking/MITMServerHijacking.module.scss index c66cbcc867..05a13be711 100644 --- a/app/renderer/src/main/src/pages/mitm/MITMServerHijacking/MITMServerHijacking.module.scss +++ b/app/renderer/src/main/src/pages/mitm/MITMServerHijacking/MITMServerHijacking.module.scss @@ -311,6 +311,7 @@ text-orientation: sideways-right; writing-mode: vertical-rl; + border-top: 1px solid #fff; &:hover { background: rgba(204, 210, 222, 0.5); } diff --git a/app/renderer/src/main/src/pages/mitm/MITMServerHijacking/MITMServerHijacking.tsx b/app/renderer/src/main/src/pages/mitm/MITMServerHijacking/MITMServerHijacking.tsx index d91e8f4358..7e9d09fef1 100644 --- a/app/renderer/src/main/src/pages/mitm/MITMServerHijacking/MITMServerHijacking.tsx +++ b/app/renderer/src/main/src/pages/mitm/MITMServerHijacking/MITMServerHijacking.tsx @@ -1,4 +1,4 @@ -import React, {Ref, useEffect, useRef, useState} from "react" +import React, {Ref, useEffect, useImperativeHandle, useRef, useState} from "react" import {Divider, Form, Modal, notification, Typography} from "antd" import emiter from "@/utils/eventBus/eventBus" import ChromeLauncherButton from "@/pages/mitm/MITMChromeLauncher" @@ -69,19 +69,37 @@ export const MITMServerHijacking: React.FC = (props) => } }, [props.enableInitialMITMPlugin, props.defaultPlugins]) + const beforeOnHomeExecStartMITM = (values) => { + stop().then(() => { + setTimeout(() => { + emiter.emit("onExecStartMITM", values) + }, 500) + }) + } + useEffect(() => { + emiter.on("onHomeExecStartMITM", beforeOnHomeExecStartMITM) + return () => { + emiter.off("onHomeExecStartMITM", beforeOnHomeExecStartMITM) + } + }, []) + const stop = useMemoizedFn(() => { // setLoading(true) - ipcRenderer - .invoke("mitm-stop-call") - .then(() => { - setStatus("idle") - }) - .catch((e: any) => { - notification["error"]({message: `停止中间人劫持失败:${e}`}) - }) - .finally(() => { - // setLoading(false) - }) + return new Promise((resolve, reject) => { + ipcRenderer + .invoke("mitm-stop-call") + .then(() => { + setStatus("idle") + resolve("ok") + }) + .catch((e: any) => { + reject(e) + notification["error"]({message: `停止中间人劫持失败:${e}`}) + }) + .finally(() => { + // setLoading(false) + }) + }) }) useEffect(() => { diff --git a/app/renderer/src/main/src/pages/mitm/MITMServerStartForm/MITMServerStartForm.tsx b/app/renderer/src/main/src/pages/mitm/MITMServerStartForm/MITMServerStartForm.tsx index 51a6ae9677..b4286729d2 100644 --- a/app/renderer/src/main/src/pages/mitm/MITMServerStartForm/MITMServerStartForm.tsx +++ b/app/renderer/src/main/src/pages/mitm/MITMServerStartForm/MITMServerStartForm.tsx @@ -25,6 +25,7 @@ import {YakitModal} from "@/components/yakitUI/YakitModal/YakitModal" import {YakitInput} from "@/components/yakitUI/YakitInput/YakitInput" import {YakitAutoCompleteRefProps} from "@/components/yakitUI/YakitAutoComplete/YakitAutoCompleteType" import {CacheDropDownGV} from "@/yakitGV" +import emiter from "@/utils/eventBus/eventBus" const MITMFormAdvancedConfiguration = React.lazy(() => import("./MITMFormAdvancedConfiguration")) const ChromeLauncherButton = React.lazy(() => import("../MITMChromeLauncher")) @@ -199,6 +200,21 @@ export const MITMServerStartForm: React.FC = React.memo const nowTime: string = Math.floor(new Date().getTime() / 1000).toString() setRemoteValue(MITMConsts.MITMStartTimeStamp, nowTime) }) + const beforeExecStartMITM = (values) => { + if (props.status !== "idle") return + try { + const valObj = JSON.parse(values) || {} + form.setFieldsValue({...valObj}) + } catch (error) {} + execStartMITM(form.getFieldsValue()) + } + useEffect(() => { + emiter.on("onExecStartMITM", beforeExecStartMITM) + return () => { + emiter.off("onExecStartMITM", beforeExecStartMITM) + } + }, []) + const [width, setWidth] = useState(0) const [agentConfigModalVisible, setAgentConfigModalVisible] = useState(false) diff --git a/app/renderer/src/main/src/pages/newHome/NewHome.tsx b/app/renderer/src/main/src/pages/newHome/NewHome.tsx deleted file mode 100644 index 652457cc54..0000000000 --- a/app/renderer/src/main/src/pages/newHome/NewHome.tsx +++ /dev/null @@ -1,989 +0,0 @@ -import React, {ForwardedRef, useEffect, useRef, useState} from "react" -import {Row, Col} from "antd" -import {ArrowRightOutlined} from "@ant-design/icons" -import {genDefaultPagination, QueryYakScriptRequest, QueryYakScriptsResponse} from "@/pages/invoker/schema" -import {NetWorkApi} from "@/services/fetch" -import {useStore} from "@/store" -import {API} from "@/services/swagger/resposeType" -import {useGetState, useMemoizedFn, useSize, useInViewport} from "ahooks" -import cloneDeep from "lodash/cloneDeep" -import {failed, success} from "@/utils/notification" -import {PluginType} from "@/pages/yakitStore/YakitStorePage" -import {ReduceCountIcon, AddCountIcon} from "@/pages/customizeMenu/icon/homeIcon" -import CountUp from "react-countup" -import {isCommunityEdition, isEnterpriseEdition} from "@/utils/envfile" -import * as echarts from "echarts" -import {YakitSpin} from "@/components/yakitUI/YakitSpin/YakitSpin" -import {ResidentPluginName, YakitRouteToPageInfo} from "@/routes/newRoute" -import { - PrivateSolidBasicCrawlerIcon, - PrivateSolidBatchPluginIcon, - PrivateSolidBruteIcon, - PrivateSolidCodecIcon, - PrivateSolidDNSLogIcon, - PrivateSolidDataCompareIcon, - PrivateSolidDirectoryScanningIcon, - PrivateSolidICMPSizeLogIcon, - PrivateSolidMitmIcon, - PrivateSolidPayloadGeneraterIcon, - PrivateSolidPayloadManagerIcon, - PrivateSolidPluginStoreIcon, - PrivateSolidPocIcon, - PrivateSolidReverseServerIcon, - PrivateSolidScanPortIcon, - PrivateSolidShellReceiverIcon, - PrivateSolidTCPPortLogIcon, - PrivateSolidWebFuzzerIcon, - PrivateSolidYakRunnerIcon -} from "@/routes/privateIcon" -import {RouteToPageProps} from "../layout/publicMenu/PublicMenu" -import {DownloadOnlinePluginByScriptNamesResponse} from "../layout/publicMenu/utils" -import emiter from "@/utils/eventBus/eventBus" -import styles from "./newHome.module.scss" -import classNames from "classnames" -import {apiFetchGroupStatistics} from "../plugins/utils" -import {YakitButton} from "@/components/yakitUI/YakitButton/YakitButton" -import {OutlineRefreshIcon} from "@/assets/icon/outline" -import {YakitRoute} from "@/enums/yakitRoute" - -const {ipcRenderer} = window.require("electron") - -interface RouteTitleProps { - title: string - echartsError?: boolean - increLoading?: boolean - echartsLoading?: boolean - onRefresh?: () => void -} - -const RouteTitle: React.FC = (props) => { - const {title, echartsError, increLoading, echartsLoading, onRefresh} = props - return ( -
- {title} - {(echartsLoading || increLoading) && ( -
- 加载中... -
- -
-
- )} - {echartsError && ( -
- 加载失败 -
- } - onClick={() => { - onRefresh && onRefresh() - }} - /> -
-
- )} -
- ) -} - -interface RouteItemProps { - dataSource: DataItem - setOpenPage: (param: RouteToPageProps) => void - load: boolean - getCustomizeMenus?: () => void -} - -const RouteItem: React.FC = (props) => { - const {dataSource, setOpenPage, load, getCustomizeMenus} = props - - // 全局登录状态 - const {userInfo} = useStore() - const goRoute = () => { - const info: RouteToPageProps = {route: dataSource.key} - if (dataSource.key === YakitRoute.Plugin_OP && dataSource.pluginId && dataSource.pluginName) { - info.pluginId = +dataSource.pluginId || 0 - info.pluginName = dataSource.pluginName - } - - setOpenPage(info) - } - - const addMenuLab = (name: string) => { - ipcRenderer - .invoke("DownloadOnlinePluginByPluginName", { - ScriptNames: [name], - Token: userInfo.token - }) - .then((rsp: DownloadOnlinePluginByScriptNamesResponse) => { - if (rsp.Data.length > 0) { - success("添加菜单成功") - if (isCommunityEdition()) ipcRenderer.invoke("refresh-public-menu") - else ipcRenderer.invoke("change-main-menu") - } - }) - .catch((e) => { - failed(`添加菜单失败:${e}`) - }) - .finally(() => { - getCustomizeMenus && getCustomizeMenus() - }) - } - const addMenu = (name: string) => { - if ( - [ResidentPluginName.BasicCrawler, ResidentPluginName.DirectoryScanning].includes(name as ResidentPluginName) - ) { - addMenuLab(name) - } - } - return ( - <> - {load && ( -
-
-
- {dataSource.icon} -
-
- {dataSource.isShow ? ( - - ) : ( -
{ - e.stopPropagation() - addMenu(dataSource.pluginName || dataSource.label) - }} - > - 获取菜单 -
- )} -
-
- {dataSource.label} -
-
- {dataSource?.describe || ""} -
-
- )} - - ) -} -interface DataItem { - id: string - key: YakitRoute - icon: JSX.Element - describe?: string - label: string - pluginName?: string - pluginId?: string - isShow: boolean -} - -interface newHomeListData { - id: string - label: string - subMenuData: DataItem[] -} - -interface RouteListProps { - load?: boolean - colLimit?: 1 | 2 | 3 - data: newHomeListData - setOpenPage: (param: RouteToPageProps) => void - getCustomizeMenus?: () => void -} - -const RouteList: React.FC = (props) => { - const {colLimit = 1, data, setOpenPage, load = true, getCustomizeMenus} = props - const [span, setSpan] = useState(24 / colLimit) - const rowCount = Math.ceil(data.subMenuData.length / colLimit) - return ( -
- - - {data.subMenuData.map((item) => ( - - - - ))} - -
- ) -} -interface PieChartProps { - goStoreRoute: (v: any) => void - inViewport?: boolean - echartsError: boolean - setEchartsError: (flag: boolean) => void - echartsLoading: boolean - setEchartsLoading: (v: boolean) => void - ref: ForwardedRef -} -interface echartListProps { - name: string - value: number -} - -const PieEcharts: React.FC = React.forwardRef((props, ref) => { - const {goStoreRoute, inViewport, echartsError, setEchartsError, echartsLoading, setEchartsLoading} = props - const {width} = useSize(document.querySelector("body")) || {width: 0, height: 0} - // 全局登录状态 - const {userInfo} = useStore() - const [_, setChartList, getChartList] = useGetState([]) - const colorList = ["#FFB660", "#4A94F8", "#5F69DD", "#56C991", "#8863F7", "#35D8EE"] - const optionRef = useRef({ - color: colorList, - title: { - show: false, - text: 0, - subtext: "插件总数", - top: "38%", - left: "23%", - textAlign: "center", - itemGap: 0, - triggerEvent: true, - textStyle: { - fontSize: 20, - color: "#31343F", - lineHeight: 32, - fontWeight: 600, - fontFamily: "PingFang HK" - }, - subtextStyle: { - color: "#85899E", - fontSize: 12, - lineHeight: 16 - } - }, - tooltip: { - trigger: "item" - }, - legend: { - show: false, - top: "middle", - right: "2%", - type: "scroll", - orient: "vertical", - icon: "circle", - padding: [0, 0, 0, 0], - // 点的大小位置 - itemWidth: 13, - itemHeight: 7, - itemStyle: { - borderWidth: 0 - // borderColor:"#0ba5ff" - }, - formatter: (name) => { - try { - const itemValue = getChartList().filter((item) => item.name === name)[0].value - return "{name|" + name + "} " + "{value|" + itemValue + "}" - } catch (error) { - return "" - } - }, - textStyle: { - rich: { - name: { - color: "#85899E", - fontSize: 12, - width: 100 - }, - value: { - color: "#31343F", - fontSize: 14, - fontWeight: 500, - width: 40, - align: "right" - } - } - } - }, - - series: [ - { - // 空心饼图内外径 - radius: ["60%", "77%"], - // 饼图上下左右位置 - center: ["24%", "50%"], - itemStyle: { - borderColor: "#F0F1F3", - borderWidth: 4 - }, - avoidLabelOverlap: false, - type: "pie", - label: { - show: false, - color: "#eeeeee", - fontSize: 14 - }, - labelLine: { - show: false - }, - data: [] - } - ] - }) - const echartsRef = useRef() - useEffect(() => { - if (width >= 1380) { - optionRef.current.legend.show = true - optionRef.current.series[0].center = ["24%", "50%"] - optionRef.current.title.left = "23%" - setEcharts(optionRef.current) - } else { - optionRef.current.legend.show = false - optionRef.current.series[0].center = ["50%", "50%"] - optionRef.current.title.left = "48%" - setEcharts(optionRef.current) - } - echartsRef.current && echartsRef.current.resize() - }, [width]) - - useEffect(() => { - if (inViewport) { - echartsRef.current && echartsRef.current.resize() - setEchartsError(false) - getPluginSearch() - } - }, [inViewport]) - - useEffect(() => { - setEchartsError(false) - getPluginSearch() - //先解绑事件,防止事件重复触发 - echartsRef.current.off("click") - echartsRef.current.off("legendselectchanged") - echartsRef.current.on("click", function (params) { - // console.log("点击", params) - onSendToTab(params.name ?? "") - }) - echartsRef.current.on("legendselectchanged", (e) => { - // console.log("点击了", e) // 如果不加off事件,就会叠加触发 - onSendToTab(e.name ?? "") - echartsRef.current.setOption({ - legend: {selected: {[e.name]: true}} - }) - }) - }, []) - - const getPluginSearch = useMemoizedFn(() => { - setEchartsError(false) - setEchartsLoading(true) - const newQuery: API.PluginsSearchRequest = {} - if (userInfo.token && userInfo.token.length > 0) { - newQuery.token = userInfo.token - } - apiFetchGroupStatistics(newQuery) - .then((res: API.PluginsSearchResponse) => { - const list = (res?.data || []).filter((item) => ["plugin_type"].includes(item.groupKey)) - if (list.length > 0) { - const data = list[0].data - const chartListCache = data.map((item) => ({ - name: PluginType[item.value] ?? "未识别", - value: item.count - })) - // @ts-ignore - optionRef.current.series[0].data = chartListCache - optionRef.current.title.text = chartListCache.map((item) => item.value).reduce((a, b) => a + b, 0) - optionRef.current.title.show = true - setChartList(chartListCache) - setEcharts(optionRef.current) - } - }) - .catch((err) => { - // failed("失败getPluginSearch:" + err) - setEchartsError(true) - }) - .finally(() => { - setEchartsLoading(false) - }) - }) - - React.useImperativeHandle(ref, () => ({ - getPluginSearch: () => getPluginSearch() - })) - - const onSendToTab = useMemoizedFn((pluginType: string) => { - let plugin_type: string = "" - for (let key in PluginType) { - if (PluginType[key] === pluginType) { - plugin_type = key - } - } - goStoreRoute({plugin_type}) - }) - - const setEcharts = (options) => { - const chartDom = document.getElementById("main-home-pie")! - if (chartDom) { - echartsRef.current = echarts.init(chartDom) - options && echartsRef.current.setOption(options) - } - } - return ( -
- ) -}) - -interface PlugInShopProps { - setOpenPage: (param: RouteToPageProps) => void - inViewport?: boolean -} - -export interface DataParams { - min?: string - max?: string - offset?: number - count?: number -} -export interface PlugInShopHotProps { - Data: DataParams -} -interface countAddObjProps { - day_incre: string - week_incre: string - day_incre_num: number - week_incre_num: number -} -interface PlugInShopNewIncreProps {} -const PlugInShop: React.FC = (props) => { - const {setOpenPage, inViewport} = props - const [countAddObj, setCountAddObj] = useState() - const [hotArr, setHotArr] = useState([]) - const [hotError, setHotError] = useState(false) - const [hotLoading, setHotLoading] = useState(false) - const [increLoading, setIncreLoading] = useState(false) - /** 判断插件图标接口是否请求成功 */ - const [echartsLoading, setEchartsLoading] = useState(false) - const [echartsError, setEchartsError] = useState(false) - const childRef = useRef(null) - const listHeightRef = useRef() - - useEffect(() => { - if (inViewport) { - setHotError(false) - getPlugInShopHot() - onRefresh() - } - }, [inViewport]) - - useEffect(() => { - ipcRenderer.on("refresh-new-home", (e, res: any) => { - setHotError(false) - getPlugInShopHot() - onRefresh() - }) - return () => { - ipcRenderer.removeAllListeners("refresh-new-home") - } - }, []) - const getPlugInShopHot = () => { - setHotLoading(true) - setHotError(false) - NetWorkApi({ - method: "get", - url: "plugin/topSearch" - }) - .then((res: API.PluginTopSearchResponse) => { - if (res) { - if (Array.isArray(res.data)) { - const newArr = res.data.map((item) => item.member).filter((item) => !!item) - setHotArr(newArr || []) - } - } - }) - .catch((err) => { - setHotError(true) - setHotArr([]) - // failed("失败getPlugInShopHot:" + err) - }) - .finally(() => { - setHotLoading(false) - }) - } - - const judgeStatus = (v: number, v1: number) => { - if (v > v1) return ">" - else if (v < v1) return "<" - else return "=" - } - - const getPlugInShopNewIncre = () => { - setIncreLoading(true) - NetWorkApi({ - method: "get", - url: "plugin/newIncre" - }) - .then((res: API.PluginIncreResponse) => { - if (res) { - const {day_incre_num, yesterday_incre_num, week_incre_num, lastWeek_incre_num} = res - const day_incre = judgeStatus(day_incre_num, yesterday_incre_num) - const week_incre = judgeStatus(week_incre_num, lastWeek_incre_num) - setCountAddObj({ - day_incre, - week_incre, - day_incre_num, - week_incre_num - }) - } - }) - .catch((err) => { - setCountAddObj(undefined) - // failed("失败plugin/newIncre:" + err) - }) - .finally(() => { - setIncreLoading(false) - }) - } - /** - * 首页点击今日新增、本周新增不做筛选,只是跳转,点击类型需要筛选 - * @description 带参数的页面跳转 - */ - const goStoreRoute = (params) => { - // emiter.emit("openPage", JSON.stringify({route: YakitRoute.Plugin_Store, params: {...params}})) - } - - const selectIconShow = (v: string) => { - if (v === ">") return - // else if (v === "=") return - else if (v === "<") return - else return <> - } - /**切换至插件商店页面,不带参数 */ - const openStoreRoute = useMemoizedFn(() => { - // setOpenPage({route: YakitRoute.Plugin_Store}) - }) - - const onRefresh = useMemoizedFn(() => { - isCommunityEdition() && getPlugInShopNewIncre() - if (childRef && childRef.current) { - childRef.current.getPluginSearch() - } - }) - return ( - <> - -
-
-
-
- {countAddObj && ( - <> -
", - [styles["reduce-border-left"]]: countAddObj?.day_incre === "<" - })} - style={{cursor: "pointer"}} - onClick={() => openStoreRoute()} - > -
今日新增数
-
- - - - {selectIconShow(countAddObj.day_incre)} -
-
-
", - [styles["reduce-border-left"]]: countAddObj?.week_incre === "<" - })} - style={{cursor: "pointer"}} - onClick={() => openStoreRoute()} - > -
本周新增数
-
- - - - {selectIconShow(countAddObj.week_incre)} -
-
- - )} -
-
-
- {/* 放大窗口图表宽度确实会自适应,但是缩小就挂掉了(并不自适应),原因:如果Chart组件的父组件Father采用flex布局 就会出现上述的问题 建议采用百分比*/} - -
-
-
-
- 热搜词 - {hotLoading && ( -
- 加载中... -
- -
-
- )} - {hotError && ( -
- 加载失败 -
- } - onClick={() => { - getPlugInShopHot() - }} - /> -
-
- )} -
- {!hotLoading && ( -
- {hotArr.length > 0 ? ( - hotArr.slice(0, 10).map((item) => { - return ( -
goStoreRoute({keyword: item})} - > - {item} -
- ) - }) - ) : ( -
暂无数据
- )} -
- )} -
-
- - ) -} - -export const newHomeList: newHomeListData[] = [ - { - id: "1", - label: "资产搜集", - subMenuData: [ - { - id: "1-1", - key: YakitRoute.Mod_ScanPort, - ...YakitRouteToPageInfo[YakitRoute.Mod_ScanPort], - icon: , - isShow: true - }, - { - id: "1-2", - key: YakitRoute.Plugin_OP, - label: "基础爬虫", - icon: , - describe: "通过爬虫可快速了解网站的整体架构", - pluginName: ResidentPluginName.BasicCrawler, - isShow: false - }, - { - id: "1-3", - key: YakitRoute.Plugin_OP, - label: "目录扫描", - icon: , - describe: "带有内置字典的综合目录扫描与爆破", - pluginName: ResidentPluginName.DirectoryScanning, - isShow: false - } - ] - }, - { - id: "2", - label: "漏洞检测", - subMenuData: [ - { - id: "2-1", - key: YakitRoute.PoC, - ...YakitRouteToPageInfo[YakitRoute.PoC], - icon: , - isShow: true - }, - { - id: "2-2", - key: YakitRoute.BatchExecutorPage, - ...YakitRouteToPageInfo[YakitRoute.BatchExecutorPage], - icon: , - isShow: true - } - ] - }, - { - id: "3", - label: "进阶功能", - subMenuData: [ - { - id: "3-1", - key: YakitRoute.Plugin_Hub, - ...YakitRouteToPageInfo[YakitRoute.Plugin_Hub], - icon: , - isShow: true - }, - { - id: "3-2", - key: YakitRoute.YakScript, - ...YakitRouteToPageInfo[YakitRoute.YakScript], - icon: , - isShow: true - } - ] - }, - { - id: "4", - label: "渗透测试工具", - subMenuData: [ - { - id: "4-1", - key: YakitRoute.HTTPHacker, - ...YakitRouteToPageInfo[YakitRoute.HTTPHacker], - icon: , - isShow: true - }, - { - id: "4-2", - key: YakitRoute.HTTPFuzzer, - ...YakitRouteToPageInfo[YakitRoute.HTTPFuzzer], - icon: , - isShow: true - }, - { - id: "4-3", - key: YakitRoute.Mod_Brute, - ...YakitRouteToPageInfo[YakitRoute.Mod_Brute], - icon: , - isShow: true - } - ] - }, - { - id: "5", - label: "小工具", - subMenuData: [ - { - id: "5-1", - key: YakitRoute.Codec, - ...YakitRouteToPageInfo[YakitRoute.Codec], - icon: , - isShow: true - }, - { - id: "5-2", - key: YakitRoute.DataCompare, - ...YakitRouteToPageInfo[YakitRoute.DataCompare], - icon: , - isShow: true - }, - { - id: "5-3", - key: YakitRoute.PayloadManager, - ...YakitRouteToPageInfo[YakitRoute.PayloadManager], - icon: , - isShow: true - } - ] - }, - { - id: "6", - label: "反连管理", - subMenuData: [ - { - id: "6-1", - key: YakitRoute.ShellReceiver, - ...YakitRouteToPageInfo[YakitRoute.ShellReceiver], - icon: , - isShow: true - }, - { - id: "6-2", - key: YakitRoute.ReverseServer_New, - ...YakitRouteToPageInfo[YakitRoute.ReverseServer_New], - icon: , - isShow: true - }, - { - id: "6-3", - key: YakitRoute.DNSLog, - ...YakitRouteToPageInfo[YakitRoute.DNSLog], - icon: , - isShow: true - }, - { - id: "6-4", - key: YakitRoute.ICMPSizeLog, - ...YakitRouteToPageInfo[YakitRoute.ICMPSizeLog], - icon: , - isShow: true - }, - { - id: "6-5", - key: YakitRoute.TCPPortLog, - ...YakitRouteToPageInfo[YakitRoute.TCPPortLog], - icon: , - isShow: true - }, - { - id: "6-6", - key: YakitRoute.PayloadGenerater_New, - ...YakitRouteToPageInfo[YakitRoute.PayloadGenerater_New], - icon: , - isShow: true - } - ] - } -] - -export interface NewHomeProps {} - -const NewHome: React.FC = (props) => { - const ref = useRef(null) - const [inViewport] = useInViewport(ref) - const [newHomeData, setNewHomeData, getNewHomeData] = useGetState(newHomeList) - // 加载是否完成 - const [load, setLoad] = useState(false) - useEffect(() => { - getCustomizeMenus() - }, [inViewport]) - - const setOpenPage = (param: RouteToPageProps) => { - ipcRenderer.invoke("open-route-page", param) - } - - // 获取自定义菜单 - const getCustomizeMenus = () => { - ipcRenderer - .invoke("QueryYakScript", { - Pagination: genDefaultPagination(1000), - IsGeneralModule: true, - Type: "yak" - } as QueryYakScriptRequest) - .then((data: QueryYakScriptsResponse) => { - const deepList: newHomeListData[] = cloneDeep(newHomeList) - data.Data.map((i) => { - if (i.ScriptName === ResidentPluginName.BasicCrawler) { - deepList[0].subMenuData[1].pluginId = `${i.Id}` - deepList[0].subMenuData[1].isShow = true - deepList[0].subMenuData[1].key = YakitRoute.Plugin_OP - } - if (i.ScriptName === ResidentPluginName.DirectoryScanning) { - deepList[0].subMenuData[2].pluginId = `${i.Id}` - deepList[0].subMenuData[2].isShow = true - deepList[0].subMenuData[2].key = YakitRoute.Plugin_OP - } - }) - setNewHomeData(deepList) - }) - .finally(() => { - setLoad(true) - }) - } - - return ( -
-
-
- -
-
-
- -
-
- -
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
- ) -} - -export default NewHome diff --git a/app/renderer/src/main/src/pages/newHome/newHome.module.scss b/app/renderer/src/main/src/pages/newHome/newHome.module.scss deleted file mode 100644 index e23a6f8fff..0000000000 --- a/app/renderer/src/main/src/pages/newHome/newHome.module.scss +++ /dev/null @@ -1,317 +0,0 @@ -.new-home-page { - display: flex; - flex-direction: column; - height: 100%; - // overflow: auto; - min-height: 700px; -} -.home-top-block { - flex: 4; - display: flex; - flex-direction: row; - height: 100%; -} -.home-bottom-block { - flex: 3; - display: flex; - flex-direction: row; - height: 100%; -} -.top-small-block { - flex: 1; - padding: 16px; -} -.top-big-block { - flex: 1.27; - display: flex; - flex-direction: column; - height: 100%; -} -.top-in { - flex: 1; - padding: 16px; -} -.bottom-in { - flex: 1; - padding: 16px; -} -.bottom-big-block { - flex: 3; - padding: 16px; -} -.bottom-small-block { - flex: 2; - padding: 16px; -} -.home-page-title { - height: 24px; - display: flex; - gap: 8px; - font-style: normal; - font-weight: 600; - font-size: 16px; - line-height: 24px; - color: #31343f; - - .spin-wrapper { - height: 24px; - padding: 5px 0; - display: flex; - gap: 4px; - - font-size: 12px; - line-height: 14px; - color: var(--yakit-primary-5); - .spin-style { - width: 14px; - height: 14px; - display: flex; - align-items: center; - } - } -} -.border-right-box { - border-right: 1px solid #eaecf3; -} -.border-bottom-box { - border-bottom: 1px solid #eaecf3; -} -.icon-box { - display: flex; - justify-content: space-between; - height: 32px; -} -.route-item { - padding: 16px; - border-radius: 4px; - height: 100%; -} -.route-item-active { - cursor: pointer; -} -.route-item-active:hover { - background: rgba(242, 139, 68, 0.06); - .right-arrow { - color: #f28b44; - } -} -.control-opacity { - opacity: 0.3; -} -.right-arrow { - font-size: 12px; - color: #b4bbca; - position: relative; - top: 8px; -} -.right-arrow-text { - font-size: 12px; - color: #f28b44; - cursor: pointer; -} -.item-label { - margin-top: 8px; - - font-style: normal; - font-weight: 400; - font-size: 14px; - line-height: 20px; - color: #31343f; -} -.item-describe { - margin-top: 8px; - font-style: normal; - font-weight: 400; - font-size: 12px; - line-height: 16px; - text-align: justify; - color: #85899e; -} -.list-box { - height: 100%; - display: flex; - flex-direction: column; -} -.list-content { - flex: 1; - position: relative; -} -.set-ant-row { - flex-flow: column; -} -.list-content-col2 { - height: 50%; -} -.list-content-col3 { - height: 33.33%; -} -.menu-icon { - position: relative; - width: 38px; - height: 34px; - svg { - position: absolute; - top: 2px; - left: 0; - width: 32px; - height: 32px; - z-index: 3; - } - .menu-icon-filter { - position: absolute; - top: -2px; - left: 10px; - border-radius: 50%; - width: 28px; - height: 28px; - background: rgba(255, 182, 96, 0.2); - backdrop-filter: blur(2px); - } -} -.plug-in-main { - height: 100%; - display: flex; - flex-direction: column; -} -.plug-in-shop { - display: flex; - flex-direction: column; - flex: 1; - padding: 0 16px; -} -.show-top-box { - flex: 2; - border-bottom: 1px solid rgb(234, 236, 243); - position: relative; -} -.add-count-box { - display: flex; - flex-direction: column; - justify-content: space-evenly; - height: 100%; -} -.common-count { - padding-left: 15px; - border-radius: 2px; -} -.common-count:hover { - background: #f0f1f3; -} -.keep-border-left { - border-left: 2px solid #b4bbca; -} -.add-border-left { - border-left: 2px solid #f4736b; -} -.reduce-border-left { - border-left: 2px solid rgb(86, 201, 145); -} -.add-title { - font-weight: 400; - font-size: 14px; - line-height: 20px; - color: #31343f; -} -.add-content { - font-weight: 600; - font-size: 20px; - line-height: 32px; - color: #31343f; -} -.add-box-show { - width: 30%; - height: 100%; - display: inline-block; - position: absolute; - left: 0px; -} -.add-box-hidden { - width: 0%; - display: none; -} -.chart-box-show { - width: 70%; - height: 100%; - display: inline-block; - position: absolute; - right: 0px; -} -.chart-box-hidden { - width: 100%; - height: 100%; - display: inline-block; - position: absolute; - right: 0px; -} -.show-bottom-box { - flex: 1; - display: flex; - flex-direction: column; - overflow-y: auto; -} -.label-item { - display: inline-block; - margin-top: 8px; - margin-right: 8px; - padding: 4px 8px; - font-weight: 400; - font-size: 12px; - line-height: 16px; - color: #85899e; - background: #f8f8f8; - border: 1px solid #eaecf3; - border-radius: 4px; - cursor: pointer; -} -.label-item:hover { - background: rgba(242, 139, 68, 0.06); - border: 1px solid #fbc6a1; - border-radius: 4px; - color: #f28b44; -} -.hot-no-data { - font-style: normal; - font-weight: 400; - font-size: 12px; - line-height: 16px; - text-align: center; - color: #85899e; - margin-top: 8px; -} -.bottom-box-title { - margin-top: 16px; - height: 20px; - display: flex; - gap: 8px; - font-weight: 400; - font-size: 14px; - line-height: 20px; - color: #31343f; - - .spin-wrapper { - height: 20px; - padding: 3px 0; - display: flex; - gap: 4px; - font-size: 12px; - line-height: 14px; - color: var(--yakit-primary-5); - .spin-style { - width: 14px; - height: 14px; - display: flex; - align-items: center; - } - } -} -.label-box { - flex: 1; -} -.echarts-box { - height: 100%; - width: 100%; - opacity: 0; -} -.echarts-box-show { - opacity: 1; -} diff --git a/app/renderer/src/main/src/pages/pluginHub/pluginHubList/HubListLocal.tsx b/app/renderer/src/main/src/pages/pluginHub/pluginHubList/HubListLocal.tsx index 3378a72d6d..9490a5c212 100644 --- a/app/renderer/src/main/src/pages/pluginHub/pluginHubList/HubListLocal.tsx +++ b/app/renderer/src/main/src/pages/pluginHub/pluginHubList/HubListLocal.tsx @@ -782,7 +782,7 @@ export const HubListLocal: React.FC = memo((props) => { return ( <> - 管理分组 + 管理
diff --git a/app/renderer/src/main/src/routes/newRoute.tsx b/app/renderer/src/main/src/routes/newRoute.tsx index 0df037c100..3472eab5da 100644 --- a/app/renderer/src/main/src/routes/newRoute.tsx +++ b/app/renderer/src/main/src/routes/newRoute.tsx @@ -133,7 +133,7 @@ import {SimpleDetect} from "@/pages/simpleDetect/SimpleDetect" import {YakitRoute} from "../enums/yakitRoute" const HTTPHacker = React.lazy(() => import("../pages/hacker/httpHacker")) -const NewHome = React.lazy(() => import("@/pages/newHome/NewHome")) +const Home = React.lazy(() => import("@/pages/home/Home")) const WebFuzzerPage = React.lazy(() => import("@/pages/fuzzer/WebFuzzerPage/WebFuzzerPage")) const PluginHub = React.lazy(() => import("@/pages/pluginHub/pluginHub/PluginHub")) @@ -409,7 +409,7 @@ export const RouteToPage: (props: PageItemProps) => ReactNode = (props) => { const {routeKey, yakScriptId, params} = props switch (routeKey) { case YakitRoute.NewHome: - return + return case YakitRoute.HTTPHacker: return ( }> diff --git a/app/renderer/src/main/src/routes/publicIcon.tsx b/app/renderer/src/main/src/routes/publicIcon.tsx index 273ef96516..8bddbdae3a 100644 --- a/app/renderer/src/main/src/routes/publicIcon.tsx +++ b/app/renderer/src/main/src/routes/publicIcon.tsx @@ -1735,3 +1735,840 @@ const PublicDefaultPlugin = () => ( export const PublicDefaultPluginIcon = (props: Partial) => { return } + +const PublicBlasting = () => ( + + + + + + +) +export const PublicBlastingIcon = (props: Partial) => { + return +} + +const PublicSequenceAnimation = () => ( + + + + + + + + + + + + + + + + + + + + +) +export const PublicSequenceAnimationIcon = (props: Partial) => { + return +} + +const PublicToolLightbulb = () => ( + + + + + + + + + + + + +) +export const PublicPublicToolLightbulbIcon = (props: Partial) => { + return +} + +const PublicToolYakScript = () => ( + + + +) +export const PublicToolYakScriptIcon = (props: Partial) => { + return +} + +const PublicToolVulinbox = () => ( + + + + + + + + + + +) +export const PublicToolVulinboxIcon = (props: Partial) => { + return +} + +const PublicToolPayload = () => ( + + + + + + + + + + + +) +export const PublicToolPayloadIcon = (props: Partial) => { + return +} + +const PublicToolDataCompare = () => ( + + + + + + + + + + +) +export const PublicToolDataCompareIcon = (props: Partial) => { + return +} + +const PublicToolPluginHub = () => ( + + + + + + + + + + + + +) +export const PublicToolPluginHubIcon = (props: Partial) => { + return +} + +const PublicToolCVE = () => ( + + + + + + + + +) +export const PublicToolCVEIcon = (props: Partial) => { + return +} + +const PublicToolShellReceiver = () => ( + + + + + + + + + + + + + +) +export const PublicToolShellReceiverIcon = (props: Partial) => { + return +} + +const PublicToolWebsocketFuzzer = () => ( + + + + + + + + + + + + + + + +) +export const PublicToolWebsocketFuzzerIcon = (props: Partial) => { + return +} + +const PublicToolSubDomainCollection = () => ( + + + + + + + + + + + +) +export const PublicToolSubDomainCollectionIcon = (props: Partial) => { + return +} + +const PublicToolBasicCrawler = () => ( + + + + + + + + + + + +) +export const PublicToolBasicCrawlerIcon = (props: Partial) => { + return +} + +const PublicToolSpaceEngine = () => ( + + + + + + + + + + +) +export const PublicToolSpaceEngineIcon = (props: Partial) => { + return +} + +const PublicToolICMPSizeLog = () => ( + + + + + + + + + + + + + +) +export const PublicToolICMPSizeLogIcon = (props: Partial) => { + return +} + +const PublicToolTCPPortLog = () => ( + + + + + + + + + + + + + + + +) +export const PublicToolTCPPortLogIcon = (props: Partial) => { + return +} + +const PublicToolReverseServer = () => ( + + + + + + + + + + + + + + + + +) +export const PublicToolReverseServerIcon = (props: Partial) => { + return +} + +const PublicToolDBHTTPHistory = () => ( + + + + + + + + + + + + + + + + +) +export const PublicToolDBHTTPHistoryIcon = (props: Partial) => { + return +} + +const PublicToolDBReport = () => ( + + + + + + + + + + + +) +export const PublicToolDBReportIcon = (props: Partial) => { + return +} + +const PublicToolDBRisk = () => ( + + + + + + +) +export const PublicToolDBRiskIcon = (props: Partial) => { + return +} + +const PublicToolModScanPort = () => ( + + + + + + + + + + + + + + + +) +export const PublicToolModScanPortIcon = (props: Partial) => { + return +} + +const PublicToolDBDomain = () => ( + + + + + + + + + + + + + + + + + + + + +) +export const PublicToolDBDomainIcon = (props: Partial) => { + return +} + +const PublicToolScreenRecording = () => ( + + + + + +) +export const PublicToolScreenRecordingIcon = (props: Partial) => { + return +} + +const PublicToolScreenshot = () => ( + + + + + + + + + + + + +) +export const PublicToolScreenshotIcon = (props: Partial) => { + return +} + +const PublicToolScreenRecorderPage = () => ( + + + + +) +export const PublicToolScreenRecorderPageIcon = (props: Partial) => { + return +} diff --git a/app/renderer/src/main/src/store/publicMenu.tsx b/app/renderer/src/main/src/store/publicMenu.tsx new file mode 100644 index 0000000000..6d6715c614 --- /dev/null +++ b/app/renderer/src/main/src/store/publicMenu.tsx @@ -0,0 +1,28 @@ +/** + * @description PublicMenu + */ + +import {ResidentPluginName} from "@/routes/newRoute" +import {create} from "zustand" + +interface ScreenRecorderProps { + pluginToId: Record + setNewPluginToId: (newPluginToId: Record) => void +} + +export const usePluginToId = create((set, get) => ({ + pluginToId: { + [ResidentPluginName.SubDomainCollection]: 0, + [ResidentPluginName.BasicCrawler]: 0, + [ResidentPluginName.DirectoryScanning]: 0 + }, + setNewPluginToId: (newPluginToId: Record) => { + const s: Record = get().pluginToId + set({ + pluginToId: { + ...s, + ...newPluginToId + } + }) + } +})) diff --git a/app/renderer/src/main/src/utils/eventBus/events/mitm.ts b/app/renderer/src/main/src/utils/eventBus/events/mitm.ts index c038a8f586..64e92f657d 100644 --- a/app/renderer/src/main/src/utils/eventBus/events/mitm.ts +++ b/app/renderer/src/main/src/utils/eventBus/events/mitm.ts @@ -6,4 +6,7 @@ export type MitmEventProps = { onSetFilterWhiteListEvent: string /** 是否开启替换规则 */ onOpenRepRuleEvent: string + /** 首页启动劫持 */ + onHomeExecStartMITM: string + onExecStartMITM: string } diff --git a/app/renderer/src/main/src/yakitGV.ts b/app/renderer/src/main/src/yakitGV.ts index d8066407ed..56da4be8b8 100644 --- a/app/renderer/src/main/src/yakitGV.ts +++ b/app/renderer/src/main/src/yakitGV.ts @@ -1,4 +1,3 @@ -import {MITMConsts} from "@/pages/mitm/MITMConsts" /** 本地文件缓存数据-键值变量 */ export enum LocalGV { /** @name 获取缓存数据里引擎的启动模式("local"|"remote") */ @@ -100,7 +99,9 @@ export enum RemoteGV { /**@name 漏洞风险导出字段缓存 */ RiskExportFields = "risk-export-fields", /**@name RiskPage页面中,高级查询内容的显/隐 */ - RiskQueryShow = "risk-query-show" + RiskQueryShow = "risk-query-show", + /**@name Home开始扫描 */ + HomeStartScanning="home_start_scanning", } /** 项目逻辑全局变量 */