Skip to content

3.2.7 · External integrations

บทนี้ catalog การเชื่อมต่อกับระบบภายนอกของ cu-central-api — 6 integrations ที่ cu-central-api เป็น service เดียวใน VTRC topology ที่เรียก


Integration map

┌─────────────────────────────────────────────────────────────┐
│  cu-central-api                                             │
└─────┬───────────────────────────────────────────────────────┘

      ├──▶ SSO              (lib/sso/)        — committed certs
      ├──▶ Conicle SFTP     (lib/conicle/)    — ssh2-sftp-client
      ├──▶ HIS heal-card    (lib/his/)        — HTTP API
      ├──▶ HRMI HTTP API    (lib/hrmi/)       — native http/https
      ├──▶ SMS gateway      (lib/notification/) — HTTP
      └──▶ SMTP             (lib/mailer/)     — nodemailer

1 · SSO integration (lib/sso/)

SSO ของ Red Cross — cu-central-api เป็น SSO client ที่เรียก SSO service เพื่อ authenticate เพิ่มเติมจาก LDAP

Committed certificates

cu-central-api/main-api/src/lib/sso/
├── DigiCert_Global_Root_CA.cer       ← root CA
├── TPRDWSSOWEB01.crt                  ← prod SSO cert
└── TUATWSSOWEB01.crt                  ← UAT SSO cert

certificate ของ SSO service (ทั้ง prod + UAT) commit อยู่ใน repo

  • เป็น public cert ไม่ใช่ private key — จึงไม่ใช่ secret leak โดยตรง
  • แต่เป็น anti-pattern — cert ควร fetch จาก secret manager หรือ truststore แทน

AES encryption

config (config.js:101-102)

AES_SECRET_KEY = ''     (env, default empty)
AES_INIT_VECTOR = ''    (env, default empty)

ใช้สำหรับ encrypt/decrypt payload ระหว่าง cu-central-api กับ SSO service

🔴 keys ทั้งสอง default เป็น empty string — ถ้า env unset การ encrypt ไม่ทำงาน (silent failure ถ้า code path ไม่ตรวจ)

.env.develop-test committed values

AES_SECRET_KEY="EoABvcD7RsFBeKRZgSOHS4LLD08To6Pc"
AES_INIT_VECTOR="AaNZRKzytx9yCAiA"

(รายละเอียด cover ใน Volume 12 Security)

ssoLogin integration ใน signin flow

ถูกเรียกหลัง Auth.signIn ใน routes.js:25 (cu-central-api/main-api/src/routes.js:25) — password ถูก forward ไป SSO service ด้วย เพื่อ mint SSO token ควบคู่กับ AD JWT


2 · Conicle SFTP (lib/conicle/)

Conicle เป็น learning management system ที่ Red Cross ใช้ — cu-central-api push ข้อมูลการเรียนผ่าน SFTP

Library

"ssh2-sftp-client": "^6.0.1"

Files

cu-central-api/main-api/src/models/hrmi/conicle/
├── conicleFIleLog.js     (typo "FIle")
├── longTerm.js           ← long-term learning records
├── migrateConicle.js
└── shortTerm.js          ← short-term learning records

Cron job

  // Every day at 03:45.
  jobs.push(schedule.scheduleJob('40 3 * * *', async () => {
    await cronMethods.conicleTransferLongTerm()
  }))

daily 03:40 — SFTP push long-term records ไป Conicle

Manual trigger

  app.post(`${API_PREFIX_PATH}/conicle/longterm`, urlencodedParser, async (req, res) => {
    const params = req.body
    if (typeof params.runLong !== 'undefined' && params.runLong === '20k') {
      console.log('Run Long term and send to Conicle.')
      await transferFileToConicle('long')
      console.log('Run finished.')
    }
    res.send('OK').end()
  })

trigger ด้วย magic value runLong=20k — pattern ที่ fragile (ไม่มี auth, ใครก็เรียกได้)

Config

CONICLE_DEST_SHORT_TERM_PATH = '/upload/inbound_files/stg/short_term/'
CONICLE_DEST_LONG_TERM_PATH = '/upload/inbound_files/stg/long_term/'
CONICLE_SFTP_HOST / PORT / USERNAME / PASSWORD

