alicezetion 1.9.6 → 1.9.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (292) hide show
  1. package/.cache/replit/modules/nodejs-20.res +1 -0
  2. package/.cache/replit/modules/replit.res +1 -0
  3. package/.cache/typescript/5.4/node_modules/.package-lock.json +137 -0
  4. package/.cache/typescript/5.4/node_modules/@types/bluebird/LICENSE +21 -0
  5. package/.cache/typescript/5.4/node_modules/@types/bluebird/README.md +15 -0
  6. package/.cache/typescript/5.4/node_modules/@types/bluebird/index.d.ts +1365 -0
  7. package/.cache/typescript/5.4/node_modules/@types/bluebird/package.json +25 -0
  8. package/.cache/typescript/5.4/node_modules/@types/caseless/LICENSE +21 -0
  9. package/.cache/typescript/5.4/node_modules/@types/caseless/README.md +48 -0
  10. package/.cache/typescript/5.4/node_modules/@types/caseless/index.d.ts +29 -0
  11. package/.cache/typescript/5.4/node_modules/@types/caseless/package.json +35 -0
  12. package/.cache/typescript/5.4/node_modules/@types/cheerio/LICENSE +21 -0
  13. package/.cache/typescript/5.4/node_modules/@types/cheerio/README.md +15 -0
  14. package/.cache/typescript/5.4/node_modules/@types/cheerio/index.d.ts +318 -0
  15. package/.cache/typescript/5.4/node_modules/@types/cheerio/package.json +71 -0
  16. package/.cache/typescript/5.4/node_modules/@types/node/LICENSE +21 -0
  17. package/.cache/typescript/5.4/node_modules/@types/node/README.md +15 -0
  18. package/.cache/typescript/5.4/node_modules/@types/node/assert/strict.d.ts +8 -0
  19. package/.cache/typescript/5.4/node_modules/@types/node/assert.d.ts +1040 -0
  20. package/.cache/typescript/5.4/node_modules/@types/node/async_hooks.d.ts +541 -0
  21. package/.cache/typescript/5.4/node_modules/@types/node/buffer.d.ts +2363 -0
  22. package/.cache/typescript/5.4/node_modules/@types/node/child_process.d.ts +1544 -0
  23. package/.cache/typescript/5.4/node_modules/@types/node/cluster.d.ts +578 -0
  24. package/.cache/typescript/5.4/node_modules/@types/node/console.d.ts +452 -0
  25. package/.cache/typescript/5.4/node_modules/@types/node/constants.d.ts +19 -0
  26. package/.cache/typescript/5.4/node_modules/@types/node/crypto.d.ts +4523 -0
  27. package/.cache/typescript/5.4/node_modules/@types/node/dgram.d.ts +596 -0
  28. package/.cache/typescript/5.4/node_modules/@types/node/diagnostics_channel.d.ts +554 -0
  29. package/.cache/typescript/5.4/node_modules/@types/node/dns/promises.d.ts +476 -0
  30. package/.cache/typescript/5.4/node_modules/@types/node/dns.d.ts +864 -0
  31. package/.cache/typescript/5.4/node_modules/@types/node/dom-events.d.ts +124 -0
  32. package/.cache/typescript/5.4/node_modules/@types/node/domain.d.ts +170 -0
  33. package/.cache/typescript/5.4/node_modules/@types/node/events.d.ts +931 -0
  34. package/.cache/typescript/5.4/node_modules/@types/node/fs/promises.d.ts +1245 -0
  35. package/.cache/typescript/5.4/node_modules/@types/node/fs.d.ts +4317 -0
  36. package/.cache/typescript/5.4/node_modules/@types/node/globals.d.ts +412 -0
  37. package/.cache/typescript/5.4/node_modules/@types/node/globals.global.d.ts +1 -0
  38. package/.cache/typescript/5.4/node_modules/@types/node/http.d.ts +1908 -0
  39. package/.cache/typescript/5.4/node_modules/@types/node/http2.d.ts +2418 -0
  40. package/.cache/typescript/5.4/node_modules/@types/node/https.d.ts +550 -0
  41. package/.cache/typescript/5.4/node_modules/@types/node/index.d.ts +89 -0
  42. package/.cache/typescript/5.4/node_modules/@types/node/inspector.d.ts +2746 -0
  43. package/.cache/typescript/5.4/node_modules/@types/node/module.d.ts +315 -0
  44. package/.cache/typescript/5.4/node_modules/@types/node/net.d.ts +999 -0
  45. package/.cache/typescript/5.4/node_modules/@types/node/os.d.ts +495 -0
  46. package/.cache/typescript/5.4/node_modules/@types/node/package.json +217 -0
  47. package/.cache/typescript/5.4/node_modules/@types/node/path.d.ts +191 -0
  48. package/.cache/typescript/5.4/node_modules/@types/node/perf_hooks.d.ts +905 -0
  49. package/.cache/typescript/5.4/node_modules/@types/node/process.d.ts +1754 -0
  50. package/.cache/typescript/5.4/node_modules/@types/node/punycode.d.ts +117 -0
  51. package/.cache/typescript/5.4/node_modules/@types/node/querystring.d.ts +153 -0
  52. package/.cache/typescript/5.4/node_modules/@types/node/readline/promises.d.ts +150 -0
  53. package/.cache/typescript/5.4/node_modules/@types/node/readline.d.ts +540 -0
  54. package/.cache/typescript/5.4/node_modules/@types/node/repl.d.ts +430 -0
  55. package/.cache/typescript/5.4/node_modules/@types/node/sea.d.ts +153 -0
  56. package/.cache/typescript/5.4/node_modules/@types/node/stream/consumers.d.ts +12 -0
  57. package/.cache/typescript/5.4/node_modules/@types/node/stream/promises.d.ts +83 -0
  58. package/.cache/typescript/5.4/node_modules/@types/node/stream/web.d.ts +367 -0
  59. package/.cache/typescript/5.4/node_modules/@types/node/stream.d.ts +1707 -0
  60. package/.cache/typescript/5.4/node_modules/@types/node/string_decoder.d.ts +67 -0
  61. package/.cache/typescript/5.4/node_modules/@types/node/test.d.ts +1718 -0
  62. package/.cache/typescript/5.4/node_modules/@types/node/timers/promises.d.ts +97 -0
  63. package/.cache/typescript/5.4/node_modules/@types/node/timers.d.ts +240 -0
  64. package/.cache/typescript/5.4/node_modules/@types/node/tls.d.ts +1217 -0
  65. package/.cache/typescript/5.4/node_modules/@types/node/trace_events.d.ts +197 -0
  66. package/.cache/typescript/5.4/node_modules/@types/node/tty.d.ts +208 -0
  67. package/.cache/typescript/5.4/node_modules/@types/node/url.d.ts +952 -0
  68. package/.cache/typescript/5.4/node_modules/@types/node/util.d.ts +2292 -0
  69. package/.cache/typescript/5.4/node_modules/@types/node/v8.d.ts +808 -0
  70. package/.cache/typescript/5.4/node_modules/@types/node/vm.d.ts +924 -0
  71. package/.cache/typescript/5.4/node_modules/@types/node/wasi.d.ts +181 -0
  72. package/.cache/typescript/5.4/node_modules/@types/node/worker_threads.d.ts +694 -0
  73. package/.cache/typescript/5.4/node_modules/@types/node/zlib.d.ts +530 -0
  74. package/.cache/typescript/5.4/node_modules/@types/npmlog/LICENSE +21 -0
  75. package/.cache/typescript/5.4/node_modules/@types/npmlog/README.md +15 -0
  76. package/.cache/typescript/5.4/node_modules/@types/npmlog/index.d.ts +84 -0
  77. package/.cache/typescript/5.4/node_modules/@types/npmlog/package.json +32 -0
  78. package/.cache/typescript/5.4/node_modules/@types/request/LICENSE +21 -0
  79. package/.cache/typescript/5.4/node_modules/@types/request/README.md +15 -0
  80. package/.cache/typescript/5.4/node_modules/@types/request/index.d.ts +395 -0
  81. package/.cache/typescript/5.4/node_modules/@types/request/package.json +70 -0
  82. package/.cache/typescript/5.4/node_modules/@types/tough-cookie/LICENSE +21 -0
  83. package/.cache/typescript/5.4/node_modules/@types/tough-cookie/README.md +15 -0
  84. package/.cache/typescript/5.4/node_modules/@types/tough-cookie/index.d.ts +321 -0
  85. package/.cache/typescript/5.4/node_modules/@types/tough-cookie/package.json +35 -0
  86. package/.cache/typescript/5.4/node_modules/asynckit/LICENSE +21 -0
  87. package/.cache/typescript/5.4/node_modules/asynckit/README.md +233 -0
  88. package/.cache/typescript/5.4/node_modules/asynckit/bench.js +76 -0
  89. package/.cache/typescript/5.4/node_modules/asynckit/index.js +6 -0
  90. package/.cache/typescript/5.4/node_modules/asynckit/lib/abort.js +29 -0
  91. package/.cache/typescript/5.4/node_modules/asynckit/lib/async.js +34 -0
  92. package/.cache/typescript/5.4/node_modules/asynckit/lib/defer.js +26 -0
  93. package/.cache/typescript/5.4/node_modules/asynckit/lib/iterate.js +75 -0
  94. package/.cache/typescript/5.4/node_modules/asynckit/lib/readable_asynckit.js +91 -0
  95. package/.cache/typescript/5.4/node_modules/asynckit/lib/readable_parallel.js +25 -0
  96. package/.cache/typescript/5.4/node_modules/asynckit/lib/readable_serial.js +25 -0
  97. package/.cache/typescript/5.4/node_modules/asynckit/lib/readable_serial_ordered.js +29 -0
  98. package/.cache/typescript/5.4/node_modules/asynckit/lib/state.js +37 -0
  99. package/.cache/typescript/5.4/node_modules/asynckit/lib/streamify.js +141 -0
  100. package/.cache/typescript/5.4/node_modules/asynckit/lib/terminator.js +29 -0
  101. package/.cache/typescript/5.4/node_modules/asynckit/package.json +63 -0
  102. package/.cache/typescript/5.4/node_modules/asynckit/parallel.js +43 -0
  103. package/.cache/typescript/5.4/node_modules/asynckit/serial.js +17 -0
  104. package/.cache/typescript/5.4/node_modules/asynckit/serialOrdered.js +75 -0
  105. package/.cache/typescript/5.4/node_modules/asynckit/stream.js +21 -0
  106. package/.cache/typescript/5.4/node_modules/combined-stream/License +19 -0
  107. package/.cache/typescript/5.4/node_modules/combined-stream/Readme.md +138 -0
  108. package/.cache/typescript/5.4/node_modules/combined-stream/lib/combined_stream.js +208 -0
  109. package/.cache/typescript/5.4/node_modules/combined-stream/package.json +25 -0
  110. package/.cache/typescript/5.4/node_modules/combined-stream/yarn.lock +17 -0
  111. package/.cache/typescript/5.4/node_modules/delayed-stream/License +19 -0
  112. package/.cache/typescript/5.4/node_modules/delayed-stream/Makefile +7 -0
  113. package/.cache/typescript/5.4/node_modules/delayed-stream/Readme.md +141 -0
  114. package/.cache/typescript/5.4/node_modules/delayed-stream/lib/delayed_stream.js +107 -0
  115. package/.cache/typescript/5.4/node_modules/delayed-stream/package.json +27 -0
  116. package/.cache/typescript/5.4/node_modules/form-data/License +19 -0
  117. package/.cache/typescript/5.4/node_modules/form-data/README.md +350 -0
  118. package/.cache/typescript/5.4/node_modules/form-data/README.md.bak +350 -0
  119. package/.cache/typescript/5.4/node_modules/form-data/index.d.ts +51 -0
  120. package/.cache/typescript/5.4/node_modules/form-data/lib/browser.js +2 -0
  121. package/.cache/typescript/5.4/node_modules/form-data/lib/form_data.js +483 -0
  122. package/.cache/typescript/5.4/node_modules/form-data/lib/populate.js +10 -0
  123. package/.cache/typescript/5.4/node_modules/form-data/package.json +68 -0
  124. package/.cache/typescript/5.4/node_modules/mime-db/HISTORY.md +507 -0
  125. package/.cache/typescript/5.4/node_modules/mime-db/LICENSE +23 -0
  126. package/.cache/typescript/5.4/node_modules/mime-db/README.md +100 -0
  127. package/.cache/typescript/5.4/node_modules/mime-db/db.json +8519 -0
  128. package/.cache/typescript/5.4/node_modules/mime-db/index.js +12 -0
  129. package/.cache/typescript/5.4/node_modules/mime-db/package.json +60 -0
  130. package/.cache/typescript/5.4/node_modules/mime-types/HISTORY.md +397 -0
  131. package/.cache/typescript/5.4/node_modules/mime-types/LICENSE +23 -0
  132. package/.cache/typescript/5.4/node_modules/mime-types/README.md +113 -0
  133. package/.cache/typescript/5.4/node_modules/mime-types/index.js +188 -0
  134. package/.cache/typescript/5.4/node_modules/mime-types/package.json +44 -0
  135. package/.cache/typescript/5.4/node_modules/types-registry/README.md +2 -0
  136. package/.cache/typescript/5.4/node_modules/types-registry/index.json +1 -0
  137. package/.cache/typescript/5.4/node_modules/types-registry/package.json +20 -0
  138. package/.cache/typescript/5.4/node_modules/undici-types/README.md +6 -0
  139. package/.cache/typescript/5.4/node_modules/undici-types/agent.d.ts +31 -0
  140. package/.cache/typescript/5.4/node_modules/undici-types/api.d.ts +43 -0
  141. package/.cache/typescript/5.4/node_modules/undici-types/balanced-pool.d.ts +18 -0
  142. package/.cache/typescript/5.4/node_modules/undici-types/cache.d.ts +36 -0
  143. package/.cache/typescript/5.4/node_modules/undici-types/client.d.ts +97 -0
  144. package/.cache/typescript/5.4/node_modules/undici-types/connector.d.ts +34 -0
  145. package/.cache/typescript/5.4/node_modules/undici-types/content-type.d.ts +21 -0
  146. package/.cache/typescript/5.4/node_modules/undici-types/cookies.d.ts +28 -0
  147. package/.cache/typescript/5.4/node_modules/undici-types/diagnostics-channel.d.ts +67 -0
  148. package/.cache/typescript/5.4/node_modules/undici-types/dispatcher.d.ts +241 -0
  149. package/.cache/typescript/5.4/node_modules/undici-types/errors.d.ts +128 -0
  150. package/.cache/typescript/5.4/node_modules/undici-types/fetch.d.ts +209 -0
  151. package/.cache/typescript/5.4/node_modules/undici-types/file.d.ts +39 -0
  152. package/.cache/typescript/5.4/node_modules/undici-types/filereader.d.ts +54 -0
  153. package/.cache/typescript/5.4/node_modules/undici-types/formdata.d.ts +108 -0
  154. package/.cache/typescript/5.4/node_modules/undici-types/global-dispatcher.d.ts +9 -0
  155. package/.cache/typescript/5.4/node_modules/undici-types/global-origin.d.ts +7 -0
  156. package/.cache/typescript/5.4/node_modules/undici-types/handlers.d.ts +9 -0
  157. package/.cache/typescript/5.4/node_modules/undici-types/header.d.ts +4 -0
  158. package/.cache/typescript/5.4/node_modules/undici-types/index.d.ts +63 -0
  159. package/.cache/typescript/5.4/node_modules/undici-types/interceptors.d.ts +5 -0
  160. package/.cache/typescript/5.4/node_modules/undici-types/mock-agent.d.ts +50 -0
  161. package/.cache/typescript/5.4/node_modules/undici-types/mock-client.d.ts +25 -0
  162. package/.cache/typescript/5.4/node_modules/undici-types/mock-errors.d.ts +12 -0
  163. package/.cache/typescript/5.4/node_modules/undici-types/mock-interceptor.d.ts +93 -0
  164. package/.cache/typescript/5.4/node_modules/undici-types/mock-pool.d.ts +25 -0
  165. package/.cache/typescript/5.4/node_modules/undici-types/package.json +55 -0
  166. package/.cache/typescript/5.4/node_modules/undici-types/patch.d.ts +71 -0
  167. package/.cache/typescript/5.4/node_modules/undici-types/pool-stats.d.ts +19 -0
  168. package/.cache/typescript/5.4/node_modules/undici-types/pool.d.ts +28 -0
  169. package/.cache/typescript/5.4/node_modules/undici-types/proxy-agent.d.ts +30 -0
  170. package/.cache/typescript/5.4/node_modules/undici-types/readable.d.ts +61 -0
  171. package/.cache/typescript/5.4/node_modules/undici-types/webidl.d.ts +220 -0
  172. package/.cache/typescript/5.4/node_modules/undici-types/websocket.d.ts +131 -0
  173. package/.cache/typescript/5.4/package-lock.json +149 -0
  174. package/.cache/typescript/5.4/package.json +1 -0
  175. package/index.js +290 -70
  176. package/leiamnash/addExternalModule.js +15 -0
  177. package/leiamnash/addUserToGroup.js +77 -0
  178. package/leiamnash/changeAdminStatus.js +47 -0
  179. package/leiamnash/changeArchivedStatus.js +41 -0
  180. package/{src → leiamnash}/changeAvatar.js +3 -2
  181. package/leiamnash/changeBio.js +64 -0
  182. package/leiamnash/changeBlockedStatus.js +36 -0
  183. package/leiamnash/changeGroupImage.js +105 -0
  184. package/leiamnash/changeNickname.js +43 -0
  185. package/leiamnash/changeThreadColor.js +61 -0
  186. package/leiamnash/changeThreadEmoji.js +41 -0
  187. package/{src → leiamnash}/chat.js +4 -29
  188. package/leiamnash/createNewGroup.js +70 -0
  189. package/leiamnash/createPoll.js +59 -0
  190. package/leiamnash/deleteMessage.js +44 -0
  191. package/leiamnash/deleteThread.js +42 -0
  192. package/leiamnash/editMessage.js +62 -0
  193. package/leiamnash/forwardAttachment.js +47 -0
  194. package/leiamnash/forwardMessage.js +0 -0
  195. package/leiamnash/getCurrentUserID.js +7 -0
  196. package/leiamnash/getEmojiUrl.js +27 -0
  197. package/leiamnash/getFriendsList.js +73 -0
  198. package/leiamnash/getInfoVideo.js +134 -0
  199. package/leiamnash/getThreadHistory.js +537 -0
  200. package/leiamnash/getThreadHistoryDeprecated.js +71 -0
  201. package/leiamnash/getThreadInfo.js +171 -0
  202. package/leiamnash/getThreadInfoDeprecated.js +56 -0
  203. package/leiamnash/getThreadList.js +213 -0
  204. package/leiamnash/getThreadListDeprecated.js +46 -0
  205. package/leiamnash/getThreadPictures.js +59 -0
  206. package/leiamnash/getUserID.js +61 -0
  207. package/leiamnash/getUserInfo.js +66 -0
  208. package/leiamnash/handleFriendRequest.js +46 -0
  209. package/leiamnash/handleMessageRequest.js +47 -0
  210. package/leiamnash/httpGet.js +47 -0
  211. package/leiamnash/httpPost.js +47 -0
  212. package/leiamnash/httpPostFormData.js +42 -0
  213. package/leiamnash/listenMqtt.js +843 -0
  214. package/leiamnash/logout.js +68 -0
  215. package/leiamnash/markAsDelivered.js +47 -0
  216. package/leiamnash/markAsRead.js +70 -0
  217. package/leiamnash/markAsReadAll.js +40 -0
  218. package/leiamnash/markAsSeen.js +48 -0
  219. package/leiamnash/muteThread.js +45 -0
  220. package/leiamnash/pinMessage.js +58 -0
  221. package/leiamnash/react.js +109 -0
  222. package/{src → leiamnash}/refreshFb_dtsg.js +1 -1
  223. package/leiamnash/removeUserFromGroup.js +45 -0
  224. package/leiamnash/resolvePhotoUrl.js +36 -0
  225. package/leiamnash/searchForThread.js +42 -0
  226. package/leiamnash/seen.js +40 -0
  227. package/leiamnash/sendMessage.js +315 -0
  228. package/leiamnash/sendTypingIndicator.js +70 -0
  229. package/leiamnash/setMessageReaction.js +103 -0
  230. package/leiamnash/setPostReaction.js +63 -0
  231. package/leiamnash/setTitle.js +70 -0
  232. package/leiamnash/threadColors.js +41 -0
  233. package/leiamnash/token.js +112 -0
  234. package/leiamnash/unfriend.js +42 -0
  235. package/leiamnash/unsendMessage.js +39 -0
  236. package/{src → leiamnash}/uploadAttachment.js +2 -1
  237. package/package.json +3 -2
  238. package/utils.js +1345 -1382
  239. package/.cache/replit/modules/nodejs-20:v28-20240213-3f08513.res +0 -1
  240. package/.cache/replit/modules/replit:v5-20240209-9e3a339.res +0 -1
  241. package/.replit +0 -1
  242. package/src/addExternalModule.js +0 -19
  243. package/src/addUserToGroup.js +0 -113
  244. package/src/changeAdminStatus.js +0 -79
  245. package/src/changeArchivedStatus.js +0 -55
  246. package/src/changeBio.js +0 -77
  247. package/src/changeBlockedStatus.js +0 -47
  248. package/src/changeGroupImage.js +0 -132
  249. package/src/changeNickname.js +0 -59
  250. package/src/changeThreadColor.js +0 -65
  251. package/src/changeThreadEmoji.js +0 -55
  252. package/src/createNewGroup.js +0 -86
  253. package/src/createPoll.js +0 -71
  254. package/src/deleteMessage.js +0 -56
  255. package/src/deleteThread.js +0 -56
  256. package/src/edit.js +0 -66
  257. package/src/forwardAttachment.js +0 -60
  258. package/src/getCurrentUserID.js +0 -7
  259. package/src/getEmojiUrl.js +0 -29
  260. package/src/getFriendsList.js +0 -83
  261. package/src/getThreadHistory.js +0 -666
  262. package/src/getThreadInfo.js +0 -232
  263. package/src/getThreadList.js +0 -241
  264. package/src/getThreadPictures.js +0 -79
  265. package/src/getUserID.js +0 -66
  266. package/src/getUserInfo.js +0 -74
  267. package/src/handleFriendRequest.js +0 -61
  268. package/src/handleMessageRequest.js +0 -65
  269. package/src/httpGet.js +0 -57
  270. package/src/httpPost.js +0 -57
  271. package/src/httpPostFormData.js +0 -63
  272. package/src/listenMqtt.js +0 -854
  273. package/src/logout.js +0 -75
  274. package/src/markAsDelivered.js +0 -58
  275. package/src/markAsRead.js +0 -80
  276. package/src/markAsReadAll.js +0 -50
  277. package/src/markAsSeen.js +0 -59
  278. package/src/muteThread.js +0 -52
  279. package/src/react.js +0 -121
  280. package/src/removeUserFromGroup.js +0 -79
  281. package/src/resolvePhotoUrl.js +0 -45
  282. package/src/searchForThread.js +0 -53
  283. package/src/seen.js +0 -50
  284. package/src/sendMessage.js +0 -477
  285. package/src/sendTypingIndicator.js +0 -103
  286. package/src/setMessageReaction.js +0 -121
  287. package/src/setPostReaction.js +0 -109
  288. package/src/setTitle.js +0 -86
  289. package/src/threadColors.js +0 -131
  290. package/src/unfriend.js +0 -52
  291. package/src/unsendMessage.js +0 -49
  292. /package/{src → leiamnash}/getMessage.js +0 -0
