WFN转换
本示例演示如何在CPE格式和Well-Formed Name (WFN)格式之间进行转换,以及如何使用WFN进行高效的处理和匹配操作。
概述
Well-Formed Name (WFN) 是CPE的内部标准表示格式,提供了一种规范化的方式来表示CPE组件,使匹配和比较操作更加高效和可靠。
完整示例
go
package main
import (
"fmt"
"log"
"github.com/scagogogo/cpe"
)
func main() {
fmt.Println("=== WFN转换示例 ===")
// 示例1:CPE到WFN转换
fmt.Println("\n1. CPE到WFN转换:")
cpeStrings := []string{
"cpe:2.3:a:microsoft:windows:10:*:*:*:*:*:*:*",
"cpe:2.3:a:apache:tomcat:9.0.0:*:*:*:*:*:*:*",
"cpe:/a:oracle:java:1.8.0_291",
"cpe:2.3:o:linux:kernel:5.4.0:*:*:*:*:*:*:*",
}
for i, cpeStr := range cpeStrings {
fmt.Printf("\n示例 %d: %s\n", i+1, cpeStr)
// 解析CPE
cpeObj, err := cpe.ParseCPE(cpeStr)
if err != nil {
log.Printf("解析CPE失败: %v", err)
continue
}
// 转换为WFN
wfn, err := cpe.CPEToWFN(cpeObj)
if err != nil {
log.Printf("转换为WFN失败: %v", err)
continue
}
fmt.Printf(" 原始CPE: %s\n", cpeStr)
fmt.Printf(" WFN格式: %s\n", wfn.String())
fmt.Printf(" 部件: %s\n", wfn.Part)
fmt.Printf(" 供应商: %s\n", wfn.Vendor)
fmt.Printf(" 产品: %s\n", wfn.Product)
fmt.Printf(" 版本: %s\n", wfn.Version)
}
// 示例2:WFN到CPE转换
fmt.Println("\n2. WFN到CPE转换:")
// 手动创建WFN
wfn := &cpe.WFN{
Part: "a",
Vendor: "adobe",
Product: "reader",
Version: "2021.001.20150",
Update: cpe.WFNAny,
Edition: cpe.WFNAny,
Language: cpe.WFNAny,
SoftwareEdition: cpe.WFNAny,
TargetSoftware: cpe.WFNAny,
TargetHardware: cpe.WFNAny,
Other: cpe.WFNAny,
}
fmt.Printf("WFN: %s\n", wfn.String())
// 转换为CPE 2.3
cpe23, err := cpe.WFNToCPE23(wfn)
if err != nil {
log.Printf("转换为CPE 2.3失败: %v", err)
} else {
fmt.Printf("CPE 2.3: %s\n", cpe23)
}
// 转换为CPE 2.2
cpe22, err := cpe.WFNToCPE22(wfn)
if err != nil {
log.Printf("转换为CPE 2.2失败: %v", err)
} else {
fmt.Printf("CPE 2.2: %s\n", cpe22)
}
// 示例3:WFN属性值
fmt.Println("\n3. WFN属性值:")
// 演示不同的WFN属性值
examples := []struct {
name string
value string
desc string
}{
{"ANY", cpe.WFNAny, "匹配任意值"},
{"NA", cpe.WFNNotApplicable, "不适用"},
{"字面值", "windows", "字面字符串值"},
{"转义值", cpe.QuoteWFNValue("special~chars"), "转义特殊字符"},
}
for _, example := range examples {
fmt.Printf(" %s: '%s' - %s\n", example.name, example.value, example.desc)
}
// 示例4:WFN匹配
fmt.Println("\n4. WFN匹配:")
// 创建源和目标WFN
sourceWFN := &cpe.WFN{
Part: "a",
Vendor: "microsoft",
Product: cpe.WFNAny, // 任意产品
Version: cpe.WFNAny, // 任意版本
}
targetWFNs := []*cpe.WFN{
{Part: "a", Vendor: "microsoft", Product: "windows", Version: "10"},
{Part: "a", Vendor: "microsoft", Product: "office", Version: "2019"},
{Part: "a", Vendor: "oracle", Product: "java", Version: "11"},
{Part: "o", Vendor: "microsoft", Product: "windows", Version: "10"},
}
fmt.Printf("源WFN: %s\n", sourceWFN.String())
fmt.Println("匹配目标:")
for i, targetWFN := range targetWFNs {
match := cpe.MatchWFN(sourceWFN, targetWFN)
status := "❌"
if match {
status = "✅"
}
fmt.Printf(" %s 目标 %d: %s\n", status, i+1, targetWFN.String())
}
// 示例5:WFN验证
fmt.Println("\n5. WFN验证:")
validationTests := []struct {
wfn *cpe.WFN
desc string
valid bool
}{
{
&cpe.WFN{Part: "a", Vendor: "microsoft", Product: "windows"},
"有效的应用程序WFN",
true,
},
{
&cpe.WFN{Part: "x", Vendor: "microsoft", Product: "windows"},
"无效的部件值",
false,
},
{
&cpe.WFN{Part: "a", Vendor: "", Product: "windows"},
"空供应商",
false,
},
{
&cpe.WFN{Part: "a", Vendor: "microsoft", Product: ""},
"空产品",
false,
},
}
for i, test := range validationTests {
err := cpe.ValidateWFN(test.wfn)
isValid := err == nil
status := "❌"
if isValid == test.valid {
status = "✅"
}
fmt.Printf(" %s 测试 %d: %s\n", status, i+1, test.desc)
fmt.Printf(" WFN: %s\n", test.wfn.String())
if err != nil {
fmt.Printf(" 错误: %v\n", err)
}
}
// 示例6:WFN规范化
fmt.Println("\n6. WFN规范化:")
unnormalizedWFN := &cpe.WFN{
Part: "A", // 应该是小写
Vendor: "Microsoft", // 应该是小写
Product: "Windows~10", // 特殊字符
Version: "10.0.19041.1234",
}
fmt.Printf("规范化前: %s\n", unnormalizedWFN.String())
normalizedWFN := cpe.NormalizeWFN(unnormalizedWFN)
fmt.Printf("规范化后: %s\n", normalizedWFN.String())
// 示例7:WFN比较
fmt.Println("\n7. WFN比较:")
wfn1 := &cpe.WFN{
Part: "a", Vendor: "apache", Product: "tomcat", Version: "9.0.0",
}
wfn2 := &cpe.WFN{
Part: "a", Vendor: "apache", Product: "tomcat", Version: "9.0.1",
}
wfn3 := &cpe.WFN{
Part: "a", Vendor: "apache", Product: "tomcat", Version: "9.0.0",
}
fmt.Printf("WFN1: %s\n", wfn1.String())
fmt.Printf("WFN2: %s\n", wfn2.String())
fmt.Printf("WFN3: %s\n", wfn3.String())
fmt.Printf("WFN1 == WFN2: %t\n", cpe.CompareWFN(wfn1, wfn2) == 0)
fmt.Printf("WFN1 == WFN3: %t\n", cpe.CompareWFN(wfn1, wfn3) == 0)
fmt.Printf("WFN1 < WFN2: %t\n", cpe.CompareWFN(wfn1, wfn2) < 0)
// 示例8:特殊字符处理
fmt.Println("\n8. 特殊字符处理:")
specialValues := []string{
"product~name",
"version*with?wildcards",
"name:with:colons",
"path\\with\\backslashes",
}
for _, value := range specialValues {
quoted := cpe.QuoteWFNValue(value)
unquoted := cpe.UnquoteWFNValue(quoted)
fmt.Printf(" 原始: %s\n", value)
fmt.Printf(" 转义: %s\n", quoted)
fmt.Printf(" 还原: %s\n", unquoted)
fmt.Printf(" 正确: %t\n\n", value == unquoted)
}
// 示例9:批量转换
fmt.Println("\n9. 批量转换:")
batchCPEs := []string{
"cpe:2.3:a:microsoft:windows:10:*:*:*:*:*:*:*",
"cpe:2.3:a:apache:tomcat:9.0.0:*:*:*:*:*:*:*",
"cpe:2.3:a:oracle:java:11.0.12:*:*:*:*:*:*:*",
"cpe:2.3:o:canonical:ubuntu:20.04:*:*:*:*:*:*:*",
}
fmt.Printf("批量转换 %d 个CPE:\n", len(batchCPEs))
wfnList := []*cpe.WFN{}
for i, cpeStr := range batchCPEs {
cpeObj, err := cpe.ParseCpe23(cpeStr)
if err != nil {
fmt.Printf(" ❌ %d. 解析失败: %s\n", i+1, cpeStr)
continue
}
wfn, err := cpe.CPEToWFN(cpeObj)
if err != nil {
fmt.Printf(" ❌ %d. 转换失败: %s\n", i+1, cpeStr)
continue
}
wfnList = append(wfnList, wfn)
fmt.Printf(" ✅ %d. %s %s %s\n", i+1, wfn.Vendor, wfn.Product, wfn.Version)
}
// 转换回CPE格式
fmt.Printf("\n转换回CPE 2.3格式:\n")
for i, wfn := range wfnList {
cpe23, err := cpe.WFNToCPE23(wfn)
if err != nil {
fmt.Printf(" ❌ %d. 转换失败\n", i+1)
} else {
fmt.Printf(" ✅ %d. %s\n", i+1, cpe23)
}
}
}
关键概念
1. WFN结构
WFN包含11个属性:
- part: 组件类型 (a, h, o)
- vendor: 供应商名称
- product: 产品名称
- version: 版本字符串
- update: 更新标识符
- edition: 版本信息
- language: 语言代码
- sw_edition: 软件版本
- target_sw: 目标软件
- target_hw: 目标硬件
- other: 其他信息
2. 特殊值
- ANY (*): 匹配任意值
- NA (-): 不适用/未定义
- 字面值: 精确字符串匹配
3. WFN优势
- 规范形式: 标准化表示
- 高效匹配: 优化的比较操作
- 验证: 内置验证规则
- 规范化: 一致的格式化
最佳实践
- 内部处理使用WFN: 将CPE字符串转换为WFN进行操作
- 验证WFN: 使用前始终验证WFN对象
- 规范化输入: 规范化WFN以确保一致的比较
- 处理特殊值: 正确处理ANY和NA值
- 转换回去: 将WFN转换回CPE格式进行输出