eCourt-note/wordaddin/services/authService.ts

64 lines
3.7 KiB
TypeScript
Raw Normal View History

2026-10-16 12:07:25 +07:00
/**
* Auth ของ add-in — e-Court pass-through ทางเดียว (ยกเลิก Keycloak 2026-10-27 ตามคำขอผู้ใช้)
* ไม่มีขั้นตอน login ใน add-in อีกต่อไป: ไฟล์ที่ e-Court stamp custom properties
* `token`/`owner` มา (`readTrackedProperties` อ่านรวม) = ใช้งานได้ทันที ไม่ต้องกดปุ่มใด ๆ
* ไฟล์ที่ไม่มีทั้งคู่ = phase no-access ของ TaskpaneApp (ขั้นตอนสำหรับเอกสารทั่วไปจะมีในอนาคต)
2026-10-16 12:07:25 +07:00
*
* token เก็บใน memory เท่านั้น — getAccessToken คืน docToken ให้ apiClient แนบ Bearer
* (ช่วงไม่ต่อ backend จริง versioningService เป็น mock ไม่เรียก apiClient อยู่แล้ว)
2026-10-16 12:07:25 +07:00
*/
import { config } from "../config";
/** state เดียว — null = ยังไม่เคย pass-through สำเร็จ (จากไฟล์ หรือ ?addindemo) */
2026-10-16 12:07:25 +07:00
let username: string | null = null;
/** token จาก custom properties ของไฟล์ (e-Court pass-through) — เก็บใน memory เท่านั้น */
let docToken: string | null = null;
2026-10-16 12:07:25 +07:00
/** dev-only — โหมด ?addindemo ของ WordAddinGate ใช้ตั้ง session ทันทีไม่อ่านไฟล์จริง */
2026-10-16 12:07:25 +07:00
export function signInForDemo(): void {
username = config.mockUsername;
}
/** ถอด field จาก JWT payload (base64url) โดยไม่ตรวจ signature — ใช้ดู uid ประกอบชื่อผู้ใช้เท่านั้น */
function decodeJwtField(token: string, field: string): string | undefined {
const payload = token.split(".")[1];
if (!payload) return undefined;
try {
// atob คืน binary string (1 char = 1 byte) — ต้องถอด UTF-8 ด้วย TextDecoder ก่อน JSON.parse
// ไม่งั้น uid ที่ไม่ใช่ ASCII (เช่น ชื่อไทย) จะกลายเป็น mojibake
const bytes = Uint8Array.from(atob(payload.replace(/-/g, "+").replace(/_/g, "/")), (char) => char.charCodeAt(0));
const json: unknown = JSON.parse(new TextDecoder().decode(bytes));
const value = typeof json === "object" && json !== null ? (json as Record<string, unknown>)[field] : undefined;
return typeof value === "string" && value !== "" ? value : undefined;
} catch {
return undefined;
}
}
/**
* e-Court pass-through — จุดเข้าเดียวของ auth: ไฟล์ที่ stamp `token`/`owner` ไว้
* username ได้จาก owner → uid ใน JWT → mockUsername (ตามลำดับ)
* คืน true = ผ่านเข้าได้ (มี token หรือ owner อย่างน้อยหนึ่งตัว)
*/
export function signInFromDocument(input: { token?: string; owner?: string }): boolean {
const token = input.token?.trim() || undefined;
const owner = input.owner?.trim() || (token ? decodeJwtField(token, "uid") : undefined);
if (!token && !owner) {
return false;
}
username = owner ?? config.mockUsername;
docToken = token ?? null;
return true;
}
/** Bearer ของ apiClient — docToken จากไฟล์ (ส่วน demo/mock คืน token ปลอม) */
2026-10-16 12:07:25 +07:00
export async function getAccessToken(): Promise<string | null> {
if (docToken) return docToken;
2026-10-16 12:07:25 +07:00
return username ? `mock-token-${username}` : null;
}
export function getUsername(): string | undefined {
return username ?? undefined;
}