package/utils.js CHANGED
@@ -1,1545 +1,1508 @@
1
- /* eslint-disable no-prototype-builtins */
2
1
  "use strict";
3
2
 
4
- let request = promisifyPromise(require("request").defaults({ jar: true, proxy: process.env.FB_PROXY }));
3
+ const bluebird = require("bluebird");
4
+ let request = bluebird.promisify(require("request").defaults({ jar: true, proxy: process.env.FB_PROXY }));
5
5
  const stream = require("stream");
6
6
  const log = require("npmlog");
7
7
  const querystring = require("querystring");
8
8
  const url = require("url");
9
9
 
10
10
  class CustomError extends Error {
11
- constructor(obj) {
12
- if (typeof obj === 'string')
13
- obj = { message: obj };
14
- if (typeof obj !== 'object' || obj === null)
15
- throw new TypeError('Object required');
16
- obj.message ? super(obj.message) : super();
17
- Object.assign(this, obj);
18
- }
19
- }
20
-
21
- function callbackToPromise(func) {
22
- return function (...args) {
23
- return new Promise((resolve, reject) => {
24
- func(...args, (err, data) => {
25
- if (err)
26
- reject(err);
27
- else
28
- resolve(data);
29
- });
30
- });
31
- };
32
- }
33
-
34
- function isHasCallback(func) {
35
- if (typeof func !== "function")
36
- return false;
37
- return func.toString().split("\n")[0].match(/(callback|cb)\s*\)/) !== null;
38
- }
39
-
40
- // replace for bluebird.promisify (but this only applies best to the `request` package)
41
- function promisifyPromise(promise) {
42
- const keys = Object.keys(promise);
43
- let promise_;
44
- if (
45
- typeof promise === "function"
46
- && isHasCallback(promise)
47
- )
48
- promise_ = callbackToPromise(promise);
49
- else
50
- promise_ = promise;
51
-
52
- for (const key of keys) {
53
- if (!promise[key]?.toString)
54
- continue;
55
-
56
- if (
57
- typeof promise[key] === "function"
58
- && isHasCallback(promise[key])
59
- ) {
60
- promise_[key] = callbackToPromise(promise[key]);
61
- }
62
- else {
63
- promise_[key] = promise[key];
64
- }
65
- }
66
-
67
- return promise_;
68
- }
69
-
70
- // replace for bluebird.delay
71
- function delay(ms) {
72
- return new Promise(resolve => setTimeout(resolve, ms));
73
- }
74
-
75
- // replace for bluebird.try
76
- function tryPromise(tryFunc) {
77
- return new Promise((resolve, reject) => {
78
- try {
79
- resolve(tryFunc());
80
- } catch (error) {
81
- reject(error);
82
- }
83
- });
11
+ constructor(obj) {
12
+ if (typeof obj === 'string')
13
+ obj = { message: obj };
14
+ if (typeof obj !== 'object' || obj === null)
15
+ throw new TypeError('Object required');
16
+ obj.message ? super(obj.message) : super();
17
+ Object.assign(this, obj);
18
+ }
84
19
  }
85
20
 
86
21
  function setProxy(url) {
87
- if (typeof url == "undefined")
88
- return request = promisifyPromise(require("request").defaults({
89
- jar: true
90
- }));
91
- return request = promisifyPromise(require("request").defaults({
92
- jar: true,
93
- proxy: url
94
- }));
22
+ if (typeof url == "undefined")
23
+ return request = bluebird.promisify(require("request").defaults({
24
+ jar: true
25
+ }));
26
+ return request = bluebird.promisify(require("request").defaults({
27
+ jar: true,
28
+ proxy: url
29
+ }));
95
30
  }
96
31
 
97
32
  function getHeaders(url, options, ctx, customHeader) {
98
- const headers = {
99
- "Content-Type": "application/x-www-form-urlencoded",
100
- Referer: "https://www.facebook.com/",
101
- Host: url.replace("https://", "").split("/")[0],
102
- Origin: "https://www.facebook.com",
103
- "User-Agent": options.userAgent,
104
- Connection: "keep-alive",
105
- "sec-fetch-site": "same-origin"
106
- };
107
- if (customHeader) {
108
- Object.assign(headers, customHeader);
109
- }
110
- if (ctx && ctx.region) {
111
- headers["X-MSGR-Region"] = ctx.region;
112
- }
113
-
114
- return headers;
33
+ const headers = {
34
+ "Content-Type": "application/x-www-form-urlencoded",
35
+ Referer: "https://www.facebook.com/",
36
+ Host: url.replace("https://", "").split("/")[0],
37
+ Origin: "https://www.facebook.com",
38
+ "User-Agent": options.userAgent,
39
+ Connection: "keep-alive",
40
+ "sec-fetch-site": "same-origin"
41
+ };
42
+ if (customHeader) {
43
+ Object.assign(headers, customHeader);
44
+ }
45
+ if (ctx && ctx.region) {
46
+ headers["X-MSGR-Region"] = ctx.region;
47
+ }
48
+
49
+ return headers;
115
50
  }
116
51
 
117
52
  function isReadableStream(obj) {
118
- return (
119
- obj instanceof stream.Stream &&
120
- (getType(obj._read) === "Function" ||
121
- getType(obj._read) === "AsyncFunction") &&
122
- getType(obj._readableState) === "Object"
123
- );
53
+ return (
54
+ obj instanceof stream.Stream &&
55
+ (getType(obj._read) === "Function" ||
56
+ getType(obj._read) === "AsyncFunction") &&
57
+ getType(obj._readableState) === "Object"
58
+ );
124
59
  }
125
60
 
126
61
  function get(url, jar, qs, options, ctx) {
127
- // I'm still confused about this
128
- if (getType(qs) === "Object") {
129
- for (const prop in qs) {
130
- if (qs.hasOwnProperty(prop) && getType(qs[prop]) === "Object") {
131
- qs[prop] = JSON.stringify(qs[prop]);
132
- }
133
- }
134
- }
135
- const op = {
136
- headers: getHeaders(url, options, ctx),
137
- timeout: 60000,
138
- qs: qs,
139
- url: url,
140
- method: "GET",
141
- jar: jar,
142
- gzip: true
143
- };
144
-
145
- return request(op).then(function (res) {
146
- return Array.isArray(res) ? res[0] : res;
147
- });
62
+ // I'm still confused about this
63
+ if (getType(qs) === "Object") {
64
+ for (const prop in qs) {
65
+ if (qs.hasOwnProperty(prop) && getType(qs[prop]) === "Object") {
66
+ qs[prop] = JSON.stringify(qs[prop]);
67
+ }
68
+ }
69
+ }
70
+ const op = {
71
+ headers: getHeaders(url, options, ctx),
72
+ timeout: 60000,
73
+ qs: qs,
74
+ url: url,
75
+ method: "GET",
76
+ jar: jar,
77
+ gzip: true
78
+ };
79
+
80
+ return request(op).then(function (res) {
81
+ return Array.isArray(res) ? res[0] : res;
82
+ });
148
83
  }
149
84
 
150
85
  function post(url, jar, form, options, ctx, customHeader) {
151
- const op = {
152
- headers: getHeaders(url, options, ctx, customHeader),
153
- timeout: 60000,
154
- url: url,
155
- method: "POST",
156
- form: form,
157
- jar: jar,
158
- gzip: true
159
- };
160
-
161
- return request(op).then(function (res) {
162
- return Array.isArray(res) ? res[0] : res;
163
- });
86
+ const op = {
87
+ headers: getHeaders(url, options, ctx, customHeader),
88
+ timeout: 60000,
89
+ url: url,
90
+ method: "POST",
91
+ form: form,
92
+ jar: jar,
93
+ gzip: true
94
+ };
95
+
96
+ return request(op).then(function (res) {
97
+ return Array.isArray(res) ? res[0] : res;
98
+ });
164
99
  }
165
100
 
166
101
  function postFormData(url, jar, form, qs, options, ctx) {
167
- const headers = getHeaders(url, options, ctx);
168
- headers["Content-Type"] = "multipart/form-data";
169
- const op = {
170
- headers: headers,
171
- timeout: 60000,
172
- url: url,
173
- method: "POST",
174
- formData: form,
175
- qs: qs,
176
- jar: jar,
177
- gzip: true
178
- };
179
-
180
- return request(op).then(function (res) {
181
- return Array.isArray(res) ? res[0] : res;
182
- });
102
+ const headers = getHeaders(url, options, ctx);
103
+ headers["Content-Type"] = "multipart/form-data";
104
+ const op = {
105
+ headers: headers,
106
+ timeout: 60000,
107
+ url: url,
108
+ method: "POST",
109
+ formData: form,
110
+ qs: qs,
111
+ jar: jar,
112
+ gzip: true
113
+ };
114
+
115
+ return request(op).then(function (res) {
116
+ return Array.isArray(res) ? res[0] : res;
117
+ });
183
118
  }
184
119
 
185
120
  function padZeros(val, len) {
186
- val = String(val);
187
- len = len || 2;
188
- while (val.length < len) val = "0" + val;
189
- return val;
121
+ val = String(val);
122
+ len = len || 2;
123
+ while (val.length < len) val = "0" + val;
124
+ return val;
190
125
  }
191
126
 
192
127
  function generateThreadingID(clientID) {
193
- const k = Date.now();
194
- const l = Math.floor(Math.random() * 4294967295);
195
- const m = clientID;
196
- return "<" + k + ":" + l + "-" + m + "@mail.projektitan.com>";
128
+ const k = Date.now();
129
+ const l = Math.floor(Math.random() * 4294967295);
130
+ const m = clientID;
131
+ return "<" + k + ":" + l + "-" + m + "@mail.projektitan.com>";
197
132
  }
198
133
 
