7.1.4 · Scorecard — meeting-vtrc-api (V1 depth)
branch: prod-meeting-vtrc-api (180 tracked files)
บทสรุป debt จาก 01 Repository map, 02 Core pipeline, และ 03 Persistence & integrations
อย่าคัดลอกค่า secret / password / PII จริงลง ticket — อ้างชื่อตัวแปรและ file:line
Severity legend
| Level | เกณฑ์ | Action |
|---|---|---|
| Critical | active security / data-loss / availability risk | ปิด surface หรือแก้ก่อน feature ใหม่ |
| High | correctness / auth hygiene hazard | วางแผนใน sprint ถัดไป |
| Medium | friction / hygiene | แก้ตามโอกาส |
| Low | cleanup / consistency | backlog |
Markdown list (สำหรับ raw readability):
- Critical = active security/data-loss/availability risk
- High = correctness/maintainability hazard, real impact
- Medium = friction/hygiene, not yet dangerous
Severity: Critical
SEC-MTVTRC-01 · .env* commit เป็น plaintext พร้อม secret จริง
ที่: .envdev, .envuat, .envprod ใน root repo (ไม่ถูก .gitignore)
Evidence: ไฟล์มี API_KEY, SECRET_JWT_*, MAIL_PASS, และใน .envuat/.envdev มี PASSWORD / HOST ของ MSSQL จริง
Impact: ใครมีสิทธิ์อ่าน repo ได้ credential ครบสำหรับ DB, SMTP, JWT, apiKey — หมุน (rotate) ทุกตัวที่เคย commit แล้ว
Remediation:
- ย้าย secret ไป secret manager / CI env
- เพิ่ม
.env*เข้า.gitignoreเหลือแค่.env.exampleที่ไม่มีค่าจริง - Purge จาก git history
- Rotate ทุก key ที่หลุด
SEC-MTVTRC-02 · GET /meeting/mockuser/one คืน PII จริงโดยไม่มี auth
ที่: routes/mockdelatlast/mockuser.ts:29-60 · mount app.ts:209-210
Evidence:
route.get("/one", async (req, res) => {
const mockdata = {
user: [
{
userID: 5596233,
name: "วินัย ตั้งสกุล",
email: "viani@redcross.or.th",
tel: "0976564322",
},
// ...
],
};
res.status(200).send(mockdata);
});Impact: unauthenticated PII disclosure; ข้อมูลฝังในซอร์สด้วย
Remediation: ลบ route จาก production build; ถ้าต้องมี mock ให้ใช้ข้อมูลสมมติ + ปิดด้วย feature flag / env ≠ prod
SEC-MTVTRC-05 · Global /meeting/secure/* auth ถูก comment — พื้นผิวเปิดเกือบทั้ง API
ที่: app.ts:104-120
Evidence: ก้อน app.all("/meeting/secure/*", checkBypassMiddleWare, checkApiKeyMiddleWare, …) ถูก comment ทั้งชุด; route ส่วนใหญ่ไม่ใส่ middleware เอง
Impact: สร้าง/ลบ/อนุมัติประชุม, ดึงรายชื่อ, สั่งส่งเมล (/corn-email), สร้าง PDF — เรียกได้โดยไม่มี Bearer/apiKey ถ้าระบบ expose path นี้
Remediation:
- เปิด global guard กลับ (หรือใส่ middleware ทีละ route อย่างน้อย mutation)
- ตรวจว่า
checkBypassMiddleWareverify secret ถูกต้อง (ดู SEC-MTVTRC-06) - Rate-limit + WAF ที่ reverse proxy
SEC-MTVTRC-06 · checkBypassMiddleWare ไม่ยิง vtrc และเรียก decodeJwt ผิดลายเซ็น
ที่: middleware/checkbypass.ts:38-78 · util/helper/jwtdecode.ts:12-19
Evidence:
- สร้าง GraphQL query
fetchEmployeeProfileForOtherServiceแต่ไม่vtrcConnector.post - เรียก
decodeJwt(token)ส่ง arg เดียว ในขณะที่ฟังก์ชันต้องการ(token, secert)
Impact: แม้จะเปิด global guard กลับ การตรวจ Bearer ผ่าน middleware นี้ก็ไม่น่าเชื่อถือ; path ที่ไม่มี Bearer ยัง next() ได้ (checkbypass.ts:28-30)
Remediation: ให้ mirror logic จาก checkbypasswhenredirect.ts (verify ด้วย SECRET_JWT_VTRC หรือ meeting secret + ตรวจ TokenMeeting); ปฏิเสธเมื่อไม่มี Bearer แทนการ next()
Severity: High
SEC-MTVTRC-03 · Health-check ส่งอีเมลจริงไปที่อยู่ส่วนบุคคล
ที่: routes/secure/meeting/health-check.ts:9-17 · mount app.ts:230-231
Hardcode address ในซอร์ส; ไม่มี auth; เรียก SMTP จริงทุกครั้ง
Remediation: เปลี่ยนเป็นเช็ค DB/authenticate หรือ SMTP connect โดยไม่ส่งเมล; ถ้าต้องทดสอบ ให้ auth + allowlist
SEC-MTVTRC-07 · Static /meeting/file และ ops hooks ไม่มี auth
| Path | ความเสี่ยง | หลักฐาน |
|---|---|---|
/meeting/file/* | อ่านไฟล์แนบ/PDF ถ้าเดาชื่อได้ | app.ts:147; guard เก่า comment :90-103 |
/meeting/secure/corn-email/ | สั่งส่งเมล+push ทั้งคิว | corn-email.ts:10-14 |
/meeting/secure/meeting/send | sendMail(4403) hardcode | meeting.ts:73-81 |
Remediation: auth บน static (signed URL หรือ Bearer); ลบ/ปิด test hooks ใน prod
SEC-MTVTRC-08 · cdbConnector ฝัง api-key + Bearer JWT ในซอร์ส
ที่: util/axiosinterceptors/cdb.connector.ts:3-26
Impact: credential ถาวรใน git; ทุก environment ใช้ token ชุดเดียวกันตาม interceptor
Remediation: ย้ายเข้า env; rotate; อย่า commit ค่าจริง
CORR-MTVTRC-05 · Cron scheduleEmail() ไม่ถูกเรียกตอน boot
ที่: app.ts:4 require myCorn แต่ไม่เรียก scheduleEmail; นิยามอยู่ที่ corn-job/email.corn.ts:6-18
Impact: ถ้าไม่มี external scheduler ยิง /corn-email อีเมลเชิญจะไม่ออกอัตโนมัติ — availability ของ notification path
Remediation: เรียก myCorn.scheduleEmail() หลัง listen หรือยืนยัน cron ภายนอกแล้วลบ dead module ให้ตรงเอกสาร ops
CORR-MTVTRC-01 · refreshtoken.ts dead + ไม่ persist
ที่: routes/auth/refreshtoken.ts:5-19 — ไม่มี app.use ใน app.ts:148-231
createToken สร้าง uuid แล้ว comment ว่าควรเก็บ DB แต่ไม่เก็บ
Remediation: mount + persist หรือลบไฟล์
Severity: Medium
SEC-MTVTRC-04 · Tinify API key hardcode
ที่: lib/Uploadimage.class.ts:5 — call tinify.fromFile comment ที่ :29-30
Remediation: ลบ key / ย้าย env; rotate key เดิม
CORR-MTVTRC-02 · addNewMeeting ไม่มี transaction
ที่: routes/secure/meeting/meeting.ts:187-243
Insert Meeting → Guest → OtherGuest → Attached แยกกัน — fail กลางทาง = orphan meeting
Remediation: sequelize.transaction() ครอบทั้งชุด
CORR-MTVTRC-03 · Delegate ไม่ส่งอีเมล (call ถูก comment)
ที่: acceptancemeeting.ts:125
Remediation: uncomment + ทดสอบ หรือลบ dead sendMailToDelegate
CORR-MTVTRC-04 · ScheduleJob ดึงเฉพาะของ "วันนี้"
ที่: util/helper/corn.email.helper.ts:19-47
executeTime > TODAY_START AND < NOW — งานค้างข้ามวันหาย
Remediation: jobStatus=ACTIVE AND executeTime <= NOW โดยไม่ผูกวัน
CORR-MTVTRC-06 · emailTask mark DONE ก่อน push สำเร็จอย่างสมบูรณ์ / ไม่มี per-item try
ที่: corn.email.helper.ts:107-114
ลำดับ: sendMail → DONE → sendNoti — push fail แล้ว job ไม่ retry; exception ใน loop หยุดงานที่เหลือ
Remediation: try/catch ราย job; แยกสถานะ mail/push หรือ mark DONE หลังทั้งคู่สำเร็จ
CORR-MTVTRC-07 · OtherGuest.belongsTo(OtherGuest) น่าจะผิด
ที่: model/meeting/meeting.ts:531
Remediation: แก้เป็น belongsTo(Meeting) แล้ว regression test include queries
QUAL-MTVTRC-01 · Mongoose dependency + mongo.config ตายแล้ว
ที่: app.ts:8, package.json:42, util/mongo.config.ts:1-14
Remediation: ลบ dependency และไฟล์; อัปเดตเอกสารที่ไม่ให้บอกว่าเป็น Mongoose stack
QUAL-MTVTRC-02 · model/login.ts นอก domain
ที่: model/login.ts:1-122, db.config.ts:43
Remediation: ยืนยันกับทีมแล้วลบถ้าไม่ใช้
QUAL-MTVTRC-03 · emailsender.ts vs Emailsender.func.ts
ที่: util/helper/emailsender.ts, lib/Emailsender.func.ts
Remediation: เปลี่ยนชื่อให้ต่างชัด (เช่น emailQueue.ts / emailTransport.ts)
QUAL-MTVTRC-04 · สะกด corn แทน cron ทั้ง public path
ที่: corn-job/, routes/secure/meeting/corn-email.ts, app.ts:228-229
Remediation: deprecation ก่อนเปลี่ยน path; หรือคง path เดิมแล้วแก้ชื่อภายในอย่างเดียว
QUAL-MTVTRC-05 · Dockerfile มีอยู่แต่ npm start บังคับ NODE_ENV=dev
ที่: Dockerfile:1-28, package.json:7
เอกสารเก่าระบุว่าไม่มี Dockerfile — แก้แล้ว: มีไฟล์จริง
ความเสี่ยงที่เหลือ: container prod อาจโหลด logic แบบ NODE_ENV != production ใน Emailsender / redirect middleware (อ่าน .envdev)
Remediation: แยก script start:prod; ส่ง NODE_ENV ตาม ARG
QUAL-MTVTRC-06 · Swagger definition เป็น JSONPlaceholder placeholder
ที่: app.ts:50-71, apis glob ./routes//.ts (:75) น่าจะผิด
Remediation: อัปเดต OpenAPI ให้ตรง route จริง หรือถอด /docs จาก prod
QUAL-MTVTRC-07 · Import auth ใน PDF/attachment แต่ไม่ apply
ที่: createpdfinvitemeeting.ts:10-13,44, attacment.ts:7-10,29
Remediation: ใส่ middleware ใน route.post/get หรือลบ import ที่ทำให้เข้าใจผิด
OBS-MTVTRC-01 · Sentry DSN hardcode ร่วมทุก environment
ที่: app.ts:80, tracesSampleRate: 1.0 (:85)
Remediation: DSN จาก env; ลด sample rate ใน prod
OBS-MTVTRC-02 · bodyParser limit 500mb
ที่: app.ts:123
Impact: memory DoS ถ้าไม่มี limit ที่ proxy
Remediation: ลด limit ให้สมเหตุสมผล + limit ที่ nginx
ตารางสรุปเร็ว
| ID | ระดับ | หัวข้อสั้น |
|---|---|---|
| SEC-MTVTRC-01 | Critical | .env* secrets in git |
| SEC-MTVTRC-02 | Critical | mockuser PII leak |
| SEC-MTVTRC-05 | Critical | global auth commented out |
| SEC-MTVTRC-06 | Critical | checkbypass broken verify |
| SEC-MTVTRC-03 | High | health-check sends real email |
| SEC-MTVTRC-07 | High | static files + ops hooks open |
| SEC-MTVTRC-08 | High | cdbConnector hardcode tokens |
| CORR-MTVTRC-05 | High | cron never started |
| CORR-MTVTRC-01 | High | refreshtoken dead |
| SEC-MTVTRC-04 | Medium | Tinify key |
| CORR-MTVTRC-02..07 | Medium | transaction, delegate mail, job window, DONE order, OtherGuest assoc |
| QUAL-MTVTRC-01..07 | Medium | mongoose, login model, filenames, corn typo, Dockerfile/NODE_ENV, swagger, dead auth imports |
| OBS-MTVTRC-01..02 | Medium | Sentry DSN, 500mb body |
เคล็ดลับตอนทำงานจริง
- Debug "อีเมลไม่ไป" → ดูแถว
ScheduleJob(ACTIVE?) → ยืนยันว่ามีใครยิง/corn-emailหรือscheduleEmailจริง → แล้วค่อย SMTP/MAIL_PASS - Path มีคำว่า
secureอย่าเชื่อ — เปิดapp.ts+ ไฟล์ route - Push ไม่ขึ้น → ดู
sendNoti+VTRC_BASE_CONNECT+API_KEY_OUTBOUND_VTRCฝั่ง vtrc-api mutationsendNotificationFrom3Party db.loginไม่ใช่ user จริงของระบบประชุม — user มาจาก GraphQL employee directory- อย่าเปิด
/meeting/mockuser/oneใน demo ที่บันทึก network
สิ่งที่ตรวจแล้ว / ยังไม่ตรวจ
ตรวจแล้วจากซอร์สบน prod-meeting-vtrc-api | ยังไม่ตรวจ |
|---|---|
Route mount ทั้งหมดใน app.ts | พฤติกรรม runtime บน UAT/prod จริง |
| Model fields + associations | DDL จริงบน MSSQL / seed StatusResponse |
| sendNoti mutation shape | ว่า vtrc-api รับ variables รูปแบบนี้สำเร็จหรือไม่ |
| Dockerfile + compose | pipeline CI ที่ส่ง ENV build-arg |
| Auth commented + mock leak | penetration test เต็มรูปแบบ |