mirror of
https://github.com/shadow1ng/fscan.git
synced 2026-09-22 03:10:42 +08:00
feat: Web 版独立入口 + SQLite 持久化存储
- 拆分 main.go 为 main_cli.go 和 main_web.go,Web 版不再包含 CLI 参数解析 - Web 版直接启动 HTTP 服务,通过 -port/-lang 控制,无需 -web flag - 结果存储从内存 map 替换为 SQLite(modernc.org/sqlite,纯 Go 零 CGO) - 数据库文件 ~/.fscan/results.db,进程重启后结果不丢失 - 修复结果分布面板跟随 tab 筛选联动的问题
This commit is contained in:
@@ -64,7 +64,7 @@ build-web: build-ui
|
|||||||
@echo "$(BLUE)构建Web版本...$(NC)"
|
@echo "$(BLUE)构建Web版本...$(NC)"
|
||||||
$(GO) build -tags web -ldflags="-s -w" -trimpath -o $(BINARY_NAME)-web .
|
$(GO) build -tags web -ldflags="-s -w" -trimpath -o $(BINARY_NAME)-web .
|
||||||
@echo "$(GREEN)✓ 构建完成: $(BINARY_NAME)-web$(NC)"
|
@echo "$(GREEN)✓ 构建完成: $(BINARY_NAME)-web$(NC)"
|
||||||
@echo "$(BLUE)提示: 运行 ./$(BINARY_NAME)-web -web 启动Web界面$(NC)"
|
@echo "$(BLUE)提示: 运行 ./$(BINARY_NAME)-web 启动Web界面(默认端口 10240)$(NC)"
|
||||||
|
|
||||||
## build-ui: 构建前端(需要Node.js和npm)
|
## build-ui: 构建前端(需要Node.js和npm)
|
||||||
build-ui:
|
build-ui:
|
||||||
|
|||||||
+4
-15
@@ -2,19 +2,8 @@
|
|||||||
|
|
||||||
package common
|
package common
|
||||||
|
|
||||||
import (
|
// WebMode Web版本始终为true
|
||||||
"flag"
|
const WebMode = true
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common/i18n"
|
// WebPort 不再使用,端口由 main_web.go 的 -port 参数控制
|
||||||
)
|
var WebPort = 0
|
||||||
|
|
||||||
// WebMode 表示是否启动Web管理界面
|
|
||||||
var WebMode bool
|
|
||||||
|
|
||||||
// WebPort Web服务器端口
|
|
||||||
var WebPort int
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
flag.BoolVar(&WebMode, "web", false, i18n.GetText("flag_web_mode"))
|
|
||||||
flag.IntVar(&WebPort, "webport", 10240, i18n.GetText("flag_web_port"))
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
module github.com/shadow1ng/fscan
|
module github.com/shadow1ng/fscan
|
||||||
|
|
||||||
go 1.20
|
go 1.25.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/fatih/color v1.18.0
|
github.com/fatih/color v1.18.0
|
||||||
@@ -24,13 +24,14 @@ require (
|
|||||||
go.ciq.dev/go-rsync v0.0.0-20240304021629-0a3bb196e6d1
|
go.ciq.dev/go-rsync v0.0.0-20240304021629-0a3bb196e6d1
|
||||||
golang.org/x/crypto v0.31.0
|
golang.org/x/crypto v0.31.0
|
||||||
golang.org/x/net v0.32.0
|
golang.org/x/net v0.32.0
|
||||||
golang.org/x/sys v0.28.0
|
golang.org/x/sys v0.42.0
|
||||||
golang.org/x/term v0.27.0
|
golang.org/x/term v0.27.0
|
||||||
golang.org/x/text v0.21.0
|
golang.org/x/text v0.21.0
|
||||||
google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c
|
google.golang.org/genproto v0.0.0-20221027153422-115e99e71e1c
|
||||||
google.golang.org/protobuf v1.28.1
|
google.golang.org/protobuf v1.28.1
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
|
modernc.org/sqlite v1.52.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -38,6 +39,7 @@ require (
|
|||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect
|
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa // indirect
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect
|
||||||
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/geoffgarside/ber v1.1.0 // indirect
|
github.com/geoffgarside/ber v1.1.0 // indirect
|
||||||
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
|
github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
|
||||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||||
@@ -53,9 +55,14 @@ require (
|
|||||||
github.com/kr/pretty v0.3.0 // indirect
|
github.com/kr/pretty v0.3.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/ncruces/go-strftime v1.0.0 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||||
github.com/stoewer/go-strcase v1.2.0 // indirect
|
github.com/stoewer/go-strcase v1.2.0 // indirect
|
||||||
golang.org/x/sync v0.11.0 // indirect
|
golang.org/x/sync v0.20.0 // indirect
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||||
|
modernc.org/libc v1.72.3 // indirect
|
||||||
|
modernc.org/mathutil v1.7.1 // indirect
|
||||||
|
modernc.org/memory v1.11.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+
|
|||||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||||
|
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
|
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI=
|
||||||
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4=
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
|
github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves=
|
||||||
@@ -16,6 +17,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
@@ -50,6 +53,8 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs=
|
||||||
|
github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||||
@@ -65,6 +70,8 @@ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9
|
|||||||
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
|
||||||
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
|
||||||
|
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
github.com/hirochachacha/go-smb2 v1.1.0 h1:b6hs9qKIql9eVXAiN0M2wSFY5xnhbHAQoCwRKbaRTZI=
|
github.com/hirochachacha/go-smb2 v1.1.0 h1:b6hs9qKIql9eVXAiN0M2wSFY5xnhbHAQoCwRKbaRTZI=
|
||||||
github.com/hirochachacha/go-smb2 v1.1.0/go.mod h1:8F1A4d5EZzrGu5R7PU163UcMRDJQl4FtcxjBfsY8TZE=
|
github.com/hirochachacha/go-smb2 v1.1.0/go.mod h1:8F1A4d5EZzrGu5R7PU163UcMRDJQl4FtcxjBfsY8TZE=
|
||||||
github.com/huin/asn1ber v0.0.0-20120622192748-af09f62e6358 h1:hVXNJ57IHkOA8FBq80UG263MEBwNUMfS9c82J2QE5UQ=
|
github.com/huin/asn1ber v0.0.0-20120622192748-af09f62e6358 h1:hVXNJ57IHkOA8FBq80UG263MEBwNUMfS9c82J2QE5UQ=
|
||||||
@@ -108,6 +115,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
|||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed h1:FI2NIv6fpef6BQl2u3IZX/Cj20tfypRF4yd+uaHOMtI=
|
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed h1:FI2NIv6fpef6BQl2u3IZX/Cj20tfypRF4yd+uaHOMtI=
|
||||||
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0=
|
github.com/mitchellh/go-vnc v0.0.0-20150629162542-723ed9867aed/go.mod h1:3rdaFaCv4AyBgu5ALFM0+tSuHrBh6v692nyQe3ikrq0=
|
||||||
|
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
|
||||||
|
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
|
github.com/nicksnyder/go-i18n/v2 v2.4.0 h1:3IcvPOAvnCKwNm0TB0dLDTuawWEj+ax/RERNC+diLMM=
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
|
github.com/nicksnyder/go-i18n/v2 v2.4.0/go.mod h1:nxYSZE9M0bf3Y70gPQjN9ha7XNHX7gMc814+6wVyEI4=
|
||||||
github.com/panjf2000/ants/v2 v2.11.3 h1:AfI0ngBoXJmYOpDh9m516vjqoUu2sLrIVgppI9TZVpg=
|
github.com/panjf2000/ants/v2 v2.11.3 h1:AfI0ngBoXJmYOpDh9m516vjqoUu2sLrIVgppI9TZVpg=
|
||||||
@@ -117,6 +126,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||||
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||||
@@ -133,6 +144,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
@@ -159,6 +171,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|||||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/mod v0.33.0 h1:tHFzIWbBifEmbwtGz65eaWyGiGZatSrT9prnU8DbVL8=
|
||||||
|
golang.org/x/mod v0.33.0/go.mod h1:swjeQEj+6r7fODbD2cqrnje9PnziFuw4bmLbBZFrQ5w=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -187,8 +201,8 @@ golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
|||||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -204,8 +218,9 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||||
|
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
@@ -236,6 +251,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
|||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
|
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
|
||||||
|
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
@@ -270,3 +287,31 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
modernc.org/cc/v4 v4.28.2 h1:3tQ0lf2ADtoby2EtSP+J7IE2SHwEJdP8ioR59wx7XpY=
|
||||||
|
modernc.org/cc/v4 v4.28.2/go.mod h1:OnovgIhbbMXMu1aISnJ0wvVD1KnW+cAUJkIrAWh+kVI=
|
||||||
|
modernc.org/ccgo/v4 v4.34.0 h1:yRLPFZieg532OT4rp4JFNIVcquwalMX26G95WQDqwCQ=
|
||||||
|
modernc.org/ccgo/v4 v4.34.0/go.mod h1:AS5WYMyBakQ+fhsHhtP8mWB82KTGPkNNJDGfGQCe0/A=
|
||||||
|
modernc.org/fileutil v1.4.0 h1:j6ZzNTftVS054gi281TyLjHPp6CPHr2KCxEXjEbD6SM=
|
||||||
|
modernc.org/fileutil v1.4.0/go.mod h1:EqdKFDxiByqxLk8ozOxObDSfcVOv/54xDs/DUHdvCUU=
|
||||||
|
modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI=
|
||||||
|
modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito=
|
||||||
|
modernc.org/gc/v3 v3.1.2 h1:ZtDCnhonXSZexk/AYsegNRV1lJGgaNZJuKjJSWKyEqo=
|
||||||
|
modernc.org/gc/v3 v3.1.2/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY=
|
||||||
|
modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks=
|
||||||
|
modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI=
|
||||||
|
modernc.org/libc v1.72.3 h1:ZnDF4tXn4NBXFutMMQC4vtbTFSXhhKzR73fv0beZEAU=
|
||||||
|
modernc.org/libc v1.72.3/go.mod h1:dn0dZNnnn1clLyvRxLxYExxiKRZIRENOfqQ8XEeg4Qs=
|
||||||
|
modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU=
|
||||||
|
modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg=
|
||||||
|
modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI=
|
||||||
|
modernc.org/memory v1.11.0/go.mod h1:/JP4VbVC+K5sU2wZi9bHoq2MAkCnrt2r98UGeSK7Mjw=
|
||||||
|
modernc.org/opt v0.2.0 h1:tGyef5ApycA7FSEOMraay9SaTk5zmbx7Tu+cJs4QKZg=
|
||||||
|
modernc.org/opt v0.2.0/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||||
|
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||||
|
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||||
|
modernc.org/sqlite v1.52.0 h1:p4dhYh2tXZCiyaqHwRVJDjIGKWyXayiQpThxgDzJaxo=
|
||||||
|
modernc.org/sqlite v1.52.0/go.mod h1:tcNzv5p84E0skkmJn038y+hWJbLQXQqEnQfeh5r2JLM=
|
||||||
|
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||||
|
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||||
|
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||||
|
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||||
|
|||||||
+2
-10
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build !web
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -10,7 +12,6 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/common/debug"
|
"github.com/shadow1ng/fscan/common/debug"
|
||||||
"github.com/shadow1ng/fscan/common/i18n"
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
"github.com/shadow1ng/fscan/core"
|
"github.com/shadow1ng/fscan/core"
|
||||||
"github.com/shadow1ng/fscan/web"
|
|
||||||
|
|
||||||
// 导入统一插件系统
|
// 导入统一插件系统
|
||||||
_ "github.com/shadow1ng/fscan/plugins/local"
|
_ "github.com/shadow1ng/fscan/plugins/local"
|
||||||
@@ -33,15 +34,6 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Web模式:启动Web服务器
|
|
||||||
if common.WebMode {
|
|
||||||
if err := web.StartServer(common.WebPort); err != nil {
|
|
||||||
common.LogError(err.Error())
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查参数互斥性
|
// 检查参数互斥性
|
||||||
if err := common.ValidateExclusiveParams(&info); err != nil {
|
if err := common.ValidateExclusiveParams(&info); err != nil {
|
||||||
common.LogError(i18n.Tr("error_generic", err))
|
common.LogError(i18n.Tr("error_generic", err))
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
//go:build web
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/shadow1ng/fscan/common"
|
||||||
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
|
"github.com/shadow1ng/fscan/web"
|
||||||
|
|
||||||
|
// 导入统一插件系统
|
||||||
|
_ "github.com/shadow1ng/fscan/plugins/local"
|
||||||
|
_ "github.com/shadow1ng/fscan/plugins/services"
|
||||||
|
_ "github.com/shadow1ng/fscan/plugins/web"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
port := flag.Int("port", 10240, "Web server listen port")
|
||||||
|
lang := flag.String("lang", "zh", "Language (zh/en)")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
i18n.SetLanguage(*lang)
|
||||||
|
|
||||||
|
fmt.Printf("fscan web v%s\n", common.GetVersion())
|
||||||
|
|
||||||
|
if err := web.StartServer(*port); err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+24
-5
@@ -21,6 +21,7 @@
|
|||||||
"@radix-ui/react-switch": "^1.2.6",
|
"@radix-ui/react-switch": "^1.2.6",
|
||||||
"@radix-ui/react-tabs": "^1.1.13",
|
"@radix-ui/react-tabs": "^1.1.13",
|
||||||
"@radix-ui/react-tooltip": "^1.2.8",
|
"@radix-ui/react-tooltip": "^1.2.8",
|
||||||
|
"@rollup/rollup-linux-x64-gnu": "^4.61.1",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"i18next": "^25.7.3",
|
"i18next": "^25.7.3",
|
||||||
@@ -2496,15 +2497,16 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
"node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||||
"version": "4.54.0",
|
"version": "4.61.1",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.61.1.tgz",
|
||||||
"integrity": "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==",
|
"integrity": "sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
"dev": true,
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
|
||||||
"os": [
|
"os": [
|
||||||
"linux"
|
"linux"
|
||||||
]
|
]
|
||||||
@@ -5318,6 +5320,23 @@
|
|||||||
"fsevents": "~2.3.2"
|
"fsevents": "~2.3.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/rollup/node_modules/@rollup/rollup-linux-x64-gnu": {
|
||||||
|
"version": "4.54.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.54.0.tgz",
|
||||||
|
"integrity": "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"dev": true,
|
||||||
|
"libc": [
|
||||||
|
"glibc"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
"node_modules/run-parallel": {
|
"node_modules/run-parallel": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
"@radix-ui/react-switch": "^1.2.6",
|
"@radix-ui/react-switch": "^1.2.6",
|
||||||
"@radix-ui/react-tabs": "^1.1.13",
|
"@radix-ui/react-tabs": "^1.1.13",
|
||||||
"@radix-ui/react-tooltip": "^1.2.8",
|
"@radix-ui/react-tooltip": "^1.2.8",
|
||||||
|
"@rollup/rollup-linux-x64-gnu": "^4.61.1",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"i18next": "^25.7.3",
|
"i18next": "^25.7.3",
|
||||||
|
|||||||
@@ -53,14 +53,14 @@ export function ResultsPage() {
|
|||||||
const fetchResults = useCallback(async () => {
|
const fetchResults = useCallback(async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const data = await getResults(filter === 'all' ? undefined : filter);
|
const data = await getResults();
|
||||||
setResults(data.items);
|
setResults(data.items);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Failed to fetch results:', err);
|
console.error('Failed to fetch results:', err);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, [filter]);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchResults();
|
fetchResults();
|
||||||
|
|||||||
+145
-77
@@ -3,15 +3,19 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"encoding/csv"
|
"encoding/csv"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shadow1ng/fscan/common/i18n"
|
"github.com/shadow1ng/fscan/common/i18n"
|
||||||
|
_ "modernc.org/sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ResultItem 扫描结果项
|
// ResultItem 扫描结果项
|
||||||
@@ -24,26 +28,66 @@ type ResultItem struct {
|
|||||||
Details interface{} `json:"details,omitempty"`
|
Details interface{} `json:"details,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResultStore 结果存储
|
// ResultStore SQLite 结果存储
|
||||||
type ResultStore struct {
|
type ResultStore struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
items []ResultItem
|
db *sql.DB
|
||||||
counter int64
|
|
||||||
stats ScanStats
|
|
||||||
// 去重
|
|
||||||
seen map[string]bool
|
|
||||||
// service 类型按 target 索引,用于更新
|
|
||||||
serviceIndex map[string]int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 全局结果存储
|
// 全局结果存储
|
||||||
var globalResultStore = &ResultStore{
|
var globalResultStore *ResultStore
|
||||||
items: make([]ResultItem, 0),
|
|
||||||
seen: make(map[string]bool),
|
func init() {
|
||||||
serviceIndex: make(map[string]int),
|
store, err := NewResultStore()
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("failed to init result store: %v", err))
|
||||||
|
}
|
||||||
|
globalResultStore = store
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add 添加结果,返回格式化后的结果项(去重,重复则返回nil)
|
// dbPath 返回数据库文件路径
|
||||||
|
func dbPath() string {
|
||||||
|
home, err := os.UserHomeDir()
|
||||||
|
if err != nil {
|
||||||
|
home = "."
|
||||||
|
}
|
||||||
|
dir := filepath.Join(home, ".fscan")
|
||||||
|
_ = os.MkdirAll(dir, 0755)
|
||||||
|
return filepath.Join(dir, "results.db")
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewResultStore 创建 SQLite 存储
|
||||||
|
func NewResultStore() (*ResultStore, error) {
|
||||||
|
db, err := sql.Open("sqlite", dbPath())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// WAL 模式,提升并发读写
|
||||||
|
if _, err := db.Exec("PRAGMA journal_mode=WAL"); err != nil {
|
||||||
|
db.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := db.Exec(`
|
||||||
|
CREATE TABLE IF NOT EXISTS results (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
time TEXT NOT NULL,
|
||||||
|
type TEXT NOT NULL,
|
||||||
|
target TEXT NOT NULL,
|
||||||
|
status TEXT NOT NULL DEFAULT '',
|
||||||
|
details TEXT NOT NULL DEFAULT '{}',
|
||||||
|
UNIQUE(type, target, status)
|
||||||
|
)
|
||||||
|
`); err != nil {
|
||||||
|
db.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ResultStore{db: db}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add 添加结果(去重,重复返回 nil)
|
||||||
func (s *ResultStore) Add(result interface{}) *ResultItem {
|
func (s *ResultStore) Add(result interface{}) *ResultItem {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
@@ -53,10 +97,10 @@ func (s *ResultStore) Add(result interface{}) *ResultItem {
|
|||||||
Details: result,
|
Details: result,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据结果类型分类
|
// 解析结果字段
|
||||||
if m, ok := result.(map[string]interface{}); ok {
|
if m, ok := result.(map[string]interface{}); ok {
|
||||||
if t, ok := m["type"].(string); ok {
|
if t, ok := m["type"].(string); ok {
|
||||||
item.Type = strings.ToLower(t) // 统一转小写
|
item.Type = strings.ToLower(t)
|
||||||
}
|
}
|
||||||
if target, ok := m["target"].(string); ok {
|
if target, ok := m["target"].(string); ok {
|
||||||
item.Target = target
|
item.Target = target
|
||||||
@@ -64,64 +108,58 @@ func (s *ResultStore) Add(result interface{}) *ResultItem {
|
|||||||
if status, ok := m["status"].(string); ok {
|
if status, ok := m["status"].(string); ok {
|
||||||
item.Status = status
|
item.Status = status
|
||||||
}
|
}
|
||||||
// 从details提取更多信息
|
|
||||||
if details, ok := m["details"].(map[string]interface{}); ok {
|
if details, ok := m["details"].(map[string]interface{}); ok {
|
||||||
item.Details = details
|
item.Details = details
|
||||||
// 组合 target:port
|
|
||||||
if port, ok := details["port"]; ok {
|
if port, ok := details["port"]; ok {
|
||||||
if item.Target != "" && !strings.Contains(item.Target, ":") {
|
if item.Target != "" && !strings.Contains(item.Target, ":") {
|
||||||
item.Target = fmt.Sprintf("%s:%v", item.Target, port)
|
item.Target = fmt.Sprintf("%s:%v", item.Target, port)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 构建更有意义的status
|
|
||||||
item.Status = buildStatusFromDetails(item.Type, item.Status, details)
|
item.Status = buildStatusFromDetails(item.Type, item.Status, details)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成去重键
|
detailsJSON, _ := json.Marshal(item.Details)
|
||||||
key := fmt.Sprintf("%s|%s|%s", item.Type, item.Target, item.Status)
|
|
||||||
if s.seen[key] {
|
|
||||||
return nil // 完全重复,不添加
|
|
||||||
}
|
|
||||||
|
|
||||||
// service/port 类型特殊处理:同一 target 只保留最详细的
|
// service/port 类型:同一 target 只保留最详细的
|
||||||
if item.Type == "service" || item.Type == "port" {
|
if item.Type == "service" || item.Type == "port" {
|
||||||
indexKey := item.Type + "|" + item.Target
|
var existID int64
|
||||||
if idx, exists := s.serviceIndex[indexKey]; exists {
|
var existStatus string
|
||||||
oldStatus := s.items[idx].Status
|
err := s.db.QueryRow(
|
||||||
// 如果旧的是基础状态,新的更详细,则更新
|
"SELECT id, status FROM results WHERE type = ? AND target = ? LIMIT 1",
|
||||||
if (oldStatus == "identified" || oldStatus == "open" || oldStatus == "") &&
|
item.Type, item.Target,
|
||||||
|
).Scan(&existID, &existStatus)
|
||||||
|
|
||||||
|
if err == nil {
|
||||||
|
// 已有记录,判断是否需要更新
|
||||||
|
if (existStatus == "identified" || existStatus == "open" || existStatus == "") &&
|
||||||
item.Status != "identified" && item.Status != "open" && item.Status != "" {
|
item.Status != "identified" && item.Status != "open" && item.Status != "" {
|
||||||
s.items[idx].Status = item.Status
|
s.db.Exec(
|
||||||
s.items[idx].Details = item.Details
|
"UPDATE results SET status = ?, details = ?, time = ? WHERE id = ?",
|
||||||
s.items[idx].Time = item.Time
|
item.Status, string(detailsJSON), item.Time.Format(time.RFC3339), existID,
|
||||||
s.seen[key] = true
|
)
|
||||||
return &s.items[idx]
|
item.ID = existID
|
||||||
|
return &item
|
||||||
}
|
}
|
||||||
// 否则跳过(保留已有信息)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// 新记录,记录索引
|
|
||||||
s.serviceIndex[indexKey] = len(s.items)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.seen[key] = true
|
// 插入(UNIQUE 约束自动去重)
|
||||||
|
res, err := s.db.Exec(
|
||||||
// 统计
|
"INSERT OR IGNORE INTO results (time, type, target, status, details) VALUES (?, ?, ?, ?, ?)",
|
||||||
switch item.Type {
|
item.Time.Format(time.RFC3339), item.Type, item.Target, item.Status, string(detailsJSON),
|
||||||
case "host":
|
)
|
||||||
s.stats.HostsScanned++
|
if err != nil {
|
||||||
case "port":
|
return nil
|
||||||
s.stats.PortsScanned++
|
|
||||||
case "service":
|
|
||||||
s.stats.ServicesFound++
|
|
||||||
case "vuln":
|
|
||||||
s.stats.VulnsFound++
|
|
||||||
}
|
}
|
||||||
|
|
||||||
s.counter++
|
affected, _ := res.RowsAffected()
|
||||||
item.ID = s.counter
|
if affected == 0 {
|
||||||
s.items = append(s.items, item)
|
return nil // 重复
|
||||||
|
}
|
||||||
|
|
||||||
|
item.ID, _ = res.LastInsertId()
|
||||||
return &item
|
return &item
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,25 +167,71 @@ func (s *ResultStore) Add(result interface{}) *ResultItem {
|
|||||||
func (s *ResultStore) List() []ResultItem {
|
func (s *ResultStore) List() []ResultItem {
|
||||||
s.mu.RLock()
|
s.mu.RLock()
|
||||||
defer s.mu.RUnlock()
|
defer s.mu.RUnlock()
|
||||||
return append([]ResultItem{}, s.items...)
|
|
||||||
|
rows, err := s.db.Query("SELECT id, time, type, target, status, details FROM results ORDER BY id")
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
return scanRows(rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stats 获取统计信息
|
// Stats 获取统计信息
|
||||||
func (s *ResultStore) Stats() ScanStats {
|
func (s *ResultStore) Stats() ScanStats {
|
||||||
s.mu.RLock()
|
s.mu.RLock()
|
||||||
defer s.mu.RUnlock()
|
defer s.mu.RUnlock()
|
||||||
return s.stats
|
|
||||||
|
var stats ScanStats
|
||||||
|
rows, err := s.db.Query("SELECT type, COUNT(*) FROM results GROUP BY type")
|
||||||
|
if err != nil {
|
||||||
|
return stats
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
for rows.Next() {
|
||||||
|
var t string
|
||||||
|
var count int
|
||||||
|
if rows.Scan(&t, &count) == nil {
|
||||||
|
switch t {
|
||||||
|
case "host":
|
||||||
|
stats.HostsScanned = count
|
||||||
|
case "port":
|
||||||
|
stats.PortsScanned = count
|
||||||
|
case "service":
|
||||||
|
stats.ServicesFound = count
|
||||||
|
case "vuln":
|
||||||
|
stats.VulnsFound = count
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stats
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear 清空结果
|
// Clear 清空结果
|
||||||
func (s *ResultStore) Clear() {
|
func (s *ResultStore) Clear() {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
s.items = make([]ResultItem, 0)
|
s.db.Exec("DELETE FROM results")
|
||||||
s.counter = 0
|
}
|
||||||
s.stats = ScanStats{}
|
|
||||||
s.seen = make(map[string]bool)
|
// scanRows 解析查询结果
|
||||||
s.serviceIndex = make(map[string]int)
|
func scanRows(rows *sql.Rows) []ResultItem {
|
||||||
|
var items []ResultItem
|
||||||
|
for rows.Next() {
|
||||||
|
var item ResultItem
|
||||||
|
var timeStr, detailsStr string
|
||||||
|
if err := rows.Scan(&item.ID, &timeStr, &item.Type, &item.Target, &item.Status, &detailsStr); err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
item.Time, _ = time.Parse(time.RFC3339, timeStr)
|
||||||
|
var details interface{}
|
||||||
|
if json.Unmarshal([]byte(detailsStr), &details) == nil {
|
||||||
|
item.Details = details
|
||||||
|
}
|
||||||
|
items = append(items, item)
|
||||||
|
}
|
||||||
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResultHandler 结果处理器
|
// ResultHandler 结果处理器
|
||||||
@@ -169,7 +253,6 @@ func (h *ResultHandler) List(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 支持类型过滤
|
|
||||||
typeFilter := r.URL.Query().Get("type")
|
typeFilter := r.URL.Query().Get("type")
|
||||||
items := h.store.List()
|
items := h.store.List()
|
||||||
|
|
||||||
@@ -190,7 +273,7 @@ func (h *ResultHandler) List(w http.ResponseWriter, r *http.Request) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExportOutput 导出输出结构(与CLI格式一致)
|
// ExportOutput 导出输出结构
|
||||||
type ExportOutput struct {
|
type ExportOutput struct {
|
||||||
ScanTime time.Time `json:"scan_time"`
|
ScanTime time.Time `json:"scan_time"`
|
||||||
Summary ExportSummary `json:"summary"`
|
Summary ExportSummary `json:"summary"`
|
||||||
@@ -208,7 +291,7 @@ type ExportSummary struct {
|
|||||||
TotalVulns int `json:"total_vulns"`
|
TotalVulns int `json:"total_vulns"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export 导出结果(与CLI格式一致)
|
// Export 导出结果
|
||||||
func (h *ResultHandler) Export(w http.ResponseWriter, r *http.Request) {
|
func (h *ResultHandler) Export(w http.ResponseWriter, r *http.Request) {
|
||||||
if r.Method != http.MethodGet {
|
if r.Method != http.MethodGet {
|
||||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
@@ -222,7 +305,6 @@ func (h *ResultHandler) Export(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
items := h.store.List()
|
items := h.store.List()
|
||||||
|
|
||||||
// 按类型分类
|
|
||||||
var hosts, ports, services, vulns []ResultItem
|
var hosts, ports, services, vulns []ResultItem
|
||||||
for _, item := range items {
|
for _, item := range items {
|
||||||
switch item.Type {
|
switch item.Type {
|
||||||
@@ -262,7 +344,6 @@ func (h *ResultHandler) Export(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Header().Set("Content-Disposition", "attachment; filename=fscan_results.csv")
|
w.Header().Set("Content-Disposition", "attachment; filename=fscan_results.csv")
|
||||||
writer := csv.NewWriter(w)
|
writer := csv.NewWriter(w)
|
||||||
|
|
||||||
// Hosts section
|
|
||||||
if len(hosts) > 0 {
|
if len(hosts) > 0 {
|
||||||
writer.Write([]string{"# Hosts"})
|
writer.Write([]string{"# Hosts"})
|
||||||
writer.Write([]string{"Target"})
|
writer.Write([]string{"Target"})
|
||||||
@@ -272,7 +353,6 @@ func (h *ResultHandler) Export(w http.ResponseWriter, r *http.Request) {
|
|||||||
writer.Write([]string{})
|
writer.Write([]string{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ports section
|
|
||||||
if len(ports) > 0 {
|
if len(ports) > 0 {
|
||||||
writer.Write([]string{"# Ports"})
|
writer.Write([]string{"# Ports"})
|
||||||
writer.Write([]string{"Target", "Port", "Status"})
|
writer.Write([]string{"Target", "Port", "Status"})
|
||||||
@@ -284,7 +364,6 @@ func (h *ResultHandler) Export(w http.ResponseWriter, r *http.Request) {
|
|||||||
writer.Write([]string{})
|
writer.Write([]string{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Services section
|
|
||||||
if len(services) > 0 {
|
if len(services) > 0 {
|
||||||
writer.Write([]string{"# Services"})
|
writer.Write([]string{"# Services"})
|
||||||
writer.Write([]string{"Target", "Service", "Version", "Banner"})
|
writer.Write([]string{"Target", "Service", "Version", "Banner"})
|
||||||
@@ -295,7 +374,6 @@ func (h *ResultHandler) Export(w http.ResponseWriter, r *http.Request) {
|
|||||||
writer.Write([]string{})
|
writer.Write([]string{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vulns section
|
|
||||||
if len(vulns) > 0 {
|
if len(vulns) > 0 {
|
||||||
writer.Write([]string{"# Vulns"})
|
writer.Write([]string{"# Vulns"})
|
||||||
writer.Write([]string{"Target", "Type", "Details"})
|
writer.Write([]string{"Target", "Type", "Details"})
|
||||||
@@ -394,19 +472,15 @@ func buildStatusFromDetails(resultType, originalStatus string, details map[strin
|
|||||||
return "open"
|
return "open"
|
||||||
|
|
||||||
case "service":
|
case "service":
|
||||||
// 服务名
|
|
||||||
if name, ok := details["name"].(string); ok && name != "" {
|
if name, ok := details["name"].(string); ok && name != "" {
|
||||||
parts = append(parts, name)
|
parts = append(parts, name)
|
||||||
}
|
}
|
||||||
// 版本
|
|
||||||
if version, ok := details["version"].(string); ok && version != "" {
|
if version, ok := details["version"].(string); ok && version != "" {
|
||||||
parts = append(parts, version)
|
parts = append(parts, version)
|
||||||
}
|
}
|
||||||
// 产品
|
|
||||||
if product, ok := details["product"].(string); ok && product != "" {
|
if product, ok := details["product"].(string); ok && product != "" {
|
||||||
parts = append(parts, product)
|
parts = append(parts, product)
|
||||||
}
|
}
|
||||||
// 系统
|
|
||||||
if os, ok := details["os"].(string); ok && os != "" {
|
if os, ok := details["os"].(string); ok && os != "" {
|
||||||
parts = append(parts, os)
|
parts = append(parts, os)
|
||||||
}
|
}
|
||||||
@@ -415,7 +489,6 @@ func buildStatusFromDetails(resultType, originalStatus string, details map[strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "vuln":
|
case "vuln":
|
||||||
// 统一漏洞显示格式
|
|
||||||
return normalizeVulnStatus(originalStatus, details)
|
return normalizeVulnStatus(originalStatus, details)
|
||||||
|
|
||||||
case "host":
|
case "host":
|
||||||
@@ -427,7 +500,6 @@ func buildStatusFromDetails(resultType, originalStatus string, details map[strin
|
|||||||
|
|
||||||
// normalizeVulnStatus 统一漏洞状态显示
|
// normalizeVulnStatus 统一漏洞状态显示
|
||||||
func normalizeVulnStatus(status string, details map[string]interface{}) string {
|
func normalizeVulnStatus(status string, details map[string]interface{}) string {
|
||||||
// 英文转中文映射
|
|
||||||
vulnTranslations := map[string]string{
|
vulnTranslations := map[string]string{
|
||||||
"weak_credential": i18n.GetText("web_result_weak_credential"),
|
"weak_credential": i18n.GetText("web_result_weak_credential"),
|
||||||
"unauthorized": i18n.GetText("unauthorized_access"),
|
"unauthorized": i18n.GetText("unauthorized_access"),
|
||||||
@@ -436,21 +508,17 @@ func normalizeVulnStatus(status string, details map[string]interface{}) string {
|
|||||||
"CVE": i18n.GetText("web_result_vulnerability"),
|
"CVE": i18n.GetText("web_result_vulnerability"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理 "weak_credential: user:pass" 格式
|
|
||||||
if strings.HasPrefix(status, "weak_credential:") {
|
if strings.HasPrefix(status, "weak_credential:") {
|
||||||
cred := strings.TrimPrefix(status, "weak_credential:")
|
cred := strings.TrimPrefix(status, "weak_credential:")
|
||||||
cred = strings.TrimSpace(cred)
|
cred = strings.TrimSpace(cred)
|
||||||
return i18n.Tr("web_result_weak_credential_detail", cred)
|
return i18n.Tr("web_result_weak_credential_detail", cred)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理其他已知格式
|
|
||||||
for eng, chn := range vulnTranslations {
|
for eng, chn := range vulnTranslations {
|
||||||
if strings.Contains(strings.ToLower(status), strings.ToLower(eng)) {
|
if strings.Contains(strings.ToLower(status), strings.ToLower(eng)) {
|
||||||
// 如果已经是中文格式,直接返回
|
|
||||||
if strings.Contains(status, chn) {
|
if strings.Contains(status, chn) {
|
||||||
return status
|
return status
|
||||||
}
|
}
|
||||||
// 替换英文部分
|
|
||||||
return strings.Replace(status, eng, chn, 1)
|
return strings.Replace(status, eng, chn, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>web-ui</title>
|
<title>web-ui</title>
|
||||||
<script type="module" crossorigin src="/assets/index-DR5QRXeN.js"></script>
|
<script type="module" crossorigin src="/assets/index-5JoZok-U.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-CTrwF18n.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-CTrwF18n.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
Reference in New Issue
Block a user