199
134
  function binaryToDecimal(data) {
200
- let ret = "";
201
- while (data !== "0") {
202
- let end = 0;
203
- let fullName = "";
204
- let i = 0;
205
- for (; i < data.length; i++) {
206
- end = 2 * end + parseInt(data[i], 10);
207
- if (end >= 10) {
208
- fullName += "1";
209
- end -= 10;
210
- }
211
- else {
212
- fullName += "0";
213
- }
214
- }
215
- ret = end.toString() + ret;
216
- data = fullName.slice(fullName.indexOf("1"));
217
- }
218
- return ret;
135
+ let ret = "";
136
+ while (data !== "0") {
137
+ let end = 0;
138
+ let fullName = "";
139
+ let i = 0;
140
+ for (; i < data.length; i++) {
141
+ end = 2 * end + parseInt(data[i], 10);
142
+ if (end >= 10) {
143
+ fullName += "1";
144
+ end -= 10;
145
+ }
146
+ else {
147
+ fullName += "0";
148
+ }
149
+ }
150
+ ret = end.toString() + ret;
151
+ data = fullName.slice(fullName.indexOf("1"));
152
+ }
153
+ return ret;
219
154
  }
220
155
 
221
156
  function generateOfflineThreadingID() {
222
- const ret = Date.now();
223
- const value = Math.floor(Math.random() * 4294967295);
224
- const str = ("0000000000000000000000" + value.toString(2)).slice(-22);
225
- const msgs = ret.toString(2) + str;
226
- return binaryToDecimal(msgs);
157
+ const ret = Date.now();
158
+ const value = Math.floor(Math.random() * 4294967295);
159
+ const str = ("0000000000000000000000" + value.toString(2)).slice(-22);
160
+ const msgs = ret.toString(2) + str;
161
+ return binaryToDecimal(msgs);
227
162
  }
228
163
 
229
164
  let h;
230
165
  const i = {};
231
166
  const j = {
232
- _: "%",
233
- A: "%2",
234
- B: "000",
235
- C: "%7d",
236
- D: "%7b%22",
237
- E: "%2c%22",
238
- F: "%22%3a",
239
- G: "%2c%22ut%22%3a1",
240
- H: "%2c%22bls%22%3a",
241
- I: "%2c%22n%22%3a%22%",
242
- J: "%22%3a%7b%22i%22%3a0%7d",
243
- K: "%2c%22pt%22%3a0%2c%22vis%22%3a",
244
- L: "%2c%22ch%22%3a%7b%22h%22%3a%22",
245
- M: "%7b%22v%22%3a2%2c%22time%22%3a1",
246
- N: ".channel%22%2c%22sub%22%3a%5b",
247
- O: "%2c%22sb%22%3a1%2c%22t%22%3a%5b",
248
- P: "%2c%22ud%22%3a100%2c%22lc%22%3a0",
249
- Q: "%5d%2c%22f%22%3anull%2c%22uct%22%3a",
250
- R: ".channel%22%2c%22sub%22%3a%5b1%5d",
251
- S: "%22%2c%22m%22%3a0%7d%2c%7b%22i%22%3a",
252
- T: "%2c%22blc%22%3a1%2c%22snd%22%3a1%2c%22ct%22%3a",
253
- U: "%2c%22blc%22%3a0%2c%22snd%22%3a1%2c%22ct%22%3a",
254
- V: "%2c%22blc%22%3a0%2c%22snd%22%3a0%2c%22ct%22%3a",
255
- W: "%2c%22s%22%3a0%2c%22blo%22%3a0%7d%2c%22bl%22%3a%7b%22ac%22%3a",
256
- X: "%2c%22ri%22%3a0%7d%2c%22state%22%3a%7b%22p%22%3a0%2c%22ut%22%3a1",
257
- Y:
258
- "%2c%22pt%22%3a0%2c%22vis%22%3a1%2c%22bls%22%3a0%2c%22blc%22%3a0%2c%22snd%22%3a1%2c%22ct%22%3a",
259
- Z:
260
- "%2c%22sb%22%3a1%2c%22t%22%3a%5b%5d%2c%22f%22%3anull%2c%22uct%22%3a0%2c%22s%22%3a0%2c%22blo%22%3a0%7d%2c%22bl%22%3a%7b%22ac%22%3a"
167
+ _: "%",
168
+ A: "%2",
169
+ B: "000",
170
+ C: "%7d",
171
+ D: "%7b%22",
172
+ E: "%2c%22",
173
+ F: "%22%3a",
174
+ G: "%2c%22ut%22%3a1",
175
+ H: "%2c%22bls%22%3a",
176
+ I: "%2c%22n%22%3a%22%",
177
+ J: "%22%3a%7b%22i%22%3a0%7d",
178
+ K: "%2c%22pt%22%3a0%2c%22vis%22%3a",
179
+ L: "%2c%22ch%22%3a%7b%22h%22%3a%22",
180
+ M: "%7b%22v%22%3a2%2c%22time%22%3a1",
181
+ N: ".channel%22%2c%22sub%22%3a%5b",
182
+ O: "%2c%22sb%22%3a1%2c%22t%22%3a%5b",
183
+ P: "%2c%22ud%22%3a100%2c%22lc%22%3a0",
184
+ Q: "%5d%2c%22f%22%3anull%2c%22uct%22%3a",
185
+ R: ".channel%22%2c%22sub%22%3a%5b1%5d",
186
+ S: "%22%2c%22m%22%3a0%7d%2c%7b%22i%22%3a",
187
+ T: "%2c%22blc%22%3a1%2c%22snd%22%3a1%2c%22ct%22%3a",
188
+ U: "%2c%22blc%22%3a0%2c%22snd%22%3a1%2c%22ct%22%3a",
189
+ V: "%2c%22blc%22%3a0%2c%22snd%22%3a0%2c%22ct%22%3a",
190
+ W: "%2c%22s%22%3a0%2c%22blo%22%3a0%7d%2c%22bl%22%3a%7b%22ac%22%3a",
191
+ X: "%2c%22ri%22%3a0%7d%2c%22state%22%3a%7b%22p%22%3a0%2c%22ut%22%3a1",
192
+ Y:
193
+ "%2c%22pt%22%3a0%2c%22vis%22%3a1%2c%22bls%22%3a0%2c%22blc%22%3a0%2c%22snd%22%3a1%2c%22ct%22%3a",
194
+ Z:
195
+ "%2c%22sb%22%3a1%2c%22t%22%3a%5b%5d%2c%22f%22%3anull%2c%22uct%22%3a0%2c%22s%22%3a0%2c%22blo%22%3a0%7d%2c%22bl%22%3a%7b%22ac%22%3a"
261
196
  };
262
197
  (function () {
263
- const l = [];
264
- for (const m in j) {
265
- i[j[m]] = m;
266
- l.push(j[m]);
267
- }
268
- l.reverse();
269
- h = new RegExp(l.join("|"), "g");
198
+ const l = [];
199
+ for (const m in j) {
200
+ i[j[m]] = m;
201
+ l.push(j[m]);
202
+ }
203
+ l.reverse();
204
+ h = new RegExp(l.join("|"), "g");
270
205
  })();
271
206
 
272
207
  function presenceEncode(str) {
273
- return encodeURIComponent(str)
274
- .replace(/([_A-Z])|%../g, function (m, n) {
275
- return n ? "%" + n.charCodeAt(0).toString(16) : m;
276
- })
277
- .toLowerCase()
278
- .replace(h, function (m) {
279
- return i[m];
280
- });
208
+ return encodeURIComponent(str)
209
+ .replace(/([_A-Z])|%../g, function (m, n) {
210
+ return n ? "%" + n.charCodeAt(0).toString(16) : m;
211
+ })
212
+ .toLowerCase()
213
+ .replace(h, function (m) {
214
+ return i[m];
215
+ });
281
216
  }
282
217
 
283
218
  // eslint-disable-next-line no-unused-vars
284
219
  function presenceDecode(str) {
285
- return decodeURIComponent(
286
- str.replace(/[_A-Z]/g, function (m) {
287
- return j[m];
288
- })
289
- );
220
+ return decodeURIComponent(
221
+ str.replace(/[_A-Z]/g, function (m) {
222
+ return j[m];
223
+ })
224
+ );
290
225
  }
291
226
 
292
227
  function generatePresence(userID) {
293
- const time = Date.now();
294
- return (
295
- "E" +
296
- presenceEncode(
297
- JSON.stringify({
298
- v: 3,
299
- time: parseInt(time / 1000, 10),
300
- user: userID,
301
- state: {
302
- ut: 0,
303
- t2: [],
304
- lm2: null,
305
- uct2: time,
306
- tr: null,
307
- tw: Math.floor(Math.random() * 4294967295) + 1,
308
- at: time
309
- },
310
- ch: {
311
- ["p_" + userID]: 0
312
- }
313
- })
314
- )
315
- );
228
+ const time = Date.now();
229
+ return (
230
+ "E" +
231
+ presenceEncode(
232
+ JSON.stringify({
233
+ v: 3,
234
+ time: parseInt(time / 1000, 10),
235
+ user: userID,
236
+ state: {
237
+ ut: 0,
238
+ t2: [],
239
+ lm2: null,
240
+ uct2: time,
241
+ tr: null,
242
+ tw: Math.floor(Math.random() * 4294967295) + 1,
243
+ at: time
244
+ },
245
+ ch: {
246
+ ["p_" + userID]: 0
247
+ }
248
+ })
249
+ )
250
+ );
316
251
  }
317
252
 
318
253
  function generateAccessiblityCookie() {
319
- const time = Date.now();
320
- return encodeURIComponent(
321
- JSON.stringify({
322
- sr: 0,
323
- "sr-ts": time,
324
- jk: 0,
325
- "jk-ts": time,
326
- kb: 0,
327
- "kb-ts": time,
328
- hcm: 0,
329
- "hcm-ts": time
330
- })
331
- );
254
+ const time = Date.now();
255
+ return encodeURIComponent(
256
+ JSON.stringify({
257
+ sr: 0,
258
+ "sr-ts": time,
259
+ jk: 0,
260
+ "jk-ts": time,
261
+ kb: 0,
262
+ "kb-ts": time,
263
+ hcm: 0,
264
+ "hcm-ts": time
265
+ })
266
+ );
332
267
  }
333
268
 
334
269
  function getGUID() {
335
- /** @type {number} */
336
- let sectionLength = Date.now();
337
- /** @type {string} */
338
- const id = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
339
- /** @type {number} */
340
- const r = Math.floor((sectionLength + Math.random() * 16) % 16);
341
- /** @type {number} */
342
- sectionLength = Math.floor(sectionLength / 16);
343
- /** @type {string} */
344
- const _guid = (c == "x" ? r : (r & 7) | 8).toString(16);
345
- return _guid;
346
- });
347
- return id;
270
+ /** @type {number} */
271
+ let sectionLength = Date.now();
272
+ /** @type {string} */
273
+ const id = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
274
+ /** @type {number} */
275
+ const r = Math.floor((sectionLength + Math.random() * 16) % 16);
276
+ /** @type {number} */
277
+ sectionLength = Math.floor(sectionLength / 16);
278
+ /** @type {string} */
279
+ const _guid = (c == "x" ? r : (r & 7) | 8).toString(16);
280
+ return _guid;
281
+ });
282
+ return id;
348
283
  }
349
284
 
350
285
  function getExtension(original_extension, fullFileName = "") {
351
- if (original_extension) {
352
- return original_extension;
353
- }
354
- else {
355
- const extension = fullFileName.split(".").pop();
356
- if (extension === fullFileName) {
357
- return "";
358
- }
359
- else {
360
- return extension;
361
- }
362
- }
286
+ if (original_extension) {
287
+ return original_extension;
288
+ }
289
+ else {
290
+ const extension = fullFileName.split(".").pop();
291
+ if (extension === fullFileName) {
292
+ return "";
293
+ }
294
+ else {
295
+ return extension;
296
+ }
297
+ }
363
298
  }
364
299
 
