mirror of
https://github.com/shadow1ng/fscan.git
synced 2025-09-14 05:56:46 +08:00
refactor: 重构common包错误消息系统并优化常量管理
主要改进: - 将output和parsers包中的硬编码错误消息迁移到i18n国际化系统 - 修复constants.go中未引用常量的使用问题 - 消除所有硬编码字符串、魔术数字和协议标识符 - 清理死代码常量MinIPv4OctetValue 具体变更: * output包: 删除19个硬编码错误消息,新增13个i18n消息键 * parsers包: 删除24个硬编码错误模板,新增22个i18n消息键 * 修复8个未引用的Default常量在对应默认选项函数中的使用 * 替换11处网络协议相关的硬编码值为常量引用 * 更新6个错误类型常量和验证逻辑的硬编码使用 * 修复2处IPv4八位组计数的硬编码为常量引用 提升效果: - 支持中英文错误消息国际化切换 - 统一常量管理,提高代码可维护性 - 消除代码重复,符合DRY原则 - 清理死代码,优化代码质量 涉及文件: 11个文件,新增210行,删除103行
This commit is contained in:
parent
84b0bb1e28
commit
20cb3356de
@ -170,6 +170,58 @@ var coreMessages = map[string]map[string]string{
|
||||
LangZH: "关闭输出系统失败: %v",
|
||||
LangEN: "Failed to close output system: %v",
|
||||
},
|
||||
"output_config_nil": {
|
||||
LangZH: "配置不能为空",
|
||||
LangEN: "Configuration cannot be nil",
|
||||
},
|
||||
"output_unsupported_format": {
|
||||
LangZH: "不支持的输出格式: %s",
|
||||
LangEN: "Unsupported output format: %s",
|
||||
},
|
||||
"output_writer_init_failed": {
|
||||
LangZH: "初始化写入器失败: %v",
|
||||
LangEN: "Failed to initialize writer: %v",
|
||||
},
|
||||
"output_writer_closed": {
|
||||
LangZH: "写入器已关闭",
|
||||
LangEN: "Writer is closed",
|
||||
},
|
||||
"output_manager_not_init": {
|
||||
LangZH: "输出管理器未初始化",
|
||||
LangEN: "Output manager not initialized",
|
||||
},
|
||||
"output_manager_closed": {
|
||||
LangZH: "输出管理器已关闭",
|
||||
LangEN: "Output manager is closed",
|
||||
},
|
||||
"output_write_failed": {
|
||||
LangZH: "写入结果失败: %v",
|
||||
LangEN: "Failed to write result: %v",
|
||||
},
|
||||
"output_flush_failed": {
|
||||
LangZH: "刷新写入器失败: %v",
|
||||
LangEN: "Failed to flush writer: %v",
|
||||
},
|
||||
"output_create_file_failed": {
|
||||
LangZH: "创建%s文件失败: %v",
|
||||
LangEN: "Failed to create %s file: %v",
|
||||
},
|
||||
"output_write_header_failed": {
|
||||
LangZH: "写入CSV头部失败: %v",
|
||||
LangEN: "Failed to write CSV header: %v",
|
||||
},
|
||||
"output_open_file_failed": {
|
||||
LangZH: "打开CSV文件失败: %v",
|
||||
LangEN: "Failed to open CSV file: %v",
|
||||
},
|
||||
"output_read_file_failed": {
|
||||
LangZH: "读取CSV文件失败: %v",
|
||||
LangEN: "Failed to read CSV file: %v",
|
||||
},
|
||||
"output_parse_time_failed": {
|
||||
LangZH: "无法解析时间: %s",
|
||||
LangEN: "Failed to parse time: %s",
|
||||
},
|
||||
|
||||
// ========================= 代理系统消息 =========================
|
||||
"proxy_init_start": {
|
||||
@ -410,6 +462,94 @@ var coreMessages = map[string]map[string]string{
|
||||
LangZH: "验证输入为空",
|
||||
LangEN: "Validation input is empty",
|
||||
},
|
||||
"parser_empty_input": {
|
||||
LangZH: "输入参数为空",
|
||||
LangEN: "Input parameters are empty",
|
||||
},
|
||||
"parser_file_empty": {
|
||||
LangZH: "文件名为空",
|
||||
LangEN: "File name is empty",
|
||||
},
|
||||
"parser_file_too_big": {
|
||||
LangZH: "文件过大: %d bytes, 最大限制: %d bytes",
|
||||
LangEN: "File too large: %d bytes, max limit: %d bytes",
|
||||
},
|
||||
"parser_cannot_open_file": {
|
||||
LangZH: "无法打开文件",
|
||||
LangEN: "Cannot open file",
|
||||
},
|
||||
"parser_file_not_exists": {
|
||||
LangZH: "文件不存在或无法访问",
|
||||
LangEN: "File does not exist or cannot be accessed",
|
||||
},
|
||||
"parser_file_read_timeout": {
|
||||
LangZH: "文件读取超时",
|
||||
LangEN: "File read timeout",
|
||||
},
|
||||
"parser_file_scan_failed": {
|
||||
LangZH: "文件扫描失败",
|
||||
LangEN: "File scan failed",
|
||||
},
|
||||
"parser_username_too_long": {
|
||||
LangZH: "用户名过长: %d字符,最大允许: %d",
|
||||
LangEN: "Username too long: %d characters, max allowed: %d",
|
||||
},
|
||||
"parser_username_invalid_chars": {
|
||||
LangZH: "用户名包含非法字符",
|
||||
LangEN: "Username contains invalid characters",
|
||||
},
|
||||
"parser_password_empty": {
|
||||
LangZH: "不允许空密码",
|
||||
LangEN: "Empty passwords not allowed",
|
||||
},
|
||||
"parser_password_too_long": {
|
||||
LangZH: "密码过长: %d字符,最大允许: %d",
|
||||
LangEN: "Password too long: %d characters, max allowed: %d",
|
||||
},
|
||||
"parser_hash_empty": {
|
||||
LangZH: "哈希值为空",
|
||||
LangEN: "Hash value is empty",
|
||||
},
|
||||
"parser_hash_invalid_format": {
|
||||
LangZH: "哈希值格式无效,需要32位十六进制字符",
|
||||
LangEN: "Invalid hash format, requires 32-character hexadecimal",
|
||||
},
|
||||
"parser_proxy_url_invalid": {
|
||||
LangZH: "代理URL格式无效: %v",
|
||||
LangEN: "Invalid proxy URL format: %v",
|
||||
},
|
||||
"parser_proxy_protocol_unsupported": {
|
||||
LangZH: "不支持的代理协议: %s",
|
||||
LangEN: "Unsupported proxy protocol: %s",
|
||||
},
|
||||
"parser_proxy_host_empty": {
|
||||
LangZH: "代理主机名为空",
|
||||
LangEN: "Proxy hostname is empty",
|
||||
},
|
||||
"parser_proxy_port_invalid": {
|
||||
LangZH: "代理端口号无效: %s",
|
||||
LangEN: "Invalid proxy port: %s",
|
||||
},
|
||||
"parser_proxy_port_out_of_range": {
|
||||
LangZH: "代理端口号超出范围: %d",
|
||||
LangEN: "Proxy port out of range: %d",
|
||||
},
|
||||
"parser_proxy_insecure": {
|
||||
LangZH: "不允许使用不安全的HTTP代理",
|
||||
LangEN: "Insecure HTTP proxy not allowed",
|
||||
},
|
||||
"parser_user_agent_too_long": {
|
||||
LangZH: "用户代理字符串过长",
|
||||
LangEN: "User agent string too long",
|
||||
},
|
||||
"parser_user_agent_invalid_chars": {
|
||||
LangZH: "用户代理包含非法字符",
|
||||
LangEN: "User agent contains invalid characters",
|
||||
},
|
||||
"parser_cookie_too_long": {
|
||||
LangZH: "Cookie字符串过长",
|
||||
LangEN: "Cookie string too long",
|
||||
},
|
||||
"parser_error_count_limit": {
|
||||
LangZH: "错误数量过多,仅显示前%d个",
|
||||
LangEN: "Too many errors, showing only first %d",
|
||||
|
@ -6,6 +6,8 @@ import (
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/shadow1ng/fscan/common/i18n"
|
||||
)
|
||||
|
||||
// Manager 输出管理器
|
||||
@ -26,7 +28,7 @@ type Manager struct {
|
||||
// NewManager 创建新的输出管理器
|
||||
func NewManager(config *ManagerConfig) (*Manager, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf(ErrConfigNil)
|
||||
return nil, fmt.Errorf(i18n.GetText("output_config_nil"))
|
||||
}
|
||||
|
||||
// 验证输出格式
|
||||
@ -73,7 +75,7 @@ func validateFormat(format OutputFormat) error {
|
||||
case FormatTXT, FormatJSON, FormatCSV:
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf(ErrUnsupportedFormat, format)
|
||||
return fmt.Errorf(i18n.GetText("output_unsupported_format"), format)
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,11 +98,11 @@ func (m *Manager) initializeWriter() error {
|
||||
case FormatCSV:
|
||||
writer, err = NewCSVWriter(m.config.OutputPath)
|
||||
default:
|
||||
return fmt.Errorf(ErrUnsupportedFormat, m.config.Format)
|
||||
return fmt.Errorf(i18n.GetText("output_unsupported_format"), m.config.Format)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf(ErrWriterInitFailed, err)
|
||||
return fmt.Errorf(i18n.GetText("output_writer_init_failed"), err)
|
||||
}
|
||||
|
||||
m.writer = writer
|
||||
@ -138,11 +140,11 @@ func (m *Manager) SaveResult(result *ScanResult) error {
|
||||
defer m.mu.RUnlock()
|
||||
|
||||
if !m.initialized {
|
||||
return fmt.Errorf(ErrManagerNotInit)
|
||||
return fmt.Errorf(i18n.GetText("output_manager_not_init"))
|
||||
}
|
||||
|
||||
if m.closed {
|
||||
return fmt.Errorf(ErrManagerClosed)
|
||||
return fmt.Errorf(i18n.GetText("output_manager_closed"))
|
||||
}
|
||||
|
||||
// 更新统计信息
|
||||
@ -188,13 +190,13 @@ func (m *Manager) flushBufferUnsafe() error {
|
||||
// 批量写入
|
||||
for _, result := range m.buffer {
|
||||
if err := m.writer.Write(result); err != nil {
|
||||
return fmt.Errorf(ErrWriteFailed, err)
|
||||
return fmt.Errorf(i18n.GetText("output_write_failed"), err)
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新写入器
|
||||
if err := m.writer.Flush(); err != nil {
|
||||
return fmt.Errorf(ErrFlushFailed, err)
|
||||
return fmt.Errorf(i18n.GetText("output_flush_failed"), err)
|
||||
}
|
||||
|
||||
// 清空缓冲区
|
||||
|
@ -8,6 +8,8 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/shadow1ng/fscan/common/i18n"
|
||||
)
|
||||
|
||||
// TXTWriter 文本格式写入器
|
||||
@ -21,7 +23,7 @@ type TXTWriter struct {
|
||||
func NewTXTWriter(filePath string) (*TXTWriter, error) {
|
||||
file, err := os.OpenFile(filePath, DefaultFileFlags, DefaultFilePermissions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(ErrCreateFileFailed, "文本", err)
|
||||
return nil, fmt.Errorf(i18n.GetText("output_create_file_failed"), "文本", err)
|
||||
}
|
||||
|
||||
return &TXTWriter{
|
||||
@ -40,7 +42,7 @@ func (w *TXTWriter) Write(result *ScanResult) error {
|
||||
defer w.mu.Unlock()
|
||||
|
||||
if w.closed {
|
||||
return fmt.Errorf(ErrWriterClosed)
|
||||
return fmt.Errorf(i18n.GetText("output_writer_closed"))
|
||||
}
|
||||
|
||||
// 格式化 Details 为键值对字符串
|
||||
@ -111,7 +113,7 @@ type JSONWriter struct {
|
||||
func NewJSONWriter(filePath string) (*JSONWriter, error) {
|
||||
file, err := os.OpenFile(filePath, DefaultFileFlags, DefaultFilePermissions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(ErrCreateFileFailed, "JSON", err)
|
||||
return nil, fmt.Errorf(i18n.GetText("output_create_file_failed"), "JSON", err)
|
||||
}
|
||||
|
||||
encoder := json.NewEncoder(file)
|
||||
@ -134,7 +136,7 @@ func (w *JSONWriter) Write(result *ScanResult) error {
|
||||
defer w.mu.Unlock()
|
||||
|
||||
if w.closed {
|
||||
return fmt.Errorf(ErrWriterClosed)
|
||||
return fmt.Errorf(i18n.GetText("output_writer_closed"))
|
||||
}
|
||||
|
||||
return w.encoder.Encode(result)
|
||||
@ -183,7 +185,7 @@ type CSVWriter struct {
|
||||
func NewCSVWriter(filePath string) (*CSVWriter, error) {
|
||||
file, err := os.OpenFile(filePath, DefaultFileFlags, DefaultFilePermissions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(ErrCreateFileFailed, "CSV", err)
|
||||
return nil, fmt.Errorf(i18n.GetText("output_create_file_failed"), "CSV", err)
|
||||
}
|
||||
|
||||
csvWriter := csv.NewWriter(file)
|
||||
@ -206,7 +208,7 @@ func (w *CSVWriter) WriteHeader() error {
|
||||
headers := CSVHeaders
|
||||
err := w.csvWriter.Write(headers)
|
||||
if err != nil {
|
||||
return fmt.Errorf(ErrWriteHeaderFailed, err)
|
||||
return fmt.Errorf(i18n.GetText("output_write_header_failed"), err)
|
||||
}
|
||||
|
||||
w.csvWriter.Flush()
|
||||
@ -220,7 +222,7 @@ func (w *CSVWriter) Write(result *ScanResult) error {
|
||||
defer w.mu.Unlock()
|
||||
|
||||
if w.closed {
|
||||
return fmt.Errorf(ErrWriterClosed)
|
||||
return fmt.Errorf(i18n.GetText("output_writer_closed"))
|
||||
}
|
||||
|
||||
// 确保头部已写入
|
||||
@ -262,7 +264,7 @@ func (w *CSVWriter) writeHeaderUnsafe() error {
|
||||
headers := CSVHeaders
|
||||
err := w.csvWriter.Write(headers)
|
||||
if err != nil {
|
||||
return fmt.Errorf(ErrWriteHeaderFailed, err)
|
||||
return fmt.Errorf(i18n.GetText("output_write_header_failed"), err)
|
||||
}
|
||||
|
||||
w.csvWriter.Flush()
|
||||
@ -333,14 +335,14 @@ func (r *CSVReader) ReadWithFilter(filter *ResultFilter) ([]*ScanResult, error)
|
||||
|
||||
file, err := os.Open(r.filePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(ErrOpenFileFailed, err)
|
||||
return nil, fmt.Errorf(i18n.GetText("output_open_file_failed"), err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
reader := csv.NewReader(file)
|
||||
records, err := reader.ReadAll()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(ErrReadFileFailed, err)
|
||||
return nil, fmt.Errorf(i18n.GetText("output_read_file_failed"), err)
|
||||
}
|
||||
|
||||
var results []*ScanResult
|
||||
@ -453,5 +455,5 @@ func parseTime(timeStr string) (time.Time, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return time.Time{}, fmt.Errorf(ErrParseTimeFailed, timeStr)
|
||||
return time.Time{}, fmt.Errorf(i18n.GetText("output_parse_time_failed"), timeStr)
|
||||
}
|
@ -113,25 +113,6 @@ const (
|
||||
TxtKeyValueFormat = "%s=%v" // 键值对格式
|
||||
)
|
||||
|
||||
// =============================================================================
|
||||
// 错误消息常量
|
||||
// =============================================================================
|
||||
|
||||
const (
|
||||
ErrConfigNil = "配置不能为空"
|
||||
ErrUnsupportedFormat = "不支持的输出格式: %s"
|
||||
ErrWriterInitFailed = "初始化写入器失败: %v"
|
||||
ErrWriterClosed = "写入器已关闭"
|
||||
ErrManagerNotInit = "输出管理器未初始化"
|
||||
ErrManagerClosed = "输出管理器已关闭"
|
||||
ErrWriteFailed = "写入结果失败: %v"
|
||||
ErrFlushFailed = "刷新写入器失败: %v"
|
||||
ErrCreateFileFailed = "创建%s文件失败: %v"
|
||||
ErrWriteHeaderFailed = "写入CSV头部失败: %v"
|
||||
ErrOpenFileFailed = "打开CSV文件失败: %v"
|
||||
ErrReadFileFailed = "读取CSV文件失败: %v"
|
||||
ErrParseTimeFailed = "无法解析时间: %s"
|
||||
)
|
||||
|
||||
// =============================================================================
|
||||
// CSV相关常量
|
||||
|
@ -7,6 +7,8 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/shadow1ng/fscan/common/i18n"
|
||||
)
|
||||
|
||||
// CredentialParser 凭据解析器
|
||||
@ -288,12 +290,12 @@ func (cp *CredentialParser) validateUsername(username string) (string, bool, err
|
||||
}
|
||||
|
||||
if len(username) > cp.options.MaxUsernameLength {
|
||||
return "", false, fmt.Errorf(ErrUsernameTooLongMsg, len(username), cp.options.MaxUsernameLength)
|
||||
return "", false, fmt.Errorf(i18n.GetText("parser_username_too_long"), len(username), cp.options.MaxUsernameLength)
|
||||
}
|
||||
|
||||
// 检查特殊字符
|
||||
if strings.ContainsAny(username, InvalidUsernameChars) {
|
||||
return "", false, fmt.Errorf("%s", ErrUsernameInvalidCharsMsg)
|
||||
return "", false, fmt.Errorf("%s", i18n.GetText("parser_username_invalid_chars"))
|
||||
}
|
||||
|
||||
return username, true, nil
|
||||
@ -302,11 +304,11 @@ func (cp *CredentialParser) validateUsername(username string) (string, bool, err
|
||||
// validatePassword 验证密码
|
||||
func (cp *CredentialParser) validatePassword(password string) (string, bool, error) {
|
||||
if len(password) == 0 && !cp.options.AllowEmptyPasswords {
|
||||
return "", false, fmt.Errorf("%s", ErrPasswordEmptyMsg)
|
||||
return "", false, fmt.Errorf("%s", i18n.GetText("parser_password_empty"))
|
||||
}
|
||||
|
||||
if len(password) > cp.options.MaxPasswordLength {
|
||||
return "", false, fmt.Errorf(ErrPasswordTooLongMsg, len(password), cp.options.MaxPasswordLength)
|
||||
return "", false, fmt.Errorf(i18n.GetText("parser_password_too_long"), len(password), cp.options.MaxPasswordLength)
|
||||
}
|
||||
|
||||
return password, true, nil
|
||||
@ -320,11 +322,11 @@ func (cp *CredentialParser) validateHash(hash string) (bool, error) {
|
||||
|
||||
hash = strings.TrimSpace(hash)
|
||||
if len(hash) == 0 {
|
||||
return false, fmt.Errorf("%s", ErrHashEmptyMsg)
|
||||
return false, fmt.Errorf("%s", i18n.GetText("parser_hash_empty"))
|
||||
}
|
||||
|
||||
if !cp.hashRegex.MatchString(hash) {
|
||||
return false, fmt.Errorf("%s", ErrHashInvalidFormatMsg)
|
||||
return false, fmt.Errorf("%s", i18n.GetText("parser_hash_invalid_format"))
|
||||
}
|
||||
|
||||
return true, nil
|
||||
|
@ -8,6 +8,8 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/shadow1ng/fscan/common/i18n"
|
||||
)
|
||||
|
||||
// FileReader 高性能文件读取器
|
||||
@ -62,14 +64,14 @@ type FileReaderOptions struct {
|
||||
// DefaultFileReaderOptions 默认文件读取器选项
|
||||
func DefaultFileReaderOptions() *FileReaderOptions {
|
||||
return &FileReaderOptions{
|
||||
MaxCacheSize: 10,
|
||||
EnableCache: true,
|
||||
MaxFileSize: 50 * 1024 * 1024, // 50MB
|
||||
Timeout: 30 * time.Second,
|
||||
EnableValidation: true,
|
||||
TrimSpace: true,
|
||||
SkipEmpty: true,
|
||||
SkipComments: true,
|
||||
MaxCacheSize: DefaultMaxCacheSize,
|
||||
EnableCache: DefaultEnableCache,
|
||||
MaxFileSize: DefaultFileReaderMaxFileSize,
|
||||
Timeout: DefaultFileReaderTimeout,
|
||||
EnableValidation: DefaultFileReaderEnableValidation,
|
||||
TrimSpace: DefaultTrimSpace,
|
||||
SkipEmpty: DefaultSkipEmpty,
|
||||
SkipComments: DefaultSkipComments,
|
||||
}
|
||||
}
|
||||
|
||||
@ -118,7 +120,7 @@ func (fr *FileReader) ReadFile(filename string, options ...*FileReaderOptions) (
|
||||
case err := <-errorChan:
|
||||
return nil, err
|
||||
case <-ctx.Done():
|
||||
return nil, NewParseError("TIMEOUT", "文件读取超时", filename, 0, ctx.Err())
|
||||
return nil, NewParseError(ErrorTypeTimeout, "文件读取超时", filename, 0, ctx.Err())
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,7 +182,7 @@ func (fr *FileReader) readFileSync(filename string, options *FileReaderOptions)
|
||||
|
||||
// 检查扫描错误
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, NewParseError(ErrorTypeReadError, ErrFileScanFailedMsg, filename, lineNum, err)
|
||||
return nil, NewParseError(ErrorTypeReadError, i18n.GetText("parser_file_scan_failed"), filename, lineNum, err)
|
||||
}
|
||||
|
||||
// 更新统计信息
|
||||
|
@ -29,11 +29,11 @@ type NetworkParserOptions struct {
|
||||
// DefaultNetworkParserOptions 默认网络解析器选项
|
||||
func DefaultNetworkParserOptions() *NetworkParserOptions {
|
||||
return &NetworkParserOptions{
|
||||
ValidateProxies: true,
|
||||
AllowInsecure: false,
|
||||
DefaultTimeout: 30 * time.Second,
|
||||
DefaultWebTimeout: 10 * time.Second,
|
||||
DefaultUserAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36",
|
||||
ValidateProxies: DefaultValidateProxies,
|
||||
AllowInsecure: DefaultAllowInsecure,
|
||||
DefaultTimeout: DefaultNetworkTimeout,
|
||||
DefaultWebTimeout: DefaultWebTimeout,
|
||||
DefaultUserAgent: DefaultUserAgent,
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,7 +147,7 @@ func (np *NetworkParser) parseHttpProxy(proxyStr string) (string, []error, []str
|
||||
// 验证代理URL
|
||||
if np.options.ValidateProxies {
|
||||
if err := np.validateProxyURL(normalizedProxy); err != nil {
|
||||
errors = append(errors, NewParseError("PROXY_ERROR", err.Error(), "http_proxy", 0, err))
|
||||
errors = append(errors, NewParseError(ErrorTypeProxyError, err.Error(), "http_proxy", 0, err))
|
||||
return "", errors, warnings
|
||||
}
|
||||
}
|
||||
@ -170,7 +170,7 @@ func (np *NetworkParser) parseSocks5Proxy(proxyStr string) (string, []error, []s
|
||||
// 验证代理URL
|
||||
if np.options.ValidateProxies {
|
||||
if err := np.validateProxyURL(normalizedProxy); err != nil {
|
||||
errors = append(errors, NewParseError("PROXY_ERROR", err.Error(), "socks5_proxy", 0, err))
|
||||
errors = append(errors, NewParseError(ErrorTypeProxyError, err.Error(), "socks5_proxy", 0, err))
|
||||
return "", errors, warnings
|
||||
}
|
||||
}
|
||||
@ -224,14 +224,14 @@ func (np *NetworkParser) parseUserAgent(userAgent string) (string, []error, []st
|
||||
}
|
||||
|
||||
// 基本格式验证
|
||||
if len(userAgent) > 512 {
|
||||
errors = append(errors, NewParseError("USERAGENT_ERROR", "用户代理字符串过长", "user_agent", 0, nil))
|
||||
if len(userAgent) > MaxUserAgentLength {
|
||||
errors = append(errors, NewParseError(ErrorTypeUserAgentError, "用户代理字符串过长", "user_agent", 0, nil))
|
||||
return "", errors, warnings
|
||||
}
|
||||
|
||||
// 检查是否包含特殊字符
|
||||
if strings.ContainsAny(userAgent, "\r\n\t") {
|
||||
errors = append(errors, NewParseError("USERAGENT_ERROR", "用户代理包含非法字符", "user_agent", 0, nil))
|
||||
if strings.ContainsAny(userAgent, InvalidUserAgentChars) {
|
||||
errors = append(errors, NewParseError(ErrorTypeUserAgentError, "用户代理包含非法字符", "user_agent", 0, nil))
|
||||
return "", errors, warnings
|
||||
}
|
||||
|
||||
@ -253,8 +253,8 @@ func (np *NetworkParser) parseCookie(cookie string) (string, []error, []string)
|
||||
}
|
||||
|
||||
// 基本格式验证
|
||||
if len(cookie) > 4096 { // HTTP Cookie长度限制
|
||||
errors = append(errors, NewParseError("COOKIE_ERROR", "Cookie字符串过长", "cookie", 0, nil))
|
||||
if len(cookie) > MaxCookieLength { // HTTP Cookie长度限制
|
||||
errors = append(errors, NewParseError(ErrorTypeCookieError, "Cookie字符串过长", "cookie", 0, nil))
|
||||
return "", errors, warnings
|
||||
}
|
||||
|
||||
@ -275,11 +275,11 @@ func (np *NetworkParser) normalizeHttpProxy(proxy string) string {
|
||||
return ProxyShortcutSOCKS5
|
||||
default:
|
||||
// 如果没有协议前缀,默认使用HTTP
|
||||
if !strings.Contains(proxy, "://") {
|
||||
if !strings.Contains(proxy, ProtocolPrefix) {
|
||||
if strings.Contains(proxy, ":") {
|
||||
return "http://" + proxy
|
||||
return HTTPPrefix + proxy
|
||||
} else {
|
||||
return "http://127.0.0.1:" + proxy
|
||||
return HTTPPrefix + "127.0.0.1:" + proxy
|
||||
}
|
||||
}
|
||||
return proxy
|
||||
@ -288,12 +288,12 @@ func (np *NetworkParser) normalizeHttpProxy(proxy string) string {
|
||||
|
||||
// normalizeSocks5Proxy 规范化Socks5代理URL
|
||||
func (np *NetworkParser) normalizeSocks5Proxy(proxy string) string {
|
||||
// 如果没有协议前缀,添加socks5://
|
||||
if !strings.HasPrefix(proxy, "socks5://") {
|
||||
// 如果没有协议前缀,添加SOCKS5协议
|
||||
if !strings.HasPrefix(proxy, SOCKS5Prefix) {
|
||||
if strings.Contains(proxy, ":") {
|
||||
return "socks5://" + proxy
|
||||
return SOCKS5Prefix + proxy
|
||||
} else {
|
||||
return "socks5://127.0.0.1:" + proxy
|
||||
return SOCKS5Prefix + "127.0.0.1:" + proxy
|
||||
}
|
||||
}
|
||||
return proxy
|
||||
@ -312,7 +312,7 @@ func (np *NetworkParser) validateProxyURL(proxyURL string) error {
|
||||
|
||||
// 检查协议
|
||||
switch parsedURL.Scheme {
|
||||
case "http", "https", "socks5":
|
||||
case ProtocolHTTP, ProtocolHTTPS, ProtocolSOCKS5:
|
||||
// 支持的协议
|
||||
default:
|
||||
return fmt.Errorf("不支持的代理协议: %s", parsedURL.Scheme)
|
||||
@ -336,7 +336,7 @@ func (np *NetworkParser) validateProxyURL(proxyURL string) error {
|
||||
}
|
||||
|
||||
// 安全检查
|
||||
if !np.options.AllowInsecure && parsedURL.Scheme == "http" {
|
||||
if !np.options.AllowInsecure && parsedURL.Scheme == ProtocolHTTP {
|
||||
return fmt.Errorf("不允许使用不安全的HTTP代理")
|
||||
}
|
||||
|
||||
|
@ -230,7 +230,7 @@ func parseShortIPRange(startIPStr, endSuffix string) ([]string, error) {
|
||||
|
||||
var hosts []string
|
||||
startIPParts := strings.Split(startIPStr, ".")
|
||||
if len(startIPParts) != 4 {
|
||||
if len(startIPParts) != IPv4OctetCount {
|
||||
return nil, fmt.Errorf("无效的IP格式: %s", startIPStr)
|
||||
}
|
||||
|
||||
|
@ -541,7 +541,7 @@ func (tp *TargetParser) parseShortIPRange(startIPStr, endSuffix string) ([]strin
|
||||
|
||||
// 分解起始IP
|
||||
ipParts := strings.Split(startIPStr, ".")
|
||||
if len(ipParts) != 4 {
|
||||
if len(ipParts) != IPv4OctetCount {
|
||||
return nil, fmt.Errorf("无效的IP地址格式: %s", startIPStr)
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/shadow1ng/fscan/common/i18n"
|
||||
)
|
||||
|
||||
// ParsedConfig 解析后的完整配置
|
||||
@ -87,7 +89,7 @@ type ParseResult struct {
|
||||
|
||||
// 预定义错误类型
|
||||
var (
|
||||
ErrEmptyInput = errors.New(ErrEmptyInputMsg)
|
||||
ErrEmptyInput = errors.New(i18n.GetText("parser_empty_input"))
|
||||
)
|
||||
|
||||
// ParserOptions 解析器选项
|
||||
|
@ -145,7 +145,6 @@ const (
|
||||
|
||||
// IP地址限制
|
||||
MaxIPv4OctetValue = 255
|
||||
MinIPv4OctetValue = 0
|
||||
IPv4OctetCount = 4
|
||||
MaxDomainLength = 253
|
||||
|
||||
@ -254,29 +253,6 @@ const (
|
||||
ErrorTypePortError = "PORT_ERROR"
|
||||
ErrorTypeExcludePortError = "EXCLUDE_PORT_ERROR"
|
||||
|
||||
// 错误消息模板
|
||||
ErrEmptyInputMsg = "输入参数为空"
|
||||
ErrFileEmptyMsg = "文件名为空"
|
||||
ErrFileTooBigMsg = "文件过大: %d bytes, 最大限制: %d bytes"
|
||||
ErrCannotOpenFileMsg = "无法打开文件"
|
||||
ErrFileNotExistsMsg = "文件不存在或无法访问"
|
||||
ErrFileReadTimeoutMsg = "文件读取超时"
|
||||
ErrFileScanFailedMsg = "文件扫描失败"
|
||||
ErrUsernameTooLongMsg = "用户名过长: %d字符,最大允许: %d"
|
||||
ErrUsernameInvalidCharsMsg = "用户名包含非法字符"
|
||||
ErrPasswordEmptyMsg = "不允许空密码"
|
||||
ErrPasswordTooLongMsg = "密码过长: %d字符,最大允许: %d"
|
||||
ErrHashEmptyMsg = "哈希值为空"
|
||||
ErrHashInvalidFormatMsg = "哈希值格式无效,需要32位十六进制字符"
|
||||
ErrProxyURLInvalidMsg = "代理URL格式无效: %v"
|
||||
ErrProxyProtocolUnsupportedMsg = "不支持的代理协议: %s"
|
||||
ErrProxyHostEmptyMsg = "代理主机名为空"
|
||||
ErrProxyPortInvalidMsg = "代理端口号无效: %s"
|
||||
ErrProxyPortOutOfRangeMsg = "代理端口号超出范围: %d"
|
||||
ErrProxyInsecureMsg = "不允许使用不安全的HTTP代理"
|
||||
ErrUserAgentTooLongMsg = "用户代理字符串过长"
|
||||
ErrUserAgentInvalidCharsMsg = "用户代理包含非法字符"
|
||||
ErrCookieTooLongMsg = "Cookie字符串过长"
|
||||
)
|
||||
|
||||
// =============================================================================
|
||||
|
Loading…
Reference in New Issue
Block a user