password อยู่ใน env (CONICLE_SFTP_PASSWORD)


3 · HIS heal-card (lib/his/)

HIS = Hospital Information System — cu-central-api ดึงข้อมูล heal-card discount จาก HIS API

Cron job

  jobs.push(schedule.scheduleJob('8 * * * *', async () => {
    console.log("In cron funciton.")
    await cronMethods.hisTransferLongTerm()
  }))

hourly — pull heal-card discount จาก HIS API มาเก็บใน dbHRMI_Center_HIS

Models

cu-central-api/main-api/src/models/hrmiHis/healCard/
├── healCardDiscount.js       ← HealCardDiscount
└── healCardDiscountLog.js    ← HealCardDiscountLog

ทั้งสองอยู่ใน connection dbHRMI_Center_HIS (DB schema dbHRMI_Center_HIS)

Library

import axios from 'axios'

HIS integration ใช้ axios (ของแท้) — ต่างจากไฟล์อื่นที่ใช้ native http/https แต่ axios ไม่ได้ declare ใน package.json (มีแค่ axois typo) ดู 3.2.8 §C5


4 · HRMI HTTP API (lib/hrmi/)

นอกจาก MSSQL direct แล้ว cu-central-api ยังเรียก HRMI ผ่าน HTTP API ด้วย (สำหรับ operations ที่ HTTP เป็น interface หลัก)

Library

cu-central-api/main-api/src/lib/hrmi/token.js (ใช้ native http/https)

ไม่ใช้ axios — ใช้ native Node http/https (เหตุผลน่าจะเป็น dependency น้อยกว่า แต่ทำให้ error handling ซับซ้อนกว่า)

Config

HRMI_END_POINT
HRMI_USERNAME
HRMI_PASSWORD
WS_HRMI_END_POINT              ← SOAP endpoint (legacy)
STACK_REQUEST_LIMIT = 300
TIME_PER_STACK_REQUEST = 100ms

STACK_REQUEST_LIMIT จำกัดการยิง batch 300 request ต่อ stack — pattern สำหรับ rate-limit ฝั่ง client

  STACK_REQUEST_LIMIT = 300,
  TIME_PER_STACK_REQUEST = 100, // millisec

Use case

  • ดึง approver chain สำหรับ leave workflow (hrmi.js resolver → hrmiLeave.getLeaveApprover)
  • ดึง medical expenses reference
  • อ่าน organization structure

5 · SMS gateway (lib/notification/)

ส่ง OTP + notification ผ่าน SMS gateway

Config

SMS_RESENT_SECONDS = 30
SMS_OTP_EXPIRE_MINUTES = 3
SMS_GATEWAY_URL
SMS_GATEWAY_KEY
SMS_SANDBOX_PHONE_NUMBER      ← bypass production SMS ใน UAT
  SMS_RESENT_SECONDS = 30,
  SMS_OTP_EXPIRE_MINUTES = 3,
  SMS_GATEWAY_URL = '',
  SMS_GATEWAY_KEY = '',
  SMS_SANDBOX_PHONE_NUMBER = '',

Library

HTTP POST ไป SMS_GATEWAY_URL พร้อม SMS_GATEWAY_KEY

ใช้ lib/httpRequest.js ที่ import axios (ที่ไม่ได้ declare — ดู 3.2.8 §C5)

import { httpPost } from './httpRequest'

🔴 httpRequest.js import axois (typo) จาก package.json — ถ้า SMS code path ทำงานจะ crash เพราะ module resolution ใช้ชื่อผิด


6 · SMTP / email (lib/mailer/)

ส่ง email ผ่าน nodemailer

Library

"email-templates": "^7.1.1"     ← pug-based templates
"nodemailer": "^6.4.11"

Templates

cu-central-api/main-api/src/email-templates/
└── requestResetPassword/
    ├── html.pug
    └── subject.pug

template เดียวที่มี — สำหรับ reset password flow

Config

