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:
+19
-10
@@ -1,6 +1,24 @@
|
||||
use crate::qr::QrCode;
|
||||
use image::{ImageBuffer, Luma};
|
||||
|
||||
/// 将单个模块填充到图像缓冲区(module_size × module_size 像素块)
|
||||
fn fill_module(
|
||||
img: &mut ImageBuffer<Luma<u8>, Vec<u8>>,
|
||||
x: u32,
|
||||
y: u32,
|
||||
module_size: u32,
|
||||
is_dark: bool,
|
||||
) {
|
||||
let px_val = if is_dark { 0u8 } else { 255u8 };
|
||||
let x0 = x * module_size;
|
||||
let y0 = y * module_size;
|
||||
for dy in 0..module_size {
|
||||
for dx in 0..module_size {
|
||||
img.put_pixel(x0 + dx, y0 + dy, Luma([px_val]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_png(qr: &QrCode, module_size: u8) -> Result<Vec<u8>, image::ImageError> {
|
||||
let matrix_size = qr.size() as u32;
|
||||
let margin = qr.margin as u32;
|
||||
@@ -20,16 +38,7 @@ pub fn render_png(qr: &QrCode, module_size: u8) -> Result<Vec<u8>, image::ImageE
|
||||
false // 白边
|
||||
};
|
||||
|
||||
let px_val = if is_dark { 0u8 } else { 255u8 };
|
||||
for dy in 0..module_size as u32 {
|
||||
for dx in 0..module_size as u32 {
|
||||
img.put_pixel(
|
||||
x * module_size as u32 + dx,
|
||||
y * module_size as u32 + dy,
|
||||
Luma([px_val]),
|
||||
);
|
||||
}
|
||||
}
|
||||
fill_module(&mut img, x, y, module_size as u32, is_dark);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,14 @@ pub fn render_svg(qr: &QrCode) -> String {
|
||||
let margin = qr.margin as u32;
|
||||
let total = matrix_size + 2 * margin;
|
||||
|
||||
let mut svg = String::new();
|
||||
// 预估 SVG 大小: 固定头部 + 每个暗模块约 48 字节
|
||||
let dark_count = qr
|
||||
.modules()
|
||||
.iter()
|
||||
.flat_map(|row| row.iter())
|
||||
.filter(|&&m| m)
|
||||
.count();
|
||||
let mut svg = String::with_capacity(200 + dark_count * 50);
|
||||
svg.push_str(&format!(
|
||||
r#"<svg xmlns="http://www.w3.org/2000/svg" width="{}" height="{}" viewBox="0 0 {} {}">"#,
|
||||
total, total, total, total
|
||||
|
||||
Reference in New Issue
Block a user