365
300
  function _formatAttachment(attachment1, attachment2) {
366
- // TODO: THIS IS REALLY BAD
367
- // This is an attempt at fixing Facebook's inconsistencies. Sometimes they give us
368
- // two attachment objects, but sometimes only one. They each contain part of the
369
- // data that you'd want so we merge them for convenience.
370
- // Instead of having a bunch of if statements guarding every access to image_data,
371
- // we set it to empty object and use the fact that it'll return undefined.
372
- const fullFileName = attachment1.filename;
373
- const fileSize = Number(attachment1.fileSize || 0);
374
- const durationVideo = attachment1.genericMetadata ? Number(attachment1.genericMetadata.videoLength) : undefined;
375
- const durationAudio = attachment1.genericMetadata ? Number(attachment1.genericMetadata.duration) : undefined;
376
- const mimeType = attachment1.mimeType;
377
-
378
- attachment2 = attachment2 || { id: "", image_data: {} };
379
- attachment1 = attachment1.mercury || attachment1;
380
- let blob = attachment1.blob_attachment || attachment1.sticker_attachment;
381
- let type =
382
- blob && blob.__typename ? blob.__typename : attachment1.attach_type;
383
- if (!type && attachment1.sticker_attachment) {
384
- type = "StickerAttachment";
385
- blob = attachment1.sticker_attachment;
386
- }
387
- else if (!type && attachment1.extensible_attachment) {
388
- if (
389
- attachment1.extensible_attachment.story_attachment &&
390
- attachment1.extensible_attachment.story_attachment.target &&
391
- attachment1.extensible_attachment.story_attachment.target.__typename &&
392
- attachment1.extensible_attachment.story_attachment.target.__typename === "MessageLocation"
393
- ) {
394
- type = "MessageLocation";
395
- }
396
- else {
397
- type = "ExtensibleAttachment";
398
- }
399
-
400
- blob = attachment1.extensible_attachment;
401
- }
402
- // TODO: Determine whether "sticker", "photo", "file" etc are still used
403
- // KEEP IN SYNC WITH getThreadHistory
404
- switch (type) {
405
- case "sticker":
406
- return {
407
- type: "sticker",
408
- ID: attachment1.metadata.stickerID.toString(),
409
- url: attachment1.url,
410
-
411
- packID: attachment1.metadata.packID.toString(),
412
- spriteUrl: attachment1.metadata.spriteURI,
413
- spriteUrl2x: attachment1.metadata.spriteURI2x,
414
- width: attachment1.metadata.width,
415
- height: attachment1.metadata.height,
416
-
417
- caption: attachment2.caption,
418
- description: attachment2.description,
419
-
420
- frameCount: attachment1.metadata.frameCount,
421
- frameRate: attachment1.metadata.frameRate,
422
- framesPerRow: attachment1.metadata.framesPerRow,
423
- framesPerCol: attachment1.metadata.framesPerCol,
424
-
425
- stickerID: attachment1.metadata.stickerID.toString(), // @Legacy
426
- spriteURI: attachment1.metadata.spriteURI, // @Legacy
427
- spriteURI2x: attachment1.metadata.spriteURI2x // @Legacy
428
- };
429
- case "file":
430
- return {
431
- type: "file",
432
- ID: attachment2.id.toString(),
433
- fullFileName: fullFileName,
434
- filename: attachment1.name,
435
- fileSize: fileSize,
436
- original_extension: getExtension(attachment1.original_extension, fullFileName),
437
- mimeType: mimeType,
438
- url: attachment1.url,
439
-
440
- isMalicious: attachment2.is_malicious,
441
- contentType: attachment2.mime_type,
442
-
443
- name: attachment1.name // @Legacy
444
- };
445
- case "photo":
446
- return {
447
- type: "photo",
448
- ID: attachment1.metadata.fbid.toString(),
449
- filename: attachment1.fileName,
450
- fullFileName: fullFileName,
451
- fileSize: fileSize,
452
- original_extension: getExtension(attachment1.original_extension, fullFileName),
453
- mimeType: mimeType,
454
- thumbnailUrl: attachment1.thumbnail_url,
455
-
456
- previewUrl: attachment1.preview_url,
457
- previewWidth: attachment1.preview_width,
458
- previewHeight: attachment1.preview_height,
459
-
460
- largePreviewUrl: attachment1.large_preview_url,
461
- largePreviewWidth: attachment1.large_preview_width,
462
- largePreviewHeight: attachment1.large_preview_height,
463
-
464
- url: attachment1.metadata.url, // @Legacy
465
- width: attachment1.metadata.dimensions.split(",")[0], // @Legacy
466
- height: attachment1.metadata.dimensions.split(",")[1], // @Legacy
467
- name: fullFileName // @Legacy
468
- };
469
- case "animated_image":
470
- return {
471
- type: "animated_image",
472
- ID: attachment2.id.toString(),
473
- filename: attachment2.filename,
474
- fullFileName: fullFileName,
475
- original_extension: getExtension(attachment2.original_extension, fullFileName),
476
- mimeType: mimeType,
477
-
478
- previewUrl: attachment1.preview_url,
479
- previewWidth: attachment1.preview_width,
480
- previewHeight: attachment1.preview_height,
481
-
482
- url: attachment2.image_data.url,
483
- width: attachment2.image_data.width,
484
- height: attachment2.image_data.height,
485
-
486
- name: attachment1.name, // @Legacy
487
- facebookUrl: attachment1.url, // @Legacy
488
- thumbnailUrl: attachment1.thumbnail_url, // @Legacy
489
- rawGifImage: attachment2.image_data.raw_gif_image, // @Legacy
490
- rawWebpImage: attachment2.image_data.raw_webp_image, // @Legacy
491
- animatedGifUrl: attachment2.image_data.animated_gif_url, // @Legacy
492
- animatedGifPreviewUrl: attachment2.image_data.animated_gif_preview_url, // @Legacy
493
- animatedWebpUrl: attachment2.image_data.animated_webp_url, // @Legacy
494
- animatedWebpPreviewUrl: attachment2.image_data.animated_webp_preview_url // @Legacy
495
- };
496
- case "share":
497
- return {
498
- type: "share",
499
- ID: attachment1.share.share_id.toString(),
500
- url: attachment2.href,
501
-
502
- title: attachment1.share.title,
503
- description: attachment1.share.description,
504
- source: attachment1.share.source,
505
-
506
- image: attachment1.share.media.image,
507
- width: attachment1.share.media.image_size.width,
508
- height: attachment1.share.media.image_size.height,
509
- playable: attachment1.share.media.playable,
510
- duration: attachment1.share.media.duration,
511
-
512
- subattachments: attachment1.share.subattachments,
513
- properties: {},
514
-
515
- animatedImageSize: attachment1.share.media.animated_image_size, // @Legacy
516
- facebookUrl: attachment1.share.uri, // @Legacy
517
- target: attachment1.share.target, // @Legacy
518
- styleList: attachment1.share.style_list // @Legacy
519
- };
520
- case "video":
521
- return {
522
- type: "video",
523
- ID: attachment1.metadata.fbid.toString(),
524
- filename: attachment1.name,
525
- fullFileName: fullFileName,
526
- original_extension: getExtension(attachment1.original_extension, fullFileName),
527
- mimeType: mimeType,
528
- duration: durationVideo,
529
-
530
- previewUrl: attachment1.preview_url,
531
- previewWidth: attachment1.preview_width,
532
- previewHeight: attachment1.preview_height,
533
-
534
- url: attachment1.url,
535
- width: attachment1.metadata.dimensions.width,
536
- height: attachment1.metadata.dimensions.height,
537
-
538
- videoType: "unknown",
539
-
540
- thumbnailUrl: attachment1.thumbnail_url // @Legacy
541
- };
542
- case "error":
543
- return {
544
- type: "error",
545
-
546
- // Save error attachments because we're unsure of their format,
547
- // and whether there are cases they contain something useful for debugging.
548
- attachment1: attachment1,
549
- attachment2: attachment2
550
- };
551
- case "MessageImage":
552
- return {
553
- type: "photo",
554
- ID: blob.legacy_attachment_id,
555
- filename: blob.filename,
556
- fullFileName: fullFileName,
557
- fileSize: fileSize,
558
- original_extension: getExtension(blob.original_extension, fullFileName),
559
- mimeType: mimeType,
560
- thumbnailUrl: blob.thumbnail.uri,
561
-
562
- previewUrl: blob.preview.uri,
563
- previewWidth: blob.preview.width,
564
- previewHeight: blob.preview.height,
565
-
566
- largePreviewUrl: blob.large_preview.uri,
567
- largePreviewWidth: blob.large_preview.width,
568
- largePreviewHeight: blob.large_preview.height,
569
-
570
- url: blob.large_preview.uri, // @Legacy
571
- width: blob.original_dimensions.x, // @Legacy
572
- height: blob.original_dimensions.y, // @Legacy
573
- name: blob.filename // @Legacy
574
- };
575
- case "MessageAnimatedImage":
576
- return {
577
- type: "animated_image",
578
- ID: blob.legacy_attachment_id,
579
- filename: blob.filename,
580
- fullFileName: fullFileName,
581
- original_extension: getExtension(blob.original_extension, fullFileName),
582
- mimeType: mimeType,
583
-
584
- previewUrl: blob.preview_image.uri,
585
- previewWidth: blob.preview_image.width,
586
- previewHeight: blob.preview_image.height,
587
-
588
- url: blob.animated_image.uri,
589
- width: blob.animated_image.width,
590
- height: blob.animated_image.height,
591
-
592
- thumbnailUrl: blob.preview_image.uri, // @Legacy
593
- name: blob.filename, // @Legacy
594
- facebookUrl: blob.animated_image.uri, // @Legacy
595
- rawGifImage: blob.animated_image.uri, // @Legacy
596
- animatedGifUrl: blob.animated_image.uri, // @Legacy
597
- animatedGifPreviewUrl: blob.preview_image.uri, // @Legacy
598
- animatedWebpUrl: blob.animated_image.uri, // @Legacy
599
- animatedWebpPreviewUrl: blob.preview_image.uri // @Legacy
600
- };
601
- case "MessageVideo":
602
- return {
603
- type: "video",
604
- ID: blob.legacy_attachment_id,
605
- filename: blob.filename,
606
- fullFileName: fullFileName,
607
- original_extension: getExtension(blob.original_extension, fullFileName),
608
- fileSize: fileSize,
609
- duration: durationVideo,
610
- mimeType: mimeType,
611
-
612
- previewUrl: blob.large_image.uri,
613
- previewWidth: blob.large_image.width,
614
- previewHeight: blob.large_image.height,
615
-
616
- url: blob.playable_url,
617
- width: blob.original_dimensions.x,
618
- height: blob.original_dimensions.y,
619
-
620
- videoType: blob.video_type.toLowerCase(),
621
-
622
- thumbnailUrl: blob.large_image.uri // @Legacy
623
- };
624
- case "MessageAudio":
625
- return {
626
- type: "audio",
627
- ID: blob.url_shimhash,
628
- filename: blob.filename,
629
- fullFileName: fullFileName,
630
- fileSize: fileSize,
631
- duration: durationAudio,
632
- original_extension: getExtension(blob.original_extension, fullFileName),
633
- mimeType: mimeType,
634
-
635
- audioType: blob.audio_type,
636
- url: blob.playable_url,
637
-
638
- isVoiceMail: blob.is_voicemail
639
- };
640
- case "StickerAttachment":
641
- case "Sticker":
642
- return {
643
- type: "sticker",
644
- ID: blob.id,
645
- url: blob.url,
646
-
647
- packID: blob.pack ? blob.pack.id : null,
648
- spriteUrl: blob.sprite_image,
649
- spriteUrl2x: blob.sprite_image_2x,
650
- width: blob.width,
651
- height: blob.height,
652
-
653
- caption: blob.label,
654
- description: blob.label,
655
-
656
- frameCount: blob.frame_count,
657
- frameRate: blob.frame_rate,
658
- framesPerRow: blob.frames_per_row,
659
- framesPerCol: blob.frames_per_column,
660
-
661
- stickerID: blob.id, // @Legacy
662
- spriteURI: blob.sprite_image, // @Legacy
663
- spriteURI2x: blob.sprite_image_2x // @Legacy
664
- };
665
- case "MessageLocation":
666
- var urlAttach = blob.story_attachment.url;
667
- var mediaAttach = blob.story_attachment.media;
668
-
669
- var u = querystring.parse(url.parse(urlAttach).query).u;
670
- var where1 = querystring.parse(url.parse(u).query).where1;
671
- var address = where1.split(", ");
672
-
673
- var latitude;
674
- var longitude;
675
-
676
- try {
677
- latitude = Number.parseFloat(address[0]);
678
- longitude = Number.parseFloat(address[1]);
679
- } catch (err) {
680
- /* empty */
681
- }
682
-
683
- var imageUrl;
684
- var width;
685
- var height;
686
-
687
- if (mediaAttach && mediaAttach.image) {
688
- imageUrl = mediaAttach.image.uri;
689
- width = mediaAttach.image.width;
690
- height = mediaAttach.image.height;
691
- }
692
-
693
- return {
694
- type: "location",
695
- ID: blob.legacy_attachment_id,
696
- latitude: latitude,
697
- longitude: longitude,
698
- image: imageUrl,
699
- width: width,
700
- height: height,
701
- url: u || urlAttach,
702
- address: where1,
703
-
704
- facebookUrl: blob.story_attachment.url, // @Legacy
705
- target: blob.story_attachment.target, // @Legacy
706
- styleList: blob.story_attachment.style_list // @Legacy
707
- };
708
- case "ExtensibleAttachment":
709
- return {
710
- type: "share",
711
- ID: blob.legacy_attachment_id,
712
- url: blob.story_attachment.url,
713
-
714
- title: blob.story_attachment.title_with_entities.text,
715
- description:
716
- blob.story_attachment.description &&
717
- blob.story_attachment.description.text,
718
- source: blob.story_attachment.source
719
- ? blob.story_attachment.source.text
720
- : null,
721
-
722
- image:
723
- blob.story_attachment.media &&
724
- blob.story_attachment.media.image &&
725
- blob.story_attachment.media.image.uri,
726
- width:
727
- blob.story_attachment.media &&
728
- blob.story_attachment.media.image &&
729
- blob.story_attachment.media.image.width,
730
- height:
731
- blob.story_attachment.media &&
732
- blob.story_attachment.media.image &&
733
- blob.story_attachment.media.image.height,
734
- playable:
735
- blob.story_attachment.media &&
736
- blob.story_attachment.media.is_playable,
737
- duration:
738
- blob.story_attachment.media &&
739
- blob.story_attachment.media.playable_duration_in_ms,
740
- playableUrl:
741
- blob.story_attachment.media == null
742
- ? null
743
- : blob.story_attachment.media.playable_url,
744
-
745
- subattachments: blob.story_attachment.subattachments,
746
- properties: blob.story_attachment.properties.reduce(function (obj, cur) {
747
- obj[cur.key] = cur.value.text;
748
- return obj;
749
- }, {}),
750
-
751
- facebookUrl: blob.story_attachment.url, // @Legacy
752
- target: blob.story_attachment.target, // @Legacy
753
- styleList: blob.story_attachment.style_list // @Legacy
754
- };
755
- case "MessageFile":
756
- return {
757
- type: "file",
758
- ID: blob.message_file_fbid,
759
- fullFileName: fullFileName,
760
- filename: blob.filename,
761
- fileSize: fileSize,
762
- mimeType: blob.mimetype,
763
- original_extension: blob.original_extension || fullFileName.split(".").pop(),
764
-
765
- url: blob.url,
766
- isMalicious: blob.is_malicious,
767
- contentType: blob.content_type,
768
-
769
- name: blob.filename
770
- };
771
- default:
772
- throw new Error(
773
- "unrecognized attach_file of type " +
774
- type +
775
- "`" +
776
- JSON.stringify(attachment1, null, 4) +
777
- " attachment2: " +
778
- JSON.stringify(attachment2, null, 4) +
779
- "`"
780
- );
781
- }
301
+ // TODO: THIS IS REALLY BAD
302
+ // This is an attempt at fixing Facebook's inconsistencies. Sometimes they give us
303
+ // two attachment objects, but sometimes only one. They each contain part of the
304
+ // data that you'd want so we merge them for convenience.
305
+ // Instead of having a bunch of if statements guarding every access to image_data,
306
+ // we set it to empty object and use the fact that it'll return undefined.
307
+ const fullFileName = attachment1.filename;
308
+ const fileSize = Number(attachment1.fileSize || 0);
309
+ const durationVideo = attachment1.genericMetadata ? Number(attachment1.genericMetadata.videoLength) : undefined;
310
+ const durationAudio = attachment1.genericMetadata ? Number(attachment1.genericMetadata.duration) : undefined;
311
+ const mimeType = attachment1.mimeType;
312
+
313
+ attachment2 = attachment2 || { id: "", image_data: {} };
314
+ attachment1 = attachment1.mercury || attachment1;
315
+ let blob = attachment1.blob_attachment || attachment1.sticker_attachment;
316
+ let type =
317
+ blob && blob.__typename ? blob.__typename : attachment1.attach_type;
318
+ if (!type && attachment1.sticker_attachment) {
319
+ type = "StickerAttachment";
320
+ blob = attachment1.sticker_attachment;
321
+ }
322
+ else if (!type && attachment1.extensible_attachment) {
323
+ if (
324
+ attachment1.extensible_attachment.story_attachment &&
325
+ attachment1.extensible_attachment.story_attachment.target &&
326
+ attachment1.extensible_attachment.story_attachment.target.__typename &&
327
+ attachment1.extensible_attachment.story_attachment.target.__typename === "MessageLocation"
328
+ ) {
329
+ type = "MessageLocation";
330
+ }
331
+ else {
332
+ type = "ExtensibleAttachment";
333
+ }
334
+
335
+ blob = attachment1.extensible_attachment;
336
+ }
337
+ // TODO: Determine whether "sticker", "photo", "file" etc are still used
338
+ // KEEP IN SYNC WITH getThreadHistory
339
+ switch (type) {
340
+ case "sticker":
341
+ return {
342
+ type: "sticker",
343
+ ID: attachment1.metadata.stickerID.toString(),
344
+ url: attachment1.url,
345
+
346
+ packID: attachment1.metadata.packID.toString(),
347
+ spriteUrl: attachment1.metadata.spriteURI,
348
+ spriteUrl2x: attachment1.metadata.spriteURI2x,
349
+ width: attachment1.metadata.width,
350
+ height: attachment1.metadata.height,
351
+
352
+ caption: attachment2.caption,
353
+ description: attachment2.description,
354
+
355
+ frameCount: attachment1.metadata.frameCount,
356
+ frameRate: attachment1.metadata.frameRate,
357
+ framesPerRow: attachment1.metadata.framesPerRow,
358
+ framesPerCol: attachment1.metadata.framesPerCol,
359
+
360
+ stickerID: attachment1.metadata.stickerID.toString(), // @Legacy
361
+ spriteURI: attachment1.metadata.spriteURI, // @Legacy
362
+ spriteURI2x: attachment1.metadata.spriteURI2x // @Legacy
363
+ };
364
+ case "file":
365
+ return {
366
+ type: "file",
367
+ ID: attachment2.id.toString(),
368
+ fullFileName: fullFileName,
369
+ filename: attachment1.name,
370
+ fileSize: fileSize,
371
+ original_extension: getExtension(attachment1.original_extension, fullFileName),
372
+ mimeType: mimeType,
373
+ url: attachment1.url,
374
+
375
+ isMalicious: attachment2.is_malicious,
376
+ contentType: attachment2.mime_type,
377
+
378
+ name: attachment1.name // @Legacy
379
+ };
380
+ case "photo":
381
+ return {
382
+ type: "photo",
383
+ ID: attachment1.metadata.fbid.toString(),
384
+ filename: attachment1.fileName,
385
+ fullFileName: fullFileName,
386
+ fileSize: fileSize,
387
+ original_extension: getExtension(attachment1.original_extension, fullFileName),
388
+ mimeType: mimeType,
389
+ thumbnailUrl: attachment1.thumbnail_url,
390
+
391
+ previewUrl: attachment1.preview_url,
392
+ previewWidth: attachment1.preview_width,
393
+ previewHeight: attachment1.preview_height,
394
+
395
+ largePreviewUrl: attachment1.large_preview_url,
396
+ largePreviewWidth: attachment1.large_preview_width,
397
+ largePreviewHeight: attachment1.large_preview_height,
398
+
399
+ url: attachment1.metadata.url, // @Legacy
400
+ width: attachment1.metadata.dimensions.split(",")[0], // @Legacy
401
+ height: attachment1.metadata.dimensions.split(",")[1], // @Legacy
402
+ name: fullFileName // @Legacy
403
+ };
404
+ case "animated_image":
405
+ return {
406
+ type: "animated_image",
407
+ ID: attachment2.id.toString(),
408
+ filename: attachment2.filename,
409
+ fullFileName: fullFileName,
410
+ original_extension: getExtension(attachment2.original_extension, fullFileName),
411
+ mimeType: mimeType,
412
+
413
+ previewUrl: attachment1.preview_url,
414
+ previewWidth: attachment1.preview_width,
415
+ previewHeight: attachment1.preview_height,
416
+
417
+ url: attachment2.image_data.url,
418
+ width: attachment2.image_data.width,
419
+ height: attachment2.image_data.height,
420
+
421
+ name: attachment1.name, // @Legacy
422
+ facebookUrl: attachment1.url, // @Legacy
423
+ thumbnailUrl: attachment1.thumbnail_url, // @Legacy
424
+ rawGifImage: attachment2.image_data.raw_gif_image, // @Legacy
425
+ rawWebpImage: attachment2.image_data.raw_webp_image, // @Legacy
426
+ animatedGifUrl: attachment2.image_data.animated_gif_url, // @Legacy
427
+ animatedGifPreviewUrl: attachment2.image_data.animated_gif_preview_url, // @Legacy
428
+ animatedWebpUrl: attachment2.image_data.animated_webp_url, // @Legacy
429
+ animatedWebpPreviewUrl: attachment2.image_data.animated_webp_preview_url // @Legacy
430
+ };
431
+ case "share":
432
+ return {
433
+ type: "share",
434
+ ID: attachment1.share.share_id.toString(),
435
+ url: attachment2.href,
436
+
437
+ title: attachment1.share.title,
438
+ description: attachment1.share.description,
439
+ source: attachment1.share.source,
440
+
441
+ image: attachment1.share.media.image,
442
+ width: attachment1.share.media.image_size.width,
443
+ height: attachment1.share.media.image_size.height,
444
+ playable: attachment1.share.media.playable,
445
+ duration: attachment1.share.media.duration,
446
+
447
+ subattachments: attachment1.share.subattachments,
448
+ properties: {},
449
+
450
+ animatedImageSize: attachment1.share.media.animated_image_size, // @Legacy
451
+ facebookUrl: attachment1.share.uri, // @Legacy
452
+ target: attachment1.share.target, // @Legacy
453
+ styleList: attachment1.share.style_list // @Legacy
454
+ };
455
+ case "video":
456
+ return {
457
+ type: "video",
458
+ ID: attachment1.metadata.fbid.toString(),
459
+ filename: attachment1.name,
460
+ fullFileName: fullFileName,
461
+ original_extension: getExtension(attachment1.original_extension, fullFileName),
462
+ mimeType: mimeType,
463
+ duration: durationVideo,
464
+
465
+ previewUrl: attachment1.preview_url,
466
+ previewWidth: attachment1.preview_width,
467
+ previewHeight: attachment1.preview_height,
468
+
469
+ url: attachment1.url,
470
+ width: attachment1.metadata.dimensions.width,
471
+ height: attachment1.metadata.dimensions.height,
472
+
473
+ videoType: "unknown",
474
+
475
+ thumbnailUrl: attachment1.thumbnail_url // @Legacy
476
+ };
477
+ case "error":
478
+ return {
479
+ type: "error",
480
+
481
+ // Save error attachments because we're unsure of their format,
482
+ // and whether there are cases they contain something useful for debugging.
483
+ attachment1: attachment1,
484
+ attachment2: attachment2
485
+ };
486
+ case "MessageImage":
487
+ return {
488
+ type: "photo",
489
+ ID: blob.legacy_attachment_id,
490
+ filename: blob.filename,
491
+ fullFileName: fullFileName,
492
+ fileSize: fileSize,
493
+ original_extension: getExtension(blob.original_extension, fullFileName),
494
+ mimeType: mimeType,
495
+ thumbnailUrl: blob.thumbnail.uri,
496
+
497
+ previewUrl: blob.preview.uri,
498
+ previewWidth: blob.preview.width,
499
+ previewHeight: blob.preview.height,
500
+
501
+ largePreviewUrl: blob.large_preview.uri,
502
+ largePreviewWidth: blob.large_preview.width,
503
+ largePreviewHeight: blob.large_preview.height,
504
+
505
+ url: blob.large_preview.uri, // @Legacy
506
+ width: blob.original_dimensions.x, // @Legacy
507
+ height: blob.original_dimensions.y, // @Legacy
508
+ name: blob.filename // @Legacy
509
+ };
510
+ case "MessageAnimatedImage":
511
+ return {
512
+ type: "animated_image",
513
+ ID: blob.legacy_attachment_id,
514
+ filename: blob.filename,
515
+ fullFileName: fullFileName,
516
+ original_extension: getExtension(blob.original_extension, fullFileName),
517
+ mimeType: mimeType,
518
+
519
+ previewUrl: blob.preview_image.uri,
520
+ previewWidth: blob.preview_image.width,
521
+ previewHeight: blob.preview_image.height,
522
+
523
+ url: blob.animated_image.uri,
524
+ width: blob.animated_image.width,
525
+ height: blob.animated_image.height,
526
+
527
+ thumbnailUrl: blob.preview_image.uri, // @Legacy
528
+ name: blob.filename, // @Legacy
529
+ facebookUrl: blob.animated_image.uri, // @Legacy
530
+ rawGifImage: blob.animated_image.uri, // @Legacy
531
+ animatedGifUrl: blob.animated_image.uri, // @Legacy
532
+ animatedGifPreviewUrl: blob.preview_image.uri, // @Legacy
533
+ animatedWebpUrl: blob.animated_image.uri, // @Legacy
534
+ animatedWebpPreviewUrl: blob.preview_image.uri // @Legacy
535
+ };
536
+ case "MessageVideo":
537
+ return {
538
+ type: "video",
539
+ ID: blob.legacy_attachment_id,
540
+ filename: blob.filename,
541
+ fullFileName: fullFileName,
542
+ original_extension: getExtension(blob.original_extension, fullFileName),
543
+ fileSize: fileSize,
544
+ duration: durationVideo,
545
+ mimeType: mimeType,
546
+
547
+ previewUrl: blob.large_image.uri,
548
+ previewWidth: blob.large_image.width,
549
+ previewHeight: blob.large_image.height,
550
+
551
+ url: blob.playable_url,
552
+ width: blob.original_dimensions.x,
553
+ height: blob.original_dimensions.y,
554
+
555
+ videoType: blob.video_type.toLowerCase(),
556
+
557
+ thumbnailUrl: blob.large_image.uri // @Legacy
558
+ };
559
+ case "MessageAudio":
560
+ return {
561
+ type: "audio",
562
+ ID: blob.url_shimhash,
563
+ filename: blob.filename,
564
+ fullFileName: fullFileName,
565
+ fileSize: fileSize,
566
+ duration: durationAudio,
567
+ original_extension: getExtension(blob.original_extension, fullFileName),
568
+ mimeType: mimeType,
569
+
570
+ audioType: blob.audio_type,
571
+ url: blob.playable_url,
572
+
573
+ isVoiceMail: blob.is_voicemail
574
+ };
575
+ case "StickerAttachment":
576
+ case "Sticker":
577
+ return {
578
+ type: "sticker",
579
+ ID: blob.id,
580
+ url: blob.url,
581
+
582
+ packID: blob.pack ? blob.pack.id : null,
583
+ spriteUrl: blob.sprite_image,
584
+ spriteUrl2x: blob.sprite_image_2x,
585
+ width: blob.width,
586
+ height: blob.height,
587
+
588
+ caption: blob.label,
589
+ description: blob.label,
590
+
591
+ frameCount: blob.frame_count,
592
+ frameRate: blob.frame_rate,
593
+ framesPerRow: blob.frames_per_row,
594
+ framesPerCol: blob.frames_per_column,
595
+
596
+ stickerID: blob.id, // @Legacy
597
+ spriteURI: blob.sprite_image, // @Legacy
598
+ spriteURI2x: blob.sprite_image_2x // @Legacy
599
+ };
600
+ case "MessageLocation":
601
+ var urlAttach = blob.story_attachment.url;
602
+ var mediaAttach = blob.story_attachment.media;
603
+
604
+ var u = querystring.parse(url.parse(urlAttach).query).u;
605
+ var where1 = querystring.parse(url.parse(u).query).where1;
606
+ var address = where1.split(", ");
607
+
608
+ var latitude;
609
+ var longitude;
610
+
611
+ try {
612
+ latitude = Number.parseFloat(address[0]);
613
+ longitude = Number.parseFloat(address[1]);
614
+ } catch (err) {
615
+ /* empty */
616
+ }
617
+
618
+ var imageUrl;
619
+ var width;
620
+ var height;
621
+
622
+ if (mediaAttach && mediaAttach.image) {
623
+ imageUrl = mediaAttach.image.uri;
624
+ width = mediaAttach.image.width;
625
+ height = mediaAttach.image.height;
626
+ }
627
+
628
+ return {
629
+ type: "location",
630
+ ID: blob.legacy_attachment_id,
631
+ latitude: latitude,
632
+ longitude: longitude,
633
+ image: imageUrl,
634
+ width: width,
635
+ height: height,
636
+ url: u || urlAttach,
637
+ address: where1,
638
+
639
+ facebookUrl: blob.story_attachment.url, // @Legacy
640
+ target: blob.story_attachment.target, // @Legacy
641
+ styleList: blob.story_attachment.style_list // @Legacy
642
+ };
643
+ case "ExtensibleAttachment":
644
+ return {
645
+ type: "share",
646
+ ID: blob.legacy_attachment_id,
647
+ url: blob.story_attachment.url,
648
+
649
+ title: blob.story_attachment.title_with_entities.text,
650
+ description:
651
+ blob.story_attachment.description &&
652
+ blob.story_attachment.description.text,
653
+ source: blob.story_attachment.source
654
+ ? blob.story_attachment.source.text
655
+ : null,
656
+
657
+ image:
658
+ blob.story_attachment.media &&
659
+ blob.story_attachment.media.image &&
660
+ blob.story_attachment.media.image.uri,
661
+ width:
662
+ blob.story_attachment.media &&
663
+ blob.story_attachment.media.image &&
664
+ blob.story_attachment.media.image.width,
665
+ height:
666
+ blob.story_attachment.media &&
667
+ blob.story_attachment.media.image &&
668
+ blob.story_attachment.media.image.height,
669
+ playable:
670
+ blob.story_attachment.media &&
671
+ blob.story_attachment.media.is_playable,
672
+ duration:
673
+ blob.story_attachment.media &&
674
+ blob.story_attachment.media.playable_duration_in_ms,
675
+ playableUrl:
676
+ blob.story_attachment.media == null
677
+ ? null
678
+ : blob.story_attachment.media.playable_url,
679
+
680
+ subattachments: blob.story_attachment.subattachments,
681
+ properties: blob.story_attachment.properties.reduce(function (obj, cur) {
682
+ obj[cur.key] = cur.value.text;
683
+ return obj;
684
+ }, {}),
685
+
686
+ facebookUrl: blob.story_attachment.url, // @Legacy
687
+ target: blob.story_attachment.target, // @Legacy
688
+ styleList: blob.story_attachment.style_list // @Legacy
689
+ };
690
+ case "MessageFile":
691
+ return {
692
+ type: "file",
693
+ ID: blob.message_file_fbid,
694
+ fullFileName: fullFileName,
695
+ filename: blob.filename,
696
+ fileSize: fileSize,
697
+ mimeType: blob.mimetype,
698
+ original_extension: blob.original_extension || fullFileName.split(".").pop(),
699
+
700
+ url: blob.url,
701
+ isMalicious: blob.is_malicious,
702
+ contentType: blob.content_type,
703
+
704
+ name: blob.filename
705
+ };
706
+ default:
707
+ throw new Error(
708
+ "unrecognized attach_file of type " +
709
+ type +
710
+ "`" +
711
+ JSON.stringify(attachment1, null, 4) +
712
+ " attachment2: " +
713
+ JSON.stringify(attachment2, null, 4) +
714
+ "`"
715
+ );
716
+ }
782
717
  }
