mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-07-13 12:52:44 +08:00
feat: 增强 gRPC 和 HTTP 网关服务
This commit is contained in:
parent
f2475bf97c
commit
c074adb3a9
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,3 +4,4 @@ main
|
|||||||
fscan.exe
|
fscan.exe
|
||||||
fscan
|
fscan
|
||||||
makefile
|
makefile
|
||||||
|
fscanapi.csv
|
||||||
|
@ -67,6 +67,11 @@ func InitOutput() error {
|
|||||||
return fmt.Errorf(GetText("output_create_dir_failed", err))
|
return fmt.Errorf(GetText("output_create_dir_failed", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ApiAddr != "" {
|
||||||
|
OutputFormat = "csv"
|
||||||
|
Outputfile = filepath.Join(dir, "fscanapi.csv")
|
||||||
|
}
|
||||||
|
|
||||||
manager := &OutputManager{
|
manager := &OutputManager{
|
||||||
outputPath: Outputfile,
|
outputPath: Outputfile,
|
||||||
outputFormat: OutputFormat,
|
outputFormat: OutputFormat,
|
||||||
@ -135,6 +140,17 @@ func SaveResult(result *ScanResult) error {
|
|||||||
LogDebug(GetText("output_saving_result", result.Type, result.Target))
|
LogDebug(GetText("output_saving_result", result.Type, result.Target))
|
||||||
return ResultOutput.saveResult(result)
|
return ResultOutput.saveResult(result)
|
||||||
}
|
}
|
||||||
|
func GetResults() ([]*ScanResult, error) {
|
||||||
|
if ResultOutput == nil {
|
||||||
|
return nil, fmt.Errorf(GetText("output_not_init"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if ResultOutput.outputFormat == "csv" {
|
||||||
|
return ResultOutput.getResult()
|
||||||
|
}
|
||||||
|
// 其他格式尚未实现读取支持
|
||||||
|
return nil, fmt.Errorf(GetText("output_format_read_not_supported"))
|
||||||
|
}
|
||||||
|
|
||||||
func (om *OutputManager) saveResult(result *ScanResult) error {
|
func (om *OutputManager) saveResult(result *ScanResult) error {
|
||||||
om.mu.Lock()
|
om.mu.Lock()
|
||||||
@ -165,6 +181,62 @@ func (om *OutputManager) saveResult(result *ScanResult) error {
|
|||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
func (om *OutputManager) getResult() ([]*ScanResult, error) {
|
||||||
|
om.mu.Lock()
|
||||||
|
defer om.mu.Unlock()
|
||||||
|
|
||||||
|
if !om.isInitialized {
|
||||||
|
LogDebug(GetText("output_not_init"))
|
||||||
|
return nil, fmt.Errorf(GetText("output_not_init"))
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(om.outputPath)
|
||||||
|
if err != nil {
|
||||||
|
LogDebug(GetText("output_open_file_failed", err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
reader := csv.NewReader(file)
|
||||||
|
records, err := reader.ReadAll()
|
||||||
|
if err != nil {
|
||||||
|
LogDebug(GetText("output_read_csv_failed", err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var results []*ScanResult
|
||||||
|
for i, row := range records {
|
||||||
|
// 跳过 CSV 头部
|
||||||
|
if i == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(row) < 5 {
|
||||||
|
continue // 数据不完整
|
||||||
|
}
|
||||||
|
|
||||||
|
t, err := time.Parse("2006-01-02 15:04:05", row[0])
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var details map[string]interface{}
|
||||||
|
if err := json.Unmarshal([]byte(row[4]), &details); err != nil {
|
||||||
|
details = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &ScanResult{
|
||||||
|
Time: t,
|
||||||
|
Type: ResultType(row[1]),
|
||||||
|
Target: row[2],
|
||||||
|
Status: row[3],
|
||||||
|
Details: details,
|
||||||
|
}
|
||||||
|
results = append(results, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
LogDebug(GetText("output_read_csv_success", len(results)))
|
||||||
|
return results, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (om *OutputManager) writeTxt(result *ScanResult) error {
|
func (om *OutputManager) writeTxt(result *ScanResult) error {
|
||||||
// 格式化 Details 为键值对字符串
|
// 格式化 Details 为键值对字符串
|
||||||
|
13
RPC/buf.gen.yaml
Normal file
13
RPC/buf.gen.yaml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
version: v1
|
||||||
|
plugins:
|
||||||
|
- plugin: go
|
||||||
|
out: lib
|
||||||
|
opt: paths=import
|
||||||
|
|
||||||
|
- plugin: go-grpc
|
||||||
|
out: lib
|
||||||
|
opt: paths=import
|
||||||
|
|
||||||
|
- plugin: grpc-gateway
|
||||||
|
out: lib
|
||||||
|
opt: paths=import
|
8
RPC/buf.lock
Normal file
8
RPC/buf.lock
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# Generated by buf. DO NOT EDIT.
|
||||||
|
version: v1
|
||||||
|
deps:
|
||||||
|
- remote: buf.build
|
||||||
|
owner: googleapis
|
||||||
|
repository: googleapis
|
||||||
|
commit: 61b203b9a9164be9a834f58c37be6f62
|
||||||
|
digest: shake256:e619113001d6e284ee8a92b1561e5d4ea89a47b28bf0410815cb2fa23914df8be9f1a6a98dcf069f5bc2d829a2cfb1ac614863be45cd4f8a5ad8606c5f200224
|
3
RPC/buf.yaml
Normal file
3
RPC/buf.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
version: v1
|
||||||
|
deps:
|
||||||
|
- buf.build/googleapis/googleapis
|
@ -2,7 +2,7 @@
|
|||||||
// versions:
|
// versions:
|
||||||
// protoc-gen-go v1.36.6
|
// protoc-gen-go v1.36.6
|
||||||
// protoc (unknown)
|
// protoc (unknown)
|
||||||
// source: proto/fscan.proto
|
// source: lib/rpc.proto
|
||||||
|
|
||||||
package lib
|
package lib
|
||||||
|
|
||||||
@ -10,6 +10,7 @@ import (
|
|||||||
_ "google.golang.org/genproto/googleapis/api/annotations"
|
_ "google.golang.org/genproto/googleapis/api/annotations"
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||||
reflect "reflect"
|
reflect "reflect"
|
||||||
sync "sync"
|
sync "sync"
|
||||||
unsafe "unsafe"
|
unsafe "unsafe"
|
||||||
@ -33,7 +34,7 @@ type StartScanRequest struct {
|
|||||||
|
|
||||||
func (x *StartScanRequest) Reset() {
|
func (x *StartScanRequest) Reset() {
|
||||||
*x = StartScanRequest{}
|
*x = StartScanRequest{}
|
||||||
mi := &file_proto_fscan_proto_msgTypes[0]
|
mi := &file_lib_rpc_proto_msgTypes[0]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@ -45,7 +46,7 @@ func (x *StartScanRequest) String() string {
|
|||||||
func (*StartScanRequest) ProtoMessage() {}
|
func (*StartScanRequest) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *StartScanRequest) ProtoReflect() protoreflect.Message {
|
func (x *StartScanRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_proto_fscan_proto_msgTypes[0]
|
mi := &file_lib_rpc_proto_msgTypes[0]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@ -58,7 +59,7 @@ func (x *StartScanRequest) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use StartScanRequest.ProtoReflect.Descriptor instead.
|
// Deprecated: Use StartScanRequest.ProtoReflect.Descriptor instead.
|
||||||
func (*StartScanRequest) Descriptor() ([]byte, []int) {
|
func (*StartScanRequest) Descriptor() ([]byte, []int) {
|
||||||
return file_proto_fscan_proto_rawDescGZIP(), []int{0}
|
return file_lib_rpc_proto_rawDescGZIP(), []int{0}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *StartScanRequest) GetSecret() string {
|
func (x *StartScanRequest) GetSecret() string {
|
||||||
@ -86,7 +87,7 @@ type StartScanResponse struct {
|
|||||||
|
|
||||||
func (x *StartScanResponse) Reset() {
|
func (x *StartScanResponse) Reset() {
|
||||||
*x = StartScanResponse{}
|
*x = StartScanResponse{}
|
||||||
mi := &file_proto_fscan_proto_msgTypes[1]
|
mi := &file_lib_rpc_proto_msgTypes[1]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@ -98,7 +99,7 @@ func (x *StartScanResponse) String() string {
|
|||||||
func (*StartScanResponse) ProtoMessage() {}
|
func (*StartScanResponse) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *StartScanResponse) ProtoReflect() protoreflect.Message {
|
func (x *StartScanResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_proto_fscan_proto_msgTypes[1]
|
mi := &file_lib_rpc_proto_msgTypes[1]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@ -111,7 +112,7 @@ func (x *StartScanResponse) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use StartScanResponse.ProtoReflect.Descriptor instead.
|
// Deprecated: Use StartScanResponse.ProtoReflect.Descriptor instead.
|
||||||
func (*StartScanResponse) Descriptor() ([]byte, []int) {
|
func (*StartScanResponse) Descriptor() ([]byte, []int) {
|
||||||
return file_proto_fscan_proto_rawDescGZIP(), []int{1}
|
return file_lib_rpc_proto_rawDescGZIP(), []int{1}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *StartScanResponse) GetTaskId() string {
|
func (x *StartScanResponse) GetTaskId() string {
|
||||||
@ -131,15 +132,15 @@ func (x *StartScanResponse) GetMessage() string {
|
|||||||
// 获取扫描结果的请求
|
// 获取扫描结果的请求
|
||||||
type TaskResultsRequest struct {
|
type TaskResultsRequest struct {
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
TaskId string `protobuf:"bytes,1,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"`
|
Secret string `protobuf:"bytes,1,opt,name=secret,proto3" json:"secret,omitempty"` // 用于身份校验
|
||||||
Offset uint32 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"`
|
Filter *Filter `protobuf:"bytes,2,opt,name=filter,proto3" json:"filter,omitempty"` // 筛选条件(如关键字、状态等)
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *TaskResultsRequest) Reset() {
|
func (x *TaskResultsRequest) Reset() {
|
||||||
*x = TaskResultsRequest{}
|
*x = TaskResultsRequest{}
|
||||||
mi := &file_proto_fscan_proto_msgTypes[2]
|
mi := &file_lib_rpc_proto_msgTypes[2]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@ -151,7 +152,7 @@ func (x *TaskResultsRequest) String() string {
|
|||||||
func (*TaskResultsRequest) ProtoMessage() {}
|
func (*TaskResultsRequest) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *TaskResultsRequest) ProtoReflect() protoreflect.Message {
|
func (x *TaskResultsRequest) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_proto_fscan_proto_msgTypes[2]
|
mi := &file_lib_rpc_proto_msgTypes[2]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@ -164,21 +165,81 @@ func (x *TaskResultsRequest) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use TaskResultsRequest.ProtoReflect.Descriptor instead.
|
// Deprecated: Use TaskResultsRequest.ProtoReflect.Descriptor instead.
|
||||||
func (*TaskResultsRequest) Descriptor() ([]byte, []int) {
|
func (*TaskResultsRequest) Descriptor() ([]byte, []int) {
|
||||||
return file_proto_fscan_proto_rawDescGZIP(), []int{2}
|
return file_lib_rpc_proto_rawDescGZIP(), []int{2}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *TaskResultsRequest) GetTaskId() string {
|
func (x *TaskResultsRequest) GetSecret() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Secret
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TaskResultsRequest) GetFilter() *Filter {
|
||||||
|
if x != nil {
|
||||||
|
return x.Filter
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Filter struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
TaskId string `protobuf:"bytes,1,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"` // 任务ID
|
||||||
|
StartTime string `protobuf:"bytes,2,opt,name=Start_time,json=StartTime,proto3" json:"Start_time,omitempty"` // 开始时间
|
||||||
|
EndTime string `protobuf:"bytes,3,opt,name=End_time,json=EndTime,proto3" json:"End_time,omitempty"` // 结束时间
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Filter) Reset() {
|
||||||
|
*x = Filter{}
|
||||||
|
mi := &file_lib_rpc_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Filter) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Filter) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *Filter) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_lib_rpc_proto_msgTypes[3]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use Filter.ProtoReflect.Descriptor instead.
|
||||||
|
func (*Filter) Descriptor() ([]byte, []int) {
|
||||||
|
return file_lib_rpc_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Filter) GetTaskId() string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.TaskId
|
return x.TaskId
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *TaskResultsRequest) GetOffset() uint32 {
|
func (x *Filter) GetStartTime() string {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.Offset
|
return x.StartTime
|
||||||
}
|
}
|
||||||
return 0
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *Filter) GetEndTime() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.EndTime
|
||||||
|
}
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取扫描结果的响应
|
// 获取扫描结果的响应
|
||||||
@ -193,7 +254,7 @@ type TaskResultsResponse struct {
|
|||||||
|
|
||||||
func (x *TaskResultsResponse) Reset() {
|
func (x *TaskResultsResponse) Reset() {
|
||||||
*x = TaskResultsResponse{}
|
*x = TaskResultsResponse{}
|
||||||
mi := &file_proto_fscan_proto_msgTypes[3]
|
mi := &file_lib_rpc_proto_msgTypes[4]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@ -205,7 +266,7 @@ func (x *TaskResultsResponse) String() string {
|
|||||||
func (*TaskResultsResponse) ProtoMessage() {}
|
func (*TaskResultsResponse) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *TaskResultsResponse) ProtoReflect() protoreflect.Message {
|
func (x *TaskResultsResponse) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_proto_fscan_proto_msgTypes[3]
|
mi := &file_lib_rpc_proto_msgTypes[4]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@ -218,7 +279,7 @@ func (x *TaskResultsResponse) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use TaskResultsResponse.ProtoReflect.Descriptor instead.
|
// Deprecated: Use TaskResultsResponse.ProtoReflect.Descriptor instead.
|
||||||
func (*TaskResultsResponse) Descriptor() ([]byte, []int) {
|
func (*TaskResultsResponse) Descriptor() ([]byte, []int) {
|
||||||
return file_proto_fscan_proto_rawDescGZIP(), []int{3}
|
return file_lib_rpc_proto_rawDescGZIP(), []int{4}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *TaskResultsResponse) GetTaskId() string {
|
func (x *TaskResultsResponse) GetTaskId() string {
|
||||||
@ -249,14 +310,14 @@ type ScanResult struct {
|
|||||||
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
|
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
|
||||||
Target string `protobuf:"bytes,3,opt,name=target,proto3" json:"target,omitempty"`
|
Target string `protobuf:"bytes,3,opt,name=target,proto3" json:"target,omitempty"`
|
||||||
Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"`
|
Status string `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"`
|
||||||
DetailsJson string `protobuf:"bytes,5,opt,name=details_json,json=detailsJson,proto3" json:"details_json,omitempty"`
|
DetailsJson *structpb.Struct `protobuf:"bytes,5,opt,name=details_json,json=detailsJson,proto3" json:"details_json,omitempty"`
|
||||||
unknownFields protoimpl.UnknownFields
|
unknownFields protoimpl.UnknownFields
|
||||||
sizeCache protoimpl.SizeCache
|
sizeCache protoimpl.SizeCache
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ScanResult) Reset() {
|
func (x *ScanResult) Reset() {
|
||||||
*x = ScanResult{}
|
*x = ScanResult{}
|
||||||
mi := &file_proto_fscan_proto_msgTypes[4]
|
mi := &file_lib_rpc_proto_msgTypes[5]
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
ms.StoreMessageInfo(mi)
|
ms.StoreMessageInfo(mi)
|
||||||
}
|
}
|
||||||
@ -268,7 +329,7 @@ func (x *ScanResult) String() string {
|
|||||||
func (*ScanResult) ProtoMessage() {}
|
func (*ScanResult) ProtoMessage() {}
|
||||||
|
|
||||||
func (x *ScanResult) ProtoReflect() protoreflect.Message {
|
func (x *ScanResult) ProtoReflect() protoreflect.Message {
|
||||||
mi := &file_proto_fscan_proto_msgTypes[4]
|
mi := &file_lib_rpc_proto_msgTypes[5]
|
||||||
if x != nil {
|
if x != nil {
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
if ms.LoadMessageInfo() == nil {
|
if ms.LoadMessageInfo() == nil {
|
||||||
@ -281,7 +342,7 @@ func (x *ScanResult) ProtoReflect() protoreflect.Message {
|
|||||||
|
|
||||||
// Deprecated: Use ScanResult.ProtoReflect.Descriptor instead.
|
// Deprecated: Use ScanResult.ProtoReflect.Descriptor instead.
|
||||||
func (*ScanResult) Descriptor() ([]byte, []int) {
|
func (*ScanResult) Descriptor() ([]byte, []int) {
|
||||||
return file_proto_fscan_proto_rawDescGZIP(), []int{4}
|
return file_lib_rpc_proto_rawDescGZIP(), []int{5}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ScanResult) GetTime() string {
|
func (x *ScanResult) GetTime() string {
|
||||||
@ -312,98 +373,104 @@ func (x *ScanResult) GetStatus() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ScanResult) GetDetailsJson() string {
|
func (x *ScanResult) GetDetailsJson() *structpb.Struct {
|
||||||
if x != nil {
|
if x != nil {
|
||||||
return x.DetailsJson
|
return x.DetailsJson
|
||||||
}
|
}
|
||||||
return ""
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var File_proto_fscan_proto protoreflect.FileDescriptor
|
var File_lib_rpc_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
const file_proto_fscan_proto_rawDesc = "" +
|
const file_lib_rpc_proto_rawDesc = "" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"\x11proto/fscan.proto\x12\x03lib\x1a\x1cgoogle/api/annotations.proto\"<\n" +
|
"\rlib/rpc.proto\x12\x03lib\x1a\x1cgoogle/api/annotations.proto\x1a\x1cgoogle/protobuf/struct.proto\"<\n" +
|
||||||
"\x10StartScanRequest\x12\x16\n" +
|
"\x10StartScanRequest\x12\x16\n" +
|
||||||
"\x06secret\x18\x01 \x01(\tR\x06secret\x12\x10\n" +
|
"\x06secret\x18\x01 \x01(\tR\x06secret\x12\x10\n" +
|
||||||
"\x03arg\x18\x02 \x01(\tR\x03arg\"F\n" +
|
"\x03arg\x18\x02 \x01(\tR\x03arg\"F\n" +
|
||||||
"\x11StartScanResponse\x12\x17\n" +
|
"\x11StartScanResponse\x12\x17\n" +
|
||||||
"\atask_id\x18\x01 \x01(\tR\x06taskId\x12\x18\n" +
|
"\atask_id\x18\x01 \x01(\tR\x06taskId\x12\x18\n" +
|
||||||
"\amessage\x18\x02 \x01(\tR\amessage\"E\n" +
|
"\amessage\x18\x02 \x01(\tR\amessage\"Q\n" +
|
||||||
"\x12TaskResultsRequest\x12\x17\n" +
|
"\x12TaskResultsRequest\x12\x16\n" +
|
||||||
"\atask_id\x18\x01 \x01(\tR\x06taskId\x12\x16\n" +
|
"\x06secret\x18\x01 \x01(\tR\x06secret\x12#\n" +
|
||||||
"\x06offset\x18\x02 \x01(\rR\x06offset\"u\n" +
|
"\x06filter\x18\x02 \x01(\v2\v.lib.FilterR\x06filter\"[\n" +
|
||||||
|
"\x06Filter\x12\x17\n" +
|
||||||
|
"\atask_id\x18\x01 \x01(\tR\x06taskId\x12\x1d\n" +
|
||||||
|
"\n" +
|
||||||
|
"Start_time\x18\x02 \x01(\tR\tStartTime\x12\x19\n" +
|
||||||
|
"\bEnd_time\x18\x03 \x01(\tR\aEndTime\"u\n" +
|
||||||
"\x13TaskResultsResponse\x12\x17\n" +
|
"\x13TaskResultsResponse\x12\x17\n" +
|
||||||
"\atask_id\x18\x01 \x01(\tR\x06taskId\x12)\n" +
|
"\atask_id\x18\x01 \x01(\tR\x06taskId\x12)\n" +
|
||||||
"\aresults\x18\x02 \x03(\v2\x0f.lib.ScanResultR\aresults\x12\x1a\n" +
|
"\aresults\x18\x02 \x03(\v2\x0f.lib.ScanResultR\aresults\x12\x1a\n" +
|
||||||
"\bfinished\x18\x03 \x01(\bR\bfinished\"\x87\x01\n" +
|
"\bfinished\x18\x03 \x01(\bR\bfinished\"\xa0\x01\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"ScanResult\x12\x12\n" +
|
"ScanResult\x12\x12\n" +
|
||||||
"\x04time\x18\x01 \x01(\tR\x04time\x12\x12\n" +
|
"\x04time\x18\x01 \x01(\tR\x04time\x12\x12\n" +
|
||||||
"\x04type\x18\x02 \x01(\tR\x04type\x12\x16\n" +
|
"\x04type\x18\x02 \x01(\tR\x04type\x12\x16\n" +
|
||||||
"\x06target\x18\x03 \x01(\tR\x06target\x12\x16\n" +
|
"\x06target\x18\x03 \x01(\tR\x06target\x12\x16\n" +
|
||||||
"\x06status\x18\x04 \x01(\tR\x06status\x12!\n" +
|
"\x06status\x18\x04 \x01(\tR\x06status\x12:\n" +
|
||||||
"\fdetails_json\x18\x05 \x01(\tR\vdetailsJson2\xa0\x02\n" +
|
"\fdetails_json\x18\x05 \x01(\v2\x17.google.protobuf.StructR\vdetailsJson2\xc4\x01\n" +
|
||||||
"\fFscanService\x12T\n" +
|
"\fFscanService\x12T\n" +
|
||||||
"\tStartScan\x12\x15.lib.StartScanRequest\x1a\x16.lib.StartScanResponse\"\x18\x82\xd3\xe4\x93\x02\x12:\x01*\"\r/v1/startscan\x12^\n" +
|
"\tStartScan\x12\x15.lib.StartScanRequest\x1a\x16.lib.StartScanResponse\"\x18\x82\xd3\xe4\x93\x02\x12:\x01*\"\r/v1/startscan\x12^\n" +
|
||||||
"\x0eGetScanResults\x12\x17.lib.TaskResultsRequest\x1a\x18.lib.TaskResultsResponse\"\x19\x82\xd3\xe4\x93\x02\x13:\x01*\"\x0e/v1/getresults\x12Z\n" +
|
"\x0eGetScanResults\x12\x17.lib.TaskResultsRequest\x1a\x18.lib.TaskResultsResponse\"\x19\x82\xd3\xe4\x93\x02\x13:\x01*\"\x0e/v1/getresultsB\bZ\x06./;libb\x06proto3"
|
||||||
"\x11StreamScanResults\x12\x17.lib.TaskResultsRequest\x1a\x0f.lib.ScanResult\"\x19\x82\xd3\xe4\x93\x02\x13\x12\x11/v1/streamresults0\x01B\x1eZ\x1cgithub.com/shadow1ng/RPC;libb\x06proto3"
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
file_proto_fscan_proto_rawDescOnce sync.Once
|
file_lib_rpc_proto_rawDescOnce sync.Once
|
||||||
file_proto_fscan_proto_rawDescData []byte
|
file_lib_rpc_proto_rawDescData []byte
|
||||||
)
|
)
|
||||||
|
|
||||||
func file_proto_fscan_proto_rawDescGZIP() []byte {
|
func file_lib_rpc_proto_rawDescGZIP() []byte {
|
||||||
file_proto_fscan_proto_rawDescOnce.Do(func() {
|
file_lib_rpc_proto_rawDescOnce.Do(func() {
|
||||||
file_proto_fscan_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proto_fscan_proto_rawDesc), len(file_proto_fscan_proto_rawDesc)))
|
file_lib_rpc_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_lib_rpc_proto_rawDesc), len(file_lib_rpc_proto_rawDesc)))
|
||||||
})
|
})
|
||||||
return file_proto_fscan_proto_rawDescData
|
return file_lib_rpc_proto_rawDescData
|
||||||
}
|
}
|
||||||
|
|
||||||
var file_proto_fscan_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
|
var file_lib_rpc_proto_msgTypes = make([]protoimpl.MessageInfo, 6)
|
||||||
var file_proto_fscan_proto_goTypes = []any{
|
var file_lib_rpc_proto_goTypes = []any{
|
||||||
(*StartScanRequest)(nil), // 0: lib.StartScanRequest
|
(*StartScanRequest)(nil), // 0: lib.StartScanRequest
|
||||||
(*StartScanResponse)(nil), // 1: lib.StartScanResponse
|
(*StartScanResponse)(nil), // 1: lib.StartScanResponse
|
||||||
(*TaskResultsRequest)(nil), // 2: lib.TaskResultsRequest
|
(*TaskResultsRequest)(nil), // 2: lib.TaskResultsRequest
|
||||||
(*TaskResultsResponse)(nil), // 3: lib.TaskResultsResponse
|
(*Filter)(nil), // 3: lib.Filter
|
||||||
(*ScanResult)(nil), // 4: lib.ScanResult
|
(*TaskResultsResponse)(nil), // 4: lib.TaskResultsResponse
|
||||||
|
(*ScanResult)(nil), // 5: lib.ScanResult
|
||||||
|
(*structpb.Struct)(nil), // 6: google.protobuf.Struct
|
||||||
}
|
}
|
||||||
var file_proto_fscan_proto_depIdxs = []int32{
|
var file_lib_rpc_proto_depIdxs = []int32{
|
||||||
4, // 0: lib.TaskResultsResponse.results:type_name -> lib.ScanResult
|
3, // 0: lib.TaskResultsRequest.filter:type_name -> lib.Filter
|
||||||
0, // 1: lib.FscanService.StartScan:input_type -> lib.StartScanRequest
|
5, // 1: lib.TaskResultsResponse.results:type_name -> lib.ScanResult
|
||||||
2, // 2: lib.FscanService.GetScanResults:input_type -> lib.TaskResultsRequest
|
6, // 2: lib.ScanResult.details_json:type_name -> google.protobuf.Struct
|
||||||
2, // 3: lib.FscanService.StreamScanResults:input_type -> lib.TaskResultsRequest
|
0, // 3: lib.FscanService.StartScan:input_type -> lib.StartScanRequest
|
||||||
1, // 4: lib.FscanService.StartScan:output_type -> lib.StartScanResponse
|
2, // 4: lib.FscanService.GetScanResults:input_type -> lib.TaskResultsRequest
|
||||||
3, // 5: lib.FscanService.GetScanResults:output_type -> lib.TaskResultsResponse
|
1, // 5: lib.FscanService.StartScan:output_type -> lib.StartScanResponse
|
||||||
4, // 6: lib.FscanService.StreamScanResults:output_type -> lib.ScanResult
|
4, // 6: lib.FscanService.GetScanResults:output_type -> lib.TaskResultsResponse
|
||||||
4, // [4:7] is the sub-list for method output_type
|
5, // [5:7] is the sub-list for method output_type
|
||||||
1, // [1:4] is the sub-list for method input_type
|
3, // [3:5] is the sub-list for method input_type
|
||||||
1, // [1:1] is the sub-list for extension type_name
|
3, // [3:3] is the sub-list for extension type_name
|
||||||
1, // [1:1] is the sub-list for extension extendee
|
3, // [3:3] is the sub-list for extension extendee
|
||||||
0, // [0:1] is the sub-list for field type_name
|
0, // [0:3] is the sub-list for field type_name
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() { file_proto_fscan_proto_init() }
|
func init() { file_lib_rpc_proto_init() }
|
||||||
func file_proto_fscan_proto_init() {
|
func file_lib_rpc_proto_init() {
|
||||||
if File_proto_fscan_proto != nil {
|
if File_lib_rpc_proto != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
type x struct{}
|
type x struct{}
|
||||||
out := protoimpl.TypeBuilder{
|
out := protoimpl.TypeBuilder{
|
||||||
File: protoimpl.DescBuilder{
|
File: protoimpl.DescBuilder{
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_fscan_proto_rawDesc), len(file_proto_fscan_proto_rawDesc)),
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_lib_rpc_proto_rawDesc), len(file_lib_rpc_proto_rawDesc)),
|
||||||
NumEnums: 0,
|
NumEnums: 0,
|
||||||
NumMessages: 5,
|
NumMessages: 6,
|
||||||
NumExtensions: 0,
|
NumExtensions: 0,
|
||||||
NumServices: 1,
|
NumServices: 1,
|
||||||
},
|
},
|
||||||
GoTypes: file_proto_fscan_proto_goTypes,
|
GoTypes: file_lib_rpc_proto_goTypes,
|
||||||
DependencyIndexes: file_proto_fscan_proto_depIdxs,
|
DependencyIndexes: file_lib_rpc_proto_depIdxs,
|
||||||
MessageInfos: file_proto_fscan_proto_msgTypes,
|
MessageInfos: file_lib_rpc_proto_msgTypes,
|
||||||
}.Build()
|
}.Build()
|
||||||
File_proto_fscan_proto = out.File
|
File_lib_rpc_proto = out.File
|
||||||
file_proto_fscan_proto_goTypes = nil
|
file_lib_rpc_proto_goTypes = nil
|
||||||
file_proto_fscan_proto_depIdxs = nil
|
file_lib_rpc_proto_depIdxs = nil
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
|
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
|
||||||
// source: proto/fscan.proto
|
// source: lib/rpc.proto
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Package lib is a reverse proxy.
|
Package lib is a reverse proxy.
|
||||||
@ -83,32 +83,6 @@ func local_request_FscanService_GetScanResults_0(ctx context.Context, marshaler
|
|||||||
return msg, metadata, err
|
return msg, metadata, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var filter_FscanService_StreamScanResults_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
|
|
||||||
|
|
||||||
func request_FscanService_StreamScanResults_0(ctx context.Context, marshaler runtime.Marshaler, client FscanServiceClient, req *http.Request, pathParams map[string]string) (FscanService_StreamScanResultsClient, runtime.ServerMetadata, error) {
|
|
||||||
var (
|
|
||||||
protoReq TaskResultsRequest
|
|
||||||
metadata runtime.ServerMetadata
|
|
||||||
)
|
|
||||||
io.Copy(io.Discard, req.Body)
|
|
||||||
if err := req.ParseForm(); err != nil {
|
|
||||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
|
||||||
}
|
|
||||||
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_FscanService_StreamScanResults_0); err != nil {
|
|
||||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
|
||||||
}
|
|
||||||
stream, err := client.StreamScanResults(ctx, &protoReq)
|
|
||||||
if err != nil {
|
|
||||||
return nil, metadata, err
|
|
||||||
}
|
|
||||||
header, err := stream.Header()
|
|
||||||
if err != nil {
|
|
||||||
return nil, metadata, err
|
|
||||||
}
|
|
||||||
metadata.HeaderMD = header
|
|
||||||
return stream, metadata, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterFscanServiceHandlerServer registers the http handlers for service FscanService to "mux".
|
// RegisterFscanServiceHandlerServer registers the http handlers for service FscanService to "mux".
|
||||||
// UnaryRPC :call FscanServiceServer directly.
|
// UnaryRPC :call FscanServiceServer directly.
|
||||||
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
||||||
@ -156,13 +130,6 @@ func RegisterFscanServiceHandlerServer(ctx context.Context, mux *runtime.ServeMu
|
|||||||
forward_FscanService_GetScanResults_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
forward_FscanService_GetScanResults_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
})
|
})
|
||||||
|
|
||||||
mux.Handle(http.MethodGet, pattern_FscanService_StreamScanResults_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
|
||||||
err := status.Error(codes.Unimplemented, "streaming calls are not yet supported in the in-process transport")
|
|
||||||
_, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
|
||||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
|
||||||
return
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,34 +203,15 @@ func RegisterFscanServiceHandlerClient(ctx context.Context, mux *runtime.ServeMu
|
|||||||
}
|
}
|
||||||
forward_FscanService_GetScanResults_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
forward_FscanService_GetScanResults_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||||
})
|
})
|
||||||
mux.Handle(http.MethodGet, pattern_FscanService_StreamScanResults_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
|
||||||
ctx, cancel := context.WithCancel(req.Context())
|
|
||||||
defer cancel()
|
|
||||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
|
||||||
annotatedContext, err := runtime.AnnotateContext(ctx, mux, req, "/lib.FscanService/StreamScanResults", runtime.WithHTTPPathPattern("/v1/streamresults"))
|
|
||||||
if err != nil {
|
|
||||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
resp, md, err := request_FscanService_StreamScanResults_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
|
||||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
|
||||||
if err != nil {
|
|
||||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
forward_FscanService_StreamScanResults_0(annotatedContext, mux, outboundMarshaler, w, req, func() (proto.Message, error) { return resp.Recv() }, mux.GetForwardResponseOptions()...)
|
|
||||||
})
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
pattern_FscanService_StartScan_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "startscan"}, ""))
|
pattern_FscanService_StartScan_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "startscan"}, ""))
|
||||||
pattern_FscanService_GetScanResults_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getresults"}, ""))
|
pattern_FscanService_GetScanResults_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "getresults"}, ""))
|
||||||
pattern_FscanService_StreamScanResults_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "streamresults"}, ""))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
forward_FscanService_StartScan_0 = runtime.ForwardResponseMessage
|
forward_FscanService_StartScan_0 = runtime.ForwardResponseMessage
|
||||||
forward_FscanService_GetScanResults_0 = runtime.ForwardResponseMessage
|
forward_FscanService_GetScanResults_0 = runtime.ForwardResponseMessage
|
||||||
forward_FscanService_StreamScanResults_0 = runtime.ForwardResponseStream
|
|
||||||
)
|
)
|
@ -5,6 +5,7 @@ package lib;
|
|||||||
option go_package = "./;lib";
|
option go_package = "./;lib";
|
||||||
|
|
||||||
import "google/api/annotations.proto";
|
import "google/api/annotations.proto";
|
||||||
|
import "google/protobuf/struct.proto";
|
||||||
|
|
||||||
service FscanService {
|
service FscanService {
|
||||||
// 启动扫描任务
|
// 启动扫描任务
|
||||||
@ -23,12 +24,12 @@ service FscanService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取扫描结果(流式)
|
// TODO: 流式获取扫描结果
|
||||||
rpc StreamScanResults(TaskResultsRequest) returns (stream ScanResult) {
|
// rpc StreamScanResults(TaskResultsRequest) returns (stream ScanResult) {
|
||||||
option (google.api.http) = {
|
// option (google.api.http) = {
|
||||||
get: "/v1/streamresults"
|
// get: "/v1/streamresults"
|
||||||
};
|
// };
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 启动任务的请求
|
// 启动任务的请求
|
||||||
@ -45,8 +46,14 @@ message StartScanResponse {
|
|||||||
|
|
||||||
// 获取扫描结果的请求
|
// 获取扫描结果的请求
|
||||||
message TaskResultsRequest {
|
message TaskResultsRequest {
|
||||||
string task_id = 1;
|
string secret = 1; // 用于身份校验
|
||||||
uint32 offset = 2;
|
Filter filter = 2; // 筛选条件(如关键字、状态等)
|
||||||
|
}
|
||||||
|
|
||||||
|
message Filter {
|
||||||
|
string task_id = 1; // 任务ID
|
||||||
|
string Start_time = 2; // 开始时间
|
||||||
|
string End_time = 3; // 结束时间
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取扫描结果的响应
|
// 获取扫描结果的响应
|
||||||
@ -62,5 +69,5 @@ message ScanResult {
|
|||||||
string type = 2;
|
string type = 2;
|
||||||
string target = 3;
|
string target = 3;
|
||||||
string status = 4;
|
string status = 4;
|
||||||
string details_json = 5;
|
google.protobuf.Struct details_json = 5;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
// versions:
|
// versions:
|
||||||
// - protoc-gen-go-grpc v1.5.1
|
// - protoc-gen-go-grpc v1.5.1
|
||||||
// - protoc (unknown)
|
// - protoc (unknown)
|
||||||
// source: proto/fscan.proto
|
// source: lib/rpc.proto
|
||||||
|
|
||||||
package lib
|
package lib
|
||||||
|
|
||||||
@ -21,7 +21,6 @@ const _ = grpc.SupportPackageIsVersion9
|
|||||||
const (
|
const (
|
||||||
FscanService_StartScan_FullMethodName = "/lib.FscanService/StartScan"
|
FscanService_StartScan_FullMethodName = "/lib.FscanService/StartScan"
|
||||||
FscanService_GetScanResults_FullMethodName = "/lib.FscanService/GetScanResults"
|
FscanService_GetScanResults_FullMethodName = "/lib.FscanService/GetScanResults"
|
||||||
FscanService_StreamScanResults_FullMethodName = "/lib.FscanService/StreamScanResults"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// FscanServiceClient is the client API for FscanService service.
|
// FscanServiceClient is the client API for FscanService service.
|
||||||
@ -32,8 +31,6 @@ type FscanServiceClient interface {
|
|||||||
StartScan(ctx context.Context, in *StartScanRequest, opts ...grpc.CallOption) (*StartScanResponse, error)
|
StartScan(ctx context.Context, in *StartScanRequest, opts ...grpc.CallOption) (*StartScanResponse, error)
|
||||||
// 获取扫描结果(非流式)
|
// 获取扫描结果(非流式)
|
||||||
GetScanResults(ctx context.Context, in *TaskResultsRequest, opts ...grpc.CallOption) (*TaskResultsResponse, error)
|
GetScanResults(ctx context.Context, in *TaskResultsRequest, opts ...grpc.CallOption) (*TaskResultsResponse, error)
|
||||||
// 获取扫描结果(流式)
|
|
||||||
StreamScanResults(ctx context.Context, in *TaskResultsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ScanResult], error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type fscanServiceClient struct {
|
type fscanServiceClient struct {
|
||||||
@ -64,25 +61,6 @@ func (c *fscanServiceClient) GetScanResults(ctx context.Context, in *TaskResults
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *fscanServiceClient) StreamScanResults(ctx context.Context, in *TaskResultsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[ScanResult], error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
stream, err := c.cc.NewStream(ctx, &FscanService_ServiceDesc.Streams[0], FscanService_StreamScanResults_FullMethodName, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
x := &grpc.GenericClientStream[TaskResultsRequest, ScanResult]{ClientStream: stream}
|
|
||||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := x.ClientStream.CloseSend(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return x, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
|
||||||
type FscanService_StreamScanResultsClient = grpc.ServerStreamingClient[ScanResult]
|
|
||||||
|
|
||||||
// FscanServiceServer is the server API for FscanService service.
|
// FscanServiceServer is the server API for FscanService service.
|
||||||
// All implementations must embed UnimplementedFscanServiceServer
|
// All implementations must embed UnimplementedFscanServiceServer
|
||||||
// for forward compatibility.
|
// for forward compatibility.
|
||||||
@ -91,8 +69,6 @@ type FscanServiceServer interface {
|
|||||||
StartScan(context.Context, *StartScanRequest) (*StartScanResponse, error)
|
StartScan(context.Context, *StartScanRequest) (*StartScanResponse, error)
|
||||||
// 获取扫描结果(非流式)
|
// 获取扫描结果(非流式)
|
||||||
GetScanResults(context.Context, *TaskResultsRequest) (*TaskResultsResponse, error)
|
GetScanResults(context.Context, *TaskResultsRequest) (*TaskResultsResponse, error)
|
||||||
// 获取扫描结果(流式)
|
|
||||||
StreamScanResults(*TaskResultsRequest, grpc.ServerStreamingServer[ScanResult]) error
|
|
||||||
mustEmbedUnimplementedFscanServiceServer()
|
mustEmbedUnimplementedFscanServiceServer()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,9 +85,6 @@ func (UnimplementedFscanServiceServer) StartScan(context.Context, *StartScanRequ
|
|||||||
func (UnimplementedFscanServiceServer) GetScanResults(context.Context, *TaskResultsRequest) (*TaskResultsResponse, error) {
|
func (UnimplementedFscanServiceServer) GetScanResults(context.Context, *TaskResultsRequest) (*TaskResultsResponse, error) {
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetScanResults not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method GetScanResults not implemented")
|
||||||
}
|
}
|
||||||
func (UnimplementedFscanServiceServer) StreamScanResults(*TaskResultsRequest, grpc.ServerStreamingServer[ScanResult]) error {
|
|
||||||
return status.Errorf(codes.Unimplemented, "method StreamScanResults not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedFscanServiceServer) mustEmbedUnimplementedFscanServiceServer() {}
|
func (UnimplementedFscanServiceServer) mustEmbedUnimplementedFscanServiceServer() {}
|
||||||
func (UnimplementedFscanServiceServer) testEmbeddedByValue() {}
|
func (UnimplementedFscanServiceServer) testEmbeddedByValue() {}
|
||||||
|
|
||||||
@ -169,17 +142,6 @@ func _FscanService_GetScanResults_Handler(srv interface{}, ctx context.Context,
|
|||||||
return interceptor(ctx, in, info, handler)
|
return interceptor(ctx, in, info, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func _FscanService_StreamScanResults_Handler(srv interface{}, stream grpc.ServerStream) error {
|
|
||||||
m := new(TaskResultsRequest)
|
|
||||||
if err := stream.RecvMsg(m); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return srv.(FscanServiceServer).StreamScanResults(m, &grpc.GenericServerStream[TaskResultsRequest, ScanResult]{ServerStream: stream})
|
|
||||||
}
|
|
||||||
|
|
||||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
|
||||||
type FscanService_StreamScanResultsServer = grpc.ServerStreamingServer[ScanResult]
|
|
||||||
|
|
||||||
// FscanService_ServiceDesc is the grpc.ServiceDesc for FscanService service.
|
// FscanService_ServiceDesc is the grpc.ServiceDesc for FscanService service.
|
||||||
// It's only intended for direct use with grpc.RegisterService,
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
// and not to be introspected or modified (even as a copy)
|
// and not to be introspected or modified (even as a copy)
|
||||||
@ -196,12 +158,6 @@ var FscanService_ServiceDesc = grpc.ServiceDesc{
|
|||||||
Handler: _FscanService_GetScanResults_Handler,
|
Handler: _FscanService_GetScanResults_Handler,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Streams: []grpc.StreamDesc{
|
Streams: []grpc.StreamDesc{},
|
||||||
{
|
Metadata: "lib/rpc.proto",
|
||||||
StreamName: "StreamScanResults",
|
|
||||||
Handler: _FscanService_StreamScanResults_Handler,
|
|
||||||
ServerStreams: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Metadata: "proto/fscan.proto",
|
|
||||||
}
|
}
|
@ -14,15 +14,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// 启动 gRPC + HTTP Gateway 服务(仅当设置了 API 地址时)
|
// 启动 gRPC + HTTP Gateway 服务(仅当设置了 API 地址时)
|
||||||
// 如果未设置 API 地址,直接返回 nil
|
|
||||||
// 如果 HTTP 启动失败,则返回 error
|
|
||||||
func StartApiServer() error {
|
func StartApiServer() error {
|
||||||
if Common.ApiAddr == "" {
|
if Common.ApiAddr == "" {
|
||||||
Common.LogDebug("未设置 API 地址,跳过 API 服务启动")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
grpcAddr := ":50051"
|
grpcAddr := "127.0.0.1:50051"
|
||||||
httpAddr := validateHTTPAddr(Common.ApiAddr, ":8088")
|
httpAddr := validateHTTPAddr(Common.ApiAddr, ":8088")
|
||||||
|
|
||||||
go runGRPCServer(grpcAddr)
|
go runGRPCServer(grpcAddr)
|
||||||
@ -61,8 +58,16 @@ func runHTTPGateway(httpAddr, grpcAddr string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加 CORS 支持
|
// 使用中间件包装 mux
|
||||||
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
handler := applyMiddlewares(mux)
|
||||||
|
|
||||||
|
Common.LogSuccess("✅ HTTP Gateway 已启动,地址: " + httpAddr)
|
||||||
|
return http.ListenAndServe(httpAddr, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册 HTTP 中间件
|
||||||
|
func applyMiddlewares(handler http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
|
||||||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
|
||||||
@ -71,11 +76,9 @@ func runHTTPGateway(httpAddr, grpcAddr string) error {
|
|||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mux.ServeHTTP(w, r)
|
|
||||||
})
|
|
||||||
|
|
||||||
Common.LogSuccess("✅ HTTP Gateway 已启动,地址: " + httpAddr)
|
handler.ServeHTTP(w, r)
|
||||||
return http.ListenAndServe(httpAddr, handler)
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 校验监听地址格式,格式非法使用默认
|
// 校验监听地址格式,格式非法使用默认
|
||||||
|
@ -10,25 +10,27 @@ import (
|
|||||||
"github.com/shadow1ng/fscan/Common"
|
"github.com/shadow1ng/fscan/Common"
|
||||||
"github.com/shadow1ng/fscan/Core"
|
"github.com/shadow1ng/fscan/Core"
|
||||||
pb "github.com/shadow1ng/fscan/RPC/lib"
|
pb "github.com/shadow1ng/fscan/RPC/lib"
|
||||||
|
structpb "google.golang.org/protobuf/types/known/structpb"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FscanService struct {
|
type FscanService struct {
|
||||||
pb.UnimplementedFscanServiceServer
|
pb.UnimplementedFscanServiceServer
|
||||||
scanMutex sync.Mutex
|
scanMutex sync.Mutex
|
||||||
isScanning int32 // 原子变量,用于标记是否正在扫描
|
isScanning int32
|
||||||
|
scanStartTime time.Time // 记录扫描开始时间
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FscanService) StartScan(ctx context.Context, req *pb.StartScanRequest) (*pb.StartScanResponse, error) {
|
func (s *FscanService) StartScan(ctx context.Context, req *pb.StartScanRequest) (*pb.StartScanResponse, error) {
|
||||||
if !atomic.CompareAndSwapInt32(&s.isScanning, 0, 1) {
|
if !atomic.CompareAndSwapInt32(&s.isScanning, 0, 1) {
|
||||||
return &pb.StartScanResponse{
|
return &pb.StartScanResponse{
|
||||||
TaskId: "",
|
TaskId: "current",
|
||||||
Message: "已有扫描任务正在运行,请稍后重试",
|
Message: "已有扫描任务正在运行,请稍后重试",
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
taskID := "uuid"
|
s.scanStartTime = time.Now() // 记录任务开始时间
|
||||||
|
|
||||||
go func(taskID string, req *pb.StartScanRequest) {
|
go func(req *pb.StartScanRequest) {
|
||||||
defer atomic.StoreInt32(&s.isScanning, 0)
|
defer atomic.StoreInt32(&s.isScanning, 0)
|
||||||
|
|
||||||
s.scanMutex.Lock()
|
s.scanMutex.Lock()
|
||||||
@ -43,69 +45,53 @@ func (s *FscanService) StartScan(ctx context.Context, req *pb.StartScanRequest)
|
|||||||
if err := Common.Parse(&info); err != nil {
|
if err := Common.Parse(&info); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//TODO: 结果保存需要在output模块中设计
|
if err := Common.CloseOutput(); err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("关闭输出系统失败: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
if err := Common.InitOutput(); err != nil {
|
if err := Common.InitOutput(); err != nil {
|
||||||
Common.LogError(fmt.Sprintf("初始化输出系统失败: %v", err))
|
Common.LogError(fmt.Sprintf("初始化输出系统失败: %v", err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
Core.Scan(info)
|
Core.Scan(info)
|
||||||
}(taskID, req)
|
|
||||||
|
Common.LogDebug("扫描任务完成")
|
||||||
|
}(req)
|
||||||
|
|
||||||
return &pb.StartScanResponse{
|
return &pb.StartScanResponse{
|
||||||
TaskId: taskID,
|
TaskId: "current",
|
||||||
Message: "扫描任务已启动",
|
Message: "成功启动扫描任务",
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetScanResults 用于获取指定任务 ID 的扫描结果。
|
|
||||||
// 参数:
|
|
||||||
// - ctx:请求上下文。
|
|
||||||
// - req:TaskResultsRequest,包含任务 ID。
|
|
||||||
// 返回值:
|
|
||||||
// - TaskResultsResponse:包含结果列表、任务状态等信息。
|
|
||||||
// - error:执行中出现的错误信息。
|
|
||||||
func (s *FscanService) GetScanResults(ctx context.Context, req *pb.TaskResultsRequest) (*pb.TaskResultsResponse, error) {
|
func (s *FscanService) GetScanResults(ctx context.Context, req *pb.TaskResultsRequest) (*pb.TaskResultsResponse, error) {
|
||||||
// TODO: 实现根据任务 ID 查询任务结果,可以从缓存、数据库或临时文件中获取。
|
results, err := Common.GetResults()
|
||||||
// 此处为模拟数据
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("读取结果失败: %w", err)
|
||||||
result := &pb.ScanResult{
|
|
||||||
Time: time.Now().Format(time.RFC3339),
|
|
||||||
Type: "port",
|
|
||||||
Target: "192.168.1.1:80",
|
|
||||||
Status: "open",
|
|
||||||
DetailsJson: `{"banner":"nginx"}`,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pbResults := make([]*pb.ScanResult, 0, len(results))
|
||||||
|
for _, r := range results {
|
||||||
|
detailsStruct, err := structpb.NewStruct(r.Details)
|
||||||
|
if err != nil {
|
||||||
|
Common.LogError(fmt.Sprintf("转换为 Struct 失败: %v", err))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pbResults = append(pbResults, &pb.ScanResult{
|
||||||
|
Time: r.Time.Format(time.RFC3339),
|
||||||
|
Type: string(r.Type),
|
||||||
|
Target: r.Target,
|
||||||
|
Status: r.Status,
|
||||||
|
DetailsJson: detailsStruct,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
finished := atomic.LoadInt32(&s.isScanning) == 0
|
||||||
return &pb.TaskResultsResponse{
|
return &pb.TaskResultsResponse{
|
||||||
TaskId: req.TaskId,
|
TaskId: req.Filter.TaskId,
|
||||||
Results: []*pb.ScanResult{result},
|
Results: pbResults,
|
||||||
Finished: true, // TODO: 判断任务是否真正完成
|
Finished: finished,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StreamScanResults 用于通过流式返回任务扫描结果,适合长时间扫描过程。
|
|
||||||
// 参数:
|
|
||||||
// - req:TaskResultsRequest,包含任务 ID。
|
|
||||||
// - stream:用于向客户端持续推送结果。
|
|
||||||
// 返回值:
|
|
||||||
// - error:执行中出现的错误信息。
|
|
||||||
func (s *FscanService) StreamScanResults(req *pb.TaskResultsRequest, stream pb.FscanService_StreamScanResultsServer) error {
|
|
||||||
// TODO: 根据任务 ID 逐步查询任务结果,并通过 stream.Send 发送给客户端。
|
|
||||||
// 可以监听任务进度,逐步推送最新结果。
|
|
||||||
|
|
||||||
for i := 0; i < 5; i++ {
|
|
||||||
result := &pb.ScanResult{
|
|
||||||
Time: time.Now().Format(time.RFC3339),
|
|
||||||
Type: "vuln",
|
|
||||||
Target: "192.168.1.1",
|
|
||||||
Status: "found",
|
|
||||||
DetailsJson: `{"vuln":"CVE-2021-12345"}`,
|
|
||||||
}
|
|
||||||
if err := stream.Send(result); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
time.Sleep(1 * time.Second) // 模拟异步推送过程
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user