playttm 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/lib.d.ts CHANGED
@@ -1,4 +1,8 @@
1
1
  export declare const isBrowserEnvironment: () => boolean;
2
+ /**
3
+ * Extract transaction amount from EMVCo / ThaiQR payload (Tag 54)
4
+ */
5
+ export declare const parseThaiQRAmount: (qrCode?: string) => string | null;
2
6
  export interface TTMConfig {
3
7
  cookies?: string;
4
8
  headers?: Record<string, string>;
@@ -81,12 +85,14 @@ export declare class ThaiTicketMajor {
81
85
  inBrowser: boolean;
82
86
  private rawCookies?;
83
87
  constructor(config?: TTMConfig);
88
+ static readonly BOT_PROTECTION_COOKIES: Set<string>;
84
89
  /**
85
90
  * Synchronize a cookie string into Chrome Extension's cookie store (chrome.cookies API).
91
+ * Automatically ignores bot protection cookies (Akamai _abck, bm_*, WAF) to prevent Access Denied (403) bans.
86
92
  */
87
93
  static syncCookiesToChrome(cookieString: string, domainUrl?: string): Promise<void>;
88
94
  /**
89
- * Setup declarativeNetRequest session rules in Chrome Extension to set Referer and Origin headers
95
+ * Setup declarativeNetRequest session rules in Chrome Extension to set Referer header for API requests only.
90
96
  */
91
97
  static setupExtensionRules(): Promise<void>;
92
98
  syncCookies(domainUrl?: string): Promise<void>;
package/dist/lib.js CHANGED
@@ -45,7 +45,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
45
45
  return (mod && mod.__esModule) ? mod : { "default": mod };
46
46
  };
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
- exports.displayQRCode = exports.ThaiTicketMajor = exports.isBrowserEnvironment = void 0;
48
+ exports.displayQRCode = exports.ThaiTicketMajor = exports.parseThaiQRAmount = exports.isBrowserEnvironment = void 0;
49
49
  const axios_1 = __importDefault(require("axios"));
50
50
  const cheerio = __importStar(require("cheerio"));
51
51
  const axios_cookiejar_support_1 = require("axios-cookiejar-support");
@@ -64,6 +64,23 @@ const isBrowserEnvironment = () => {
64
64
  return false;
65
65
  };
66
66
  exports.isBrowserEnvironment = isBrowserEnvironment;
67
+ /**
68
+ * Extract transaction amount from EMVCo / ThaiQR payload (Tag 54)
69
+ */
70
+ const parseThaiQRAmount = (qrCode) => {
71
+ if (!qrCode)
72
+ return null;
73
+ const match = qrCode.match(/(?:^|[^0-9])54(\d{2})([0-9.]+)/);
74
+ if (match) {
75
+ const len = parseInt(match[1], 10);
76
+ const amountStr = match[2].substring(0, len);
77
+ if (!isNaN(parseFloat(amountStr))) {
78
+ return amountStr;
79
+ }
80
+ }
81
+ return null;
82
+ };
83
+ exports.parseThaiQRAmount = parseThaiQRAmount;
67
84
  // ==========================================
68
85
  // Main Library Class
69
86
  // ==========================================
@@ -109,6 +126,7 @@ class ThaiTicketMajor {
109
126
  }
110
127
  /**
111
128
  * Synchronize a cookie string into Chrome Extension's cookie store (chrome.cookies API).
129
+ * Automatically ignores bot protection cookies (Akamai _abck, bm_*, WAF) to prevent Access Denied (403) bans.
112
130
  */
113
131
  static syncCookiesToChrome(cookieString_1) {
114
132
  return __awaiter(this, arguments, void 0, function* (cookieString, domainUrl = "https://booking.thaiticketmajor.com") {
@@ -128,6 +146,11 @@ class ThaiTicketMajor {
128
146
  const value = trimmed.substring(eqIndex + 1).trim();
129
147
  if (!name)
130
148
  continue;
149
+ // DO NOT overwrite Akamai / WAF bot tokens!
150
+ // Writing stale _abck or bm_* triggers Akamai Bot Protection -> Access Denied.
151
+ if (ThaiTicketMajor.BOT_PROTECTION_COOKIES.has(name.toLowerCase())) {
152
+ continue;
153
+ }
131
154
  try {
132
155
  yield chrome.cookies.set({
133
156
  url: domainUrl,
@@ -152,11 +175,11 @@ class ThaiTicketMajor {
152
175
  });
153
176
  }
154
177
  /**
155
- * Setup declarativeNetRequest session rules in Chrome Extension to set Referer and Origin headers
178
+ * Setup declarativeNetRequest session rules in Chrome Extension to set Referer header for API requests only.
156
179
  */
157
180
  static setupExtensionRules() {
158
181
  return __awaiter(this, void 0, void 0, function* () {
159
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
182
+ var _a, _b, _c, _d, _e, _f, _g;
160
183
  if (typeof chrome === "undefined" || !((_a = chrome === null || chrome === void 0 ? void 0 : chrome.declarativeNetRequest) === null || _a === void 0 ? void 0 : _a.updateSessionRules)) {
161
184
  return;
162
185
  }
@@ -175,20 +198,12 @@ class ThaiTicketMajor {
175
198
  operation: ((_c = chrome.declarativeNetRequest.HeaderOperation) === null || _c === void 0 ? void 0 : _c.SET) || "set",
176
199
  value: "https://booking.thaiticketmajor.com",
177
200
  },
178
- {
179
- header: "Origin",
180
- operation: ((_d = chrome.declarativeNetRequest.HeaderOperation) === null || _d === void 0 ? void 0 : _d.SET) || "set",
181
- value: "https://booking.thaiticketmajor.com",
182
- },
183
201
  ],
184
202
  },
185
203
  condition: {
186
204
  urlFilter: "thaiticketmajor.com",
187
205
  resourceTypes: [
188
- ((_e = chrome.declarativeNetRequest.ResourceType) === null || _e === void 0 ? void 0 : _e.XMLHTTPREQUEST) || "xmlhttprequest",
189
- ((_f = chrome.declarativeNetRequest.ResourceType) === null || _f === void 0 ? void 0 : _f.SUB_FRAME) || "sub_frame",
190
- ((_g = chrome.declarativeNetRequest.ResourceType) === null || _g === void 0 ? void 0 : _g.MAIN_FRAME) || "main_frame",
191
- ((_h = chrome.declarativeNetRequest.ResourceType) === null || _h === void 0 ? void 0 : _h.OTHER) || "other",
206
+ ((_d = chrome.declarativeNetRequest.ResourceType) === null || _d === void 0 ? void 0 : _d.XMLHTTPREQUEST) || "xmlhttprequest",
192
207
  ],
193
208
  },
194
209
  },
@@ -196,11 +211,11 @@ class ThaiTicketMajor {
196
211
  id: 1002,
197
212
  priority: 1,
198
213
  action: {
199
- type: ((_j = chrome.declarativeNetRequest.RuleActionType) === null || _j === void 0 ? void 0 : _j.MODIFY_HEADERS) || "modifyHeaders",
214
+ type: ((_e = chrome.declarativeNetRequest.RuleActionType) === null || _e === void 0 ? void 0 : _e.MODIFY_HEADERS) || "modifyHeaders",
200
215
  requestHeaders: [
201
216
  {
202
217
  header: "Referer",
203
- operation: ((_k = chrome.declarativeNetRequest.HeaderOperation) === null || _k === void 0 ? void 0 : _k.SET) || "set",
218
+ operation: ((_f = chrome.declarativeNetRequest.HeaderOperation) === null || _f === void 0 ? void 0 : _f.SET) || "set",
204
219
  value: "https://kpaymentgateway.kasikornbank.com/",
205
220
  },
206
221
  ],
@@ -208,8 +223,7 @@ class ThaiTicketMajor {
208
223
  condition: {
209
224
  urlFilter: "kasikornbank.com",
210
225
  resourceTypes: [
211
- ((_l = chrome.declarativeNetRequest.ResourceType) === null || _l === void 0 ? void 0 : _l.XMLHTTPREQUEST) || "xmlhttprequest",
212
- ((_m = chrome.declarativeNetRequest.ResourceType) === null || _m === void 0 ? void 0 : _m.OTHER) || "other",
226
+ ((_g = chrome.declarativeNetRequest.ResourceType) === null || _g === void 0 ? void 0 : _g.XMLHTTPREQUEST) || "xmlhttprequest",
213
227
  ],
214
228
  },
215
229
  },
@@ -799,7 +813,7 @@ class ThaiTicketMajor {
799
813
  */
800
814
  quickBook(options) {
801
815
  return __awaiter(this, void 0, void 0, function* () {
802
- var _a, _b, _c, _d;
816
+ var _a, _b, _c, _d, _e;
803
817
  const { eventUrl, roundIndex = 0, roundId, zoneId, ticketCount = 1, seatSelection = "random", attendees = [], deliveryType = "1", payType = "KBQR", paymentDelayMs = 1500, } = options;
804
818
  if (options.onProgress) {
805
819
  this.onProgressCallback = options.onProgress;
@@ -928,7 +942,14 @@ class ThaiTicketMajor {
928
942
  const orderEncData = yield this.orderEncKBankQR(zoneData.k, payCfmData);
929
943
  const kbankInfo = yield this.getKBankQR(orderEncData);
930
944
  const kbankAuth = yield this.paymentKBankQR(orderEncData, kbankInfo);
931
- const qrResult = yield this.generateThaiQR(kbankAuth.orderId, kbankAuth.apiKey, orderEncData.amount);
945
+ const targetAmount = orderEncData.transactionamount ||
946
+ orderEncData.totalamount ||
947
+ orderEncData.amount ||
948
+ payCfmData.amount ||
949
+ kbankInfo.totalamount ||
950
+ paymentAllData["cal_totalamount"] ||
951
+ "0";
952
+ const qrResult = yield this.generateThaiQR(kbankAuth.orderId, kbankAuth.apiKey, targetAmount);
932
953
  const qrRawCode = (qrResult === null || qrResult === void 0 ? void 0 : qrResult.paint_text) ||
933
954
  (qrResult === null || qrResult === void 0 ? void 0 : qrResult.raw_qr_code) ||
934
955
  (qrResult === null || qrResult === void 0 ? void 0 : qrResult.qr_code) ||
@@ -936,8 +957,14 @@ class ThaiTicketMajor {
936
957
  ((_c = qrResult === null || qrResult === void 0 ? void 0 : qrResult.data) === null || _c === void 0 ? void 0 : _c.qr_code) ||
937
958
  ((_d = qrResult === null || qrResult === void 0 ? void 0 : qrResult.data) === null || _d === void 0 ? void 0 : _d.raw_qr_code) ||
938
959
  (typeof qrResult === "string" ? qrResult : "");
960
+ const qrAmount = (0, exports.parseThaiQRAmount)(qrRawCode);
961
+ const finalAmount = qrAmount ||
962
+ (targetAmount && targetAmount !== "0" ? targetAmount : null) ||
963
+ (qrResult === null || qrResult === void 0 ? void 0 : qrResult.amount) ||
964
+ ((_e = qrResult === null || qrResult === void 0 ? void 0 : qrResult.data) === null || _e === void 0 ? void 0 : _e.amount) ||
965
+ "0";
939
966
  const displayQR = (customTitle) => {
940
- const title = customTitle || `ThaiQR Payment (KBank) - ยอดชำระ: ${orderEncData.amount || paymentAllData["cal_totalamount"]} บาท`;
967
+ const title = customTitle || `ThaiQR Payment (KBank) - ยอดชำระ: ${finalAmount} บาท`;
941
968
  ThaiTicketMajor.displayQRCode(qrRawCode, title);
942
969
  };
943
970
  if (options.printQR !== false && qrRawCode) {
@@ -946,7 +973,7 @@ class ThaiTicketMajor {
946
973
  return {
947
974
  success: true,
948
975
  orderId: kbankAuth.orderId,
949
- amount: orderEncData.amount || paymentAllData["cal_totalamount"],
976
+ amount: String(finalAmount),
950
977
  qrRawCode,
951
978
  qrData: qrResult,
952
979
  displayQR,
@@ -957,7 +984,7 @@ class ThaiTicketMajor {
957
984
  venue: paymentAllData["venue"],
958
985
  zone: targetZone.value,
959
986
  ticketCount,
960
- totalAmount: orderEncData.amount || paymentAllData["cal_totalamount"],
987
+ totalAmount: String(finalAmount),
961
988
  seats: summarySeats.length > 0 ? summarySeats : undefined,
962
989
  },
963
990
  rawPayload: {
@@ -989,5 +1016,24 @@ class ThaiTicketMajor {
989
1016
  }
990
1017
  }
991
1018
  exports.ThaiTicketMajor = ThaiTicketMajor;
1019
+ ThaiTicketMajor.BOT_PROTECTION_COOKIES = new Set([
1020
+ "_abck",
1021
+ "bm_sz",
1022
+ "ak_bmsc",
1023
+ "bm_sv",
1024
+ "bm_mi",
1025
+ "hwwafsesid",
1026
+ "hwwafsestime",
1027
+ "__cf_bm",
1028
+ "cf_clearance",
1029
+ "_ga",
1030
+ "_gid",
1031
+ "_gcl_au",
1032
+ "_fbp",
1033
+ "_clck",
1034
+ "_clsk",
1035
+ "_ttp",
1036
+ "_twpid",
1037
+ ]);
992
1038
  exports.displayQRCode = ThaiTicketMajor.displayQRCode;
993
1039
  exports.default = ThaiTicketMajor;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playttm",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Make HTML Metadata to JSON",
5
5
  "main": "dist/lib.js",
6
6
  "types": "dist/lib.d.ts",
package/src/lib.ts CHANGED
@@ -18,6 +18,22 @@ export const isBrowserEnvironment = (): boolean => {
18
18
  return false;
19
19
  };
20
20
 
21
+ /**
22
+ * Extract transaction amount from EMVCo / ThaiQR payload (Tag 54)
23
+ */
24
+ export const parseThaiQRAmount = (qrCode?: string): string | null => {
25
+ if (!qrCode) return null;
26
+ const match = qrCode.match(/(?:^|[^0-9])54(\d{2})([0-9.]+)/);
27
+ if (match) {
28
+ const len = parseInt(match[1], 10);
29
+ const amountStr = match[2].substring(0, len);
30
+ if (!isNaN(parseFloat(amountStr))) {
31
+ return amountStr;
32
+ }
33
+ }
34
+ return null;
35
+ };
36
+
21
37
  // ==========================================
22
38
  // Interfaces & Types
23
39
  // ==========================================
@@ -175,8 +191,29 @@ export class ThaiTicketMajor {
175
191
  }
176
192
  }
177
193
 
194
+ public static readonly BOT_PROTECTION_COOKIES = new Set([
195
+ "_abck",
196
+ "bm_sz",
197
+ "ak_bmsc",
198
+ "bm_sv",
199
+ "bm_mi",
200
+ "hwwafsesid",
201
+ "hwwafsestime",
202
+ "__cf_bm",
203
+ "cf_clearance",
204
+ "_ga",
205
+ "_gid",
206
+ "_gcl_au",
207
+ "_fbp",
208
+ "_clck",
209
+ "_clsk",
210
+ "_ttp",
211
+ "_twpid",
212
+ ]);
213
+
178
214
  /**
179
215
  * Synchronize a cookie string into Chrome Extension's cookie store (chrome.cookies API).
216
+ * Automatically ignores bot protection cookies (Akamai _abck, bm_*, WAF) to prevent Access Denied (403) bans.
180
217
  */
181
218
  public static async syncCookiesToChrome(cookieString: string, domainUrl: string = "https://booking.thaiticketmajor.com"): Promise<void> {
182
219
  if (typeof chrome === "undefined" || !chrome?.cookies?.set) {
@@ -194,6 +231,12 @@ export class ThaiTicketMajor {
194
231
  const value = trimmed.substring(eqIndex + 1).trim();
195
232
  if (!name) continue;
196
233
 
234
+ // DO NOT overwrite Akamai / WAF bot tokens!
235
+ // Writing stale _abck or bm_* triggers Akamai Bot Protection -> Access Denied.
236
+ if (ThaiTicketMajor.BOT_PROTECTION_COOKIES.has(name.toLowerCase())) {
237
+ continue;
238
+ }
239
+
197
240
  try {
198
241
  await chrome.cookies.set({
199
242
  url: domainUrl,
@@ -216,7 +259,7 @@ export class ThaiTicketMajor {
216
259
  }
217
260
 
218
261
  /**
219
- * Setup declarativeNetRequest session rules in Chrome Extension to set Referer and Origin headers
262
+ * Setup declarativeNetRequest session rules in Chrome Extension to set Referer header for API requests only.
220
263
  */
221
264
  public static async setupExtensionRules(): Promise<void> {
222
265
  if (typeof chrome === "undefined" || !chrome?.declarativeNetRequest?.updateSessionRules) {
@@ -238,20 +281,12 @@ export class ThaiTicketMajor {
238
281
  operation: chrome.declarativeNetRequest.HeaderOperation?.SET || "set",
239
282
  value: "https://booking.thaiticketmajor.com",
240
283
  },
241
- {
242
- header: "Origin",
243
- operation: chrome.declarativeNetRequest.HeaderOperation?.SET || "set",
244
- value: "https://booking.thaiticketmajor.com",
245
- },
246
284
  ],
247
285
  },
248
286
  condition: {
249
287
  urlFilter: "thaiticketmajor.com",
250
288
  resourceTypes: [
251
289
  chrome.declarativeNetRequest.ResourceType?.XMLHTTPREQUEST || "xmlhttprequest",
252
- chrome.declarativeNetRequest.ResourceType?.SUB_FRAME || "sub_frame",
253
- chrome.declarativeNetRequest.ResourceType?.MAIN_FRAME || "main_frame",
254
- chrome.declarativeNetRequest.ResourceType?.OTHER || "other",
255
290
  ],
256
291
  },
257
292
  },
@@ -272,7 +307,6 @@ export class ThaiTicketMajor {
272
307
  urlFilter: "kasikornbank.com",
273
308
  resourceTypes: [
274
309
  chrome.declarativeNetRequest.ResourceType?.XMLHTTPREQUEST || "xmlhttprequest",
275
- chrome.declarativeNetRequest.ResourceType?.OTHER || "other",
276
310
  ],
277
311
  },
278
312
  },
@@ -1234,7 +1268,16 @@ export class ThaiTicketMajor {
1234
1268
  const kbankInfo = await this.getKBankQR(orderEncData);
1235
1269
  const kbankAuth = await this.paymentKBankQR(orderEncData, kbankInfo);
1236
1270
 
1237
- const qrResult = await this.generateThaiQR(kbankAuth.orderId, kbankAuth.apiKey, orderEncData.amount);
1271
+ const targetAmount =
1272
+ orderEncData.transactionamount ||
1273
+ orderEncData.totalamount ||
1274
+ orderEncData.amount ||
1275
+ payCfmData.amount ||
1276
+ kbankInfo.totalamount ||
1277
+ paymentAllData["cal_totalamount"] ||
1278
+ "0";
1279
+
1280
+ const qrResult = await this.generateThaiQR(kbankAuth.orderId, kbankAuth.apiKey, targetAmount);
1238
1281
 
1239
1282
  const qrRawCode =
1240
1283
  qrResult?.paint_text ||
@@ -1245,8 +1288,16 @@ export class ThaiTicketMajor {
1245
1288
  qrResult?.data?.raw_qr_code ||
1246
1289
  (typeof qrResult === "string" ? qrResult : "");
1247
1290
 
1291
+ const qrAmount = parseThaiQRAmount(qrRawCode);
1292
+ const finalAmount =
1293
+ qrAmount ||
1294
+ (targetAmount && targetAmount !== "0" ? targetAmount : null) ||
1295
+ qrResult?.amount ||
1296
+ qrResult?.data?.amount ||
1297
+ "0";
1298
+
1248
1299
  const displayQR = (customTitle?: string) => {
1249
- const title = customTitle || `ThaiQR Payment (KBank) - ยอดชำระ: ${orderEncData.amount || paymentAllData["cal_totalamount"]} บาท`;
1300
+ const title = customTitle || `ThaiQR Payment (KBank) - ยอดชำระ: ${finalAmount} บาท`;
1250
1301
  ThaiTicketMajor.displayQRCode(qrRawCode, title);
1251
1302
  };
1252
1303
 
@@ -1257,7 +1308,7 @@ export class ThaiTicketMajor {
1257
1308
  return {
1258
1309
  success: true,
1259
1310
  orderId: kbankAuth.orderId,
1260
- amount: orderEncData.amount || paymentAllData["cal_totalamount"],
1311
+ amount: String(finalAmount),
1261
1312
  qrRawCode,
1262
1313
  qrData: qrResult,
1263
1314
  displayQR,
@@ -1268,7 +1319,7 @@ export class ThaiTicketMajor {
1268
1319
  venue: paymentAllData["venue"],
1269
1320
  zone: targetZone.value,
1270
1321
  ticketCount,
1271
- totalAmount: orderEncData.amount || paymentAllData["cal_totalamount"],
1322
+ totalAmount: String(finalAmount),
1272
1323
  seats: summarySeats.length > 0 ? summarySeats : undefined,
1273
1324
  },
1274
1325
  rawPayload: {