借閱助手台南市立圖書館

SYSTEM HANDBOOK

系統架構與維運說明

本頁說明網站使用的技術、資料如何查詢與排序、LINE 如何通知、排程如何設定,以及從官方 App 找出後端 API 的過程。頁面不包含任何帳密、Token 或 LINE User ID。

技術棧

層級技術用途
前端HTML5、CSS3、原生 JavaScript登入表單、響應式卡片/清單、LINE 訊息預覽;沒有前端框架與追蹤碼。
後端Node.js 20、Express 4、Axios接收查詢、呼叫館方 API、正規化資料及串接 LINE。
安全Helmet、express-rate-limit、HMAC-SHA256CSP/安全標頭、流量限制、LINE Webhook 驗簽及 Cron 保護。
通知LINE Messaging API以 Push/Multicast Message 發送到期提醒。
雲端Cloud Run、Cloud Build、Secret Manager、Cloud Scheduler容器部署、機密注入與每日定時觸發。
測試Node.js Test Runner驗證日期、API 解析、排序、訊息與排程篩選。

整個流程如何串接

1. 使用者送出帳密
2. Cloud Run 接收
3. 呼叫館方 API
4. 正規化及排序
5. 網頁呈現/LINE 推播

網頁即時查詢

  1. 表單以 HTTPS 將帳號及密碼送到 POST /api/query,按 Enter 與按查詢按鈕效果相同。
  2. 後端依官方 App 的規則將密碼做 UTF-8 Base64 後反轉,呼叫 patronAuth 取得館內讀者識別碼。
  3. 再以該識別碼呼叫 patronLoans,取得書名、借閱日、到期日、續借次數與預約人數。
  4. 後端計算剩餘天數、優先原因並排序,僅回傳借閱資料,不回傳帳密或完整借閱證號。
  5. 瀏覽器產生卡片與 LINE 預覽;密碼不寫入 localStorage、Cookie 或應用程式日誌。

每日自動通知

  1. Cloud Scheduler 以 HTTPS POST 呼叫 /api/cron/run,並在標頭附上 Secret Manager 管理的 Cron 密鑰。
  2. 後端讀取 Secret Manager 注入的多帳戶設定,逐一向館方查詢。
  3. 依網頁排序保留第 1 至第 5 類書籍;沒有符合項目就不發訊息。
  4. 有符合項目時,以帳戶 label 組成訊息並透過 LINE Messaging API 推播。

原本 App 後端 API 如何取得

API 不是猜測網址,也不是爬 HTML;它是從「臺南市立圖書館 wow 愛讀冊」iOS App 的實際網路流量確認。使用的是方法 B:Windows 電腦執行 mitmproxy/mitmweb,iPhone 與電腦連同一個 Wi-Fi,再把 iPhone Wi-Fi HTTP Proxy 指向電腦的 8080 port。

  1. 電腦啟動 mitmweb,iPhone Safari 開啟 http://mitm.it 安裝 CA 描述檔。
  2. 在 iOS「設定 → 一般 → 關於本機 → 憑證信任設定」啟用完整信任。
  3. 確認 Safari 可經代理正常開網頁,再重新開啟 wow 愛讀冊 App。
  4. 在 App 登入並開啟借閱清單,於 mitmweb 依 host 與 JSON 回應篩選請求。
  5. 比對登入與借閱清單 request/response,確認 API base URL、identify=TNpatronAuthpatronLoans 與密碼編碼規則。
  6. 以測試程式重播請求,確認欄位後實作於 src/library-scraper.js。抓包完成後移除手機 Proxy;CA 憑證也可停用或刪除。

限制:這是官方 App 使用但未公開文件化的 API。館方可能隨時更換 URL、欄位或驗證方式;本系統沒有繞過帳號權限,也只能查詢使用者提供之有效帳戶。

查詢、判斷與排序規則

資料判斷

排序優先級

  1. 已逾期。
  2. 有人預約。
  3. 已續借至少三次。
  4. 今天到期。
  5. 一至五天內到期。
  6. 其他借閱書籍。
  7. 同一優先級內依到期日由早到晚;同時符合多項時採最高順位。

LINE 通知規則

排程時間與修改方式

正式環境時區固定為 Asia/Taipei(UTC+8),目前有兩個 Cloud Scheduler Job:

Job時間Cron
tainan-library-notify-morning每天 07:000 7 * * *
tainan-library-notify-night每天 18:000 18 * * *

查看設定

gcloud scheduler jobs describe JOB_NAME --location asia-east1 --project gen-lang-client-0942368175

修改時間

gcloud scheduler jobs update http JOB_NAME --location asia-east1 --schedule "0 8 * * *" --time-zone "Asia/Taipei" --project gen-lang-client-0942368175

上例會改成每天 08:00。修改排程不需要重新部署 Cloud Run;若更換 Cron Secret,則必須同步更新 Secret Manager、Cloud Run secret reference 與 Scheduler request header。

安全檢查與現況

項目處理
完整借閱證號出現在 API response已移除。
公開手動 LINE 推播可遭濫用只允許排程 Secret 內已登記帳戶,另設低頻率限制;通知對象不可由 request 指定。
Inline JavaScript/CSS 導致 CSP 過寬已拆成獨立靜態檔,禁止 inline script、object 與外部字型。
輸入及 request body 無明確上限已限制欄位長度與 JSON 16 KB。
Cron Secret 一般字串比較已改為固定時間比較。
敏感 API 被代理快取所有 /api response 加上 Cache-Control: no-store
套件漏洞部署前執行 production dependency audit 與自動測試。

仍存在的外部限制

維運與可增強功能

部署

npm test
npm audit --omit=dev
gcloud run deploy tainan-library --source . --region asia-east1 --project gen-lang-client-0942368175

建議後續順序

  1. 加入 Cloud Monitoring 告警,監測查詢失敗率與排程失敗。
  2. 若館方提供續借 API,再新增需二次確認的一鍵續借;目前不應以猜測端點實作。
  3. 加入受保護的帳戶管理介面,取代人工更新 SUBSCRIBERS_JSON Secret。
  4. 加入通知歷史與去重機制,避免同一天重複通知完全相同內容。
頁首