783
718
 
784
719
  function formatAttachment(attachments, attachmentIds, attachmentMap, shareMap) {
785
- attachmentMap = shareMap || attachmentMap;
786
- return attachments
787
- ? attachments.map(function (val, i) {
788
- if (
789
- !attachmentMap ||
790
- !attachmentIds ||
791
- !attachmentMap[attachmentIds[i]]
792
- ) {
793
- return _formatAttachment(val);
794
- }
795
- return _formatAttachment(val, attachmentMap[attachmentIds[i]]);
796
- })
797
- : [];
720
+ attachmentMap = shareMap || attachmentMap;
721
+ return attachments
722
+ ? attachments.map(function (val, i) {
723
+ if (
724
+ !attachmentMap ||
725
+ !attachmentIds ||
726
+ !attachmentMap[attachmentIds[i]]
727
+ ) {
728
+ return _formatAttachment(val);
729
+ }
730
+ return _formatAttachment(val, attachmentMap[attachmentIds[i]]);
731
+ })
732
+ : [];
798
733
  }
799
734
 
800
735
  function formatDeltaMessage(m) {
801
- const md = m.delta.messageMetadata;
802
-
803
- const mdata =
804
- m.delta.data === undefined
805
- ? []
806
- : m.delta.data.prng === undefined
807
- ? []
808
- : JSON.parse(m.delta.data.prng);
809
- const m_id = mdata.map(u => u.i);
810
- const m_offset = mdata.map(u => u.o);
811
- const m_length = mdata.map(u => u.l);
812
- const mentions = {};
813
- for (let i = 0; i < m_id.length; i++) {
814
- mentions[m_id[i]] = m.delta.body.substring(
815
- m_offset[i],
816
- m_offset[i] + m_length[i]
817
- );
818
- }
819
- return {
820
- type: "message",
821
- senderID: formatID(md.actorFbId.toString()),
822
- body: m.delta.body || "",
823
- threadID: formatID(
824
- (md.threadKey.threadFbId || md.threadKey.otherUserFbId).toString()
825
- ),
826
- messageID: md.messageId,
827
- attachments: (m.delta.attachments || []).map(v => _formatAttachment(v)),
828
- mentions: mentions,
829
- timestamp: md.timestamp,
830
- isGroup: !!md.threadKey.threadFbId,
831
- participantIDs: m.delta.participants || (md.cid ? md.cid.canonicalParticipantFbids : []) || []
832
- };
736
+ const md = m.delta.messageMetadata;
737
+
738
+ const mdata =
739
+ m.delta.data === undefined
740
+ ? []
741
+ : m.delta.data.prng === undefined
742
+ ? []
743
+ : JSON.parse(m.delta.data.prng);
744
+ const m_id = mdata.map(u => u.i);
745
+ const m_offset = mdata.map(u => u.o);
746
+ const m_length = mdata.map(u => u.l);
747
+ const mentions = {};
748
+ for (let i = 0; i < m_id.length; i++) {
749
+ mentions[m_id[i]] = m.delta.body.substring(
750
+ m_offset[i],
751
+ m_offset[i] + m_length[i]
752
+ );
753
+ }
754
+ return {
755
+ type: "message",
756
+ senderID: formatID(md.actorFbId.toString()),
757
+ body: m.delta.body || "",
758
+ threadID: formatID(
759
+ (md.threadKey.threadFbId || md.threadKey.otherUserFbId).toString()
760
+ ),
761
+ messageID: md.messageId,
762
+ attachments: (m.delta.attachments || []).map(v => _formatAttachment(v)),
763
+ mentions: mentions,
764
+ timestamp: md.timestamp,
765
+ isGroup: !!md.threadKey.threadFbId,
766
+ participantIDs: m.delta.participants || (md.cid ? md.cid.canonicalParticipantFbids : []) || []
767
+ };
833
768
  }
834
769
 
835
770
  function formatID(id) {
836
- if (id != undefined && id != null) {
837
- return id.replace(/(fb)?id[:.]/, "");
838
- }
839
- else {
840
- return id;
841
- }
771
+ if (id != undefined && id != null) {
772
+ return id.replace(/(fb)?id[:.]/, "");
773
+ }
774
+ else {
775
+ return id;
776
+ }
842
777
  }
843
778
 
