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
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:
parent
2e951f99f4
commit
c0833c00f7
24 changed files with 858 additions and 460 deletions
|
|
@ -114,6 +114,10 @@ const TaskpaneApp: React.FC<{ demo?: "untracked" | "tracking" }> = ({ demo }) =>
|
|||
|
||||
/** ข้อความบนหน้า no-access — ต่างกันตามสาเหตุ (ไม่มี token ในไฟล์ / token หมดอายุ) */
|
||||
const [noAccessNotice, setNoAccessNotice] = useState<string | null>(null);
|
||||
/** no-access ที่ "ลองใหม่" ช่วยได้ — เฉพาะเคสอ่านไฟล์ไม่สำเร็จ (เช่น office.js มาช้า
|
||||
* บนเครื่องช้า หรือ Word สะดุดชั่วคราว) กดแล้ววน detect() ใหม่ · เคสอื่น (ticket
|
||||
* หมดอายุ/ลายเซ็นไม่ผ่าน/ขอ token ไม่ได้) retry ไม่ช่วย ต้องขอไฟล์ใหม่/เน็ตกลับมา */
|
||||
const [noAccessRetryable, setNoAccessRetryable] = useState(false);
|
||||
|
||||
const [starting, setStarting] = useState(false);
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
|
@ -183,6 +187,7 @@ const TaskpaneApp: React.FC<{ demo?: "untracked" | "tracking" }> = ({ demo }) =>
|
|||
const detect = useCallback(async () => {
|
||||
setPhase("checking");
|
||||
setBootError(null);
|
||||
setNoAccessRetryable(false);
|
||||
try {
|
||||
let properties: metadataService.TrackedDocumentProperties | null = null;
|
||||
try {
|
||||
|
|
@ -191,7 +196,8 @@ const TaskpaneApp: React.FC<{ demo?: "untracked" | "tracking" }> = ({ demo }) =>
|
|||
properties = null;
|
||||
}
|
||||
if (!properties) {
|
||||
setNoAccessNotice("อ่านข้อมูลเอกสารไม่สำเร็จ — ลองปิดแล้วเปิด task pane อีกครั้ง");
|
||||
setNoAccessNotice("อ่านข้อมูลเอกสารไม่สำเร็จ — ลองกด \"ลองใหม่\" หรือปิดแล้วเปิด task pane อีกครั้ง");
|
||||
setNoAccessRetryable(true);
|
||||
setPhase("no-access");
|
||||
return;
|
||||
}
|
||||
|
|
@ -469,6 +475,15 @@ const TaskpaneApp: React.FC<{ demo?: "untracked" | "tracking" }> = ({ demo }) =>
|
|||
<p className="text-sm text-ink-soft">
|
||||
{noAccessNotice ?? "ไม่พบ ticket ของ e-Court ในไฟล์ — ขณะนี้ add-in ใช้ได้กับเอกสารที่ส่งมาจาก e-Court เท่านั้น"}
|
||||
</p>
|
||||
{noAccessRetryable ? (
|
||||
<button
|
||||
type="button"
|
||||
className="focus-ring w-fit rounded-md border border-error/40 bg-white px-2 py-1.5 text-xs text-error-ink"
|
||||
onClick={() => void detect()}
|
||||
>
|
||||
ลองใหม่
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 ตลอดไป)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue