Refactor ticket verification and installation scripts
All checks were successful
Deploy eCourt Note Web to Server / Validate Database Schema (Drizzle) (push) Successful in 3s
Deploy eCourt Note Web to Server / Build Web Docker Image (push) Successful in 1m17s
Deploy eCourt Note Web to Server / Deploy eCourt Note Web to Server (push) Successful in 4s
Deploy eCourt Note Web to Server / Notify Deployment Status (push) Successful in 1s
All checks were successful
Deploy eCourt Note Web to Server / Validate Database Schema (Drizzle) (push) Successful in 3s
Deploy eCourt Note Web to Server / Build Web Docker Image (push) Successful in 1m17s
Deploy eCourt Note Web to Server / Deploy eCourt Note Web to Server (push) Successful in 4s
Deploy eCourt Note Web to Server / Notify Deployment Status (push) Successful in 1s
- Split `verifyAddinTicket` into two functions: `verifyAddinTicketHmac` (ignores expiration) and `verifyAddinTicket` (checks expiration). - Add `hasVersionByUser` function to check if a document has been previously worked on by a user, allowing expired tickets to be accepted if the user has a history with the document. - Update OpenAPI specification to reflect changes in ticket expiration handling. - Introduce new scripts for installing and uninstalling the Word add-in on Windows and macOS, providing a streamlined process for sideloading the add-in. - Enhance tests for ticket verification to cover new functionality regarding expired tickets and user history.
This commit is contained in:
parent
3726cb742f
commit
b1449ab668
14 changed files with 727 additions and 75 deletions
|
|
@ -33,15 +33,15 @@ export function addinTicketSecret(): string {
|
|||
}
|
||||
|
||||
/**
|
||||
* ตรวจ ticket เต็มชุด (HMAC → parse → exp) — ไม่แยกสาเหตุออกมา
|
||||
* (route ตอบ 401 ข้อความเดียวกันทุกกรณี กันใช้ endpoint เป็น oracle —
|
||||
* add-in รู้สาเหตุจริงจากการตรวจเองฝั่ง client อยู่แล้ว)
|
||||
* ตรวจ ticket แบบไม่สน exp (HMAC → parse) — ใช้เมื่อ route จะตัดสิน "ticket หมดอายุ
|
||||
* แต่เอกสารนี้เคยทำงานโดย uid เดียวกัน" เองผ่าน DB (requirement ขั้น 7: กลับมาทำ
|
||||
* เอกสารเดิมผ่านได้แม้ ticket หมดอายุ) — ตัวตนของผู้ถือยังยึด HMAC ของ e-Court
|
||||
* เหมือนเดิม แค่ไม่ใช้อายุ ticket เป็นเกณฑ์ตัดสิทธิ์ ณ จุดนี้
|
||||
*/
|
||||
export function verifyAddinTicket(
|
||||
export function verifyAddinTicketHmac(
|
||||
ticketData: string,
|
||||
hmacHex: string,
|
||||
secret: string,
|
||||
nowSec: number = Math.floor(Date.now() / 1000),
|
||||
): { ok: true; ticket: DocverTicket } | { ok: false } {
|
||||
const digest = normalizeHexDigest(hmacHex);
|
||||
if (digest === null) return { ok: false };
|
||||
|
|
@ -55,10 +55,26 @@ export function verifyAddinTicket(
|
|||
|
||||
const parsed = parseDocverTicket(ticketData);
|
||||
if (!parsed.ok) return { ok: false };
|
||||
if (isTicketExpired(parsed.ticket.exp, nowSec)) return { ok: false };
|
||||
return { ok: true, ticket: parsed.ticket };
|
||||
}
|
||||
|
||||
/**
|
||||
* ตรวจ ticket เต็มชุด (HMAC → parse → exp) — ไม่แยกสาเหตุออกมา
|
||||
* (route ตอบ 401 ข้อความเดียวกันทุกกรณี กันใช้ endpoint เป็น oracle —
|
||||
* add-in รู้สาเหตุจริงจากการตรวจเองฝั่ง client อยู่แล้ว)
|
||||
*/
|
||||
export function verifyAddinTicket(
|
||||
ticketData: string,
|
||||
hmacHex: string,
|
||||
secret: string,
|
||||
nowSec: number = Math.floor(Date.now() / 1000),
|
||||
): { ok: true; ticket: DocverTicket } | { ok: false } {
|
||||
const verified = verifyAddinTicketHmac(ticketData, hmacHex, secret);
|
||||
if (!verified.ok) return { ok: false };
|
||||
if (isTicketExpired(verified.ticket.exp, nowSec)) return { ok: false };
|
||||
return verified;
|
||||
}
|
||||
|
||||
/** แปลง ticket → claims ของ access_token (uid→userid, uname→username, tid→template) */
|
||||
export function ticketToDocverClaims(ticket: DocverTicket): DocverTokenClaims {
|
||||
return { userid: ticket.uid, username: ticket.uname, fid: ticket.fid, template: ticket.tid };
|
||||
|
|
|
|||
|
|
@ -206,6 +206,22 @@ export async function findVersionForDoc(
|
|||
return row?.version ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* เอกสาร (docId) นี้เคยมี version ที่สร้างโดย userId นี้หรือยัง — ใช้เป็นหลักฐาน
|
||||
* "เคยทำงานกับเอกสารนี้" ตอนยอมรับ ticket ที่หมดอายุ (requirement ขั้น 7:
|
||||
* กลับมาทำเอกสารเดิมผ่านได้แม้ ticket หมดอายุ — ตัวตนยังยึด HMAC ของ e-Court
|
||||
* ทางเข้า /api/documents/token ของ add-in) · อ่านอย่างเดียว ไม่แตะ MinIO
|
||||
*/
|
||||
export async function hasVersionByUser(docId: string, userId: string): Promise<boolean> {
|
||||
const [row] = await db
|
||||
.select({ one: sql`1` })
|
||||
.from(documentVersions)
|
||||
.innerJoin(documents, eq(documentVersions.documentId, documents.id))
|
||||
.where(and(eq(documents.docId, docId), eq(documentVersions.userId, userId)))
|
||||
.limit(1);
|
||||
return row !== undefined;
|
||||
}
|
||||
|
||||
export type InsertVersionInput = {
|
||||
/** กำหนดเอง (ไม่ปล่อย defaultRandom) เพราะ object ใน MinIO เขียนด้วย uuid นี้ไปก่อนแล้ว */
|
||||
versionId: string;
|
||||
|
|
|
|||
|
|
@ -629,8 +629,9 @@ export const openApiSpec = {
|
|||
"2. **add-in ใน Word** — ไม่ต้องมี `x-api-key` ส่ง body `{ticket_data, HmacSha256}` " +
|
||||
"ตาม schema `TicketTokenRequest` (คู่ค่าที่ e-Court stamp ไว้ใน custom properties " +
|
||||
"ของไฟล์ .docx) — server ตรวจลายเซ็น HMAC-SHA256 ด้วย env `ADDIN_TICKET_SECRET` " +
|
||||
'(ไม่ตั้ง → env `SECRET` → `"super_secret"`) และเวลาหมดอายุ (`exp`) ของ ticket ' +
|
||||
"ก่อน แล้วออก token จาก claims ที่อยู่ในตัว ticket เอง\n\n" +
|
||||
'(ไม่ตั้ง → env `SECRET` → `"super_secret"`) แล้วออก token จาก claims ที่อยู่ในตัว ticket เอง · ' +
|
||||
"**ticket หมดอายุ** ยังออกให้ต่อเมื่อเอกสารนี้ (`fid`) เคยมี version ที่สร้างโดย `uid` เดียวกัน " +
|
||||
"(ผู้ที่เคยทำงานกับเอกสารเดิมกลับมาใช้ต่อได้แม้ ticket หมดอายุ — ไม่เคยทำงาน = 401)\n\n" +
|
||||
"ได้ token แล้วแนบเป็น `Authorization: Bearer <token>` กับทุก request ถัดไป",
|
||||
security: [{ ApiKeyAuth: [] }],
|
||||
requestBody: {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue