Add new template format with hashing algorithm
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 1m18s
Deploy eCourt Note Web to Server / Deploy eCourt Note Web to Server (push) Successful in 6s
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 1m18s
Deploy eCourt Note Web to Server / Deploy eCourt Note Web to Server (push) Successful in 6s
Deploy eCourt Note Web to Server / Notify Deployment Status (push) Successful in 0s
This commit is contained in:
parent
280cc2da40
commit
ac6c0dc71e
17 changed files with 2157 additions and 609 deletions
1263
lib/lib-tmpl.ts
Executable file
1263
lib/lib-tmpl.ts
Executable file
File diff suppressed because it is too large
Load diff
112
lib/lib-utils.ts
Normal file
112
lib/lib-utils.ts
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
|
||||
import { createHmac, createPrivateKey, createPublicKey, timingSafeEqual, verify, sign } from 'node:crypto';
|
||||
/**
|
||||
* คำนวณ HMAC-SHA256 จาก string หรือ JSON Object
|
||||
*/
|
||||
export function generateHmacSha256(data: string | object, secretKey: string): string {
|
||||
const payload = typeof data === 'string' ? data : JSON.stringify(data);
|
||||
return createHmac('sha256', secretKey)
|
||||
.update(payload, 'utf8')
|
||||
.digest('hex');
|
||||
}
|
||||
|
||||
/**
|
||||
* ตรวจสอบความถูกต้องของ HMAC (ใช้ timingSafeEqual เพื่อป้องกัน Timing Attacks)
|
||||
*/
|
||||
export function verifyHmacSha256(data: string | object, secretKey: string, expectedHmac: string): boolean {
|
||||
const calculatedHmac = generateHmacSha256(data, secretKey);
|
||||
const a = Buffer.from(calculatedHmac, 'hex');
|
||||
const b = Buffer.from(expectedHmac, 'hex');
|
||||
|
||||
if (a.length !== b.length) {
|
||||
return false;
|
||||
}
|
||||
return timingSafeEqual(a, b);
|
||||
}
|
||||
// ==========================================
|
||||
// ตัวอย่างการใช้งาน
|
||||
// ==========================================
|
||||
/*
|
||||
const secret = 'my-super-secret-key';
|
||||
const jsonData = {
|
||||
userId: 12345,
|
||||
action: 'transfer',
|
||||
amount: 500
|
||||
};
|
||||
|
||||
// 1. สร้าง HMAC
|
||||
const hmacSignature = generateHmacSha256(jsonData, secret);
|
||||
console.log('HMAC Signature (Hex):', hmacSignature);
|
||||
|
||||
// 2. ตรวจสอบ HMAC
|
||||
const isValid = verifyHmacSha256(jsonData, secret, hmacSignature);
|
||||
console.log('Is Signature Valid?:', isValid); // true
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* ฟังก์ชันสำหรับลงนามดิจิทัล (Sign) ข้อมูลด้วย Ed25519 Private Key (Hex)
|
||||
* @param message ข้อความดิบที่ต้องการเซ็น (string หรือ Buffer)
|
||||
* @param privateKeyHex คีย์ลับในรูปแบบ Hex String (ความยาว 64 ตัวอักษร)
|
||||
* @returns ลายเซ็น (Signature) ในรูปแบบ Hex String (ความยาว 128 ตัวอักษร)
|
||||
*/
|
||||
export function signDataEd25519(message: string | Buffer, privateKeyHex: string): string {
|
||||
const rawKeyBuffer = Buffer.from(privateKeyHex, 'hex');
|
||||
// ตัดเอาเฉพาะ 32 bytes (Seed) กรณีที่ Hex ยาว 64 bytes (ที่ต่อกับ Public Key มา)
|
||||
const seed = rawKeyBuffer.length === 64 ? rawKeyBuffer.subarray(0, 32) : rawKeyBuffer;
|
||||
// PKCS#8 Header สำหรับ Ed25519 Private Key
|
||||
const pkcs8Header = Buffer.from('302e020100300506032b657004220420', 'hex');
|
||||
const pkcs8Buffer = Buffer.concat([pkcs8Header, seed]);
|
||||
|
||||
const privateKey = createPrivateKey({
|
||||
key: pkcs8Buffer,
|
||||
format: 'der',
|
||||
type: 'pkcs8',
|
||||
});
|
||||
|
||||
const dataBuffer = typeof message === 'string' ? Buffer.from(message, 'utf-8') : message;
|
||||
const signatureBuffer = sign(null, dataBuffer, privateKey);
|
||||
return signatureBuffer.toString('hex');
|
||||
}
|
||||
|
||||
/**
|
||||
* ฟังก์ชันสำหรับตรวจสอบลายเซ็น (Verify) ด้วย Ed25519 Public Key (Hex)
|
||||
* @param message ข้อความดิบที่ใช้ในการเซ็น (string หรือ Buffer)
|
||||
* @param signatureHex ลายเซ็นในรูปแบบ Hex String
|
||||
* @param publicKeyHex คีย์สาธารณะในรูปแบบ Hex String (ความยาว 64 ตัวอักษร)
|
||||
* @returns ผลลัพธ์ความถูกต้อง (true = ผ่าน, false = ไม่ผ่าน)
|
||||
*/
|
||||
export function verifyDataEd25519(message: string | Buffer, signatureHex: string, publicKeyHex: string): boolean {
|
||||
try {
|
||||
const rawPublicKey = Buffer.from(publicKeyHex, 'hex');
|
||||
|
||||
// SPKI Header สำหรับ Ed25519 Public Key (32 bytes)
|
||||
const spkiHeader = Buffer.from('302a300506032b6570032100', 'hex');
|
||||
const spkiBuffer = Buffer.concat([spkiHeader, rawPublicKey]);
|
||||
|
||||
const publicKey = createPublicKey({
|
||||
key: spkiBuffer,
|
||||
format: 'der',
|
||||
type: 'spki',
|
||||
});
|
||||
|
||||
const dataBuffer = typeof message === 'string' ? Buffer.from(message, 'utf-8') : message;
|
||||
const signatureBuffer = Buffer.from(signatureHex, 'hex');
|
||||
|
||||
return verify(null, dataBuffer, publicKey, signatureBuffer);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ฟังก์ชันสำหรับเรียงคีย์ของ Object ตามตัวอักษรเพื่อไม่ให้โครงสร้าง JSON เพี้ยน
|
||||
*/
|
||||
export function sortObjectKeys(obj: Record<string, unknown>): Record<string, unknown> {
|
||||
return Object.keys(obj)
|
||||
.sort()
|
||||
.reduce((result: Record<string, unknown>, key: string) => {
|
||||
result[key] = obj[key];
|
||||
return result;
|
||||
}, {});
|
||||
}
|
||||
|
|
@ -92,6 +92,20 @@ export const openApiSpec = {
|
|||
format: "binary",
|
||||
description: "ไฟล์ .docx ที่มี Content Control",
|
||||
},
|
||||
secret: {
|
||||
type: "string",
|
||||
description:
|
||||
"ค่า secret สำหรับ validate HMAC-SHA256 กับข้อมูลใน custom property" ,
|
||||
example:
|
||||
"super_secret",
|
||||
},
|
||||
public_key: {
|
||||
type: "string",
|
||||
description:
|
||||
"Public key ในรูปแบบ HEX <br/> openssl genpkey -algorithm ED25519 -out private.pem <br/> openssl pkey -in private.pem -outform DER | tail -c 32 | xxd -p -c 32 > private.hex <br/>openssl pkey -in private.pem -pubout -outform DER | tail -c 32 | xxd -p -c 32 > public.hex",
|
||||
example:
|
||||
"66b09b4a1b66271d5728c592c2409657e1c070a7bf371bf9f6ed457855270546",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -140,9 +154,23 @@ export const openApiSpec = {
|
|||
dataJson: {
|
||||
type: "string",
|
||||
description:
|
||||
"JSON เป็น string ตรง ๆ (ทางเลือกแทนการแนบไฟล์ data)",
|
||||
"JSON เป็น string ตรง ๆ (ทางเลือกแทนการแนบไฟล์ data)<br/>{\"info:\"{\"ticket_data\":\"JSON String\"},\"dc:\"{..},\"dc:\"{\"blackyear\": \"๙๐/๒๕๖๙\",...}}",
|
||||
example:
|
||||
'{"notname":"คำสั่งเรียก ให้ทำคำให้การ","blackno":"คดีหมายเลขดำที่","blackyear":"๑๐/๒๕๖๙"}',
|
||||
'',
|
||||
},
|
||||
secret: {
|
||||
type: "string",
|
||||
description:
|
||||
"ค่า secret สำหรับทดสอบการทำ HMAC-SHA256",
|
||||
example:
|
||||
'super_secret',
|
||||
},
|
||||
private_key: {
|
||||
type: "string",
|
||||
description:
|
||||
"Private key ในรูปแบบ HEX <br/> openssl genpkey -algorithm ED25519 -out private.pem <br/> openssl pkey -in private.pem -outform DER | tail -c 32 | xxd -p -c 32 > private.hex <br/>openssl pkey -in private.pem -pubout -outform DER | tail -c 32 | xxd -p -c 32 > public.hex",
|
||||
example:
|
||||
'8f2077b57b39399b6a7828f35da03a63ade8e3a36a6bf437b091a8bdb3d18ee1',
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue