前面五天做的事情,某種程度上都是「品質問題」:元件抓不到、畫面不穩、框畫歪了、圓標擋到東西,最壞的結果是手冊看起來不夠專業。今天這一篇的性質比較不一樣,如果沒處理好,是有可能會出大事的。
會不小心跟著截圖一起流出去的東西,種類比想像中多:授權金鑰、裝置序號、API token、內網伺服器位址、客戶名稱、真實錄影畫面裡拍到的人臉。這些東西一旦印在要交給客戶或第三方的手冊裡,就不是排版問題,而是實質的資訊外洩。
範例 App 的「系統設定 → 授權與裝置」區塊就是照這個情境設計的,三個欄位全部都是不該出現在手冊裡的東西:

順帶一提,這一整塊是 role=admin 才會渲染的,操作員登入時根本不存在於 DOM 裡。要拍到它得先照 Day 09 的做法注入 role (i.e. 這個敏感資訊是特定權限的人才看得到)。

處理敏感資訊大致有三種模式,適用場合不太一樣:
AB-1234-XXXX-0000。三種各套一個,長出來是這樣:

這裡想特別講的是「替換」。一般直覺會覺得「替換」只是「比較好看」的選項,但在使用手冊的場景,它常常是最合適的那一個。手冊的目的是教使用者「這個欄位該填什麼」,如果整條塗黑,讀者就不知道這裡期待的輸入長什麼樣子 (是純數字?還是有固定分段格式?)。換成一組格式正確的假資料,可以同時滿足「不外洩」與「讀者知道該填什麼」兩件事。
反過來說,色塊很適合當預設值,反正有疑慮就先全部遮起來就對了XD
跟 Day 11 的標註一樣,遮蔽也不碰截圖的像素,而是在按下快門之前先把 DOM 動一動,截圖時一起拍進去。設定檔裡就是一個 redact 陣列:
{
"screenshot": "settings-license-01.png",
"redact": [
{ "testid": "license-input" },
{ "testid": "license-server-ip", "mode": "blur" },
{ "testid": "license-serial", "mode": "replace", "text": "AB-1234-XXXX-0000" }
]
}
三種模式對應到三種完全不同的手法:
const mode = rule.mode ?? 'box'
if (mode === 'box') {
// 量好座標,稍後交給疊層畫實心色塊
boxes.push((await locator.boundingBox())!)
} else if (mode === 'blur') {
await locator.evaluate((el) => { el.style.filter = 'blur(6px)' })
} else {
await locator.evaluate((el, text) => { el.value = text }, rule.text)
}
色塊之所以走疊層而不是直接把元件塗黑,是因為疊層蓋的是「畫面上那塊矩形」,跟元件內部是文字、圖片還是 canvas 無關,一套寫法全部通用。
遮蔽層跟 Day 11 的標註層是兩層獨立的疊層,順序上有個小地方要注意:遮蔽層的 z-index 要比標註層低一階。兩層都設成一樣的話,就會變成看後面誰蓋誰,圓標有機會被色塊吃掉。分好層之後,遮蔽與標註可以在同一張圖上共存:

如果畫面裡會拍到真人 (例如監控串流),處理方式有三種:換掉影像來源、事後人工打馬賽克、取得肖像使用同意。
推薦的是第一種,而且它跟 Day 09 是同一件事:串流畫面本來就該用 page.route() 換成固定的 fixture 圖,換的時候順手挑一張不含真人的圖就好,從源頭上就不會拍到人臉。
這是今天最重要的一段。
假設某次改版把 license-input 改名成別的名字,或整塊搬到別的頁面,設定檔裡的 redact 規則就找不到目標了。如果實作上選擇「找不到就跳過」,產出會是這樣:

後面兩條規則照常生效,看起來像是有在運作,只有第一個欄位原封不動——而且整個過程不會有任何錯誤訊息。這種產出如果沒有人工審稿,會一路混進交付物裡。
所以 redact 的規則找不到目標時,唯一正確的處理是中止整個 build:
if ((await locator.count()) === 0) {
throw new Error(
`redact 找不到目標:${rule.selector}\n` +
` 遮罩沒有被套用,敏感資訊會原封不動留在截圖裡,因此中止整個 build。`,
)
}
模糊的強度是連續的,這代表它有一個「看起來有遮、其實讀得出來」的灰色地帶。下面這張圖上面那欄是 blur(2px),下面那欄是 blur(6px):

blur(2px) 的金鑰其實還讀得出來,而且手冊的截圖通常是 deviceScaleFactor: 2 拍的,放大看更清楚。順帶一提,如果改用馬賽克 (像素化) 而不是高斯模糊,對規律的等寬字元其實有機會被還原回去,所以真正機敏的東西 (金鑰、憑證) 還是直接用色塊最乾脆,模糊留給「只是不想給人看,但外流也不至於出事」的東西。
前面提到說,授權區塊是注入 role=admin 才會出現的。也就是說,比「遮得好不好」更前面的一個問題是:
這一章真的需要拍這個畫面嗎?
如果手冊的讀者是操作員,那最好的做法不是把授權區塊拍下來再遮好,而是根本不要注入 admin。遮蔽是不得不拍時的補救手段,不是拍攝範圍的許可證。
到這裡,一張時機、範圍、標註、遮蔽都正確的截圖就完成了,單點技術的部分告一段落。明天要把這六天的東西全部收攏進一份設定檔裡,用宣告式的方式描述完整的一本手冊。