Phase 5 Iteration 1: Bảo mật — mã hoá + quyền hạn, gỡ mật khẩu, redaction THẬT, xoá metadata

Engine:
- qpdf.rs: Permissions (in/sửa/copy/chú thích) map sang cờ AES-256 của qpdf;
  encrypt_with_password_perms (API cũ giữ tương thích); decrypt_remove_password
  (--password --decrypt, sai mật khẩu trả lỗi không ghi file rác)
- redact.rs MỚI — redaction thật, nghiêng về xoá thừa (an toàn):
  text/path/shading/form giao vùng → xoá nguyên object; ảnh giao vùng → đọc
  pixel gốc qua get_raw_image, BÔI ĐEN đúng phần giao trong dữ liệu ảnh rồi
  thay ảnh (không đọc được → xoá cả ảnh); vẽ khối đen phủ vùng
- meta.rs: strip_metadata — xoá /Info trailer + XMP /Metadata catalog, xoá cả
  tham chiếu lẫn object đích (lopdf; file trailer phi chuẩn qua qpdf trước)

Tauri + UI (thanh 🔒 Bảo mật):
- Commands: redact_apply (nhiều trang, chain file tạm), security_encrypt,
  security_decrypt, security_strip_metadata
- Redact 2 bước như Foxit: tool quét vùng (khối đen mờ viền đỏ, bấm để bỏ,
  giữ tool quét nhiều vùng) → Áp dụng (n) → lưu file mới
- Dialog Đặt mật khẩu (user/confirm/owner + 4 checkbox quyền), Gỡ mật khẩu,
  Xoá metadata — modal chuyên nghiệp, không prompt/alert

Test (6 mới, tổng 58/58 ngoài qpdf-fixture):
- redact: chuỗi mật biến mất khỏi extract + tâm vùng render đen; đọc lại RAW
  image từ file kết quả — nửa redact đen trong chính dữ liệu ảnh
- encrypt+perms round-trip + qpdf --show-encryption xác nhận cấm in;
  decrypt gỡ mật khẩu, mật khẩu sai fail; metadata biến mất khỏi BYTES file
- qpdf_safety: 5/7 xanh trên Linux; 2 test repair fixture corrupt-truncated
  fail do khác biệt qpdf 11.9 Linux (bản Windows dự án xử lý được) — ghi chú
  trong docs/15, cần xác nhận lại trên máy Windows

