wa-multi-mongodb 3.10.8 → 3.11.1

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.
Files changed (38) hide show
  1. package/dist/Socket/index.d.ts +5 -0
  2. package/dist/Socket/index.d.ts.map +1 -1
  3. package/dist/Socket/index.js +42 -3
  4. package/dist/Utils/group-cache.d.ts.map +1 -1
  5. package/dist/Utils/group-cache.js +20 -12
  6. package/dist/Utils/index.d.ts +1 -0
  7. package/dist/Utils/index.d.ts.map +1 -1
  8. package/dist/Utils/index.js +1 -0
  9. package/dist/Utils/mongo-auth-state.d.ts.map +1 -1
  10. package/dist/Utils/mongo-auth-state.js +5 -3
  11. package/dist/Utils/save-media.d.ts.map +1 -1
  12. package/dist/Utils/save-media.js +6 -4
  13. package/dist/Utils/security.d.ts +7 -0
  14. package/dist/Utils/security.d.ts.map +1 -0
  15. package/dist/Utils/security.js +44 -0
  16. package/dist/cjs/Socket/index.d.ts +5 -0
  17. package/dist/cjs/Socket/index.d.ts.map +1 -1
  18. package/dist/cjs/Socket/index.js +43 -3
  19. package/dist/cjs/Utils/group-cache.d.ts.map +1 -1
  20. package/dist/cjs/Utils/group-cache.js +20 -12
  21. package/dist/cjs/Utils/index.d.ts +1 -0
  22. package/dist/cjs/Utils/index.d.ts.map +1 -1
  23. package/dist/cjs/Utils/index.js +1 -0
  24. package/dist/cjs/Utils/mongo-auth-state.d.ts.map +1 -1
  25. package/dist/cjs/Utils/mongo-auth-state.js +5 -3
  26. package/dist/cjs/Utils/save-media.d.ts.map +1 -1
  27. package/dist/cjs/Utils/save-media.js +6 -4
  28. package/dist/cjs/Utils/security.d.ts +7 -0
  29. package/dist/cjs/Utils/security.d.ts.map +1 -0
  30. package/dist/cjs/Utils/security.js +56 -0
  31. package/dist/cjs/index.d.ts +1 -0
  32. package/dist/cjs/index.d.ts.map +1 -1
  33. package/dist/cjs/index.js +1 -0
  34. package/dist/index.d.ts +1 -0
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +1 -0
  37. package/package.json +9 -8
  38. package/readme.md +1302 -1246
@@ -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.toLID = exports.toPhoneNumber = exports.isPNFormat = exports.isLIDFormat = exports.getAllLIDMappings = exports.getLIDForPN = exports.getPNForLID = exports.clearAllGroupMetadataCache = exports.clearSessionGroupMetadataCache = exports.clearGroupMetadataCache = exports.getGroupMetadata = exports.setGroupCacheConfig = exports.getSessionStatus = exports.getPairingCodeSessions = exports.reconnectAllPairingCodeSessions = exports.reconnect = exports.setCredentialsDir = exports.setMongoDBNames = exports.loadSessionsFromMongo = exports.onPairingCode = exports.onMessageUpdate = exports.onConnecting = exports.onDisconnected = exports.onConnected = exports.onQRUpdated = exports.onMessageReceived = exports.loadSessionsFromStorage = exports.getSession = exports.getAllSessionSync = exports.getAllSession = exports.deleteSession = exports.startWhatsapp = exports.startSessionWithPairingCode = exports.startSession = exports.setMongoURI = void 0;
48
+ exports.toLID = exports.toPhoneNumber = exports.isPNFormat = exports.isLIDFormat = exports.getAllLIDMappings = exports.getLIDForPN = exports.getPNForLID = exports.clearAllGroupMetadataCache = exports.clearSessionGroupMetadataCache = exports.clearGroupMetadataCache = exports.getGroupMetadata = exports.setGroupCacheConfig = exports.getSessionStatus = exports.getPairingCodeSessions = exports.reconnectAllPairingCodeSessions = exports.reconnect = exports.setCredentialsDir = exports.setMongoDBNames = exports.loadSessionsFromMongo = exports.onPairingCode = exports.onMessageUpdate = exports.onConnecting = exports.onDisconnected = exports.onConnected = exports.onQRUpdated = exports.onMessageReceived = exports.loadSessionsFromStorage = exports.downloadMediaMessage = exports.getSession = exports.getAllSessionSync = exports.getAllSession = exports.deleteSession = exports.startWhatsapp = exports.startSessionWithPairingCode = exports.startSession = exports.setMongoURI = void 0;
49
49
  exports.setMongoCollection = setMongoCollection;
50
50
  const baileys_1 = __importStar(require("baileys"));
51
51
  const path_1 = __importDefault(require("path"));