844
779
  function formatMessage(m) {
845
- const originalMessage = m.message ? m.message : m;
846
- const obj = {
847
- type: "message",
848
- senderName: originalMessage.sender_name,
849
- senderID: formatID(originalMessage.sender_fbid.toString()),
850
- participantNames: originalMessage.group_thread_info
851
- ? originalMessage.group_thread_info.participant_names
852
- : [originalMessage.sender_name.split(" ")[0]],
853
- participantIDs: originalMessage.group_thread_info
854
- ? originalMessage.group_thread_info.participant_ids.map(function (v) {
855
- return formatID(v.toString());
856
- })
857
- : [formatID(originalMessage.sender_fbid)],
858
- body: originalMessage.body || "",
859
- threadID: formatID(
860
- (
861
- originalMessage.thread_fbid || originalMessage.other_user_fbid
862
- ).toString()
863
- ),
864
- threadName: originalMessage.group_thread_info
865
- ? originalMessage.group_thread_info.name
866
- : originalMessage.sender_name,
867
- location: originalMessage.coordinates ? originalMessage.coordinates : null,
868
- messageID: originalMessage.mid
869
- ? originalMessage.mid.toString()
870
- : originalMessage.message_id,
871
- attachments: formatAttachment(
872
- originalMessage.attachments,
873
- originalMessage.attachmentIds,
874
- originalMessage.attachment_map,
875
- originalMessage.share_map
876
- ),
877
- timestamp: originalMessage.timestamp,
878
- timestampAbsolute: originalMessage.timestamp_absolute,
879
- timestampRelative: originalMessage.timestamp_relative,
880
- timestampDatetime: originalMessage.timestamp_datetime,
881
- tags: originalMessage.tags,
882
- reactions: originalMessage.reactions ? originalMessage.reactions : [],
883
- isUnread: originalMessage.is_unread
884
- };
885
-
886
- if (m.type === "pages_messaging")
887
- obj.pageID = m.realtime_viewer_fbid.toString();
888
- obj.isGroup = obj.participantIDs.length > 2;
889
-
890
- return obj;
780
+ const originalMessage = m.message ? m.message : m;
781
+ const obj = {
782
+ type: "message",
783
+ senderName: originalMessage.sender_name,
784
+ senderID: formatID(originalMessage.sender_fbid.toString()),
785
+ participantNames: originalMessage.group_thread_info
786
+ ? originalMessage.group_thread_info.participant_names
787
+ : [originalMessage.sender_name.split(" ")[0]],
788
+ participantIDs: originalMessage.group_thread_info
789
+ ? originalMessage.group_thread_info.participant_ids.map(function (v) {
790
+ return formatID(v.toString());
791
+ })
792
+ : [formatID(originalMessage.sender_fbid)],
793
+ body: originalMessage.body || "",
794
+ threadID: formatID(
795
+ (
796
+ originalMessage.thread_fbid || originalMessage.other_user_fbid
797
+ ).toString()
798
+ ),
799
+ threadName: originalMessage.group_thread_info
800
+ ? originalMessage.group_thread_info.name
801
+ : originalMessage.sender_name,
802
+ location: originalMessage.coordinates ? originalMessage.coordinates : null,
803
+ messageID: originalMessage.mid
804
+ ? originalMessage.mid.toString()
805
+ : originalMessage.message_id,
806
+ attachments: formatAttachment(
807
+ originalMessage.attachments,
808
+ originalMessage.attachmentIds,
809
+ originalMessage.attachment_map,
810
+ originalMessage.share_map
811
+ ),
812
+ timestamp: originalMessage.timestamp,
813
+ timestampAbsolute: originalMessage.timestamp_absolute,
814
+ timestampRelative: originalMessage.timestamp_relative,
815
+ timestampDatetime: originalMessage.timestamp_datetime,
816
+ tags: originalMessage.tags,
817
+ reactions: originalMessage.reactions ? originalMessage.reactions : [],
818
+ isUnread: originalMessage.is_unread
819
+ };
820
+
821
+ if (m.type === "pages_messaging")
822
+ obj.pageID = m.realtime_viewer_fbid.toString();
823
+ obj.isGroup = obj.participantIDs.length > 2;
824
+
825
+ return obj;
891
826
  }
892
827
 
893
828
  function formatEvent(m) {
894
- const originalMessage = m.message ? m.message : m;
895
- let logMessageType = originalMessage.log_message_type;
896
- let logMessageData;
897
- if (logMessageType === "log:generic-admin-text") {
898
- logMessageData = originalMessage.log_message_data.untypedData;
899
- logMessageType = getAdminTextMessageType(
900
- originalMessage.log_message_data.message_type
901
- );
902
- }
903
- else {
904
- logMessageData = originalMessage.log_message_data;
905
- }
906
-
907
- return Object.assign(formatMessage(originalMessage), {
908
- type: "event",
909
- logMessageType: logMessageType,
910
- logMessageData: logMessageData,
911
- logMessageBody: originalMessage.log_message_body
912
- });
829
+ const originalMessage = m.message ? m.message : m;
830
+ let logMessageType = originalMessage.log_message_type;
831
+ let logMessageData;
832
+ if (logMessageType === "log:generic-admin-text") {
833
+ logMessageData = originalMessage.log_message_data.untypedData;
834
+ logMessageType = getAdminTextMessageType(
835
+ originalMessage.log_message_data.message_type
836
+ );
837
+ }
838
+ else {
839
+ logMessageData = originalMessage.log_message_data;
840
+ }
841
+
842
+ return Object.assign(formatMessage(originalMessage), {
843
+ type: "event",
844
+ logMessageType: logMessageType,
845
+ logMessageData: logMessageData,
846
+ logMessageBody: originalMessage.log_message_body
847
+ });
913
848
  }
914
849
 
915
850
  function formatHistoryMessage(m) {
916
- switch (m.action_type) {
917
- case "ma-type:log-message":
918
- return formatEvent(m);
919
- default:
920
- return formatMessage(m);
921
- }
851
+ switch (m.action_type) {
852
+ case "ma-type:log-message":
853
+ return formatEvent(m);
854
+ default:
855
+ return formatMessage(m);
856
+ }
922
857
  }
923
858
 
924
859
  // Get a more readable message type for AdminTextMessages
925
860
  function getAdminTextMessageType(type) {
926
- switch (type) {
927
- case "change_thread_theme":
928
- return "log:thread-color";
929
- case "change_thread_icon":
930
- case "change_thread_quick_reaction":
931
- return "log:thread-icon";
932
- case "change_thread_nickname":
933
- return "log:user-nickname";
934
- case "change_thread_admins":
935
- return "log:thread-admins";
936
- case "group_poll":
937
- return "log:thread-poll";
938
- case "change_thread_approval_mode":
939
- return "log:thread-approval-mode";
940
- case "messenger_call_log":
941
- case "participant_joined_group_call":
942
- return "log:thread-call";
943
- default:
944
- return type;
945
- }
861
+ switch (type) {
862
+ case "change_thread_theme":
863
+ return "log:thread-color";
864
+ case "change_thread_icon":
865
+ return "log:thread-icon";
866
+ case "change_thread_nickname":
867
+ return "log:user-nickname";
868
+ case "change_thread_admins":
869
+ return "log:thread-admins";
870
+ case "group_poll":
871
+ return "log:thread-poll";
872
+ case "change_thread_approval_mode":
873
+ return "log:thread-approval-mode";
874
+ case "messenger_call_log":
875
+ case "participant_joined_group_call":
876
+ return "log:thread-call";
877
+ default:
878
+ return type;
879
+ }
946
880
  }
947
881
 
948
882
  function formatDeltaEvent(m) {
949
- let logMessageType;
950
- let logMessageData;
951
-
952
- // log:thread-color => {theme_color}
953
- // log:user-nickname => {participant_id, nickname}
954
- // log:thread-icon => {thread_icon}
955
- // log:thread-name => {name}
956
- // log:subscribe => {addedParticipants - [Array]}
957
- // log:unsubscribe => {leftParticipantFbId}
958
-
959
- switch (m.class) {
960
- case "AdminTextMessage":
961
- logMessageData = m.untypedData;
962
- logMessageType = getAdminTextMessageType(m.type);
963
- break;
964
- case "ThreadName":
965
- logMessageType = "log:thread-name";
966
- logMessageData = { name: m.name };
967
- break;
968
- case "ParticipantsAddedToGroupThread":
969
- logMessageType = "log:subscribe";
970
- logMessageData = { addedParticipants: m.addedParticipants };
971
- break;
972
- case "ParticipantLeftGroupThread":
973
- logMessageType = "log:unsubscribe";
974
- logMessageData = { leftParticipantFbId: m.leftParticipantFbId };
975
- break;
976
- case "ApprovalQueue":
977
- logMessageType = "log:approval-queue";
978
- logMessageData = {
979
- approvalQueue: {
980
- action: m.action,
981
- recipientFbId: m.recipientFbId,
982
- requestSource: m.requestSource,
983
- ...m.messageMetadata
984
- }
985
- };
986
- }
987
-
988
- return {
989
- type: "event",
990
- threadID: formatID(
991
- (
992
- m.messageMetadata.threadKey.threadFbId ||
993
- m.messageMetadata.threadKey.otherUserFbId
994
- ).toString()
995
- ),
996
- messageID: m.messageMetadata.messageId.toString(),
997
- logMessageType: logMessageType,
998
- logMessageData: logMessageData,
999
- logMessageBody: m.messageMetadata.adminText,
1000
- timestamp: m.messageMetadata.timestamp,
1001
- author: m.messageMetadata.actorFbId,
1002
- participantIDs: (m.participants || []).map(p => p.toString())
1003
- };
883
+ let logMessageType;
884
+ let logMessageData;
885
+
886
+ // log:thread-color => {theme_color}
887
+ // log:user-nickname => {participant_id, nickname}
888
+ // log:thread-icon => {thread_icon}
889
+ // log:thread-name => {name}
890
+ // log:subscribe => {addedParticipants - [Array]}
891
+ // log:unsubscribe => {leftParticipantFbId}
892
+
893
+ switch (m.class) {
894
+ case "AdminTextMessage":
895
+ logMessageData = m.untypedData;
896
+ logMessageType = getAdminTextMessageType(m.type);
897
+ break;
898
+ case "ThreadName":
899
+ logMessageType = "log:thread-name";
900
+ logMessageData = { name: m.name };
901
+ break;
902
+ case "ParticipantsAddedToGroupThread":
903
+ logMessageType = "log:subscribe";
904
+ logMessageData = { addedParticipants: m.addedParticipants };
905
+ break;
906
+ case "ParticipantLeftGroupThread":
907
+ logMessageType = "log:unsubscribe";
908
+ logMessageData = { leftParticipantFbId: m.leftParticipantFbId };
909
+ break;
910
+ case "ApprovalQueue":
911
+ logMessageType = "log:approval-queue";
912
+ logMessageData = {
913
+ approvalQueue: {
914
+ action: m.action,
915
+ recipientFbId: m.recipientFbId,
916
+ requestSource: m.requestSource,
917
+ ...m.messageMetadata
918
+ }
919
+ };
920
+ }
921
+
922
+ return {
923
+ type: "event",
924
+ threadID: formatID(
925
+ (
926
+ m.messageMetadata.threadKey.threadFbId ||
927
+ m.messageMetadata.threadKey.otherUserFbId
928
+ ).toString()
929
+ ),
930
+ messageID: m.messageMetadata.messageId.toString(),
931
+ logMessageType: logMessageType,
932
+ logMessageData: logMessageData,
933
+ logMessageBody: m.messageMetadata.adminText,
934
+ timestamp: m.messageMetadata.timestamp,
935
+ author: m.messageMetadata.actorFbId,
936
+ participantIDs: (m.participants || []).map(p => p.toString())
937
+ };
1004
938
  }
1005
939
 
1006
940
  function formatTyp(event) {
1007
- return {
1008
- isTyping: !!event.st,
1009
- from: event.from.toString(),
1010
- threadID: formatID(
1011
- (event.to || event.thread_fbid || event.from).toString()
1012
- ),
1013
- // When receiving typ indication from mobile, `from_mobile` isn't set.
1014
- // If it is, we just use that value.
1015
- fromMobile: event.hasOwnProperty("from_mobile") ? event.from_mobile : true,
1016
- userID: (event.realtime_viewer_fbid || event.from).toString(),
1017
- type: "typ"
1018
- };
941
+ return {
942
+ isTyping: !!event.st,
943
+ from: event.from.toString(),
944
+ threadID: formatID(
945
+ (event.to || event.thread_fbid || event.from).toString()
946
+ ),
947
+ // When receiving typ indication from mobile, `from_mobile` isn't set.
948
+ // If it is, we just use that value.
949
+ fromMobile: event.hasOwnProperty("from_mobile") ? event.from_mobile : true,
950
+ userID: (event.realtime_viewer_fbid || event.from).toString(),
951
+ type: "typ"
952
+ };
1019
953
  }
1020
954
 
1021
955
  function formatDeltaReadReceipt(delta) {
1022
- // otherUserFbId seems to be used as both the readerID and the threadID in a 1-1 chat.
1023
- // In a group chat actorFbId is used for the reader and threadFbId for the thread.
1024
- return {
1025
- reader: (delta.threadKey.otherUserFbId || delta.actorFbId).toString(),
1026
- time: delta.actionTimestampMs,
1027
- threadID: formatID(
1028
- (delta.threadKey.otherUserFbId || delta.threadKey.threadFbId).toString()
1029
- ),
1030
- type: "read_receipt"
1031
- };
956
+ // otherUserFbId seems to be used as both the readerID and the threadID in a 1-1 chat.
957
+ // In a group chat actorFbId is used for the reader and threadFbId for the thread.
958
+ return {
959
+ reader: (delta.threadKey.otherUserFbId || delta.actorFbId).toString(),
960
+ time: delta.actionTimestampMs,
961
+ threadID: formatID(
962
+ (delta.threadKey.otherUserFbId || delta.threadKey.threadFbId).toString()
963
+ ),
964
+ type: "read_receipt"
965
+ };
1032
966
  }
1033
967
 
1034
968
  function formatReadReceipt(event) {
1035
- return {
1036
- reader: event.reader.toString(),
1037
- time: event.time,
1038
- threadID: formatID((event.thread_fbid || event.reader).toString()),
1039
- type: "read_receipt"
1040
- };
969
+ return {
970
+ reader: event.reader.toString(),
971
+ time: event.time,
972
+ threadID: formatID((event.thread_fbid || event.reader).toString()),
973
+ type: "read_receipt"
974
+ };
1041
975
  }
1042
976
 
1043
977
  function formatRead(event) {
1044
- return {
1045
- threadID: formatID(
1046
- (
1047
- (event.chat_ids && event.chat_ids[0]) ||
1048
- (event.thread_fbids && event.thread_fbids[0])
1049
- ).toString()
1050
- ),
1051
- time: event.timestamp,
1052
- type: "read"
1053
- };
978
+ return {
979
+ threadID: formatID(
980
+ (
981
+ (event.chat_ids && event.chat_ids[0]) ||
982
+ (event.thread_fbids && event.thread_fbids[0])
983
+ ).toString()
984
+ ),
985
+ time: event.timestamp,
986
+ type: "read"
987
+ };
1054
988
  }
1055
989
 
1056
990
  function getFrom(str, startToken, endToken) {
1057
- const start = str.indexOf(startToken) + startToken.length;
1058
- if (start < startToken.length) return "";
1059
-
1060
- const lastHalf = str.substring(start);
1061
- const end = lastHalf.indexOf(endToken);
1062
- if (end === -1) {
1063
- throw new Error(
1064
- "Could not find endTime `" + endToken + "` in the given string."
1065
- );
1066
- }
1067
- return lastHalf.substring(0, end);
991
+ const start = str.indexOf(startToken) + startToken.length;
992
+ if (start < startToken.length) return "";
993
+
994
+ const lastHalf = str.substring(start);
995
+ const end = lastHalf.indexOf(endToken);
996
+ if (end === -1) {
997
+ throw new Error(
998
+ "Could not find endTime `" + endToken + "` in the given string."
999
+ );
1000
+ }
1001
+ return lastHalf.substring(0, end);
1068
1002
  }
1069
1003
 
1070
1004
  function makeParsable(html) {
1071
- const withoutForLoop = html.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*/, "");
1072
-
1073
- // (What the fuck FB, why windows style newlines?)
1074
- // So sometimes FB will send us base multiple objects in the same response.
1075
- // They're all valid JSON, one after the other, at the top level. We detect
1076
- // that and make it parse-able by JSON.parse.
1077
- // Ben - July 15th 2017
1078
- //
1079
- // It turns out that Facebook may insert random number of spaces before
1080
- // next object begins (issue #616)
1081
- // rav_kr - 2018-03-19
1082
- const maybeMultipleObjects = withoutForLoop.split(/\}\r\n *\{/);
1083
- if (maybeMultipleObjects.length === 1) return maybeMultipleObjects;
1084
-
1085
- return "[" + maybeMultipleObjects.join("},{") + "]";
1005
+ const withoutForLoop = html.replace(/for\s*\(\s*;\s*;\s*\)\s*;\s*/, "");
1006
+
1007
+ // (What the fuck FB, why windows style newlines?)
1008
+ // So sometimes FB will send us base multiple objects in the same response.
1009
+ // They're all valid JSON, one after the other, at the top level. We detect
1010
+ // that and make it parse-able by JSON.parse.
1011
+ // Ben - July 15th 2017
1012
+ //
1013
+ // It turns out that Facebook may insert random number of spaces before
1014
+ // next object begins (issue #616)
1015
+ // rav_kr - 2018-03-19
1016
+ const maybeMultipleObjects = withoutForLoop.split(/\}\r\n *\{/);
1017
+ if (maybeMultipleObjects.length === 1) return maybeMultipleObjects;
1018
+
1019
+ return "[" + maybeMultipleObjects.join("},{") + "]";
1086
1020
  }
1087
1021
 
1088
1022
  function arrToForm(form) {
1089
- return arrayToObject(
1090
- form,
1091
- function (v) {
1092
- return v.name;
1093
- },
1094
- function (v) {
1095
- return v.val;
1096
- }
1097
- );
1023
+ return arrayToObject(
1024
+ form,
1025
+ function (v) {
1026
+ return v.name;
1027
+ },
1028
+ function (v) {
1029
+ return v.val;
1030
+ }
1031
+ );
1098
1032
  }
1099
1033
 
1100
1034
  function arrayToObject(arr, getKey, getValue) {
1101
- return arr.reduce(function (acc, val) {
1102
- acc[getKey(val)] = getValue(val);
1103
- return acc;
1104
- }, {});
1035
+ return arr.reduce(function (acc, val) {
1036
+ acc[getKey(val)] = getValue(val);
1037
+ return acc;
1038
+ }, {});
1105
1039
  }
1106
1040
 
