fix: 全面代码审查修复 — 安全/类型/持久化/代码质量 (28项)
🔴 CRITICAL (1): - tauri.conf.json: CSP 从 null 改为最小权限策略 🟠 HIGH (6): - 新建 capabilities/default.json: Tauri v2 权限约束(store/dialog/clipboard) - cli: 路径遍历防护 — 拒绝含 ParentDir 组件的输出路径 - HistoryList: 删除/清空同步持久化到 store,历史点击用 formData 回填 - ExportPanel: 移除 console.warn,getCurrentText any→QrState - useQrEncode: WiFi 密码在历史中脱敏显示(P:***),Store 实例缓存 🟡 MEDIUM (10): - mode.rs: Kanji fallback 从 UTF-8 字节改为 13-bit 零值占位(段内模式一致) - mode.rs: Shift JIS 第二字节跳过 0x7F 空洞,修正行内索引 - mode.rs: encode_numeric/alphanumeric 添加 debug_assert! 前置条件 - mask.rs: best_matrix.unwrap()→expect() 附错误信息 - version.rs: ec_info 仅返回 count>0 的 BlockInfo,EcInfo/BlockInfo 加 Debug+Clone - types/index.ts: HistoryEntry.mode string→ModeType,新增 formData 字段 - qrContext.tsx: 使用缓存 Store 加载历史 🟢 LOW (11): - cargo fmt 全部文件 - svg.rs: String::new()→with_capacity() 预分配 - patterns.rs: encode_format_info 拆分为两行提高可读性 - png.rs: 提取 fill_module() 辅助函数降低嵌套 - ErrorBoundary: 添加 componentDidCatch 错误日志入口 - QrPreview: dangerouslySetInnerHTML→<img>+data URL(安全),loading 状态指示 - galois.rs/version.rs: 5 处 #[allow(clippy::indexing_slicing)]+安全文档 - 新建 utils/qrText.ts: 集中管理 6 种模式的文本构造,消除 ExportPanel/mode 间重复 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -44,18 +44,45 @@ fn test_dump_format_info() {
|
||||
|
||||
// 格式信息位置 (按标准顺序 bit14→bit0)
|
||||
let coords = [
|
||||
(0, 8), (1, 8), (2, 8), (3, 8), (4, 8), (5, 8), (7, 8), (8, 8),
|
||||
(8, 7), (8, 5), (8, 4), (8, 3), (8, 2), (8, 1), (8, 0),
|
||||
(0, 8),
|
||||
(1, 8),
|
||||
(2, 8),
|
||||
(3, 8),
|
||||
(4, 8),
|
||||
(5, 8),
|
||||
(7, 8),
|
||||
(8, 8),
|
||||
(8, 7),
|
||||
(8, 5),
|
||||
(8, 4),
|
||||
(8, 3),
|
||||
(8, 2),
|
||||
(8, 1),
|
||||
(8, 0),
|
||||
];
|
||||
|
||||
let mut fmt_bits = 0u16;
|
||||
for (i, &(x, y)) in coords.iter().enumerate() {
|
||||
let bit = if m[y as usize][x as usize] { 1u16 } else { 0u16 };
|
||||
let bit = if m[y as usize][x as usize] {
|
||||
1u16
|
||||
} else {
|
||||
0u16
|
||||
};
|
||||
fmt_bits = (fmt_bits << 1) | bit;
|
||||
print!("{} ", if m[y as usize][x as usize] { '█' } else { '_' });
|
||||
print!(
|
||||
"{} ",
|
||||
if m[y as usize][x as usize] {
|
||||
'█'
|
||||
} else {
|
||||
'_'
|
||||
}
|
||||
);
|
||||
}
|
||||
println!();
|
||||
println!("读取的格式信息 (原始, 含 XOR mask 0x5412): 0x{:04X}", fmt_bits);
|
||||
println!(
|
||||
"读取的格式信息 (原始, 含 XOR mask 0x5412): 0x{:04X}",
|
||||
fmt_bits
|
||||
);
|
||||
|
||||
// 去掉 XOR mask
|
||||
let unmasked = fmt_bits ^ 0x5412;
|
||||
@@ -63,7 +90,10 @@ fn test_dump_format_info() {
|
||||
let ec_bits = (unmasked >> 13) & 0x03;
|
||||
let mask_bits = (unmasked >> 10) & 0x07;
|
||||
let bch = unmasked & 0x3FF;
|
||||
println!("EC bits: {:02b} 掩码 bits: {:03b} BCH: 0x{:03X}", ec_bits, mask_bits, bch);
|
||||
println!(
|
||||
"EC bits: {:02b} 掩码 bits: {:03b} BCH: 0x{:03X}",
|
||||
ec_bits, mask_bits, bch
|
||||
);
|
||||
|
||||
// 期望值
|
||||
let expected = {
|
||||
@@ -71,7 +101,14 @@ fn test_dump_format_info() {
|
||||
encode_format_info(qr.level.indicator_bits(), qr.mask)
|
||||
};
|
||||
println!("期望的格式信息: 0x{:04X}", expected);
|
||||
println!("匹配: {}", if fmt_bits == expected { "✅" } else { "❌ 不匹配!" });
|
||||
println!(
|
||||
"匹配: {}",
|
||||
if fmt_bits == expected {
|
||||
"✅"
|
||||
} else {
|
||||
"❌ 不匹配!"
|
||||
}
|
||||
);
|
||||
assert_eq!(fmt_bits, expected, "格式信息不匹配!");
|
||||
}
|
||||
#[test]
|
||||
@@ -84,11 +121,30 @@ fn test_finder_patterns_present() {
|
||||
let s = size as u8;
|
||||
let finders: [(u8, u8); 3] = [(0, 0), (s - 7, 0), (0, s - 7)];
|
||||
for (fx, fy) in finders {
|
||||
assert!(m[fy as usize][fx as usize], "定位({},{}): 左上角应为暗", fx, fy);
|
||||
assert!(m[fy as usize][(fx + 6) as usize], "定位({},{}): 右上角应为暗", fx, fy);
|
||||
assert!(m[(fy + 6) as usize][fx as usize], "定位({},{}): 左下角应为暗", fx, fy);
|
||||
assert!(
|
||||
m[fy as usize][fx as usize],
|
||||
"定位({},{}): 左上角应为暗",
|
||||
fx, fy
|
||||
);
|
||||
assert!(
|
||||
m[fy as usize][(fx + 6) as usize],
|
||||
"定位({},{}): 右上角应为暗",
|
||||
fx,
|
||||
fy
|
||||
);
|
||||
assert!(
|
||||
m[(fy + 6) as usize][fx as usize],
|
||||
"定位({},{}): 左下角应为暗",
|
||||
fx,
|
||||
fy
|
||||
);
|
||||
// 内部 3×3 是暗色
|
||||
assert!(m[(fy + 2) as usize][(fx + 2) as usize], "定位({},{}): 中心3×3应为暗", fx, fy);
|
||||
assert!(
|
||||
m[(fy + 2) as usize][(fx + 2) as usize],
|
||||
"定位({},{}): 中心3×3应为暗",
|
||||
fx,
|
||||
fy
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,8 +184,10 @@ fn test_format_info_written() {
|
||||
let qr = QrCode::encode("HELLO", QrConfig::default()).unwrap();
|
||||
let m = qr.modules();
|
||||
// 格式信息在定位图案旁,检查几个位置不是全亮
|
||||
assert!(m[8][0] || m[8][1] || m[8][2] || !m[8][0],
|
||||
"格式信息应已写入");
|
||||
assert!(
|
||||
m[8][0] || m[8][1] || m[8][2] || !m[8][0],
|
||||
"格式信息应已写入"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -140,8 +198,10 @@ fn test_svg_valid_structure() {
|
||||
assert!(svg.starts_with("<svg"), "SVG 应以 <svg 开头");
|
||||
assert!(svg.contains("rect"), "SVG 应包含 rect 元素");
|
||||
assert!(svg.contains("fill=\"black\""), "SVG 暗模块应是黑色");
|
||||
assert!(svg.ends_with("</svg>\n") || svg.ends_with("</svg>"),
|
||||
"SVG 应以 </svg> 结尾");
|
||||
assert!(
|
||||
svg.ends_with("</svg>\n") || svg.ends_with("</svg>"),
|
||||
"SVG 应以 </svg> 结尾"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -163,7 +223,10 @@ fn test_qr_structure_dump() {
|
||||
let size = qr.size() as usize;
|
||||
let m = qr.modules();
|
||||
|
||||
println!("\n=== QR Matrix {}x{} v{} mask{} ===", size, size, qr.version.0, qr.mask);
|
||||
println!(
|
||||
"\n=== QR Matrix {}x{} v{} mask{} ===",
|
||||
size, size, qr.version.0, qr.mask
|
||||
);
|
||||
for y in 0..size {
|
||||
for x in 0..size {
|
||||
print!("{}", if m[y][x] { "##" } else { " " });
|
||||
@@ -174,9 +237,17 @@ fn test_qr_structure_dump() {
|
||||
// 统计
|
||||
let dark: usize = m.iter().flatten().filter(|&&x| x).count();
|
||||
let total = size * size;
|
||||
println!("\n暗/总: {}/{} = {:.1}%", dark, total, dark as f64 / total as f64 * 100.0);
|
||||
println!(
|
||||
"\n暗/总: {}/{} = {:.1}%",
|
||||
dark,
|
||||
total,
|
||||
dark as f64 / total as f64 * 100.0
|
||||
);
|
||||
println!("尺寸: {}×{}", size, size);
|
||||
println!("版本: {} 掩码: {} 纠错: {:?}", qr.version.0, qr.mask, qr.level);
|
||||
println!(
|
||||
"版本: {} 掩码: {} 纠错: {:?}",
|
||||
qr.version.0, qr.mask, qr.level
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user