我們在自己的帳戶上執行了一次退款,用來驗證帳本是否正確地反向記錄。它確實做到了。隨後有人查看了帳戶狀態的其餘部分,真正的發現就藏在那裡:方案仍然處於啟用狀態,而且會一直保持到下個月中旬。
錢退回來了,存取權限卻保留著。任何願意點選「退款」的人,每個月都能重複這麼做。這不是靠測試發現的,因為沒有任何測試提出過這個問題。
結束那筆付款所購買的週期
在一次全額退款中,那筆付款開啟的週期現在會立即結束,並且會記錄一則生命週期事件來說明原因。
是立即結束——但不是什麼都不留。如果你原本在某個方案上,升級到了更貴的方案,而升級的那筆付款被退款了,你會回到之前所在的方案,而不是免費層級。那個月是你另外單獨付費的,並沒有被退款。如果連那個月也一併收回,就等於平台在拿走客戶仍然擁有的東西。只有在沒有任何仍處於啟用狀態的先前方案時,才會降落到免費層級。
存取權利有兩個部分
這項修復的第一個版本只是結束了訂閱紀錄本身,然後就停在那裡。但你享有什麼權限,取決於兩件事:預算讀取的那條紀錄,以及付款成功時被授予的一個角色權限。任何其他結束訂閱的路徑都會明確撤銷這個角色權限。而這一個沒有,於是一個已退款的帳戶會在名義上被取消,實際上卻仍然保留著付費層級的權限。
現在角色權限也會一併被撤銷,並且會落在恢復後的那個方案的層級上,而不是籠統地降到「免費」——這和恢復方案本身的邏輯是一致的。
通知服務商
帳戶頁面顯示的是「免費層級」。支付服務商的後台卻顯示「已啟用,下次扣款在下個月」。退款結束了我們這一側的事情,卻從未通知另一側,於是客戶被排在佇列裡,等著為一個他已經獲得退款、也無法再使用的方案再次被扣款——而且他沒有辦法從我們這邊的介面上停止這一切,因為取消操作需要一個處於啟用狀態的訂閱,而我們剛剛取消的正是他的那份訂閱。
退款現在會在發起該筆付款的服務商那裡停止自動續訂。這不是立即終止:自動續訂會停止,因此不會再有資金流動,服務商自己的紀錄會按照它自己的排程自然結束,而不是在它剛剛處理完的一筆退款之下被強行撕掉。
有一個例外,是所有者在發布前發現的。如果你被恢復到的方案運行在同一個服務商訂閱上,取消它就會讓你留下一個永遠不會續訂、也永遠不會扣款的方案——這恰好是本次要修復的那個漏洞的鏡像版本,而且同樣悄無聲息。這種情況現在會被明確指出並保持不變。
只有開啟週期的那筆付款才能結束這個週期
在這個服務商這裡,月中的一次升級會針對現有紀錄收取一筆小額的按比例差價。如果退還這筆小額費用,系統會找到一個訂閱,把它全部取消,再去尋找之前的方案,卻什麼都找不到,於是把客戶降到免費層級——就因為一次月中的調整。現在只有開啟目前週期的那筆付款才能結束這個週期。在此之後發生的一切都只是金錢層面的問題,而帳本對此早已給出了答案。
四條支付通道全部涵蓋,而不只是那條正在使用的
我們支援的四家支付處理商裡,有三家今天沒有任何客戶在使用。撤銷邏輯本可以只在正在使用的那條通道上修復,而這幾乎就是最初的做法。改變這一點的理由是:一旦其他某家服務商在未來某天重新啟用,這個漏洞就會捲土重來,而到那時,不會有人記得它曾經存在過。
這個程式碼儲存庫已經六次交付過同一類被遺忘的陷阱。現在撤銷邏輯存在於一份統一的契約背後,四家處理商都透過同一行程式碼呼叫它——這樣一來,未來重新啟用其中某一家的維護者,無需讀過這些內容中的任何一部分,就能自然獲得這項能力。