1107
1041
  function getSignatureID() {
1108
- return Math.floor(Math.random() * 2147483648).toString(16);
1042
+ return Math.floor(Math.random() * 2147483648).toString(16);
1109
1043
  }
1110
1044
 
1111
1045
  function generateTimestampRelative() {
1112
- const d = new Date();
1113
- return d.getHours() + ":" + padZeros(d.getMinutes());
1046
+ const d = new Date();
1047
+ return d.getHours() + ":" + padZeros(d.getMinutes());
1114
1048
  }
1115
1049
 
1116
1050
  function makeDefaults(html, userID, ctx) {
1117
- let reqCounter = 1;
1118
- const fb_dtsg = getFrom(html, 'name="fb_dtsg" value="', '"');
1119
-
1120
- // @Hack Ok we've done hacky things, this is definitely on top 5.
1121
- // We totally assume the object is flat and try parsing until a }.
1122
- // If it works though it's cool because we get a bunch of extra data things.
1123
- //
1124
- // Update: we don't need this. Leaving it in in case we ever do.
1125
- // Ben - July 15th 2017
1126
-
1127
- // var siteData = getFrom(html, "[\"SiteData\",[],", "},");
1128
- // try {
1129
- // siteData = JSON.parse(siteData + "}");
1130
- // } catch(e) {
1131
- // log.warn("makeDefaults", "Couldn't parse SiteData. Won't have access to some variables.");
1132
- // siteData = {};
1133
- // }
1134
-
1135
- let ttstamp = "2";
1136
- for (let i = 0; i < fb_dtsg.length; i++) {
1137
- ttstamp += fb_dtsg.charCodeAt(i);
1138
- }
1139
- const revision = getFrom(html, 'revision":', ",");
1140
-
1141
- function mergeWithDefaults(obj) {
1142
- // @TODO This is missing a key called __dyn.
1143
- // After some investigation it seems like __dyn is some sort of set that FB
1144
- // calls BitMap. It seems like certain responses have a "define" key in the
1145
- // res.jsmods arrays. I think the code iterates over those and calls `set`
1146
- // on the bitmap for each of those keys. Then it calls
1147
- // bitmap.toCompressedString() which returns what __dyn is.
1148
- //
1149
- // So far the API has been working without this.
1150
- //
1151
- // Ben - July 15th 2017
1152
- const newObj = {
1153
- __user: userID,
1154
- __req: (reqCounter++).toString(36),
1155
- __rev: revision,
1156
- __a: 1,
1157
- // __af: siteData.features,
1158
- fb_dtsg: ctx.fb_dtsg ? ctx.fb_dtsg : fb_dtsg,
1159
- jazoest: ctx.ttstamp ? ctx.ttstamp : ttstamp
1160
- // __spin_r: siteData.__spin_r,
1161
- // __spin_b: siteData.__spin_b,
1162
- // __spin_t: siteData.__spin_t,
1163
- };
1164
-
1165
- // @TODO this is probably not needed.
1166
- // Ben - July 15th 2017
1167
- // if (siteData.be_key) {
1168
- // newObj[siteData.be_key] = siteData.be_mode;
1169
- // }
1170
- // if (siteData.pkg_cohort_key) {
1171
- // newObj[siteData.pkg_cohort_key] = siteData.pkg_cohort;
1172
- // }
1173
-
1174
- if (!obj) return newObj;
1175
-
1176
- for (const prop in obj) {
1177
- if (obj.hasOwnProperty(prop)) {
1178
- if (!newObj[prop]) {
1179
- newObj[prop] = obj[prop];
1180
- }
1181
- }
1182
- }
1183
-
1184
- return newObj;
1185
- }
1186
-
1187
- function postWithDefaults(url, jar, form, ctxx, customHeader = {}) {
1188
- return post(url, jar, mergeWithDefaults(form), ctx.globalOptions, ctxx || ctx, customHeader);
1189
- }
1190
-
1191
- function getWithDefaults(url, jar, qs, ctxx, customHeader = {}) {
1192
- return get(url, jar, mergeWithDefaults(qs), ctx.globalOptions, ctxx || ctx, customHeader);
1193
- }
1194
-
1195
- function postFormDataWithDefault(url, jar, form, qs, ctxx) {
1196
- return postFormData(
1197
- url,
1198
- jar,
1199
- mergeWithDefaults(form),
1200
- mergeWithDefaults(qs),
1201
- ctx.globalOptions,
1202
- ctxx || ctx
1203
- );
1204
- }
1205
-
1206
- return {
1207
- get: getWithDefaults,
1208
- post: postWithDefaults,
1209
- postFormData: postFormDataWithDefault
1210
- };
1051
+ let reqCounter = 1;
1052
+ const fb_dtsg = getFrom(html, 'name="fb_dtsg" value="', '"');
1053
+
1054
+ // @Hack Ok we've done hacky things, this is definitely on top 5.
1055
+ // We totally assume the object is flat and try parsing until a }.
1056
+ // If it works though it's cool because we get a bunch of extra data things.
1057
+ //
1058
+ // Update: we don't need this. Leaving it in in case we ever do.
1059
+ // Ben - July 15th 2017
1060
+
1061
+ // var siteData = getFrom(html, "[\"SiteData\",[],", "},");
1062
+ // try {
1063
+ // siteData = JSON.parse(siteData + "}");
1064
+ // } catch(e) {
1065
+ // log.warn("makeDefaults", "Couldn't parse SiteData. Won't have access to some variables.");
1066
+ // siteData = {};
1067
+ // }
1068
+
1069
+ let ttstamp = "2";
1070
+ for (let i = 0; i < fb_dtsg.length; i++) {
1071
+ ttstamp += fb_dtsg.charCodeAt(i);
1072
+ }
1073
+ const revision = getFrom(html, 'revision":', ",");
1074
+
1075
+ function mergeWithDefaults(obj) {
1076
+ // @TODO This is missing a key called __dyn.
1077
+ // After some investigation it seems like __dyn is some sort of set that FB
1078
+ // calls BitMap. It seems like certain responses have a "define" key in the
1079
+ // res.jsmods arrays. I think the code iterates over those and calls `set`
1080
+ // on the bitmap for each of those keys. Then it calls
1081
+ // bitmap.toCompressedString() which returns what __dyn is.
1082
+ //
1083
+ // So far the API has been working without this.
1084
+ //
1085
+ // Ben - July 15th 2017
1086
+ const newObj = {
1087
+ __user: userID,
1088
+ __req: (reqCounter++).toString(36),
1089
+ __rev: revision,
1090
+ __a: 1,
1091
+ // __af: siteData.features,
1092
+ fb_dtsg: ctx.fb_dtsg ? ctx.fb_dtsg : fb_dtsg,
1093
+ jazoest: ctx.ttstamp ? ctx.ttstamp : ttstamp
1094
+ // __spin_r: siteData.__spin_r,
1095
+ // __spin_b: siteData.__spin_b,
1096
+ // __spin_t: siteData.__spin_t,
1097
+ };
1098
+
1099
+ // @TODO this is probably not needed.
1100
+ // Ben - July 15th 2017
1101
+ // if (siteData.be_key) {
1102
+ // newObj[siteData.be_key] = siteData.be_mode;
1103
+ // }
1104
+ // if (siteData.pkg_cohort_key) {
1105
+ // newObj[siteData.pkg_cohort_key] = siteData.pkg_cohort;
1106
+ // }
1107
+
1108
+ if (!obj) return newObj;
1109
+
1110
+ for (const prop in obj) {
1111
+ if (obj.hasOwnProperty(prop)) {
1112
+ if (!newObj[prop]) {
1113
+ newObj[prop] = obj[prop];
1114
+ }
1115
+ }
1116
+ }
1117
+
1118
+ return newObj;
1119
+ }
1120
+
1121
+ function postWithDefaults(url, jar, form, ctxx, customHeader = {}) {
1122
+ return post(url, jar, mergeWithDefaults(form), ctx.globalOptions, ctxx || ctx, customHeader);
1123
+ }
1124
+
1125
+ function getWithDefaults(url, jar, qs, ctxx, customHeader = {}) {
1126
+ return get(url, jar, mergeWithDefaults(qs), ctx.globalOptions, ctxx || ctx, customHeader);
1127
+ }
1128
+
1129
+ function postFormDataWithDefault(url, jar, form, qs, ctxx) {
1130
+ return postFormData(
1131
+ url,
1132
+ jar,
1133
+ mergeWithDefaults(form),
1134
+ mergeWithDefaults(qs),
1135
+ ctx.globalOptions,
1136
+ ctxx || ctx
1137
+ );
1138
+ }
1139
+
1140
+ return {
1141
+ get: getWithDefaults,
1142
+ post: postWithDefaults,
1143
+ postFormData: postFormDataWithDefault
1144
+ };
1211
1145
  }
1212
1146
 
1213
1147
  function parseAndCheckLogin(ctx, defaultFuncs, retryCount, sourceCall) {
1214
- if (retryCount == undefined) {
1215
- retryCount = 0;
1216
- }
1217
- if (sourceCall == undefined) {
1218
- try {
1219
- throw new Error();
1220
- }
1221
- catch (e) {
1222
- sourceCall = e;
1223
- }
1224
- }
1225
- return function (data) {
1226
- return tryPromise(function () {
1227
- log.verbose("parseAndCheckLogin", data.body);
1228
- if (data.statusCode >= 500 && data.statusCode < 600) {
1229
- if (retryCount >= 5) {
1230
- throw new CustomError({
1231
- message: "Request retry failed. Check the `res` and `statusCode` property on this error.",
1232
- statusCode: data.statusCode,
1233
- res: data.body,
1234
- error: "Request retry failed. Check the `res` and `statusCode` property on this error.",
1235
- sourceCall: sourceCall
1236
- });
1237
- }
1238
- retryCount++;
1239
- const retryTime = Math.floor(Math.random() * 5000);
1240
- log.warn(
1241
- "parseAndCheckLogin",
1242
- "Got status code " +
1243
- data.statusCode +
1244
- " - " +
1245
- retryCount +
1246
- ". attempt to retry in " +
1247
- retryTime +
1248
- " milliseconds..."
1249
- );
1250
- const url =
1251
- data.request.uri.protocol +
1252
- "//" +
1253
- data.request.uri.hostname +
1254
- data.request.uri.pathname;
1255
- if (
1256
- data.request.headers["Content-Type"].split(";")[0] ===
1257
- "multipart/form-data"
1258
- ) {
1259
- return delay(retryTime)
1260
- .then(function () {
1261
- return defaultFuncs.postFormData(
1262
- url,
1263
- ctx.jar,
1264
- data.request.formData,
1265
- {}
1266
- );
1267
- })
1268
- .then(parseAndCheckLogin(ctx, defaultFuncs, retryCount, sourceCall));
1269
- }
1270
- else {
1271
- return delay(retryTime)
1272
- .then(function () {
1273
- return defaultFuncs.post(url, ctx.jar, data.request.formData);
1274
- })
1275
- .then(parseAndCheckLogin(ctx, defaultFuncs, retryCount, sourceCall));
1276
- }
1277
- }
1278
- if (data.statusCode !== 200)
1279
- throw new CustomError({
1280
- message: "parseAndCheckLogin got status code: " + data.statusCode + ". Bailing out of trying to parse response.",
1281
- statusCode: data.statusCode,
1282
- res: data.body,
1283
- error: "parseAndCheckLogin got status code: " + data.statusCode + ". Bailing out of trying to parse response.",
1284
- sourceCall: sourceCall
1285
- });
1286
-
1287
- let res = null;
1288
- try {
1289
- res = JSON.parse(makeParsable(data.body));
1290
- } catch (e) {
1291
- throw new CustomError({
1292
- message: "JSON.parse error. Check the `detail` property on this error.",
1293
- detail: e,
1294
- res: data.body,
1295
- error: "JSON.parse error. Check the `detail` property on this error.",
1296
- sourceCall: sourceCall
1297
- });
1298
- }
1299
-
1300
- // In some cases the response contains only a redirect URL which should be followed
1301
- if (res.redirect && data.request.method === "GET") {
1302
- return defaultFuncs
1303
- .get(res.redirect, ctx.jar)
1304
- .then(parseAndCheckLogin(ctx, defaultFuncs, undefined, sourceCall));
1305
- }
1306
-
1307
- // TODO: handle multiple cookies?
1308
- if (
1309
- res.jsmods &&
1310
- res.jsmods.require &&
1311
- Array.isArray(res.jsmods.require[0]) &&
1312
- res.jsmods.require[0][0] === "Cookie"
1313
- ) {
1314
- res.jsmods.require[0][3][0] = res.jsmods.require[0][3][0].replace(
1315
- "_js_",
1316
- ""
1317
- );
1318
- const cookie = formatCookie(res.jsmods.require[0][3], "facebook");
1319
- const cookie2 = formatCookie(res.jsmods.require[0][3], "messenger");
1320
- ctx.jar.setCookie(cookie, "https://www.facebook.com");
1321
- ctx.jar.setCookie(cookie2, "https://www.messenger.com");
1322
- }
1323
-
1324
- // On every request we check if we got a DTSG and we mutate the context so that we use the latest
1325
- // one for the next requests.
1326
- if (res.jsmods && Array.isArray(res.jsmods.require)) {
1327
- const arr = res.jsmods.require;
1328
- for (const i in arr) {
1329
- if (arr[i][0] === "DTSG" && arr[i][1] === "setToken") {
1330
- ctx.fb_dtsg = arr[i][3][0];
1331
-
1332
- // Update ttstamp since that depends on fb_dtsg
1333
- ctx.ttstamp = "2";
1334
- for (let j = 0; j < ctx.fb_dtsg.length; j++) {
1335
- ctx.ttstamp += ctx.fb_dtsg.charCodeAt(j);
1336
- }
1337
- }
1338
- }
1339
- }
1340
-
1341
- if (res.error === 1357001) {
1342
- throw new CustomError({
1343
- message: "Facebook blocked login. Please visit https://facebook.com and check your account.",
1344
- error: "Not logged in.",
1345
- res: res,
1346
- statusCode: data.statusCode,
1347
- sourceCall: sourceCall
1348
- });
1349
- }
1350
- return res;
1351
- });
1352
- };
1148
+ if (retryCount == undefined) {
1149
+ retryCount = 0;
1150
+ }
1151
+ if (sourceCall == undefined) {
1152
+ try {
1153
+ throw new Error();
1154
+ }
1155
+ catch (e) {
1156
+ sourceCall = e;
1157
+ }
1158
+ }
1159
+ return function (data) {
1160
+ return bluebird.try(function () {
1161
+ log.verbose("parseAndCheckLogin", data.body);
1162
+ if (data.statusCode >= 500 && data.statusCode < 600) {
1163
+ if (retryCount >= 5) {
1164
+ throw new CustomError({
1165
+ message: "Request retry failed. Check the `res` and `statusCode` property on this error.",
1166
+ statusCode: data.statusCode,
1167
+ res: data.body,
1168
+ error: "Request retry failed. Check the `res` and `statusCode` property on this error.",
1169
+ sourceCall: sourceCall
1170
+ });
1171
+ }
1172
+ retryCount++;
1173
+ const retryTime = Math.floor(Math.random() * 5000);
1174
+ log.warn(
1175
+ "parseAndCheckLogin",
1176
+ "Got status code " +
1177
+ data.statusCode +
1178
+ " - " +
1179
+ retryCount +
1180
+ ". attempt to retry in " +
1181
+ retryTime +
1182
+ " milliseconds..."
1183
+ );
1184
+ const url =
1185
+ data.request.uri.protocol +
1186
+ "//" +
1187
+ data.request.uri.hostname +
1188
+ data.request.uri.pathname;
1189
+ if (
1190
+ data.request.headers["Content-Type"].split(";")[0] ===
1191
+ "multipart/form-data"
1192
+ ) {
1193
+ return bluebird
1194
+ .delay(retryTime)
1195
+ .then(function () {
1196
+ return defaultFuncs.postFormData(
1197
+ url,
1198
+ ctx.jar,
1199
+ data.request.formData,
1200
+ {}
1201
+ );
1202
+ })
1203
+ .then(parseAndCheckLogin(ctx, defaultFuncs, retryCount, sourceCall));
1204
+ }
1205
+ else {
1206
+ return bluebird
1207
+ .delay(retryTime)
1208
+ .then(function () {
1209
+ return defaultFuncs.post(url, ctx.jar, data.request.formData);
1210
+ })
1211
+ .then(parseAndCheckLogin(ctx, defaultFuncs, retryCount, sourceCall));
1212
+ }
1213
+ }
1214
+ if (data.statusCode !== 200)
1215
+ throw new CustomError({
1216
+ message: "parseAndCheckLogin got status code: " + data.statusCode + ". Bailing out of trying to parse response.",
1217
+ statusCode: data.statusCode,
1218
+ res: data.body,
1219
+ error: "parseAndCheckLogin got status code: " + data.statusCode + ". Bailing out of trying to parse response.",
1220
+ sourceCall: sourceCall
1221
+ });
1222
+
1223
+ let res = null;
1224
+ try {
1225
+ res = JSON.parse(makeParsable(data.body));
1226
+ } catch (e) {
1227
+ throw new CustomError({
1228
+ message: "JSON.parse error. Check the `detail` property on this error.",
1229
+ detail: e,
1230
+ res: data.body,
1231
+ error: "JSON.parse error. Check the `detail` property on this error.",
1232
+ sourceCall: sourceCall
1233
+ });
1234
+ }
1235
+
1236
+ // In some cases the response contains only a redirect URL which should be followed
1237
+ if (res.redirect && data.request.method === "GET") {
1238
+ return defaultFuncs
1239
+ .get(res.redirect, ctx.jar)
1240
+ .then(parseAndCheckLogin(ctx, defaultFuncs, undefined, sourceCall));
1241
+ }
1242
+
1243
+ // TODO: handle multiple cookies?
1244
+ if (
1245
+ res.jsmods &&
1246
+ res.jsmods.require &&
1247
+ Array.isArray(res.jsmods.require[0]) &&
1248
+ res.jsmods.require[0][0] === "Cookie"
1249
+ ) {
1250
+ res.jsmods.require[0][3][0] = res.jsmods.require[0][3][0].replace(
1251
+ "_js_",
1252
+ ""
1253
+ );
1254
+ const cookie = formatCookie(res.jsmods.require[0][3], "facebook");
1255
+ const cookie2 = formatCookie(res.jsmods.require[0][3], "messenger");
1256
+ ctx.jar.setCookie(cookie, "https://www.facebook.com");
1257
+ ctx.jar.setCookie(cookie2, "https://www.messenger.com");
1258
+ }
1259
+
1260
+ // On every request we check if we got a DTSG and we mutate the context so that we use the latest
1261
+ // one for the next requests.
1262
+ if (res.jsmods && Array.isArray(res.jsmods.require)) {
1263
+ const arr = res.jsmods.require;
1264
+ for (const i in arr) {
1265
+ if (arr[i][0] === "DTSG" && arr[i][1] === "setToken") {
1266
+ ctx.fb_dtsg = arr[i][3][0];
1267
+
1268
+ // Update ttstamp since that depends on fb_dtsg
1269
+ ctx.ttstamp = "2";
1270
+ for (let j = 0; j < ctx.fb_dtsg.length; j++) {
1271
+ ctx.ttstamp += ctx.fb_dtsg.charCodeAt(j);
1272
+ }
1273
+ }
1274
+ }
1275
+ }
1276
+
1277
+ if (res.error === 1357001) {
1278
+ throw new CustomError({
1279
+ message: "Facebook blocked login. Please visit https://facebook.com and check your account.",
1280
+ error: "Not logged in.",
1281
+ res: res,
1282
+ statusCode: data.statusCode,
1283
+ sourceCall: sourceCall
1284
+ });
1285
+ }
1286
+ return res;
1287
+ });
1288
+ };
1353
1289
  }
