Refactor authentication flow and ticket handling in add-in
All checks were successful
Deploy eCourt Note Web to Server / Validate Database Schema (Drizzle) (push) Successful in 4s
Deploy eCourt Note Web to Server / Build Web Docker Image (push) Successful in 1m23s
Deploy eCourt Note Web to Server / Deploy eCourt Note Web to Server (push) Successful in 5s
Deploy eCourt Note Web to Server / Notify Deployment Status (push) Successful in 0s

- Removed client-side HMAC verification; server now handles all HMAC checks.
- Updated ticket processing logic to improve UX and security.
- Adjusted API request handling to return discriminated results based on HTTP status.
- Enhanced error messages for better clarity on authentication failures.
- Added unit tests for the new token endpoint to ensure compliance with updated contract.
- Cleaned up unused code and comments related to previous HMAC handling.
This commit is contained in:
Suphonchai Phoonsawat 2026-11-04 21:18:19 +07:00
parent 2e951f99f4
commit c0833c00f7
24 changed files with 858 additions and 460 deletions

View file

@ -22,8 +22,14 @@ import TaskpaneApp from "./TaskpaneApp";
/** office.js self-host จาก postinstall scripts/fetch-office-js.mjs (intranet ไม่ใช้ CDN) */
const OFFICE_JS_SRC = withBasePath("/wordaddin/office-js/office.js");
/** Office.onReady callback ไม่ยิงภายใน 5 วิหลังฉีด script ก็ proceed (กัน webview แปลก ๆ — โหลดสำเร็จแต่ onReady เงียบ) */
/**
* ช่วง poll ของ fallback — ทุก 5 วิเช็คว่า global `Office` โผล่แล้วหรือยัง:
* โผล่แล้วแต่ onReady เงียบ (webview แปลก ๆ) = proceed ตามเจตนาเดิม · ยังไม่โผล่
* (เครื่อง/เน็ตช้า — script ยังโหลดไม่เสร็จ) = รอต่อรอบหน้า ไม่ proceed บอด ๆ
*/
const ONREADY_FALLBACK_MS = 5_000;
/** เพดานรวมหลัง inject script — ครบแล้วยังไม่มี Office = ไปหน้า error (มีปุ่มลองใหม่) */
const ONREADY_HARD_CAP_MS = 60_000;
/**
* โหลด office.js ครั้งเดียวต่อ page เป็น singleton promise ระดับ module —
@ -43,7 +49,28 @@ function ensureOfficeJs(): Promise<boolean> {
return;
}
const script = document.createElement("script");
const fallbackTimer = setTimeout(() => resolve(true), ONREADY_FALLBACK_MS);
const startedAt = Date.now();
let fallbackTimer: ReturnType<typeof setTimeout>;
const armFallback = () => {
fallbackTimer = setTimeout(() => {
// Office โผล่แล้ว (script evaluate แล้ว) = proceed ได้เลย ไม่รอ onReady —
// กัน webview ที่โหลดสำเร็จแต่ callback เงียบ (เจตนาเดิมของ fallback)
if (typeof Office !== "undefined") {
resolve(true);
return;
}
// ยังไม่มี Office global = เครื่องช้า script ยังไม่โหลดเสร็จ — รอต่อ (re-arm)
// จนครบเพดานค่อยยอมแพ้ไปหน้า error กัน proceed แล้ว Word.run พังกลางคัน
if (Date.now() - startedAt >= ONREADY_HARD_CAP_MS) {
officeReadyPromise = null;
script.remove();
resolve(false);
return;
}
armFallback();
}, ONREADY_FALLBACK_MS);
};
armFallback(); // ตั้งก่อนเสียบ src เหมือนเดิม — ครอบทั้ง network fetch + evaluate + รอ onReady
const onReady = () => {
// เคลียร์ timer เฉพาะเมื่อ callback ของ Office.onReady ยิงจริง — ถ้าเคลียร์ตั้งแต่ onload
// แล้ว onReady เงียบ fallback จะตายไปก่อนทำหน้าที่ (ค้าง loading ตลอดไป)