Docs: 15-phase5-summary (kèm kế hoạch Iteration 2: chữ ký số PAdES, lưu tối
ưu, redact tỉa ký tự), 16-phase5-user-tests (S1–S12), README, roadmap, 14.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HgnbPwSoRGNH7LHsDUmRpk
This commit is contained in:
2026-07-15 08:26:20 +00:00
co-authored by Claude Fable 5
parent fed43b2fb7
commit 8d9076f60c
15 changed files with 978 additions and 15 deletions
+1 -1
View File
@@ -43,7 +43,7 @@ Một ứng dụng desktop có thể **xem, chú thích, tổ chức trang, và
- Thêm text box mới, đổi font/size/màu.
**DoD:** sửa được text 1 dòng & 1 đoạn trên ≥80% file mẫu thường; thêm/xoá/di chuyển ảnh; lưu mở lại đúng; tiếng Việt hiển thị & sửa đúng dấu; có test corpus chuyên cho edit.
## Phase 5 — Bảo mật & Chữ ký ⏳ KẾ TIẾP (đang ở đây)
## Phase 5 — Bảo mật & Chữ ký ✅ Iteration 1 HOÀN TẤT (mã hoá+quyền, gỡ mật khẩu, redaction thật, xoá metadata — xem [docs/15-phase5-summary.md](15-phase5-summary.md)) · Iteration 2: chữ ký số
**Mục tiêu:** Tính năng đáng tiền cho doanh nghiệp.
- Mật khẩu mở/permission; mã hoá **AES-256**; xoá mật khẩu.
- **Redaction thật** (xoá nội dung + ảnh + metadata, không chỉ vẽ đè) + kiểm chứng đã xoá.
+4 -3
View File
@@ -130,11 +130,12 @@ Foxit hơn" — chi phí khổng lồ, không giải quyết gap nào ở mục
Đã xong (lõi, có test): Viewer ✅ · Annotate ✅ · Organize + lưu vững ✅ ·
**Edit text/object giữ font ✅ (iteration 2) · Reflow đoạn "như Word" ✅
(iteration 3)**.
(iteration 3) · Bảo mật iteration 1 ✅ (mã hoá AES-256 + quyền, gỡ mật khẩu,
redaction thật kiểm chứng được, xoá metadata — docs/15)**.
Thứ tự đề xuất tiếp theo, bám giá trị người dùng:
1. **Phase 5 Bảo mật + "Lưu tối ưu"** (mục 3.3 gộp vào đây): mã hoá UI (nợ
Phase 3), redaction thật, subset font, dọn rác, chữ ký số.
1. **Phase 5 Iteration 2**: chữ ký số PAdES + xác thực; "Lưu tối ưu" (mục
3.3: subset font, dọn object rác); redact tỉa theo ký tự.
2. Phase 6 Form → Phase 7 OCR/Convert → Phase 8 phát hành (theo roadmap).
3. Song song, rải theo từng phase: mở rộng font matching (3.4), nấc 1 của
hiệu năng phiên sửa (3.2) khi chạm file lớn thực tế, và v2 của reflow
+80
View File
@@ -0,0 +1,80 @@
# 15 — Tổng kết Phase 5 (Bảo mật) · Iteration 1
> Trạng thái: **mã hoá + permissions, gỡ mật khẩu, redaction THẬT, xoá
> metadata — hoàn tất, có test kiểm chứng nội dung thật sự biến mất.**
> Chữ ký số (PAdES) là Iteration 2 — kế hoạch ở mục 5.
## 1. Khảo sát Foxit (chuẩn nghiệm thu)
- **Protect › Password Protect**: user/owner password, AES-256, tick quyền
in/sửa/copy/chú thích. → ta làm dialog tương đương.
- **Protect › Mark for Redaction → Apply**: quét vùng → khối đen dashed →
Apply xoá nội dung THẬT (text không còn select/search được, ảnh bị đục),
vẽ khối đen. → ta làm đúng luồng 2 bước này.
- **Remove hidden information**: xoá metadata Author/Producer/XMP.
## 2. Đã làm
### Engine
- **`qpdf.rs`**: `Permissions {allow_print, allow_modify, allow_extract,
allow_annotate}` map sang cờ AES-256 của qpdf (`--print/--modify/--extract/
--annotate`); `encrypt_with_password_perms(...)` (API cũ giữ nguyên, uỷ
quyền với quyền đầy đủ); `decrypt_remove_password(input, password, output)`
(`qpdf --password=… --decrypt`) — password sai trả lỗi, không ghi file rác.
- **`redact.rs` (mới) — redaction THẬT, nghiêng về xoá thừa (an toàn)**:
- Text/path/shading/form GIAO vùng → xoá NGUYÊN object khỏi trang (v1 xoá
cả run bị chạm — sót chữ là lỗi bảo mật, xoá thừa thì không).
- Ảnh giao vùng → `get_raw_image` đọc pixel gốc, **bôi đen đúng phần giao
trong dữ liệu ảnh** rồi thay ảnh (nội dung gốc không còn trong file);
không đọc được pixel → xoá cả ảnh.
- Vẽ khối đen phủ mỗi vùng (dấu hiệu thị giác chuẩn redaction).
- **`meta.rs::strip_metadata`**: xoá `/Info` trong trailer (Author/Producer/
CreationDate…) + stream XMP `/Metadata` trong catalog — xoá cả THAM CHIẾU
lẫn OBJECT đích (kiểm bằng soi bytes thô của file kết quả). Qua lopdf;
trailer phi chuẩn được qpdf chuẩn hoá trước (fallback trong Tauri command).
### Tauri + UI (thanh "🔒 Bảo mật")
- Commands: `redact_apply` (nhiều trang, chain qua file tạm, trả số object đã
xử lý), `security_encrypt`, `security_decrypt`, `security_strip_metadata`.
- **Redact 2 bước như Foxit**: nút *⬛ Đánh dấu redact* (tool kéo-quét trên
trang, giữ tool để quét nhiều vùng; khối đen mờ viền đỏ dashed, bấm vào
khối để bỏ) → *Áp dụng redact (n)* → chọn nơi lưu → mở file kết quả.
- **Đặt mật khẩu**: dialog user/confirm/owner password + 4 checkbox quyền →
lưu bản mã hoá riêng (file đang mở giữ nguyên).
- **Gỡ mật khẩu**: nhập mật khẩu → chọn file khoá → lưu bản đã gỡ → mở luôn.
- **Xoá metadata**: 1 nút → lưu bản sạch → mở luôn. Không dùng prompt/alert.
## 3. Test (6 mới; tổng engine 58/58 ngoài qpdf-fixture)
- `redact_removes_text_content_for_real` — chuỗi mật biến mất khỏi
`extract_text`, chuỗi ngoài vùng còn nguyên, tâm vùng render ra ĐEN.
- `redact_blacks_out_image_pixels_for_real` — đọc lại RAW IMAGE từ file kết
quả: nửa bị redact đen trong chính dữ liệu ảnh, nửa kia vẫn màu gốc
(chứng minh không phải "vẽ đè").
- `encrypt_with_perms_round_trip_and_flags` — không mật khẩu bị chặn, đúng
user/owner mở được, `qpdf --show-encryption` xác nhận quyền in bị cấm.
- `decrypt_removes_password` + `decrypt_with_wrong_password_fails`.
- `strip_metadata_removes_info_and_xmp` — Producer/Author biến mất khỏi
BYTES của file, trailer sạch, file vẫn mở/đọc bình thường.
- `qpdf_safety` cũ: 5/7 xanh trên Linux CI; 2 test repair fixture
`corrupt-truncated.pdf` fail do **qpdf 11.9 Linux không dựng lại được
fixture này** (bản qpdf Windows của dự án xử lý được — khác biệt phiên bản
qpdf, không phải hồi quy code; cần xác nhận lại trên máy Windows).
## 4. Đối chiếu FINAL TARGET & RULE
- Redaction là "xoá thật + kiểm chứng được", không phải vẽ đè — test đọc lại
bytes/pixel/extract để chứng minh, đúng DoD roadmap.
- Không thoả hiệp dialog: mọi thao tác có UI chuyên nghiệp (modal + toolbar).
- Điểm CHƯA đạt 100% so với Foxit (ghi nhận, có kế hoạch):
- Redact theo VÙNG QUÉT, xoá cả run text bị chạm (Foxit tỉa theo ký tự).
Nâng cấp v2: cắt run tại ranh giới ký tự bằng char-box (đã có
`page_char_boxes` từ Phase 1) + tái tạo phần giữ lại như reflow.
- Chưa xoá "hidden information" dạng attachment/script/comment ẩn — gộp
vào Iteration 2.
## 5. Iteration 2 (kế tiếp của Phase 5) — Chữ ký số PAdES + Lưu tối ưu
1. **Ký số**: tạo chữ ký PAdES-B (CMS/PKCS#7 qua crate `cms`/`rsa`/`p256`),
ghi `/ByteRange` + placeholder `/Contents`, incremental update để không
phá chữ ký cũ; xác thực bằng Acrobat làm DoD. Đọc chứng chỉ PFX/PKCS#12.
2. **Xác thực chữ ký** khi mở (hiện trạng thái valid/invalid).
3. **Lưu tối ưu** (từ docs/14 mục 3.3): subset font nhúng theo glyph dùng
thật + `qpdf --object-streams=generate` dọn object rác sau edit.
4. Redact tỉa theo ký tự (mục 4) + quét "hidden info" còn lại.
+36
View File
@@ -0,0 +1,36 @@
# 16 — Checklist test thủ công Phase 5 (Bảo mật)
Quan trọng nhất: xác nhận **redaction xoá thật** (S4–S6) và **file mã hoá mở
đúng ở Foxit/Adobe** (S8) — đây là tính năng an toàn, sai là lộ dữ liệu.
## Chạy
```powershell
cd c:\Project\FoFreeXit\app\src-tauri
cargo run
```
## Bảng test
| # | Thao tác | Kỳ vọng | KQ |
|---|----------|---------|----|
| S1 | Bấm **🔒 Bảo mật** | Hiện thanh Bảo mật (redact / mật khẩu / metadata) | |
| S2 | Bấm **⬛ Đánh dấu redact** → kéo quét 1 vùng chữ | Khối đen mờ viền đỏ dashed phủ vùng; đếm ở nút "Áp dụng redact (n)" tăng | |
| S3 | Quét thêm vùng thứ 2 (trang khác cũng được) → bấm vào 1 khối | Khối bị bấm biến mất (bỏ đánh dấu); đếm giảm | |
| S4 | **Áp dụng redact** → lưu file mới | File mới mở lên: vùng redact là khối ĐEN | |
| S5 | Trong file kết quả: Ctrl+F tìm đúng chữ đã redact; thử chọn & copy vùng đó | **KHÔNG tìm thấy, không copy được** — nội dung đã bị xoá thật | |
| S6 | Redact đè lên 1 phần ẢNH rồi áp dụng; mở file kết quả ở Foxit, dùng Edit Object xem ảnh | Phần ảnh bị redact ĐEN NGAY TRONG ẢNH (kéo ảnh ra vẫn đen), không phải hình chữ nhật đè | |
| S7 | **🔑 Đặt mật khẩu**: nhập mật khẩu + bỏ tick "In" → lưu | File mới đòi mật khẩu khi mở | |
| S8 | Mở file S7 ở **Foxit/Adobe**: nhập đúng mật khẩu; thử In | Mở được bằng đúng mật khẩu; lệnh In bị chặn/mờ | |
| S9 | Nhập SAI mật khẩu ở app | Báo lỗi, không mở | |
| S10 | **🔓 Gỡ mật khẩu**: nhập mật khẩu hiện tại → chọn file S7 → lưu | File kết quả mở KHÔNG cần mật khẩu, nội dung nguyên vẹn | |
| S11 | Gỡ mật khẩu với mật khẩu SAI | Báo lỗi rõ ràng, không tạo file hỏng | |
| S12 | **🧹 Xoá metadata** → lưu → mở file kết quả ở Foxit: File › Properties | Author/Producer/Created… trống; app vẫn mở đọc bình thường | |
## Mẫu phản hồi
```
[Mã] (vd S5) — Phần mềm mở: <Foxit/Adobe/Chrome> — Hiện tượng: <mô tả> —
Kỳ vọng: <...> — Ưu tiên: cao/vừa/thấp
```
> Giới hạn đã biết (Iteration 1): redact xoá NGUYÊN text run bị vùng quét
> chạm vào (an toàn — thừa còn hơn sót; tỉa theo ký tự ở iteration 2); chữ ký
> số PAdES là Iteration 2 — xem `docs/15-phase5-summary.md` mục 5.