1354
1290
 
1291
+ /*
1355
1292
  function checkLiveCookie(ctx, defaultFuncs) {
1356
- return defaultFuncs
1357
- .get("https://m.facebook.com/me", ctx.jar)
1358
- .then(function (res) {
1359
- if (res.body.indexOf(ctx.i_userID || ctx.userID) === -1) {
1360
- throw new CustomError({
1361
- message: "Not logged in.",
1362
- error: "Not logged in."
1363
- });
1364
- }
1365
- return true;
1366
- });
1293
+ return defaultFuncs
1294
+ .get("https://m.facebook.com/me", ctx.jar)
1295
+ .then(function (res) {
1296
+ if (res.body.indexOf(ctx.i_userID || ctx.userID) === -1) {
1297
+ throw new CustomError({
1298
+ message: "Not logged in.",
1299
+ error: "Not logged in."
1300
+ });
1301
+ }
1302
+ return true;
1303
+ });
1367
1304
  }
1305
+ */
1368
1306
 
1369
1307
  function saveCookies(jar) {
1370
- return function (res) {
1371
- const cookies = res.headers["set-cookie"] || [];
1372
- cookies.forEach(function (c) {
1373
- if (c.indexOf(".facebook.com") > -1) {
1374
- jar.setCookie(c, "https://www.facebook.com");
1375
- }
1376
- const c2 = c.replace(/domain=\.facebook\.com/, "domain=.messenger.com");
1377
- jar.setCookie(c2, "https://www.messenger.com");
1378
- });
1379
- return res;
1380
- };
1308
+ return function (res) {
1309
+ const cookies = res.headers["set-cookie"] || [];
1310
+ cookies.forEach(function (c) {
1311
+ if (c.indexOf(".facebook.com") > -1) {
1312
+ jar.setCookie(c, "https://www.facebook.com");
1313
+ }
1314
+ const c2 = c.replace(/domain=\.facebook\.com/, "domain=.messenger.com");
1315
+ jar.setCookie(c2, "https://www.messenger.com");
1316
+ });
1317
+ return res;
1318
+ };
1381
1319
  }
1382
1320
 
1383
1321
  const NUM_TO_MONTH = [
1384
- "Jan",
1385
- "Feb",
1386
- "Mar",
1387
- "Apr",
1388
- "May",
1389
- "Jun",
1390
- "Jul",
1391
- "Aug",
1392
- "Sep",
1393
- "Oct",
1394
- "Nov",
1395
- "Dec"
1322
+ "Jan",
1323
+ "Feb",
1324
+ "Mar",
1325
+ "Apr",
1326
+ "May",
1327
+ "Jun",
1328
+ "Jul",
1329
+ "Aug",
1330
+ "Sep",
1331
+ "Oct",
1332
+ "Nov",
1333
+ "Dec"
1396
1334
  ];
1397
1335
  const NUM_TO_DAY = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
1398
1336
  function formatDate(date) {
1399
- let d = date.getUTCDate();
1400
- d = d >= 10 ? d : "0" + d;
1401
- let h = date.getUTCHours();
1402
- h = h >= 10 ? h : "0" + h;
1403
- let m = date.getUTCMinutes();
1404
- m = m >= 10 ? m : "0" + m;
1405
- let s = date.getUTCSeconds();
1406
- s = s >= 10 ? s : "0" + s;
1407
- return (
1408
- NUM_TO_DAY[date.getUTCDay()] +
1409
- ", " +
1410
- d +
1411
- " " +
1412
- NUM_TO_MONTH[date.getUTCMonth()] +
1413
- " " +
1414
- date.getUTCFullYear() +
1415
- " " +
1416
- h +
1417
- ":" +
1418
- m +
1419
- ":" +
1420
- s +
1421
- " GMT"
1422
- );
1337
+ let d = date.getUTCDate();
1338
+ d = d >= 10 ? d : "0" + d;
1339
+ let h = date.getUTCHours();
1340
+ h = h >= 10 ? h : "0" + h;
1341
+ let m = date.getUTCMinutes();
1342
+ m = m >= 10 ? m : "0" + m;
1343
+ let s = date.getUTCSeconds();
1344
+ s = s >= 10 ? s : "0" + s;
1345
+ return (
1346
+ NUM_TO_DAY[date.getUTCDay()] +
1347
+ ", " +
1348
+ d +
1349
+ " " +
1350
+ NUM_TO_MONTH[date.getUTCMonth()] +
1351
+ " " +
1352
+ date.getUTCFullYear() +
1353
+ " " +
1354
+ h +
1355
+ ":" +
1356
+ m +
1357
+ ":" +
1358
+ s +
1359
+ " GMT"
1360
+ );
1423
1361
  }
1424
1362
 
1425
1363
  function formatCookie(arr, url) {
1426
- return (
1427
- arr[0] + "=" + arr[1] + "; Path=" + arr[3] + "; Domain=" + url + ".com"
1428
- );
1364
+ return (
1365
+ arr[0] + "=" + arr[1] + "; Path=" + arr[3] + "; Domain=" + url + ".com"
1366
+ );
1429
1367
  }
1430
1368
 
1431
1369
  function formatThread(data) {
1432
- return {
1433
- threadID: formatID(data.thread_fbid.toString()),
1434
- participants: data.participants.map(formatID),
1435
- participantIDs: data.participants.map(formatID),
1436
- name: data.name,
1437
- nicknames: data.custom_nickname,
1438
- snippet: data.snippet,
1439
- snippetAttachments: data.snippet_attachments,
1440
- snippetSender: formatID((data.snippet_sender || "").toString()),
1441
- unreadCount: data.unread_count,
1442
- messageCount: data.message_count,
1443
- imageSrc: data.image_src,
1444
- timestamp: data.timestamp,
1445
- serverTimestamp: data.server_timestamp, // what is this?
1446
- muteUntil: data.mute_until,
1447
- isCanonicalUser: data.is_canonical_user,
1448
- isCanonical: data.is_canonical,
1449
- isSubscribed: data.is_subscribed,
1450
- folder: data.folder,
1451
- isArchived: data.is_archived,
1452
- recipientsLoadable: data.recipients_loadable,
1453
- hasEmailParticipant: data.has_email_participant,
1454
- readOnly: data.read_only,
1455
- canReply: data.can_reply,
1456
- cannotReplyReason: data.cannot_reply_reason,
1457
- lastMessageTimestamp: data.last_message_timestamp,
1458
- lastReadTimestamp: data.last_read_timestamp,
1459
- lastMessageType: data.last_message_type,
1460
- emoji: data.custom_like_icon,
1461
- color: data.custom_color,
1462
- adminIDs: data.admin_ids,
1463
- threadType: data.thread_type
1464
- };
1370
+ return {
1371
+ threadID: formatID(data.thread_fbid.toString()),
1372
+ participants: data.participants.map(formatID),
1373
+ participantIDs: data.participants.map(formatID),
1374
+ name: data.name,
1375
+ nicknames: data.custom_nickname,
1376
+ snippet: data.snippet,
1377
+ snippetAttachments: data.snippet_attachments,
1378
+ snippetSender: formatID((data.snippet_sender || "").toString()),
1379
+ unreadCount: data.unread_count,
1380
+ messageCount: data.message_count,
1381
+ imageSrc: data.image_src,
1382
+ timestamp: data.timestamp,
1383
+ serverTimestamp: data.server_timestamp, // what is this?
1384
+ muteUntil: data.mute_until,
1385
+ isCanonicalUser: data.is_canonical_user,
1386
+ isCanonical: data.is_canonical,
1387
+ isSubscribed: data.is_subscribed,
1388
+ folder: data.folder,
1389
+ isArchived: data.is_archived,
1390
+ recipientsLoadable: data.recipients_loadable,
1391
+ hasEmailParticipant: data.has_email_participant,
1392
+ readOnly: data.read_only,
1393
+ canReply: data.can_reply,
1394
+ cannotReplyReason: data.cannot_reply_reason,
1395
+ lastMessageTimestamp: data.last_message_timestamp,
1396
+ lastReadTimestamp: data.last_read_timestamp,
1397
+ lastMessageType: data.last_message_type,
1398
+ emoji: data.custom_like_icon,
1399
+ color: data.custom_color,
1400
+ adminIDs: data.admin_ids,
1401
+ threadType: data.thread_type
1402
+ };
1465
1403
  }
1466
1404
 
1467
1405
  function getType(obj) {
1468
- return Object.prototype.toString.call(obj).slice(8, -1);
1406
+ return Object.prototype.toString.call(obj).slice(8, -1);
1469
1407
  }
1470
1408
 
1471
1409
  function formatProxyPresence(presence, userID) {
1472
- if (presence.lat === undefined || presence.p === undefined) return null;
1473
- return {
1474
- type: "presence",
1475
- timestamp: presence.lat * 1000,
1476
- userID: userID,
1477
- statuses: presence.p
1478
- };
1410
+ if (presence.lat === undefined || presence.p === undefined) return null;
1411
+ return {
1412
+ type: "presence",
1413
+ timestamp: presence.lat * 1000,
1414
+ userID: userID,
1415
+ statuses: presence.p
1416
+ };
1479
1417
  }
1480
1418
 
1481
1419
  function formatPresence(presence, userID) {
1482
- return {
1483
- type: "presence",
1484
- timestamp: presence.la * 1000,
1485
- userID: userID,
1486
- statuses: presence.a
1487
- };
1420
+ return {
1421
+ type: "presence",
1422
+ timestamp: presence.la * 1000,
1423
+ userID: userID,
1424
+ statuses: presence.a
1425
+ };
1488
1426
  }
1489
1427
 
1490
1428
  function decodeClientPayload(payload) {
1491
- /*
1492
- Special function which Client using to "encode" clients JSON payload
1493
- */
1494
- return JSON.parse(String.fromCharCode.apply(null, payload));
1429
+ /*
1430
+ Special function which Client using to "encode" clients JSON payload
1431
+ */
1432
+ return JSON.parse(String.fromCharCode.apply(null, payload));
1495
1433
  }
1496
1434
 
1497
1435
  function getAppState(jar) {
1498
- return jar
1499
- .getCookies("https://www.facebook.com")
1500
- .concat(jar.getCookies("https://facebook.com"))
1501
- .concat(jar.getCookies("https://www.messenger.com"));
1436
+ return jar
1437
+ .getCookies("https://www.facebook.com")
1438
+ .concat(jar.getCookies("https://facebook.com"))
1439
+ .concat(jar.getCookies("https://www.messenger.com"));
1502
1440
  }
1503
- module.exports = {
1504
- CustomError,
1505
- isReadableStream,
1506
- get,
1507
- post,
1508
- postFormData,
1509
- generateThreadingID,
1510
- generateOfflineThreadingID,
1511
- getGUID,
1512
- getFrom,
1513
- makeParsable,
1514
- arrToForm,
1515
- getSignatureID,
1516
- getJar: request.jar,
1517
- generateTimestampRelative,
1518
- makeDefaults,
1519
- parseAndCheckLogin,
1520
- saveCookies,
1521
- getType,
1522
- _formatAttachment,
1523
- formatHistoryMessage,
1524
- formatID,
1525
- formatMessage,
1526
- formatDeltaEvent,
1527
- formatDeltaMessage,
1528
- formatProxyPresence,
1529
- formatPresence,
1530
- formatTyp,
1531
- formatDeltaReadReceipt,
1532
- formatCookie,
1533
- formatThread,
1534
- formatReadReceipt,
1535
- formatRead,
1536
- generatePresence,
1537
- generateAccessiblityCookie,
1538
- formatDate,
1539
- decodeClientPayload,
1540
- getAppState,
1541
- getAdminTextMessageType,
1542
- setProxy,
1543
- checkLiveCookie
1544
- };
1545
1441
 
1442
+ /*
1443
+ function createAccess_token(jar, globalOptions) {
1444
+ return function (res) {
1445
+ return get('https://business.facebook.com/business_locations', jar, null, globalOptions)
1446
+ .then(function (resp) {
1447
+ var accessToken = /"],\["(\S+)","436761779744620",{/g.exec(resp.body);
1448
+ if (accessToken) accessToken = accessToken[1].split('"],["').pop();
1449
+ else accessToken = 'NONE';
1450
+ return [(res || resp.body), accessToken];
1451
+ })
1452
+ .catch(() => {
1453
+ return [(res || null), 'NONE'];
1454
+ })
1455
+ }
1456
+ }
1457
+ */
1458
+
1459
+ function getCurrentTimestamp() {
1460
+ const date = new Date();
1461
+ const unixTime = date.getTime();
1462
+ return unixTime;
1463
+ }
1464
+
1465
+ module.exports = {
1466
+ CustomError,
1467
+ isReadableStream,
1468
+ get,
1469
+ post,
1470
+ postFormData,
1471
+ generateThreadingID,
1472
+ generateOfflineThreadingID,
1473
+ getGUID,
1474
+ getFrom,
1475
+ makeParsable,
1476
+ arrToForm,
1477
+ getSignatureID,
1478
+ getJar: request.jar,
1479
+ generateTimestampRelative,
1480
+ makeDefaults,
1481
+ parseAndCheckLogin,
1482
+ saveCookies,
1483
+ getType,
1484
+ _formatAttachment,
1485
+ formatHistoryMessage,
1486
+ formatID,
1487
+ formatMessage,
1488
+ formatDeltaEvent,
1489
+ formatDeltaMessage,
1490
+ formatProxyPresence,
1491
+ formatPresence,
1492
+ formatTyp,
1493
+ formatDeltaReadReceipt,
1494
+ formatCookie,
1495
+ formatThread,
1496
+ formatReadReceipt,
1497
+ formatRead,
1498
+ generatePresence,
1499
+ generateAccessiblityCookie,
1500
+ formatDate,
1501
+ decodeClientPayload,
1502
+ getAppState,
1503
+ getAdminTextMessageType,
1504
+ setProxy,
1505
+ //checkLiveCookie,
1506
+ //createAccess_token,
1507
+ getCurrentTimestamp
1508
+ }