SMTP_HOST
SMTP_USERNAME
SMTP_PASSWORD
SMTP_PORT
SMTP_SECURE
EMAIL_TLS_REJECT_UNAUTHORIZED = null   ← 🟡 ถ้า set เป็น false = TLS ปิด
EMAIL_SEND_FROM
EMAIL_BCC_RECEIVE_BACKUP
  SMTP_HOST = '',
  SMTP_USERNAME = '',
  SMTP_PASSWORD = '',
  SMTP_PORT = '',
  SMTP_SECURE = '',
  // Using for SMTP host is not required authorize.
  // You can set to false
  EMAIL_TLS_REJECT_UNAUTHORIZED = null,
  EMAIL_SEND_FROM = '',
  EMAIL_BCC_RECEIVE_BACKUP,

🔴 EMAIL_TLS_REJECT_UNAUTHORIZED เป็น env ที่สามารถปิด TLS verification ได้ — ถ้า set false ในการ deploy ใด email จะถูกส่งผ่าน unencrypted channel (MITM risk)


Dependency overview

IntegrationLibraryVersionสถานะ
SSOnative crypto + AES🟡 committed certs + AES key default empty
Conicle SFTPssh2-sftp-client^6.0.1🟢 OK
HISaxios (ไม่ declare)🔴 missing dep — crash risk
HRMI HTTPnative http/https🟢 OK
SMSnative HTTP + lib/httpRequest.js🔴 httpRequest.js ใช้ axois typo
SMTPnodemailer + email-templates^6.4.11 / ^7.1.1🟡 EMAIL_TLS_REJECT_UNAUTHORIZED อาจปิด TLS

Cross-cutting concerns

Timeout

ไม่มี centralized timeout config — แต่ละ integration ตั้ง timeout เอง (หรือไม่ตั้งเลย)

IntegrationTimeoutSource
MSSQLrequestTimeout: 30000connector.js:15
LDAP(ไม่มี — ใช้ default)activeDirectory.connector.js
SSO(ไม่มี)
Conicle SFTP(default ssh2)
HIS(ไม่มี)
HRMI HTTPSTACK_REQUEST_LIMIT (แต่ไม่ใช่ timeout)
SMS(ไม่มี)
SMTP(default nodemailer)

🔴 ถ้า upstream service down บางตัว (เช่น SSO, HIS) request อาจ hang ไม่มี timeout

Retry

ไม่มี retry logic — ถ้า integration fail จะ throw โดยตรง (หรือในบางกรณี catch + log + return null — silent failure)

Circuit breaker

ไม่มี — ถ้า upstream down ทุก request จะพยายามเชื่อมต่อไปเรื่อย ๆ


Secret management

SecretStorage
SSO AES key + IVenv (AES_SECRET_KEY, AES_INIT_VECTOR)
Conicle SFTP passwordenv (CONICLE_SFTP_PASSWORD)
HRMI passwordenv (HRMI_PASSWORD)
SMS gateway keyenv (SMS_GATEWAY_KEY)
SMTP passwordenv (SMTP_PASSWORD)
AD service accountenv (AD_USERNAME, AD_PASSWORD)
SSO username/passwordenv (SSO_USERNAME, SSO_PASSWORD)
MSSQL passwordenv (DB_PASSWORD)
JWT signing keyenv (JWT_SECRET)
HMAC keyenv (HASH_KEY)

ทุก secret อยู่ใน env — แต่ .env.develop-test (UAT) commit อยู่ใน repo (Volume 12 Security)


สรุป integration health

IntegrationSeverityปัญหา
SSO🟡committed certs + AES key default empty
Conicle SFTP🟢
HIS🔴import axios ที่ไม่ declare — crash risk
HRMI HTTP🟢
SMS🔴ผ่าน httpRequest.js ที่ import axois typo — crash risk
SMTP🟡EMAIL_TLS_REJECT_UNAUTHORIZED env ที่อาจปิด TLS
Cross-cutting🔴ไม่มี timeout/retry/circuit breaker
Manual trigger /conicle/longterm🟡ไม่มี auth — magic value เป็น secret เพียงตัวเดียว

อ่านต่อ → 3.2.8 Security + debt