@@ -60,6 +60,7 @@ const message_status_1 = require("../Utils/message-status");
60
60
  const mongodb_1 = require("mongodb");
61
61
  const mongo_auth_state_1 = require("../Utils/mongo-auth-state");
62
62
  const create_delay_1 = require("../Utils/create-delay");
63
+ const security_1 = require("../Utils/security");
63
64
  const sessions = new Map();
64
65
  /**
65
66
  * Valid PlatformType values that WhatsApp recognizes
@@ -184,6 +185,7 @@ function initMongo() {
184
185
  });
185
186
  }
186
187
  const startSession = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (sessionId = "mysession", options = { printQR: true }) {
188
+ sessionId = (0, security_1.assertValidSessionId)(sessionId);
187
189
  if (isSessionExistAndRunning(sessionId))
188
190
  throw new Error_1.WhatsappError(Defaults_1.Messages.sessionAlreadyExist(sessionId));
189
191
  yield initMongo();
@@ -352,6 +354,7 @@ exports.startSession = startSession;
352
354
  * @returns Promise<WASocket> The WhatsApp socket instance
353
355
  */
354
356
  const startSessionWithPairingCode = (sessionId_1, phoneNumber_1, ...args_1) => __awaiter(void 0, [sessionId_1, phoneNumber_1, ...args_1], void 0, function* (sessionId, phoneNumber, options = {}) {
357
+ sessionId = (0, security_1.assertValidSessionId)(sessionId);
355
358
  if (isSessionExistAndRunning(sessionId))
356
359
  throw new Error_1.WhatsappError(Defaults_1.Messages.sessionAlreadyExist(sessionId));
357
360
  // Simpan informasi session pairing code untuk auto-reconnect
@@ -395,7 +398,7 @@ const startSessionWithPairingCode = (sessionId_1, phoneNumber_1, ...args_1) => _
395
398
  const code = yield sock.requestPairingCode(phoneNumberFormatted);
396
399
  // Pastikan kode ada dan merupakan string
397
400
  if (code && typeof code === 'string') {
398
- console.log(`Pairing code untuk session ${sessionId}: ${code}`);
401
+ console.log(`Pairing code untuk session ${sessionId}: ${(0, security_1.maskSensitiveValue)(code)}`);
399
402
  // Panggil callback yang terdaftar
400
403
  (_a = callback.get(Defaults_1.CALLBACK_KEY.ON_PAIRING_CODE)) === null || _a === void 0 ? void 0 : _a(sessionId, code);
401
404
  (_b = options.onPairingCode) === null || _b === void 0 ? void 0 : _b.call(options, code);
@@ -565,6 +568,7 @@ exports.startWhatsapp = exports.startSession;
565
568
  * @param sessionId Session ID to soft delete
566
569
  */
567
570
  const softDeleteSession = (sessionId_1, ...args_1) => __awaiter(void 0, [sessionId_1, ...args_1], void 0, function* (sessionId, preserveData = false) {
571
+ sessionId = (0, security_1.assertValidSessionId)(sessionId);
568
572
  const session = (0, exports.getSession)(sessionId);
569
573
  try {
570
574
  yield (session === null || session === void 0 ? void 0 : session.logout());
@@ -600,6 +604,7 @@ const softDeleteSession = (sessionId_1, ...args_1) => __awaiter(void 0, [session
600
604
  }
601
605
  });
602
606
  const deleteSession = (sessionId) => __awaiter(void 0, void 0, void 0, function* () {
607
+ sessionId = (0, security_1.assertValidSessionId)(sessionId);
603
608
  const session = (0, exports.getSession)(sessionId);
604
609
  try {
605
610
  yield (session === null || session === void 0 ? void 0 : session.logout());
@@ -661,9 +666,30 @@ exports.getAllSession = getAllSession;
661
666
  // Untuk backward compatibility
662
667
  const getAllSessionSync = () => Array.from(sessions.keys());
663
668
  exports.getAllSessionSync = getAllSessionSync;
664
- const getSession = (key) => sessions.get(key);
669
+ const getSession = (key) => sessions.get((0, security_1.assertValidSessionId)(key));
665
670
  exports.getSession = getSession;
671
+ const downloadMediaMessage = (_a) => __awaiter(void 0, [_a], void 0, function* ({ sessionId, message, key, }) {
672
+ const session = (0, exports.getSession)(sessionId);
673
+ if (!session) {
674
+ throw new Error_1.WhatsappError(Defaults_1.Messages.sessionNotFound(sessionId));
675
+ }
676
+ if (!message) {
677
+ throw new Error_1.WhatsappError("Message is required to download media");
678
+ }
679
+ try {
680
+ const buffer = yield (0, baileys_1.downloadMediaMessage)(message, "buffer", {}, {
681
+ logger: P,
682
+ reuploadRequest: session.updateMediaMessage,
683
+ });
684
+ return buffer;
685
+ }
686
+ catch (error) {
687
+ throw new Error_1.WhatsappError(`Failed to download media: ${error.message || String(error)}`);
688
+ }
689
+ });
690
+ exports.downloadMediaMessage = downloadMediaMessage;
666
691
  const isSessionExistAndRunning = (sessionId) => {
692
+ sessionId = (0, security_1.assertValidSessionId)(sessionId);
667
693
  // Cek jika session sudah berjalan di memory
668
694
  if ((0, exports.getSession)(sessionId)) {
669
695
  return true;
@@ -676,6 +702,7 @@ const isSessionExistAndRunning = (sessionId) => {
676
702
  * @returns Boolean indicating if session should be loaded
677
703
  */
678
704
  const shouldLoadSession = (sessionId) => __awaiter(void 0, void 0, void 0, function* () {
705
+ sessionId = (0, security_1.assertValidSessionId)(sessionId);
679
706
  // Jika session sudah berjalan di memory, tidak perlu load lagi
680
707
  if ((0, exports.getSession)(sessionId)) {
681
708
  return false;
@@ -784,6 +811,7 @@ exports.setCredentialsDir = setCredentialsDir;
784
811
  */
785
812
  const reconnect = (sessionId) => __awaiter(void 0, void 0, void 0, function* () {
786
813
  try {
814
+ sessionId = (0, security_1.assertValidSessionId)(sessionId);
787
815
  // Cek jika session masih ada di memory
788
816
  const existingSession = sessions.get(sessionId);
789
817
  // Hapus session terlebih dahulu untuk menghindari konflik
@@ -903,6 +931,7 @@ exports.getPairingCodeSessions = getPairingCodeSessions;
903
931
  * @returns Object with session status information
904
932
  */
905
933
  const getSessionStatus = (sessionId) => {
934
+ sessionId = (0, security_1.assertValidSessionId)(sessionId);
906
935
  const isRunning = !!(0, exports.getSession)(sessionId);
907
936
  const isPairingCodeSession = pairingCodeSessions.has(sessionId);
908
937
  const retryAttempts = retryCount.get(sessionId) || 0;
@@ -922,6 +951,8 @@ const setGroupCacheConfig = (options) => {
922
951
  exports.setGroupCacheConfig = setGroupCacheConfig;
923
952
  // Fungsi baru untuk mendapatkan atau memuat data grup dengan multi-session support
924
953
  const getGroupMetadata = (sessionId_1, jid_1, ...args_1) => __awaiter(void 0, [sessionId_1, jid_1, ...args_1], void 0, function* (sessionId, jid, forceFetch = false) {
954
+ sessionId = (0, security_1.assertValidSessionId)(sessionId);
955
+ jid = (0, security_1.assertValidJidIdentifier)(jid, "jid");
925
956
  // Get the session socket
926
957
  const sock = (0, exports.getSession)(sessionId);
927
958
  if (!sock) {
@@ -951,11 +982,14 @@ const getGroupMetadata = (sessionId_1, jid_1, ...args_1) => __awaiter(void 0, [s
951
982
  exports.getGroupMetadata = getGroupMetadata;
952
983
  // Fungsi baru untuk menghapus cache grup tertentu
953
984
  const clearGroupMetadataCache = (sessionId, jid) => __awaiter(void 0, void 0, void 0, function* () {
985
+ sessionId = (0, security_1.assertValidSessionId)(sessionId);
986
+ jid = (0, security_1.assertValidJidIdentifier)(jid, "jid");
954
987
  yield Utils_1.groupCache.delete(sessionId, jid);
955
988
  });
956
989
  exports.clearGroupMetadataCache = clearGroupMetadataCache;
957
990
  // Fungsi untuk membersihkan seluruh cache grup untuk session tertentu
958
991
  const clearSessionGroupMetadataCache = (sessionId) => __awaiter(void 0, void 0, void 0, function* () {
992
+ sessionId = (0, security_1.assertValidSessionId)(sessionId);
959
993
  yield Utils_1.groupCache.clearSessionCache(sessionId);
960
994
  });
961
995
  exports.clearSessionGroupMetadataCache = clearSessionGroupMetadataCache;
@@ -989,6 +1023,8 @@ exports.clearAllGroupMetadataCache = clearAllGroupMetadataCache;
989
1023
  */
990
1024
  const getPNForLID = (sessionId, lid) => __awaiter(void 0, void 0, void 0, function* () {
991
1025
  var _a, _b;
1026
+ sessionId = (0, security_1.assertValidSessionId)(sessionId);
1027
+ lid = (0, security_1.assertValidJidIdentifier)(lid, "lid");
992
1028
  const session = (0, exports.getSession)(sessionId);
993
1029
  if (!session) {
994
1030
  return {
@@ -1057,6 +1093,7 @@ exports.getPNForLID = getPNForLID;
1057
1093
  */
1058
1094
  const getLIDForPN = (sessionId, pn) => __awaiter(void 0, void 0, void 0, function* () {
1059
1095
  var _a, _b;
1096
+ sessionId = (0, security_1.assertValidSessionId)(sessionId);
1060
1097
  const session = (0, exports.getSession)(sessionId);
1061
1098
  if (!session) {
1062
1099
  return {
@@ -1123,6 +1160,7 @@ exports.getLIDForPN = getLIDForPN;
1123
1160
  * @note This may return an empty array if no mappings are available yet.
1124
1161
  */
1125
1162
  const getAllLIDMappings = (sessionId) => __awaiter(void 0, void 0, void 0, function* () {
1163
+ sessionId = (0, security_1.assertValidSessionId)(sessionId);
1126
1164
  const session = (0, exports.getSession)(sessionId);
1127
1165
  if (!session) {
1128
1166
  throw new Error_1.WhatsappError(Defaults_1.Messages.sessionNotFound(sessionId));
@@ -1217,6 +1255,7 @@ exports.isPNFormat = isPNFormat;
1217
1255
  * ```
1218
1256
  */
1219
1257
  const toPhoneNumber = (sessionId, jid) => __awaiter(void 0, void 0, void 0, function* () {
1258
+ sessionId = (0, security_1.assertValidSessionId)(sessionId);
1220
1259
  // Handle null/undefined input
1221
1260
  if (!jid) {
1222
1261
  return null;
@@ -1268,6 +1307,7 @@ exports.toPhoneNumber = toPhoneNumber;
1268
1307
  * ```
1269
1308
  */
1270
1309
  const toLID = (sessionId, jid) => __awaiter(void 0, void 0, void 0, function* () {
1310
+ sessionId = (0, security_1.assertValidSessionId)(sessionId);
1271
1311
  // If already in LID format, return as-is
1272
1312
  if ((0, exports.isLIDFormat)(jid)) {
1273
1313
  return jid;
@@ -1 +1 @@
1
- {"version":3,"file":"group-cache.d.ts","sourceRoot":"","sources":["../../../src/Utils/group-cache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAKxC,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAqB;IAC5C,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAuB;IAGvC,OAAO;WAUO,WAAW,IAAI,kBAAkB;IAQlC,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBpD,OAAO,CAAC,cAAc;IAKT,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAoCtE,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IA4B/E,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBzD,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBzD,SAAS,CAAC,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE;IAU5D,KAAK,IAAI,IAAI;CAGrB;AAGD,eAAO,MAAM,UAAU,oBAAmC,CAAC"}
1
+ {"version":3,"file":"group-cache.d.ts","sourceRoot":"","sources":["../../../src/Utils/group-cache.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAMxC,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAqB;IAC5C,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,eAAe,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAuB;IAGvC,OAAO;WAUO,WAAW,IAAI,kBAAkB;IAQlC,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBpD,OAAO,CAAC,cAAc;IAKT,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAsCtE,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B/E,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuBzD,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBzD,SAAS,CAAC,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE;IAU5D,KAAK,IAAI,IAAI;CAGrB;AAGD,eAAO,MAAM,UAAU,oBAAmC,CAAC"}
@@ -16,6 +16,7 @@ exports.groupCache = exports.GroupMetadataCache = void 0;
16
16
  const node_cache_1 = __importDefault(require("node-cache"));
17
17
  const mongodb_1 = require("mongodb");
18
18
  const Defaults_1 = require("../Defaults");
19
+ const security_1 = require("./security");
19
20
  // Class untuk mengelola cache group metadata dengan pendekatan hybrid (NodeCache + MongoDB)
20
21
  class GroupMetadataCache {
21
22
  // Konstruktor private untuk singleton pattern
@@ -64,8 +65,10 @@ class GroupMetadataCache {
64
65
  // Mendapatkan metadata grup dari cache atau MongoDB
65
66
  get(sessionId, groupId) {
66
67
  return __awaiter(this, void 0, void 0, function* () {
68
+ const safeSessionId = (0, security_1.assertValidSessionId)(sessionId);
69
+ const safeGroupId = (0, security_1.assertValidJidIdentifier)(groupId, "groupId");
67
70
  // Buat kunci cache dengan kombinasi sessionId dan groupId
68
- const cacheKey = this.createCacheKey(sessionId, groupId);
71
+ const cacheKey = this.createCacheKey(safeSessionId, safeGroupId);
69
72
  // Coba ambil dari cache memory dulu
70
73
  const cachedData = this.cache.get(cacheKey);
71
74
  if (cachedData) {
@@ -75,8 +78,8 @@ class GroupMetadataCache {
75
78
  if (this.mongoCollection) {
76
79
  try {
77
80
  const data = yield this.mongoCollection.findOne({
78
- id: groupId,
79
- sessionId: sessionId
81
+ id: safeGroupId,
82
+ sessionId: safeSessionId
80
83
  });
81
84
  if (data) {
82
85
  // Hapus _id dari MongoDB yang tidak diperlukan
@@ -97,18 +100,20 @@ class GroupMetadataCache {
97
100
  // Menyimpan metadata grup ke cache dan MongoDB
98
101
  set(sessionId, groupId, metadata) {
99
102
  return __awaiter(this, void 0, void 0, function* () {
103
+ const safeSessionId = (0, security_1.assertValidSessionId)(sessionId);
104
+ const safeGroupId = (0, security_1.assertValidJidIdentifier)(groupId, "groupId");
100
105
  // Buat kunci cache dengan kombinasi sessionId dan groupId
101
- const cacheKey = this.createCacheKey(sessionId, groupId);
106
+ const cacheKey = this.createCacheKey(safeSessionId, safeGroupId);
102
107
  // Simpan ke cache memory
103
108
  this.cache.set(cacheKey, metadata);
104
109
  // Jika MongoDB tersedia, simpan juga ke MongoDB
105
110
  if (this.mongoCollection) {
106
111
  try {
107
112
  // Tambahkan sessionId ke data yang disimpan
108
- const dataToStore = Object.assign(Object.assign({}, metadata), { sessionId });
113
+ const dataToStore = Object.assign(Object.assign({}, metadata), { sessionId: safeSessionId });
109
114
  yield this.mongoCollection.updateOne({
110
- id: groupId,
111
- sessionId: sessionId
115
+ id: safeGroupId,
116
+ sessionId: safeSessionId
112
117
  }, { $set: dataToStore }, { upsert: true });
113
118
  }
114
119
  catch (error) {
@@ -120,16 +125,18 @@ class GroupMetadataCache {
120
125
  // Menghapus metadata grup dari cache dan MongoDB
121
126
  delete(sessionId, groupId) {
122
127
  return __awaiter(this, void 0, void 0, function* () {
128
+ const safeSessionId = (0, security_1.assertValidSessionId)(sessionId);
129
+ const safeGroupId = (0, security_1.assertValidJidIdentifier)(groupId, "groupId");
123
130
  // Buat kunci cache dengan kombinasi sessionId dan groupId
124
- const cacheKey = this.createCacheKey(sessionId, groupId);
131
+ const cacheKey = this.createCacheKey(safeSessionId, safeGroupId);
125
132
  // Hapus dari cache memory
126
133
  this.cache.del(cacheKey);
127
134
  // Jika MongoDB tersedia, hapus juga dari MongoDB
128
135
  if (this.mongoCollection) {
129
136
  try {
130
137
  yield this.mongoCollection.deleteOne({
131
- id: groupId,
132
- sessionId: sessionId
138
+ id: safeGroupId,
139
+ sessionId: safeSessionId
133
140
  });
134
141
  }
135
142
  catch (error) {
@@ -141,10 +148,11 @@ class GroupMetadataCache {
141
148
  // Menghapus semua cache untuk session tertentu
142
149
  clearSessionCache(sessionId) {
143
150
  return __awaiter(this, void 0, void 0, function* () {
151
+ const safeSessionId = (0, security_1.assertValidSessionId)(sessionId);
144
152
  // Hapus dari MongoDB
145
153
  if (this.mongoCollection) {
146
154
  try {
147
- yield this.mongoCollection.deleteMany({ sessionId: sessionId });
155
+ yield this.mongoCollection.deleteMany({ sessionId: safeSessionId });
148
156
  }
149
157
  catch (error) {
150
158
  console.error(`Error clearing session ${sessionId} cache from MongoDB:`, error);
@@ -153,7 +161,7 @@ class GroupMetadataCache {
153
161
  // Hapus dari memory cache
154
162
  // Karena NodeCache tidak mendukung wildcard delete, kita harus mendapatkan semua kunci dulu
155
163
  const allKeys = this.cache.keys();
156
- const sessionKeys = allKeys.filter(key => key.startsWith(`${sessionId}:`));
164
+ const sessionKeys = allKeys.filter(key => key.startsWith(`${safeSessionId}:`));
157
165
  sessionKeys.forEach(key => this.cache.del(key));
158
166
  });
159
167
  }
@@ -3,4 +3,5 @@ export * from "./is-exist";
3
3
  export * from "./create-delay";
4
4
  export * from "./group-cache";
5
5
  export * from "./lid-utils";
6
+ export * from "./security";
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/Utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/Utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC"}
@@ -19,5 +19,6 @@ __exportStar(require("./is-exist"), exports);
19
19
  __exportStar(require("./create-delay"), exports);
20
20
  __exportStar(require("./group-cache"), exports);
21
21
  __exportStar(require("./lid-utils"), exports);
22
+ __exportStar(require("./security"), exports);
22
23
  // Note: setCredentialsDir & setMongoDBNames have been moved to src/Socket/index.ts
23
24
  // Please import them directly from there instead
@@ -1 +1 @@
1
- {"version":3,"file":"mongo-auth-state.d.ts","sourceRoot":"","sources":["../../../src/Utils/mongo-auth-state.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAuB,MAAM,SAAS,CAAC;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAuC1C,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU;;;;kBAgC7D,CAAC,SAAS,MAAM,iBAAiB,QAAQ,CAAC,OAAO,MAAM,EAAE;;;2BAWhD,GAAG;;;;GAqB/B"}
1
+ {"version":3,"file":"mongo-auth-state.d.ts","sourceRoot":"","sources":["../../../src/Utils/mongo-auth-state.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAuB,MAAM,SAAS,CAAC;AACtE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAwC1C,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU;;;;kBAkC7D,CAAC,SAAS,MAAM,iBAAiB,QAAQ,CAAC,OAAO,MAAM,EAAE;;;2BAWhD,GAAG;;;;GAqB/B"}
@@ -13,6 +13,7 @@ exports.useMongoAuthState = useMongoAuthState;
13
13
  const WAProto_1 = require("baileys/WAProto");
14
14
  const crypto_1 = require("baileys/lib/Utils/crypto");
15
15
  const generics_1 = require("baileys/lib/Utils/generics");
16
+ const security_1 = require("./security");
16
17
  const BufferJSON = {
17
18
  replacer: (_, value) => {
18
19
  if (Buffer.isBuffer(value) || value instanceof Uint8Array || (value === null || value === void 0 ? void 0 : value.type) === "Buffer") {
@@ -50,17 +51,18 @@ const initAuthCreds = () => {
50
51
  };
51
52
  function useMongoAuthState(sessionId, collection) {
52
53
  return __awaiter(this, void 0, void 0, function* () {
54
+ const safeSessionId = (0, security_1.assertValidSessionId)(sessionId);
53
55
  const readState = () => __awaiter(this, void 0, void 0, function* () {
54
- const doc = yield collection.findOne({ sessionId });
56
+ const doc = yield collection.findOne({ sessionId: safeSessionId });
55
57
  return (doc === null || doc === void 0 ? void 0 : doc.state)
56
58
  ? JSON.parse(JSON.stringify(doc.state), BufferJSON.reviver)
57
59
  : null;
58
60
  });
59
61
  const writeState = (state) => __awaiter(this, void 0, void 0, function* () {
60
- yield collection.updateOne({ sessionId }, { $set: { state: JSON.parse(JSON.stringify(state, BufferJSON.replacer)) } }, { upsert: true });
62
+ yield collection.updateOne({ sessionId: safeSessionId }, { $set: { state: JSON.parse(JSON.stringify(state, BufferJSON.replacer)) } }, { upsert: true });
61
63
  });
62
64
  const removeKey = (key) => __awaiter(this, void 0, void 0, function* () {
63
- yield collection.updateOne({ sessionId }, { $unset: { [`state.keys.${key}`]: "" } });
65
+ yield collection.updateOne({ sessionId: safeSessionId }, { $unset: { [`state.keys.${key}`]: "" } });
64
66
  });
65
67
  const savedState = (yield readState()) || {};
66
68
  const creds = savedState.creds || initAuthCreds();
@@ -1 +1 @@
1
- {"version":3,"file":"save-media.d.ts","sourceRoot":"","sources":["../../../src/Utils/save-media.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAQ3C,eAAO,MAAM,gBAAgB,GAAU,KAAK,eAAe,EAAE,MAAM,MAAM,kBAOxE,CAAC;AACF,eAAO,MAAM,gBAAgB,GAAU,KAAK,eAAe,EAAE,MAAM,MAAM,kBAOxE,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,KAAK,eAAe,EACpB,MAAM,MAAM,kBAUb,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAU,KAAK,eAAe,EAAE,MAAM,MAAM,kBAOxE,CAAC"}
1
+ {"version":3,"file":"save-media.d.ts","sourceRoot":"","sources":["../../../src/Utils/save-media.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAU3C,eAAO,MAAM,gBAAgB,GAAU,KAAK,eAAe,EAAE,MAAM,MAAM,kBAOxE,CAAC;AACF,eAAO,MAAM,gBAAgB,GAAU,KAAK,eAAe,EAAE,MAAM,MAAM,kBAOxE,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,KAAK,eAAe,EACpB,MAAM,MAAM,kBAUb,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAU,KAAK,eAAe,EAAE,MAAM,MAAM,kBAOxE,CAAC"}
@@ -16,8 +16,10 @@ exports.saveAudioHandler = exports.saveDocumentHandler = exports.saveVideoHandle
16
16
  const baileys_1 = require("baileys");
17
17
  const error_1 = __importDefault(require("./error"));
18
18
  const promises_1 = __importDefault(require("fs/promises"));
19
- const saveMedia = (path, data) => __awaiter(void 0, void 0, void 0, function* () {
20
- yield promises_1.default.writeFile(path, data.toString("base64"), "base64");
19
+ const security_1 = require("./security");
20
+ const saveMedia = (filePath, data) => __awaiter(void 0, void 0, void 0, function* () {
21
+ const safePath = (0, security_1.assertSafeFilePath)(filePath);
22
+ yield promises_1.default.writeFile(safePath, data.toString("base64"), "base64");
21
23
  });
22
24
  const saveImageHandler = (msg, path) => __awaiter(void 0, void 0, void 0, function* () {
23
25
  var _a;
@@ -40,8 +42,8 @@ const saveDocumentHandler = (msg, path) => __awaiter(void 0, void 0, void 0, fun
40
42
  if (!((_a = msg.message) === null || _a === void 0 ? void 0 : _a.documentMessage))
41
43
  throw new error_1.default("Message is not contain Document");
42
44
  const buf = yield (0, baileys_1.downloadMediaMessage)(msg, "buffer", {});
43
- const ext = (_b = msg.message.documentMessage.fileName) === null || _b === void 0 ? void 0 : _b.split(".").pop();
44
- path += "." + ext;
45
+ const ext = (0, security_1.sanitizeFileExtension)((_b = msg.message.documentMessage.fileName) === null || _b === void 0 ? void 0 : _b.split(".").pop());
46
+ path = `${(0, security_1.assertSafeFilePath)(path)}.${ext}`;
45
47
  return saveMedia(path, buf);
46
48
  });
47
49
  exports.saveDocumentHandler = saveDocumentHandler;
@@ -0,0 +1,7 @@
1
+ export declare const assertValidIdentifier: (value: string, fieldName: string) => string;
2
+ export declare const assertValidSessionId: (sessionId: string) => string;
3
+ export declare const assertValidJidIdentifier: (value: string, fieldName: string) => string;
4
+ export declare const assertSafeFilePath: (filePath: string) => string;
5
+ export declare const sanitizeFileExtension: (extension?: string) => string;
6
+ export declare const maskSensitiveValue: (value: string, visibleChars?: number) => string;
7
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../../src/Utils/security.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,qBAAqB,GAAI,OAAO,MAAM,EAAE,WAAW,MAAM,KAAG,MAQxE,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,WAAW,MAAM,KAAG,MACV,CAAC;AAEhD,eAAO,MAAM,wBAAwB,GAAI,OAAO,MAAM,EAAE,WAAW,MAAM,KAAG,MAQ3E,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,UAAU,MAAM,KAAG,MAiBrD,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAAI,YAAY,MAAM,KAAG,MAK1D,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,OAAO,MAAM,EAAE,qBAAgB,KAAG,MAKpE,CAAC"}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.maskSensitiveValue = exports.sanitizeFileExtension = exports.assertSafeFilePath = exports.assertValidJidIdentifier = exports.assertValidSessionId = exports.assertValidIdentifier = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const Error_1 = require("../Error");
9
+ const SAFE_IDENTIFIER_PATTERN = /^[A-Za-z0-9_-]{1,128}$/;
10
+ const SAFE_JID_IDENTIFIER_PATTERN = /^[A-Za-z0-9_@.:-]{1,192}$/;
11
+ const assertValidIdentifier = (value, fieldName) => {
12
+ if (typeof value !== "string" || !SAFE_IDENTIFIER_PATTERN.test(value)) {
13
+ throw new Error_1.WhatsappError(`${fieldName} hanya boleh berisi huruf, angka, underscore, atau dash dengan panjang 1-128 karakter`);
14
+ }
15
+ return value;
16
+ };
17
+ exports.assertValidIdentifier = assertValidIdentifier;
18
+ const assertValidSessionId = (sessionId) => (0, exports.assertValidIdentifier)(sessionId, "sessionId");
19
+ exports.assertValidSessionId = assertValidSessionId;
20
+ const assertValidJidIdentifier = (value, fieldName) => {
21
+ if (typeof value !== "string" || !SAFE_JID_IDENTIFIER_PATTERN.test(value)) {
22
+ throw new Error_1.WhatsappError(`${fieldName} berisi karakter tidak valid atau melebihi 192 karakter`);
23
+ }
24
+ return value;
25
+ };
26
+ exports.assertValidJidIdentifier = assertValidJidIdentifier;
27
+ const assertSafeFilePath = (filePath) => {
28
+ if (typeof filePath !== "string" || filePath.trim().length === 0) {
29
+ throw new Error_1.WhatsappError("File path is required");
30
+ }
31
+ if (filePath.includes("\0")) {
32
+ throw new Error_1.WhatsappError("File path contains invalid characters");
33
+ }
34
+ const normalized = path_1.default.normalize(filePath);
35
+ const baseName = path_1.default.basename(normalized);
36
+ if (!baseName || baseName === "." || baseName === "..") {
37
+ throw new Error_1.WhatsappError("File path must include a valid file name");
38
+ }
39
+ return normalized;
40
+ };
41
+ exports.assertSafeFilePath = assertSafeFilePath;
42
+ const sanitizeFileExtension = (extension) => {
43
+ if (!extension)
44
+ return "bin";
45
+ const cleanExtension = extension.replace(/[^A-Za-z0-9]/g, "").slice(0, 16);
46
+ return cleanExtension || "bin";
47
+ };
48
+ exports.sanitizeFileExtension = sanitizeFileExtension;
49
+ const maskSensitiveValue = (value, visibleChars = 2) => {
50
+ if (!value)
51
+ return "";
52
+ if (value.length <= visibleChars * 2)
53
+ return "*".repeat(value.length);
54
+ return `${value.slice(0, visibleChars)}${"*".repeat(value.length - visibleChars * 2)}${value.slice(-visibleChars)}`;
55
+ };
56
+ exports.maskSensitiveValue = maskSensitiveValue;
@@ -4,5 +4,6 @@ export * from "./Utils";
4
4
  export * from "./Types";
5
5
  export * from "./Profile";
6
6
  export * from "./Error";
7
+ export * from "./Defaults";
7
8
  export * as baileys from "baileys";
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AAExB,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAE3B,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC"}
package/dist/cjs/index.js CHANGED
@@ -43,4 +43,5 @@ __exportStar(require("./Utils"), exports);
43
43
  __exportStar(require("./Types"), exports);
44
44
  __exportStar(require("./Profile"), exports);
45
45
  __exportStar(require("./Error"), exports);
46
+ __exportStar(require("./Defaults"), exports);
46
47
  exports.baileys = __importStar(require("baileys"));
package/dist/index.d.ts CHANGED
@@ -4,5 +4,6 @@ export * from "./Utils/index.js";
4
4
  export * from "./Types/index.js";
5
5
  export * from "./Profile/index.js";
6
6
  export * from "./Error/index.js";
7
+ export * from "./Defaults/index.js";
7
8
  export * as baileys from "baileys";
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AAExB,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC;AACxB,cAAc,SAAS,CAAC;AACxB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAE3B,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -4,4 +4,5 @@ export * from "./Utils/index.js";
4
4
  export * from "./Types/index.js";
5
5
  export * from "./Profile/index.js";
6
6
  export * from "./Error/index.js";
7
+ export * from "./Defaults/index.js";
7
8
  export * as baileys from "baileys";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wa-multi-mongodb",
3
- "version": "3.10.8",
3
+ "version": "3.11.1",
4
4
  "description": "Multi Session Whatsapp Library with MongoDB Integration",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/index.js",
@@ -21,7 +21,9 @@
21
21
  "build:esm": "tsc && tsc-esm-fix --source=dist --target=dist",
22
22
  "build:cjs": "tsc -p tsconfig.cjs.json",
23
23
  "start": "npm run build && node ./dist/index.js",
24
- "test": "echo \"Error: no test specified\" && exit 1"
24
+ "test": "npm run build",
25
+ "audit:security": "npm audit --audit-level=high || true",
26
+ "ci": "npm test"
25
27
  },
26
28
  "author": "wahdalo",
27
29
  "license": "ISC",
@@ -31,15 +33,14 @@
31
33
  "@types/node-cache": "^4.1.3",
32
34
  "@types/qrcode": "^1.5.5",
33
35
  "aws4": "^1.13.2",
34
- "baileys": "^7.0.0-rc.9",
36
+ "baileys": "^7.0.0-rc11",
35
37
  "dotenv": "^16.5.0",
36
38
  "link-preview-js": "^3.0.14",
37
- "mime": "^3.0.0",
39
+ "mime": "^4.1.0",
38
40
  "mongodb": "^5.7.0",
39
41
  "node-cache": "^5.1.2",
40
- "pino": "^9.5.0",
41
- "qrcode": "^1.5.4",
42
- "qrcode-terminal": "^0.12.0"
42
+ "pino": "^10.3.1",
43
+ "qrcode": "^1.5.4"
43
44
  },
44
45
  "repository": {
45
46
  "type": "git",
@@ -54,4 +55,4 @@
54
55
  "tslib": "^2.8.1",
55
56
  "typescript": "^5.7.2"
56
57
  }
57
- }
58
+ }