From 781c16f2195bc00795589b026c73e390c4fd7432 Mon Sep 17 00:00:00 2001 From: Hossam Mansour <6911267+7osCraft@users.noreply.github.com> Date: Thu, 28 Nov 2019 00:47:47 +0200 Subject: [PATCH 01/10] Added support for MQTT --- index.js | 2 + package-lock.json | 483 +++++++++++++++++++++++++++++++++++++++-- package.json | 1 + src/listenMqtt.js | 443 +++++++++++++++++++++++++++++++++++++ src/markAsDelivered.js | 46 ++++ src/mqtt/fbconnect.js | 139 ++++++++++++ src/mqtt/fbws.js | 93 ++++++++ 7 files changed, 1185 insertions(+), 22 deletions(-) create mode 100644 src/listenMqtt.js create mode 100644 src/markAsDelivered.js create mode 100644 src/mqtt/fbconnect.js create mode 100644 src/mqtt/fbws.js diff --git a/index.js b/index.js index 4214511f..5bbf365d 100644 --- a/index.js +++ b/index.js @@ -99,7 +99,9 @@ function buildAPI(globalOptions, html, jar) { 'getUserInfo', 'handleMessageRequest', 'listen', + 'listenMqtt', 'logout', + 'markAsDelivered', 'markAsRead', 'markAsReadAll', 'muteThread', diff --git a/package-lock.json b/package-lock.json index 4920970b..1b49c33b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -119,6 +119,11 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -172,8 +177,12 @@ "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" }, "bcrypt-pbkdf": { "version": "1.0.2", @@ -183,6 +192,15 @@ "tweetnacl": "^0.14.3" } }, + "bl": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", + "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, "bluebird": { "version": "2.11.0", "resolved": "http://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", @@ -197,7 +215,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -206,8 +223,16 @@ "buffer-from": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "callback-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/callback-stream/-/callback-stream-1.1.0.tgz", + "integrity": "sha1-RwGlEmbwbgbqpx/BcjOCLYdfSQg=", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "> 1.0.0 < 3.0.0" + } }, "caller-path": { "version": "0.1.0", @@ -344,17 +369,31 @@ "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", "dev": true }, + "commist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/commist/-/commist-1.1.0.tgz", + "integrity": "sha512-rraC8NXWOEjhADbZe9QBNzLAN5Q3fsTPQtBV+fEVj6xKIgDgNiEVE6ZNfHpZOqfQ21YUzfVNUXLOEZquYvQPPg==", + "requires": { + "leven": "^2.1.0", + "minimist": "^1.1.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + } + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, "requires": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -394,6 +433,15 @@ "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=" }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -495,6 +543,17 @@ "domelementtype": "1" } }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -504,11 +563,84 @@ "safer-buffer": "^2.1.0" } }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, "entities": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=" }, + "es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" + } + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "~0.3.5" + }, + "dependencies": { + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + } + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -623,6 +755,30 @@ "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", "dev": true }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "ext": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.2.1.tgz", + "integrity": "sha512-x+OKKC57tNiLhDW26UmWtvQBpvO+2wxdC/A0jP7RkmjAc4gze9/U98hQyIYJUzo9A+o9ntMHpC+LH3pWMSbrVQ==", + "requires": { + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", + "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==" + } + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -719,8 +875,7 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "functional-red-black-tree": { "version": "1.0.1", @@ -752,7 +907,6 @@ "version": "7.1.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -762,6 +916,32 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "requires": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + } + }, "globals": { "version": "11.8.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.8.0.tgz", @@ -828,6 +1008,17 @@ "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, + "help-me": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-1.1.0.tgz", + "integrity": "sha1-jy1QjQYAtKRW2i8IZVbn5cBWo8Y=", + "requires": { + "callback-stream": "^1.0.2", + "glob-stream": "^6.1.0", + "through2": "^2.0.1", + "xtend": "^4.0.0" + } + }, "htmlparser2": { "version": "3.9.2", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", @@ -876,7 +1067,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -909,12 +1099,39 @@ "through": "^2.3.6" } }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", "dev": true }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "^2.1.0" + } + }, + "is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=" + }, "is-path-cwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", @@ -945,6 +1162,14 @@ "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", "dev": true }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "requires": { + "is-unc-path": "^1.0.0" + } + }, "is-resolvable": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", @@ -956,6 +1181,19 @@ "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -1030,8 +1268,7 @@ "json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" }, "json-stringify-safe": { "version": "5.0.1", @@ -1049,6 +1286,11 @@ "verror": "1.10.0" } }, + "leven": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-2.1.0.tgz", + "integrity": "sha1-wuep93IJTe6dNCAq6KzORoeHVYA=" + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -1173,7 +1415,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -1266,6 +1507,46 @@ } } }, + "mqtt": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mqtt/-/mqtt-3.0.0.tgz", + "integrity": "sha512-0nKV6MAc1ibKZwaZQUTb3iIdT4NVpj541BsYrqrGBcQdQ7Jd0MnZD1/6/nj1UFdGTboK9ZEUXvkCu2nPCugHFA==", + "requires": { + "base64-js": "^1.3.0", + "commist": "^1.0.0", + "concat-stream": "^1.6.2", + "end-of-stream": "^1.4.1", + "es6-map": "^0.1.5", + "help-me": "^1.0.1", + "inherits": "^2.0.3", + "minimist": "^1.2.0", + "mqtt-packet": "^6.0.0", + "pump": "^3.0.0", + "readable-stream": "^2.3.6", + "reinterval": "^1.1.0", + "split2": "^3.1.0", + "websocket-stream": "^5.1.2", + "xtend": "^4.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" + } + } + }, + "mqtt-packet": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/mqtt-packet/-/mqtt-packet-6.2.1.tgz", + "integrity": "sha512-ZxG5QVb7+gMix5n4DClym9dQoCZC6DoNEqgMkMi/GMXvIU4Wsdx+/6KBavw50HHFH9kN1lBSY7phxNlAS2+jnw==", + "requires": { + "bl": "^1.2.2", + "inherits": "^2.0.3", + "process-nextick-args": "^2.0.0", + "safe-buffer": "^5.1.2" + } + }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -1284,6 +1565,11 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + }, "npmlog": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-1.2.1.tgz", @@ -1317,7 +1603,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, "requires": { "wrappy": "1" } @@ -1345,17 +1630,29 @@ "wordwrap": "~1.0.0" } }, + "ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", + "requires": { + "readable-stream": "^2.0.1" + } + }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { "version": "1.0.2", @@ -1429,6 +1726,36 @@ "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", @@ -1459,6 +1786,16 @@ "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", "dev": true }, + "reinterval": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reinterval/-/reinterval-1.1.0.tgz", + "integrity": "sha1-M2Hs+jymwYKDOA3Qu5VG85D17Oc=" + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, "request": { "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", @@ -1597,6 +1934,26 @@ "is-fullwidth-code-point": "^2.0.0" } }, + "split2": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.1.1.tgz", + "integrity": "sha512-emNzr1s7ruq4N+1993yht631/JH+jaj0NYBosuKmLcq+JkGQ9MmTw1RB1fGaTCzUuseRIClrlSLHRNYGwWQ58Q==", + "requires": { + "readable-stream": "^3.0.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -1619,6 +1976,11 @@ "tweetnacl": "~0.14.0" } }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" + }, "string-width": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", @@ -1692,6 +2054,24 @@ "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "through2-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", + "requires": { + "through2": "~2.0.0", + "xtend": "~4.0.0" + } + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -1701,6 +2081,15 @@ "os-tmpdir": "~1.0.2" } }, + "to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", + "requires": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + } + }, "to-iso-string": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz", @@ -1729,6 +2118,11 @@ "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -1741,8 +2135,26 @@ "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" + }, + "unique-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "requires": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } }, "util-deprecate": { "version": "1.0.2", @@ -1764,6 +2176,19 @@ "extsprintf": "^1.2.0" } }, + "websocket-stream": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/websocket-stream/-/websocket-stream-5.5.0.tgz", + "integrity": "sha512-EXy/zXb9kNHI07TIMz1oIUIrPZxQRA8aeJ5XYg5ihV8K4kD1DuA+FY6R96HfdIHzlSzS8HiISAfrm+vVQkZBug==", + "requires": { + "duplexify": "^3.5.1", + "inherits": "^2.0.1", + "readable-stream": "^2.3.3", + "safe-buffer": "^5.1.2", + "ws": "^3.2.0", + "xtend": "^4.0.0" + } + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -1782,8 +2207,7 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write": { "version": "0.2.1", @@ -1794,6 +2218,21 @@ "mkdirp": "^0.5.1" } }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", diff --git a/package.json b/package.json index ce597202..133a6ec9 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "dependencies": { "bluebird": "^2.9.27", "cheerio": "^0.22.0", + "mqtt": "^3.0.0", "npmlog": "^1.2.0", "request": "^2.53.0" }, diff --git a/src/listenMqtt.js b/src/listenMqtt.js new file mode 100644 index 00000000..7d54c76f --- /dev/null +++ b/src/listenMqtt.js @@ -0,0 +1,443 @@ +"use strict"; +var fbconnect = require("./mqtt/fbconnect"); +var utils = require("../utils"); +var log = require("npmlog"); + +var identity = function () { }; +var lastSeqId = 0; + +var defaultFuncs = undefined; + +function listenMqtt(ctx, globalCallback) { + var sessionID = Math.floor(Math.random() * 9007199254740991) + 1; + var username = { + u: ctx.userID, + s: sessionID, + cp: 3, + ecp: 10, + chat_on: true, + fg: false, + d: utils.getGUID(), + ct: "websocket", + mqtt_sid: "", + //App id from facebook + aid: "219994525426954", + st: [], + pm: [], + dc: "", + no_auto_fg: true, + gas: null + }; + var cookies = ctx.jar.getCookies("https://www.facebook.com").join("; "); + + //Region could be changed for better ping. + var host = 'wss://edge-chat.facebook.com/chat?region=atn&sid=' + sessionID; + + var options = { + clientId: "mqttwsclient", + protocolId: 'MQIsdp', + protocolVersion: 3, + username: JSON.stringify(username), + wsOptions: { + 'headers': { + 'Cookie': cookies, + 'Origin': 'https://www.facebook.com', + 'User-Agent': ctx.globalOptions.userAgent, + 'Referer': 'https://www.facebook.com', + }, + origin: 'https://www.facebook.com', + protocolVersion: 13 + } + }; + + var client = fbconnect.connect(host, options); + + client.on('error', function (err) { + log.error(err); + client.end(); + }); + + client.on('connect', function () { + client.subscribe(["/legacy_web", "/webrtc", "/br_sr", "/sr_res", "/t_ms", "/thread_typing", "/orca_typing_notifications", "/notify_disconnect", "/orca_presence"], + (err, granted) => { + client.unsubscribe('/orca_message_notifications', (err) => { + var queue = { + sync_api_version: 10, + max_deltas_able_to_process: 1000, + delta_batch_size: 500, + encoding: "JSON", + entity_fbid: ctx.userID, + initial_titan_sequence_id: lastSeqId, + device_params: null + }; + + client.publish('/messenger_sync_create_queue', JSON.stringify(queue), { qos: 0, retain: false }) + }); + }); + }); + + client.on('message', function (topic, message, packet) { + var jsonMessage = JSON.parse(message); + if (topic === "/t_ms") { + if (jsonMessage.lastIssuedSeqId) { + lastSeqId = parseInt(jsonMessage.lastIssuedSeqId); + } else { + if (jsonMessage.deltas) { + lastSeqId = parseInt(jsonMessage.deltas[0].irisSeqId); + } + } + + //If it contains more than 1 delta + for (var i in jsonMessage.deltas) { + var delta = jsonMessage.deltas[i]; + parseDelta(ctx, globalCallback, { "delta": delta }); + } + } else if (topic === "/thread_typing" || topic === "/orca_typing_notifications") { + var typ = { + type: "typ", + isTyping: !!jsonMessage.state, + from: jsonMessage.sender_fbid.toString(), + threadID: utils.formatID((jsonMessage.thread || jsonMessage.sender_fbid).toString()) + } + globalCallback(null, typ); + } else if (topic === "/orca_presence") { + if (!ctx.globalOptions.updatePresence) { + for (var i in jsonMessage.list) { + var data = jsonMessage.list[i]; + var userID = data["u"]; + + var presence = { + type: "presence", + userID: userID, + timestamp: data["l"], + statuses: data["p"] + }; + globalCallback(null, presence); + } + } + } + + }); + + client.on('close', function () { + // client.end(); + }); +} + +function parseDelta(ctx, globalCallback, v) { + if (v.delta.class == "NewMessage") { + //Not tested for pages + if (ctx.globalOptions.pageID && + ctx.globalOptions.pageID != v.queue + ) + return; + + (function resolveAttachmentUrl(i) { + if (i == v.delta.attachments.length) { + var fmtMsg; + try { + fmtMsg = utils.formatDeltaMessage(v); + } catch (err) { + return globalCallback({ + error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.", + detail: err, + res: v, + type: "parse_error" + }); + } + return !ctx.globalOptions.selfListen && + fmtMsg.senderID === ctx.userID ? + undefined : + globalCallback(null, fmtMsg); + } else { + if ( + v.delta.attachments[i].mercury.attach_type == "photo" + ) { + api.resolvePhotoUrl( + v.delta.attachments[i].fbid, + (err, url) => { + if (!err) + v.delta.attachments[ + i + ].mercury.metadata.url = url; + return resolveAttachmentUrl(i + 1); + } + ); + } else { + return resolveAttachmentUrl(i + 1); + } + } + })(0); + } + + if (v.delta.class == "ClientPayload") { + var clientPayload = utils.decodeClientPayload( + v.delta.payload + ); + if (clientPayload && clientPayload.deltas) { + for (var i in clientPayload.deltas) { + var delta = clientPayload.deltas[i]; + if (delta.deltaMessageReaction && !!ctx.globalOptions.listenEvents) { + globalCallback(null, { + type: "message_reaction", + threadID: delta.deltaMessageReaction.threadKey + .threadFbId ? + delta.deltaMessageReaction.threadKey.threadFbId : delta.deltaMessageReaction.threadKey + .otherUserFbId, + messageID: delta.deltaMessageReaction.messageId, + reaction: delta.deltaMessageReaction.reaction, + senderID: delta.deltaMessageReaction.senderId, + userID: delta.deltaMessageReaction.userId, + timestamp: delta.deltaMessageReaction.timestamp + }); + } else if (delta.deltaRecallMessageData && !!ctx.globalOptions.listenEvents) { + globalCallback(null, { + type: "message_unsend", + threadID: delta.deltaRecallMessageData.threadKey.threadFbId ? + delta.deltaRecallMessageData.threadKey.threadFbId : delta.deltaRecallMessageData.threadKey + .otherUserFbId, + messageID: delta.deltaRecallMessageData.messageID, + senderID: delta.deltaRecallMessageData.senderID, + deletionTimestamp: delta.deltaRecallMessageData.deletionTimestamp, + timestamp: delta.deltaRecallMessageData.timestamp + }); + } else if (delta.deltaMessageReply) { + //Mention block - #1 + var mdata = + delta.deltaMessageReply.message.data === undefined ? [] : + delta.deltaMessageReply.message.data.prng === undefined ? [] : + JSON.parse(delta.deltaMessageReply.message.data.prng); + var m_id = mdata.map(u => u.i); + var m_offset = mdata.map(u => u.o); + var m_length = mdata.map(u => u.l); + + var mentions = {}; + + for (var i = 0; i < m_id.length; i++) { + mentions[m_id[i]] = delta.deltaMessageReply.message.body.substring( + m_offset[i], + m_offset[i] + m_length[i] + ); + } + //Mention block - 1# + //Mention block - #2 + var mdata = + delta.deltaMessageReply.repliedToMessage.data === undefined ? [] : + delta.deltaMessageReply.repliedToMessage.data.prng === undefined ? [] : + JSON.parse(delta.deltaMessageReply.repliedToMessage.data.prng); + var m_id = mdata.map(u => u.i); + var m_offset = mdata.map(u => u.o); + var m_length = mdata.map(u => u.l); + + var rmentions = {}; + + for (var i = 0; i < m_id.length; i++) { + rmentions[m_id[i]] = delta.deltaMessageReply.repliedToMessage.body.substring( + m_offset[i], + m_offset[i] + m_length[i] + ); + } + //Mention block - 2# + + globalCallback(null, { + type: "message_reply", + threadID: delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId ? + delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId : delta.deltaMessageReply.message.messageMetadata.threadKey + .otherUserFbId, + messageID: delta.deltaMessageReply.message.messageMetadata.messageId, + senderID: delta.deltaMessageReply.message.messageMetadata.actorFbId, + attachments: delta.deltaMessageReply.message.attachments.map(function (att) { + var mercury = JSON.parse(att.mercuryJSON); + Object.assign(att, mercury); + return att; + }).map(att => utils._formatAttachment(att)), + body: delta.deltaMessageReply.message.body || "", + isGroup: !!delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId, + mentions: mentions, + timestamp: delta.deltaMessageReply.repliedToMessage.messageMetadata.timestamp, + messageReply: { + threadID: delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId ? + delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId : delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey + .otherUserFbId, + messageID: delta.deltaMessageReply.repliedToMessage.messageMetadata.messageId, + senderID: delta.deltaMessageReply.repliedToMessage.messageMetadata.actorFbId, + attachments: delta.deltaMessageReply.repliedToMessage.attachments.map(function (att) { + var mercury = JSON.parse(att.mercuryJSON); + Object.assign(att, mercury); + return att; + }).map(att => utils._formatAttachment(att)), + body: delta.deltaMessageReply.repliedToMessage.body || "", + isGroup: !!delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId, + mentions: rmentions + } + }); + } + } + return; + } + } + + if (v.delta.class !== "NewMessage" && + !ctx.globalOptions.listenEvents + ) + return; + switch (v.delta.class) { + case "ReadReceipt": + var fmtMsg; + try { + fmtMsg = utils.formatDeltaReadReceipt(v.delta); + } catch (err) { + return globalCallback({ + error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.", + detail: err, + res: v.delta, + type: "parse_error" + }); + } + return globalCallback(null, fmtMsg); + case "AdminTextMessage": + switch (v.delta.type) { + case "change_thread_theme": + case "change_thread_nickname": + case "change_thread_icon": + break; + case "group_poll": + var fmtMsg; + try { + fmtMsg = utils.formatDeltaEvent(v.delta); + } catch (err) { + return globalCallback({ + error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.", + detail: err, + res: v.delta, + type: "parse_error" + }); + } + return globalCallback(null, fmtMsg); + break; + default: + return; + } + //For group images + case "ForcedFetch": + var mid = v.delta.messageId; + var tid = v.delta.threadKey.threadFbId.toString(); + const form = { + "av": ctx.globalOptions.pageID, + "queries": JSON.stringify({ + "o0": { + "doc_id": "1768656253222505", + "query_params": { + "thread_and_message_id": { + "thread_id": tid, + "message_id": mid, + } + } + } + }) + }; + + defaultFuncs + .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form) + .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) + .then((resData) => { + if (resData[resData.length - 1].error_results > 0) { + throw resData[0].o0.errors; + } + + if (resData[resData.length - 1].successful_results === 0) { + throw { error: "forcedFetch: there was no successful_results", res: resData }; + } + + var fetchData = resData[0].o0.data.message; + + globalCallback(null, { + type: "change_thread_image", + threadID: utils.formatID(tid.toString()), + snippet: fetchData.snippet, + timestamp: fetchData.timestamp_precise, + author: fetchData.message_sender.id, + image: { + attachmentID: fetchData.image_with_metadata.legacy_attachment_id, + width: fetchData.image_with_metadata.original_dimensions.x, + height: fetchData.image_with_metadata.original_dimensions.y, + url: fetchData.image_with_metadata.preview.uri + } + }); + }) + .catch((err) => { + log.error("forcedFetch", err); + }); + break; + case "ThreadName": + case "ParticipantsAddedToGroupThread": + case "ParticipantLeftGroupThread": + var formattedEvent; + try { + formattedEvent = utils.formatDeltaEvent(v.delta); + } catch (err) { + return globalCallback({ + error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.", + detail: err, + res: v.delta, + type: "parse_error" + }); + } + return (!ctx.globalOptions.selfListen && + formattedEvent.author.toString() === ctx.userID) || + !ctx.loggedIn ? + undefined : + globalCallback(null, formattedEvent); + } +} + +module.exports = function (df, api, ctx) { + var currentlyRunning = null; + var globalCallback = identity; + defaultFuncs = df; + return function (callback) { + globalCallback = callback; + const form = { + "av": ctx.globalOptions.pageID, + "queries": JSON.stringify({ + "o0": { + "doc_id": "1349387578499440", + "query_params": { + "limit": 1, + "before": null, + "tags": ["INBOX"], + "includeDeliveryReceipts": false, + "includeSeqID": true + } + } + }) + }; + + defaultFuncs + .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form) + .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) + .then((resData) => { + if (resData[resData.length - 1].error_results > 0) { + throw resData[0].o0.errors; + } + + if (resData[resData.length - 1].successful_results === 0) { + throw { error: "getSeqId: there was no successful_results", res: resData }; + } + + if (resData[0].o0.data.viewer.message_threads.sync_sequence_id) { + lastSeqId = resData[0].o0.data.viewer.message_threads.sync_sequence_id; + listenMqtt(ctx, globalCallback); + } + + }) + .catch((err) => { + log.error("getSeqId", err); + return callback(err); + }); + + + //return function(){}; + } +}; + diff --git a/src/markAsDelivered.js b/src/markAsDelivered.js new file mode 100644 index 00000000..e4ba9c17 --- /dev/null +++ b/src/markAsDelivered.js @@ -0,0 +1,46 @@ +"use strict"; + +var utils = require("../utils"); +var log = require("npmlog"); + +module.exports = function(defaultFuncs, api, ctx) { + + return function markAsDelivered(threadID, messageID, callback) { + if (!callback) { + callback = function() {}; + } + + if(!threadID || !messageID) + { + return callback("Error: messageID or threadID is not defined"); + } + + var form = {}; + + form["message_ids[0]"] = messageID; + form["thread_ids[" + threadID + "][0]"] = messageID; + + + console.log(form); + + defaultFuncs + .post( + "https://www.facebook.com/ajax/mercury/delivery_receipts.php", + ctx.jar, + form + ) + .then(utils.saveCookies(ctx.jar)) + .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) + .then(function(resData) { + if (resData.error) { + throw resData; + } + + return callback(); + }) + .catch(function(err) { + log.error("markAsDelivered", err); + return callback(err); + }); + }; +}; diff --git a/src/mqtt/fbconnect.js b/src/mqtt/fbconnect.js new file mode 100644 index 00000000..9dfd7be9 --- /dev/null +++ b/src/mqtt/fbconnect.js @@ -0,0 +1,139 @@ +'use strict' + +var mqtt = require('mqtt') +var url = require('url') +var xtend = require('xtend') +var protocols = {} +protocols.ws = require('./fbws') +protocols.wss = require('./fbws') + +/** + * Parse the auth attribute and merge username and password in the options object. + * + * @param {Object} [opts] option object + */ +function parseAuthOptions (opts) { + var matches + if (opts.auth) { + matches = opts.auth.match(/^(.+):(.+)$/) + if (matches) { + opts.username = matches[1] + opts.password = matches[2] + } else { + opts.username = opts.auth + } + } +} + +/** + * connect - connect to an MQTT broker. + * + * @param {String} [brokerUrl] - url of the broker, optional + * @param {Object} opts - see MqttClient#constructor + */ +function connect (brokerUrl, opts) { + if ((typeof brokerUrl === 'object') && !opts) { + opts = brokerUrl + brokerUrl = null + } + + opts = opts || {} + + if (brokerUrl) { + var parsed = url.parse(brokerUrl, true) + if (parsed.port != null) { + parsed.port = Number(parsed.port) + } + + opts = xtend(parsed, opts) + + if (opts.protocol === null) { + throw new Error('Missing protocol') + } + opts.protocol = opts.protocol.replace(/:$/, '') + } + + // merge in the auth options if supplied + parseAuthOptions(opts) + + // support clientId passed in the query string of the url + if (opts.query && typeof opts.query.clientId === 'string') { + opts.clientId = opts.query.clientId + } + + if (opts.cert && opts.key) { + if (opts.protocol) { + if (['mqtts', 'wss', 'wxs', 'alis'].indexOf(opts.protocol) === -1) { + switch (opts.protocol) { + case 'mqtt': + opts.protocol = 'mqtts' + break + case 'ws': + opts.protocol = 'wss' + break + case 'wx': + opts.protocol = 'wxs' + break + case 'ali': + opts.protocol = 'alis' + break + default: + throw new Error('Unknown protocol for secure connection: "' + opts.protocol + '"!') + } + } + } else { + // don't know what protocol he want to use, mqtts or wss + throw new Error('Missing secure protocol key') + } + } + + if (!protocols[opts.protocol]) { + var isSecure = ['mqtts', 'wss'].indexOf(opts.protocol) !== -1 + opts.protocol = [ + 'mqtt', + 'mqtts', + 'ws', + 'wss', + 'wx', + 'wxs', + 'ali', + 'alis' + ].filter(function (key, index) { + if (isSecure && index % 2 === 0) { + // Skip insecure protocols when requesting a secure one. + return false + } + return (typeof protocols[key] === 'function') + })[0] + } + + if (opts.clean === false && !opts.clientId) { + throw new Error('Missing clientId for unclean clients') + } + + if (opts.protocol) { + opts.defaultProtocol = opts.protocol + } + + function wrapper (client) { + if (opts.servers) { + if (!client._reconnectCount || client._reconnectCount === opts.servers.length) { + client._reconnectCount = 0 + } + + opts.host = opts.servers[client._reconnectCount].host + opts.port = opts.servers[client._reconnectCount].port + opts.protocol = (!opts.servers[client._reconnectCount].protocol ? opts.defaultProtocol : opts.servers[client._reconnectCount].protocol) + opts.hostname = opts.host + + client._reconnectCount++ + } + + return protocols[opts.protocol](client, opts) + } + + return new mqtt.Client(wrapper, opts) +} + +module.exports = connect +module.exports.connect = connect \ No newline at end of file diff --git a/src/mqtt/fbws.js b/src/mqtt/fbws.js new file mode 100644 index 00000000..20135ddc --- /dev/null +++ b/src/mqtt/fbws.js @@ -0,0 +1,93 @@ +//From mqtt.js +'use strict' + +var websocket = require('websocket-stream') +var urlModule = require('url') +var WSS_OPTIONS = [ + 'rejectUnauthorized', + 'ca', + 'cert', + 'key', + 'pfx', + 'passphrase' +] +var IS_BROWSER = process.title === 'browser' + +function buildUrl (opts, client) { + var url = opts.protocol + '://' + opts.hostname + ':' + opts.port + opts.path + if (typeof (opts.transformWsUrl) === 'function') { + url = opts.transformWsUrl(url, opts, client) + } + return url +} + +function setDefaultOpts (opts) { + if (!opts.hostname) { + opts.hostname = 'localhost' + } + if (!opts.port) { + if (opts.protocol === 'wss') { + opts.port = 443 + } else { + opts.port = 80 + } + } + if (!opts.path) { + opts.path = '/' + } + + if (!opts.wsOptions) { + opts.wsOptions = {} + } + if (!IS_BROWSER && opts.protocol === 'wss') { + // Add cert/key/ca etc options + WSS_OPTIONS.forEach(function (prop) { + if (opts.hasOwnProperty(prop) && !opts.wsOptions.hasOwnProperty(prop)) { + opts.wsOptions[prop] = opts[prop] + } + }) + } +} + +function createWebSocket (client, opts) { + var websocketSubProtocol = + (opts.protocolId === 'MQIsdp') && (opts.protocolVersion === 3) + ? 'mqttv3.1' + : 'mqtt' + + setDefaultOpts(opts) + var url = buildUrl(opts, client) + return websocket(url, undefined, opts.wsOptions) +} + +function buildBuilder (client, opts) { + return createWebSocket(client, opts) +} + +function buildBuilderBrowser (client, opts) { + if (!opts.hostname) { + opts.hostname = opts.host + } + + if (!opts.hostname) { + // Throwing an error in a Web Worker if no `hostname` is given, because we + // can not determine the `hostname` automatically. If connecting to + // localhost, please supply the `hostname` as an argument. + if (typeof (document) === 'undefined') { + throw new Error('Could not determine host. Specify host manually.') + } + var parsed = urlModule.parse(document.URL) + opts.hostname = parsed.hostname + + if (!opts.port) { + opts.port = parsed.port + } + } + return createWebSocket(client, opts) +} + +if (IS_BROWSER) { + module.exports = buildBuilderBrowser +} else { + module.exports = buildBuilder +} \ No newline at end of file From 0d073dca32889e5907ff48e094c48a2bc378071d Mon Sep 17 00:00:00 2001 From: Hossam Mansour <6911267+7osCraft@users.noreply.github.com> Date: Thu, 28 Nov 2019 02:46:30 +0200 Subject: [PATCH 02/10] Added docs for listenMqtt --- DOCS.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/DOCS.md b/DOCS.md index 39812cc6..ffd5ace9 100644 --- a/DOCS.md +++ b/DOCS.md @@ -25,6 +25,7 @@ * [`api.getUserInfo`](#getUserInfo) * [`api.handleMessageRequest`](#handleMessageRequest) * [`api.listen`](#listen) +* [`api.listenMqtt`](#listenMqtt) * [`api.logout`](#logout) * [`api.markAsRead`](#markAsRead) * [`api.markAsReadAll`](#markAsReadAll) @@ -1308,6 +1309,20 @@ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, ap --------------------------------------- + +### api.listenMqtt(callback) (Experimental) +Same as [`api.listen`](#listen) but uses MQTT to recieve data. +Will call `callback` when a new message is received on this account. +By default this won't receive events (joining/leaving a chat, title change etc...) but it can be activated with `api.setOptions({listenEvents: true})`. This will by default ignore messages sent by the current account, you can enable listening to your own messages with `api.setOptions({selfListen: true})`. + +__Arguments__ + +- `callback(error, message)`: A callback called every time the logged-in account receives a new message. + +Messages and Events are the same as [`api.listen`](#listen) + +--------------------------------------- + ### api.logout([callback]) From af94fe10fb9516ead49ddd8e7710886f93b0a7f8 Mon Sep 17 00:00:00 2001 From: Hossam Mohsen <6911267+7osCraft@users.noreply.github.com> Date: Thu, 28 Nov 2019 02:56:05 +0200 Subject: [PATCH 03/10] Update listenMqtt.js --- src/listenMqtt.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/listenMqtt.js b/src/listenMqtt.js index 7d54c76f..d7b9137e 100644 --- a/src/listenMqtt.js +++ b/src/listenMqtt.js @@ -6,9 +6,7 @@ var log = require("npmlog"); var identity = function () { }; var lastSeqId = 0; -var defaultFuncs = undefined; - -function listenMqtt(ctx, globalCallback) { +function listenMqtt(ctx, globalCallback, defaultFuncs) { var sessionID = Math.floor(Math.random() * 9007199254740991) + 1; var username = { u: ctx.userID, @@ -90,7 +88,7 @@ function listenMqtt(ctx, globalCallback) { //If it contains more than 1 delta for (var i in jsonMessage.deltas) { var delta = jsonMessage.deltas[i]; - parseDelta(ctx, globalCallback, { "delta": delta }); + parseDelta(ctx, globalCallback, defaultFuncs, { "delta": delta }); } } else if (topic === "/thread_typing" || topic === "/orca_typing_notifications") { var typ = { @@ -124,7 +122,7 @@ function listenMqtt(ctx, globalCallback) { }); } -function parseDelta(ctx, globalCallback, v) { +function parseDelta(ctx, globalCallback, defaultFuncs, v) { if (v.delta.class == "NewMessage") { //Not tested for pages if (ctx.globalOptions.pageID && @@ -394,7 +392,6 @@ function parseDelta(ctx, globalCallback, v) { module.exports = function (df, api, ctx) { var currentlyRunning = null; var globalCallback = identity; - defaultFuncs = df; return function (callback) { globalCallback = callback; const form = { @@ -427,7 +424,7 @@ module.exports = function (df, api, ctx) { if (resData[0].o0.data.viewer.message_threads.sync_sequence_id) { lastSeqId = resData[0].o0.data.viewer.message_threads.sync_sequence_id; - listenMqtt(ctx, globalCallback); + listenMqtt(ctx, globalCallback, df); } }) From 89e10b0be71be29a76fdc503707148046ae3f338 Mon Sep 17 00:00:00 2001 From: Hossam Mansour <6911267+7osCraft@users.noreply.github.com> Date: Thu, 28 Nov 2019 11:09:22 +0200 Subject: [PATCH 04/10] Fixed listenMqtt error --- src/listenMqtt.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/listenMqtt.js b/src/listenMqtt.js index d7b9137e..530975a6 100644 --- a/src/listenMqtt.js +++ b/src/listenMqtt.js @@ -389,7 +389,7 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { } } -module.exports = function (df, api, ctx) { +module.exports = function (defaultFuncs, api, ctx) { var currentlyRunning = null; var globalCallback = identity; return function (callback) { @@ -424,7 +424,7 @@ module.exports = function (df, api, ctx) { if (resData[0].o0.data.viewer.message_threads.sync_sequence_id) { lastSeqId = resData[0].o0.data.viewer.message_threads.sync_sequence_id; - listenMqtt(ctx, globalCallback, df); + listenMqtt(ctx, globalCallback, defaultFuncs); } }) From dd61e5dfc8110a26ca0de762ebd9860a5f0a45fd Mon Sep 17 00:00:00 2001 From: Hossam Mansour <6911267+7osCraft@users.noreply.github.com> Date: Thu, 28 Nov 2019 22:21:42 +0200 Subject: [PATCH 05/10] Fixed indentation. Fixed some bugs too. --- DOCS.md | 4 +- src/listenMqtt.js | 867 +++++++++++++++++++++-------------------- src/markAsDelivered.js | 18 +- src/mqtt/fbconnect.js | 6 +- src/mqtt/fbws.js | 10 +- 5 files changed, 461 insertions(+), 444 deletions(-) diff --git a/DOCS.md b/DOCS.md index ffd5ace9..94546f56 100644 --- a/DOCS.md +++ b/DOCS.md @@ -1312,8 +1312,10 @@ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, ap ### api.listenMqtt(callback) (Experimental) Same as [`api.listen`](#listen) but uses MQTT to recieve data. + Will call `callback` when a new message is received on this account. -By default this won't receive events (joining/leaving a chat, title change etc...) but it can be activated with `api.setOptions({listenEvents: true})`. This will by default ignore messages sent by the current account, you can enable listening to your own messages with `api.setOptions({selfListen: true})`. +By default this won't receive events (joining/leaving a chat, title change etc...) but it can be activated with `api.setOptions({listenEvents: true})`. This will by default ignore messages sent by the current account, you can enable listening to your own messages with `api.setOptions({selfListen: true})`. This returns `stopListening` that will stop the `listen` loop and is guaranteed to prevent any future calls to the callback given to `listenMqtt`. An immediate call to `stopListening` when an error occurs will prevent the listen function to continue. + __Arguments__ diff --git a/src/listenMqtt.js b/src/listenMqtt.js index 530975a6..1abcc3be 100644 --- a/src/listenMqtt.js +++ b/src/listenMqtt.js @@ -5,436 +5,453 @@ var log = require("npmlog"); var identity = function () { }; var lastSeqId = 0; +var client = undefined; function listenMqtt(ctx, globalCallback, defaultFuncs) { - var sessionID = Math.floor(Math.random() * 9007199254740991) + 1; - var username = { - u: ctx.userID, - s: sessionID, - cp: 3, - ecp: 10, - chat_on: true, - fg: false, - d: utils.getGUID(), - ct: "websocket", - mqtt_sid: "", - //App id from facebook - aid: "219994525426954", - st: [], - pm: [], - dc: "", - no_auto_fg: true, - gas: null - }; - var cookies = ctx.jar.getCookies("https://www.facebook.com").join("; "); - - //Region could be changed for better ping. - var host = 'wss://edge-chat.facebook.com/chat?region=atn&sid=' + sessionID; - - var options = { - clientId: "mqttwsclient", - protocolId: 'MQIsdp', - protocolVersion: 3, - username: JSON.stringify(username), - wsOptions: { - 'headers': { - 'Cookie': cookies, - 'Origin': 'https://www.facebook.com', - 'User-Agent': ctx.globalOptions.userAgent, - 'Referer': 'https://www.facebook.com', - }, - origin: 'https://www.facebook.com', - protocolVersion: 13 - } - }; - - var client = fbconnect.connect(host, options); - - client.on('error', function (err) { - log.error(err); - client.end(); - }); - - client.on('connect', function () { - client.subscribe(["/legacy_web", "/webrtc", "/br_sr", "/sr_res", "/t_ms", "/thread_typing", "/orca_typing_notifications", "/notify_disconnect", "/orca_presence"], - (err, granted) => { - client.unsubscribe('/orca_message_notifications', (err) => { - var queue = { - sync_api_version: 10, - max_deltas_able_to_process: 1000, - delta_batch_size: 500, - encoding: "JSON", - entity_fbid: ctx.userID, - initial_titan_sequence_id: lastSeqId, - device_params: null - }; - - client.publish('/messenger_sync_create_queue', JSON.stringify(queue), { qos: 0, retain: false }) - }); - }); - }); - - client.on('message', function (topic, message, packet) { - var jsonMessage = JSON.parse(message); - if (topic === "/t_ms") { - if (jsonMessage.lastIssuedSeqId) { - lastSeqId = parseInt(jsonMessage.lastIssuedSeqId); - } else { - if (jsonMessage.deltas) { - lastSeqId = parseInt(jsonMessage.deltas[0].irisSeqId); - } - } - - //If it contains more than 1 delta - for (var i in jsonMessage.deltas) { - var delta = jsonMessage.deltas[i]; - parseDelta(ctx, globalCallback, defaultFuncs, { "delta": delta }); - } - } else if (topic === "/thread_typing" || topic === "/orca_typing_notifications") { - var typ = { - type: "typ", - isTyping: !!jsonMessage.state, - from: jsonMessage.sender_fbid.toString(), - threadID: utils.formatID((jsonMessage.thread || jsonMessage.sender_fbid).toString()) - } - globalCallback(null, typ); - } else if (topic === "/orca_presence") { - if (!ctx.globalOptions.updatePresence) { - for (var i in jsonMessage.list) { - var data = jsonMessage.list[i]; - var userID = data["u"]; - - var presence = { - type: "presence", - userID: userID, - timestamp: data["l"], - statuses: data["p"] - }; - globalCallback(null, presence); - } - } - } - - }); - - client.on('close', function () { - // client.end(); - }); + var sessionID = Math.floor(Math.random() * 9007199254740991) + 1; + var username = { + u: ctx.userID, + s: sessionID, + cp: 3, + ecp: 10, + chat_on: true, + fg: false, + d: utils.getGUID(), + ct: "websocket", + mqtt_sid: "", + //App id from facebook + aid: "219994525426954", + st: [], + pm: [], + dc: "", + no_auto_fg: true, + gas: null + }; + var cookies = ctx.jar.getCookies("https://www.facebook.com").join("; "); + + //Region could be changed for better ping. + var host = 'wss://edge-chat.facebook.com/chat?region=atn&sid=' + sessionID; + + var options = { + clientId: "mqttwsclient", + protocolId: 'MQIsdp', + protocolVersion: 3, + username: JSON.stringify(username), + wsOptions: { + 'headers': { + 'Cookie': cookies, + 'Origin': 'https://www.facebook.com', + 'User-Agent': ctx.globalOptions.userAgent, + 'Referer': 'https://www.facebook.com', + }, + origin: 'https://www.facebook.com', + protocolVersion: 13 + } + }; + + client = fbconnect.connect(host, options); + + client.on('error', function (err) { + log.error(err); + client.end(); + }); + + client.on('connect', function () { + client.subscribe(["/legacy_web", "/webrtc", "/br_sr", "/sr_res", "/t_ms", "/thread_typing", "/orca_typing_notifications", "/notify_disconnect", "/orca_presence"], + (err, granted) => { + client.unsubscribe('/orca_message_notifications', (err) => { + var queue = { + sync_api_version: 10, + max_deltas_able_to_process: 1000, + delta_batch_size: 500, + encoding: "JSON", + entity_fbid: ctx.userID, + initial_titan_sequence_id: lastSeqId, + device_params: null + }; + + client.publish('/messenger_sync_create_queue', JSON.stringify(queue), { qos: 0, retain: false }) + }); + }); + }); + + client.on('message', function (topic, message, packet) { + var jsonMessage = JSON.parse(message); + if (topic === "/t_ms") { + if (jsonMessage.lastIssuedSeqId) { + lastSeqId = parseInt(jsonMessage.lastIssuedSeqId); + } else { + if (jsonMessage.deltas) { + lastSeqId = parseInt(jsonMessage.deltas[0].irisSeqId); + } + } + + //If it contains more than 1 delta + for (var i in jsonMessage.deltas) { + var delta = jsonMessage.deltas[i]; + parseDelta(ctx, globalCallback, defaultFuncs, { "delta": delta }); + } + } else if (topic === "/thread_typing" || topic === "/orca_typing_notifications") { + var typ = { + type: "typ", + isTyping: !!jsonMessage.state, + from: jsonMessage.sender_fbid.toString(), + threadID: utils.formatID((jsonMessage.thread || jsonMessage.sender_fbid).toString()) + } + globalCallback(null, typ); + } else if (topic === "/orca_presence") { + if (!ctx.globalOptions.updatePresence) { + for (var i in jsonMessage.list) { + var data = jsonMessage.list[i]; + var userID = data["u"]; + + var presence = { + type: "presence", + userID: userID, + timestamp: data["l"], + statuses: data["p"] + }; + globalCallback(null, presence); + } + } + } + + }); + + client.on('close', function () { + // client.end(); + }); } function parseDelta(ctx, globalCallback, defaultFuncs, v) { - if (v.delta.class == "NewMessage") { - //Not tested for pages - if (ctx.globalOptions.pageID && - ctx.globalOptions.pageID != v.queue - ) - return; - - (function resolveAttachmentUrl(i) { - if (i == v.delta.attachments.length) { - var fmtMsg; - try { - fmtMsg = utils.formatDeltaMessage(v); - } catch (err) { - return globalCallback({ - error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.", - detail: err, - res: v, - type: "parse_error" - }); - } - return !ctx.globalOptions.selfListen && - fmtMsg.senderID === ctx.userID ? - undefined : - globalCallback(null, fmtMsg); - } else { - if ( - v.delta.attachments[i].mercury.attach_type == "photo" - ) { - api.resolvePhotoUrl( - v.delta.attachments[i].fbid, - (err, url) => { - if (!err) - v.delta.attachments[ - i - ].mercury.metadata.url = url; - return resolveAttachmentUrl(i + 1); - } - ); - } else { - return resolveAttachmentUrl(i + 1); - } - } - })(0); - } - - if (v.delta.class == "ClientPayload") { - var clientPayload = utils.decodeClientPayload( - v.delta.payload - ); - if (clientPayload && clientPayload.deltas) { - for (var i in clientPayload.deltas) { - var delta = clientPayload.deltas[i]; - if (delta.deltaMessageReaction && !!ctx.globalOptions.listenEvents) { - globalCallback(null, { - type: "message_reaction", - threadID: delta.deltaMessageReaction.threadKey - .threadFbId ? - delta.deltaMessageReaction.threadKey.threadFbId : delta.deltaMessageReaction.threadKey - .otherUserFbId, - messageID: delta.deltaMessageReaction.messageId, - reaction: delta.deltaMessageReaction.reaction, - senderID: delta.deltaMessageReaction.senderId, - userID: delta.deltaMessageReaction.userId, - timestamp: delta.deltaMessageReaction.timestamp - }); - } else if (delta.deltaRecallMessageData && !!ctx.globalOptions.listenEvents) { - globalCallback(null, { - type: "message_unsend", - threadID: delta.deltaRecallMessageData.threadKey.threadFbId ? - delta.deltaRecallMessageData.threadKey.threadFbId : delta.deltaRecallMessageData.threadKey - .otherUserFbId, - messageID: delta.deltaRecallMessageData.messageID, - senderID: delta.deltaRecallMessageData.senderID, - deletionTimestamp: delta.deltaRecallMessageData.deletionTimestamp, - timestamp: delta.deltaRecallMessageData.timestamp - }); - } else if (delta.deltaMessageReply) { - //Mention block - #1 - var mdata = - delta.deltaMessageReply.message.data === undefined ? [] : - delta.deltaMessageReply.message.data.prng === undefined ? [] : - JSON.parse(delta.deltaMessageReply.message.data.prng); - var m_id = mdata.map(u => u.i); - var m_offset = mdata.map(u => u.o); - var m_length = mdata.map(u => u.l); - - var mentions = {}; - - for (var i = 0; i < m_id.length; i++) { - mentions[m_id[i]] = delta.deltaMessageReply.message.body.substring( - m_offset[i], - m_offset[i] + m_length[i] - ); - } - //Mention block - 1# - //Mention block - #2 - var mdata = - delta.deltaMessageReply.repliedToMessage.data === undefined ? [] : - delta.deltaMessageReply.repliedToMessage.data.prng === undefined ? [] : - JSON.parse(delta.deltaMessageReply.repliedToMessage.data.prng); - var m_id = mdata.map(u => u.i); - var m_offset = mdata.map(u => u.o); - var m_length = mdata.map(u => u.l); - - var rmentions = {}; - - for (var i = 0; i < m_id.length; i++) { - rmentions[m_id[i]] = delta.deltaMessageReply.repliedToMessage.body.substring( - m_offset[i], - m_offset[i] + m_length[i] - ); - } - //Mention block - 2# - - globalCallback(null, { - type: "message_reply", - threadID: delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId ? - delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId : delta.deltaMessageReply.message.messageMetadata.threadKey - .otherUserFbId, - messageID: delta.deltaMessageReply.message.messageMetadata.messageId, - senderID: delta.deltaMessageReply.message.messageMetadata.actorFbId, - attachments: delta.deltaMessageReply.message.attachments.map(function (att) { - var mercury = JSON.parse(att.mercuryJSON); - Object.assign(att, mercury); - return att; - }).map(att => utils._formatAttachment(att)), - body: delta.deltaMessageReply.message.body || "", - isGroup: !!delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId, - mentions: mentions, - timestamp: delta.deltaMessageReply.repliedToMessage.messageMetadata.timestamp, - messageReply: { - threadID: delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId ? - delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId : delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey - .otherUserFbId, - messageID: delta.deltaMessageReply.repliedToMessage.messageMetadata.messageId, - senderID: delta.deltaMessageReply.repliedToMessage.messageMetadata.actorFbId, - attachments: delta.deltaMessageReply.repliedToMessage.attachments.map(function (att) { - var mercury = JSON.parse(att.mercuryJSON); - Object.assign(att, mercury); - return att; - }).map(att => utils._formatAttachment(att)), - body: delta.deltaMessageReply.repliedToMessage.body || "", - isGroup: !!delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId, - mentions: rmentions - } - }); - } - } - return; - } - } - - if (v.delta.class !== "NewMessage" && - !ctx.globalOptions.listenEvents - ) - return; - switch (v.delta.class) { - case "ReadReceipt": - var fmtMsg; - try { - fmtMsg = utils.formatDeltaReadReceipt(v.delta); - } catch (err) { - return globalCallback({ - error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.", - detail: err, - res: v.delta, - type: "parse_error" - }); - } - return globalCallback(null, fmtMsg); - case "AdminTextMessage": - switch (v.delta.type) { - case "change_thread_theme": - case "change_thread_nickname": - case "change_thread_icon": - break; - case "group_poll": - var fmtMsg; - try { - fmtMsg = utils.formatDeltaEvent(v.delta); - } catch (err) { - return globalCallback({ - error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.", - detail: err, - res: v.delta, - type: "parse_error" - }); - } - return globalCallback(null, fmtMsg); - break; - default: - return; - } - //For group images - case "ForcedFetch": - var mid = v.delta.messageId; - var tid = v.delta.threadKey.threadFbId.toString(); - const form = { - "av": ctx.globalOptions.pageID, - "queries": JSON.stringify({ - "o0": { - "doc_id": "1768656253222505", - "query_params": { - "thread_and_message_id": { - "thread_id": tid, - "message_id": mid, - } - } - } - }) - }; - - defaultFuncs - .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form) - .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) - .then((resData) => { - if (resData[resData.length - 1].error_results > 0) { - throw resData[0].o0.errors; - } - - if (resData[resData.length - 1].successful_results === 0) { - throw { error: "forcedFetch: there was no successful_results", res: resData }; - } - - var fetchData = resData[0].o0.data.message; - - globalCallback(null, { - type: "change_thread_image", - threadID: utils.formatID(tid.toString()), - snippet: fetchData.snippet, - timestamp: fetchData.timestamp_precise, - author: fetchData.message_sender.id, - image: { - attachmentID: fetchData.image_with_metadata.legacy_attachment_id, - width: fetchData.image_with_metadata.original_dimensions.x, - height: fetchData.image_with_metadata.original_dimensions.y, - url: fetchData.image_with_metadata.preview.uri - } - }); - }) - .catch((err) => { - log.error("forcedFetch", err); - }); - break; - case "ThreadName": - case "ParticipantsAddedToGroupThread": - case "ParticipantLeftGroupThread": - var formattedEvent; - try { - formattedEvent = utils.formatDeltaEvent(v.delta); - } catch (err) { - return globalCallback({ - error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.", - detail: err, - res: v.delta, - type: "parse_error" - }); - } - return (!ctx.globalOptions.selfListen && - formattedEvent.author.toString() === ctx.userID) || - !ctx.loggedIn ? - undefined : - globalCallback(null, formattedEvent); - } + console.log(JSON.stringify(v, null, 4)); + if (v.delta.class == "NewMessage") { + //Not tested for pages + if (ctx.globalOptions.pageID && + ctx.globalOptions.pageID != v.queue + ) + return; + + (function resolveAttachmentUrl(i) { + if (i == v.delta.attachments.length) { + var fmtMsg; + try { + fmtMsg = utils.formatDeltaMessage(v); + } catch (err) { + return globalCallback({ + error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.", + detail: err, + res: v, + type: "parse_error" + }); + } + return !ctx.globalOptions.selfListen && + fmtMsg.senderID === ctx.userID ? + undefined : + globalCallback(null, fmtMsg); + } else { + if ( + v.delta.attachments[i].mercury.attach_type == "photo" + ) { + api.resolvePhotoUrl( + v.delta.attachments[i].fbid, + (err, url) => { + if (!err) + v.delta.attachments[ + i + ].mercury.metadata.url = url; + return resolveAttachmentUrl(i + 1); + } + ); + } else { + return resolveAttachmentUrl(i + 1); + } + } + })(0); + } + + if (v.delta.class == "ClientPayload") { + var clientPayload = utils.decodeClientPayload( + v.delta.payload + ); + if (clientPayload && clientPayload.deltas) { + for (var i in clientPayload.deltas) { + var delta = clientPayload.deltas[i]; + console.log(JSON.stringify(delta, null, 4)); + if (delta.deltaMessageReaction && !!ctx.globalOptions.listenEvents) { + globalCallback(null, { + type: "message_reaction", + threadID: delta.deltaMessageReaction.threadKey + .threadFbId ? + delta.deltaMessageReaction.threadKey.threadFbId : delta.deltaMessageReaction.threadKey + .otherUserFbId, + messageID: delta.deltaMessageReaction.messageId, + reaction: delta.deltaMessageReaction.reaction, + senderID: delta.deltaMessageReaction.senderId, + userID: delta.deltaMessageReaction.userId + }); + } else if (delta.deltaRecallMessageData && !!ctx.globalOptions.listenEvents) { + globalCallback(null, { + type: "message_unsend", + threadID: delta.deltaRecallMessageData.threadKey.threadFbId ? + delta.deltaRecallMessageData.threadKey.threadFbId : delta.deltaRecallMessageData.threadKey + .otherUserFbId, + messageID: delta.deltaRecallMessageData.messageID, + senderID: delta.deltaRecallMessageData.senderID, + deletionTimestamp: delta.deltaRecallMessageData.deletionTimestamp, + timestamp: delta.deltaRecallMessageData.timestamp + }); + } else if (delta.deltaMessageReply) { + //Mention block - #1 + var mdata = + delta.deltaMessageReply.message === undefined ? [] : + delta.deltaMessageReply.message.data === undefined ? [] : + delta.deltaMessageReply.message.data.prng === undefined ? [] : + JSON.parse(delta.deltaMessageReply.message.data.prng); + var m_id = mdata.map(u => u.i); + var m_offset = mdata.map(u => u.o); + var m_length = mdata.map(u => u.l); + + var mentions = {}; + + for (var i = 0; i < m_id.length; i++) { + mentions[m_id[i]] = delta.deltaMessageReply.message.body.substring( + m_offset[i], + m_offset[i] + m_length[i] + ); + } + //Mention block - 1# + //Mention block - #2 + var mdata = + delta.deltaMessageReply.repliedToMessage === undefined ? [] : + delta.deltaMessageReply.repliedToMessage.data === undefined ? [] : + delta.deltaMessageReply.repliedToMessage.data.prng === undefined ? [] : + JSON.parse(delta.deltaMessageReply.repliedToMessage.data.prng); + var m_id = mdata.map(u => u.i); + var m_offset = mdata.map(u => u.o); + var m_length = mdata.map(u => u.l); + + var rmentions = {}; + + for (var i = 0; i < m_id.length; i++) { + rmentions[m_id[i]] = delta.deltaMessageReply.repliedToMessage.body.substring( + m_offset[i], + m_offset[i] + m_length[i] + ); + } + //Mention block - 2# + + var callbackToReturn = { + type: "message_reply", + threadID: delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId ? + delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId : delta.deltaMessageReply.message.messageMetadata.threadKey + .otherUserFbId, + messageID: delta.deltaMessageReply.message.messageMetadata.messageId, + senderID: delta.deltaMessageReply.message.messageMetadata.actorFbId, + attachments: delta.deltaMessageReply.message.attachments.map(function (att) { + var mercury = JSON.parse(att.mercuryJSON); + Object.assign(att, mercury); + return att; + }).map(att => utils._formatAttachment(att)), + body: delta.deltaMessageReply.message.body || "", + isGroup: !!delta.deltaMessageReply.message.messageMetadata.threadKey.threadFbId, + mentions: mentions, + timestamp: delta.deltaMessageReply.message.messageMetadata.timestamp, + + }; + + if (delta.deltaMessageReply.repliedToMessage) { + callbackToReturn.messageReply = { + threadID: delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId ? + delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId : delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey + .otherUserFbId, + messageID: delta.deltaMessageReply.repliedToMessage.messageMetadata.messageId, + senderID: delta.deltaMessageReply.repliedToMessage.messageMetadata.actorFbId, + attachments: delta.deltaMessageReply.repliedToMessage.attachments.map(function (att) { + var mercury = JSON.parse(att.mercuryJSON); + Object.assign(att, mercury); + return att; + }).map(att => utils._formatAttachment(att)), + body: delta.deltaMessageReply.repliedToMessage.body || "", + isGroup: !!delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId, + mentions: rmentions, + timestamp: delta.deltaMessageReply.repliedToMessage.messageMetadata.timestamp, + }; + } + + globalCallback(null, callbackToReturn); + } + } + return; + } + } + + if (v.delta.class !== "NewMessage" && + !ctx.globalOptions.listenEvents + ) + return; + switch (v.delta.class) { + case "ReadReceipt": + var fmtMsg; + try { + fmtMsg = utils.formatDeltaReadReceipt(v.delta); + } catch (err) { + return globalCallback({ + error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.", + detail: err, + res: v.delta, + type: "parse_error" + }); + } + return globalCallback(null, fmtMsg); + case "AdminTextMessage": + switch (v.delta.type) { + case "change_thread_theme": + case "change_thread_nickname": + case "change_thread_icon": + break; + case "group_poll": + var fmtMsg; + try { + fmtMsg = utils.formatDeltaEvent(v.delta); + } catch (err) { + return globalCallback({ + error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.", + detail: err, + res: v.delta, + type: "parse_error" + }); + } + return globalCallback(null, fmtMsg); + break; + default: + return; + } + //For group images + case "ForcedFetch": + var mid = v.delta.messageId; + var tid = v.delta.threadKey.threadFbId.toString(); + const form = { + "av": ctx.globalOptions.pageID, + "queries": JSON.stringify({ + "o0": { + "doc_id": "1768656253222505", + "query_params": { + "thread_and_message_id": { + "thread_id": tid, + "message_id": mid, + } + } + } + }) + }; + + defaultFuncs + .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form) + .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) + .then((resData) => { + if (resData[resData.length - 1].error_results > 0) { + throw resData[0].o0.errors; + } + + if (resData[resData.length - 1].successful_results === 0) { + throw { error: "forcedFetch: there was no successful_results", res: resData }; + } + + var fetchData = resData[0].o0.data.message; + + (!ctx.globalOptions.selfListen && + formattedEvent.author.toString() === ctx.userID) || + !ctx.loggedIn ? + undefined : + globalCallback(null, { + type: "change_thread_image", + threadID: utils.formatID(tid.toString()), + snippet: fetchData.snippet, + timestamp: fetchData.timestamp_precise, + author: fetchData.message_sender.id, + image: { + attachmentID: fetchData.image_with_metadata.legacy_attachment_id, + width: fetchData.image_with_metadata.original_dimensions.x, + height: fetchData.image_with_metadata.original_dimensions.y, + url: fetchData.image_with_metadata.preview.uri + } + }); + }) + .catch((err) => { + log.error("forcedFetch", err); + }); + break; + case "ThreadName": + case "ParticipantsAddedToGroupThread": + case "ParticipantLeftGroupThread": + var formattedEvent; + try { + formattedEvent = utils.formatDeltaEvent(v.delta); + } catch (err) { + return globalCallback({ + error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.", + detail: err, + res: v.delta, + type: "parse_error" + }); + } + return (!ctx.globalOptions.selfListen && + formattedEvent.author.toString() === ctx.userID) || + !ctx.loggedIn ? + undefined : + globalCallback(null, formattedEvent); + } } module.exports = function (defaultFuncs, api, ctx) { - var currentlyRunning = null; - var globalCallback = identity; - return function (callback) { - globalCallback = callback; - const form = { - "av": ctx.globalOptions.pageID, - "queries": JSON.stringify({ - "o0": { - "doc_id": "1349387578499440", - "query_params": { - "limit": 1, - "before": null, - "tags": ["INBOX"], - "includeDeliveryReceipts": false, - "includeSeqID": true - } - } - }) - }; - - defaultFuncs - .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form) - .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) - .then((resData) => { - if (resData[resData.length - 1].error_results > 0) { - throw resData[0].o0.errors; - } - - if (resData[resData.length - 1].successful_results === 0) { - throw { error: "getSeqId: there was no successful_results", res: resData }; - } - - if (resData[0].o0.data.viewer.message_threads.sync_sequence_id) { - lastSeqId = resData[0].o0.data.viewer.message_threads.sync_sequence_id; - listenMqtt(ctx, globalCallback, defaultFuncs); - } - - }) - .catch((err) => { - log.error("getSeqId", err); - return callback(err); - }); - - - //return function(){}; - } -}; - + var globalCallback = identity; + return function (callback) { + globalCallback = callback; + const form = { + "av": ctx.globalOptions.pageID, + "queries": JSON.stringify({ + "o0": { + "doc_id": "1349387578499440", + "query_params": { + "limit": 1, + "before": null, + "tags": ["INBOX"], + "includeDeliveryReceipts": false, + "includeSeqID": true + } + } + }) + }; + + defaultFuncs + .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form) + .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) + .then((resData) => { + if (resData[resData.length - 1].error_results > 0) { + throw resData[0].o0.errors; + } + + if (resData[resData.length - 1].successful_results === 0) { + throw { error: "getSeqId: there was no successful_results", res: resData }; + } + + if (resData[0].o0.data.viewer.message_threads.sync_sequence_id) { + lastSeqId = resData[0].o0.data.viewer.message_threads.sync_sequence_id; + listenMqtt(ctx, globalCallback, defaultFuncs); + } + + }) + .catch((err) => { + log.error("getSeqId", err); + return callback(err); + }); + + var stopListening = function () { + globalCallback = identity; + client.end(); + }; + + return stopListening; + } +}; \ No newline at end of file diff --git a/src/markAsDelivered.js b/src/markAsDelivered.js index e4ba9c17..bfa3d9e4 100644 --- a/src/markAsDelivered.js +++ b/src/markAsDelivered.js @@ -3,17 +3,15 @@ var utils = require("../utils"); var log = require("npmlog"); -module.exports = function(defaultFuncs, api, ctx) { - +module.exports = function (defaultFuncs, api, ctx) { return function markAsDelivered(threadID, messageID, callback) { if (!callback) { - callback = function() {}; + callback = function () { }; } - if(!threadID || !messageID) - { - return callback("Error: messageID or threadID is not defined"); - } + if (!threadID || !messageID) { + return callback("Error: messageID or threadID is not defined"); + } var form = {}; @@ -21,7 +19,7 @@ module.exports = function(defaultFuncs, api, ctx) { form["thread_ids[" + threadID + "][0]"] = messageID; - console.log(form); + console.log(form); defaultFuncs .post( @@ -31,14 +29,14 @@ module.exports = function(defaultFuncs, api, ctx) { ) .then(utils.saveCookies(ctx.jar)) .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) - .then(function(resData) { + .then(function (resData) { if (resData.error) { throw resData; } return callback(); }) - .catch(function(err) { + .catch(function (err) { log.error("markAsDelivered", err); return callback(err); }); diff --git a/src/mqtt/fbconnect.js b/src/mqtt/fbconnect.js index 9dfd7be9..5eb84f22 100644 --- a/src/mqtt/fbconnect.js +++ b/src/mqtt/fbconnect.js @@ -12,7 +12,7 @@ protocols.wss = require('./fbws') * * @param {Object} [opts] option object */ -function parseAuthOptions (opts) { +function parseAuthOptions(opts) { var matches if (opts.auth) { matches = opts.auth.match(/^(.+):(.+)$/) @@ -31,7 +31,7 @@ function parseAuthOptions (opts) { * @param {String} [brokerUrl] - url of the broker, optional * @param {Object} opts - see MqttClient#constructor */ -function connect (brokerUrl, opts) { +function connect(brokerUrl, opts) { if ((typeof brokerUrl === 'object') && !opts) { opts = brokerUrl brokerUrl = null @@ -115,7 +115,7 @@ function connect (brokerUrl, opts) { opts.defaultProtocol = opts.protocol } - function wrapper (client) { + function wrapper(client) { if (opts.servers) { if (!client._reconnectCount || client._reconnectCount === opts.servers.length) { client._reconnectCount = 0 diff --git a/src/mqtt/fbws.js b/src/mqtt/fbws.js index 20135ddc..5704a132 100644 --- a/src/mqtt/fbws.js +++ b/src/mqtt/fbws.js @@ -13,7 +13,7 @@ var WSS_OPTIONS = [ ] var IS_BROWSER = process.title === 'browser' -function buildUrl (opts, client) { +function buildUrl(opts, client) { var url = opts.protocol + '://' + opts.hostname + ':' + opts.port + opts.path if (typeof (opts.transformWsUrl) === 'function') { url = opts.transformWsUrl(url, opts, client) @@ -21,7 +21,7 @@ function buildUrl (opts, client) { return url } -function setDefaultOpts (opts) { +function setDefaultOpts(opts) { if (!opts.hostname) { opts.hostname = 'localhost' } @@ -49,7 +49,7 @@ function setDefaultOpts (opts) { } } -function createWebSocket (client, opts) { +function createWebSocket(client, opts) { var websocketSubProtocol = (opts.protocolId === 'MQIsdp') && (opts.protocolVersion === 3) ? 'mqttv3.1' @@ -60,11 +60,11 @@ function createWebSocket (client, opts) { return websocket(url, undefined, opts.wsOptions) } -function buildBuilder (client, opts) { +function buildBuilder(client, opts) { return createWebSocket(client, opts) } -function buildBuilderBrowser (client, opts) { +function buildBuilderBrowser(client, opts) { if (!opts.hostname) { opts.hostname = opts.host } From 8afbee70d47064310068d76fd346c3ecaaa76243 Mon Sep 17 00:00:00 2001 From: Hossam Mansour <6911267+7osCraft@users.noreply.github.com> Date: Thu, 28 Nov 2019 22:39:12 +0200 Subject: [PATCH 06/10] Fixed a mistake --- src/listenMqtt.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/listenMqtt.js b/src/listenMqtt.js index 1abcc3be..d860ce24 100644 --- a/src/listenMqtt.js +++ b/src/listenMqtt.js @@ -124,7 +124,6 @@ function listenMqtt(ctx, globalCallback, defaultFuncs) { } function parseDelta(ctx, globalCallback, defaultFuncs, v) { - console.log(JSON.stringify(v, null, 4)); if (v.delta.class == "NewMessage") { //Not tested for pages if (ctx.globalOptions.pageID && @@ -177,7 +176,6 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { if (clientPayload && clientPayload.deltas) { for (var i in clientPayload.deltas) { var delta = clientPayload.deltas[i]; - console.log(JSON.stringify(delta, null, 4)); if (delta.deltaMessageReaction && !!ctx.globalOptions.listenEvents) { globalCallback(null, { type: "message_reaction", @@ -428,7 +426,7 @@ module.exports = function (defaultFuncs, api, ctx) { .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form) .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) .then((resData) => { - if (resData[resData.length - 1].error_results > 0) { + if (resData && resData[resData.length - 1].error_results > 0) { throw resData[0].o0.errors; } From aa8a43b5a4daac223498e96321ebb607ce31858f Mon Sep 17 00:00:00 2001 From: Hossam Mansour <6911267+7osCraft@users.noreply.github.com> Date: Sat, 30 Nov 2019 00:07:17 +0200 Subject: [PATCH 07/10] Fixed missing break. --- src/listenMqtt.js | 1 + src/markAsDelivered.js | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/listenMqtt.js b/src/listenMqtt.js index d860ce24..dd06108e 100644 --- a/src/listenMqtt.js +++ b/src/listenMqtt.js @@ -325,6 +325,7 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { default: return; } + break; //For group images case "ForcedFetch": var mid = v.delta.messageId; diff --git a/src/markAsDelivered.js b/src/markAsDelivered.js index bfa3d9e4..279a7524 100644 --- a/src/markAsDelivered.js +++ b/src/markAsDelivered.js @@ -18,9 +18,6 @@ module.exports = function (defaultFuncs, api, ctx) { form["message_ids[0]"] = messageID; form["thread_ids[" + threadID + "][0]"] = messageID; - - console.log(form); - defaultFuncs .post( "https://www.facebook.com/ajax/mercury/delivery_receipts.php", From ca3c5544c9dc4a2c83de09edbf55a0db8de186b3 Mon Sep 17 00:00:00 2001 From: Hossam Mansour <6911267+7osCraft@users.noreply.github.com> Date: Sat, 30 Nov 2019 23:18:33 +0200 Subject: [PATCH 08/10] Some refactoring and fixing --- index.js | 3 +- src/listenMqtt.js | 102 ++++++++++++++++++++++------------------- src/markAsDelivered.js | 41 ----------------- src/mqtt/fbconnect.js | 15 ++---- src/mqtt/fbws.js | 34 ++------------ 5 files changed, 61 insertions(+), 134 deletions(-) delete mode 100644 src/markAsDelivered.js diff --git a/index.js b/index.js index 5bbf365d..d0013b1c 100644 --- a/index.js +++ b/index.js @@ -99,9 +99,8 @@ function buildAPI(globalOptions, html, jar) { 'getUserInfo', 'handleMessageRequest', 'listen', - 'listenMqtt', + 'listenMqtt', 'logout', - 'markAsDelivered', 'markAsRead', 'markAsReadAll', 'muteThread', diff --git a/src/listenMqtt.js b/src/listenMqtt.js index dd06108e..81d2191c 100644 --- a/src/listenMqtt.js +++ b/src/listenMqtt.js @@ -330,56 +330,62 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { case "ForcedFetch": var mid = v.delta.messageId; var tid = v.delta.threadKey.threadFbId.toString(); - const form = { - "av": ctx.globalOptions.pageID, - "queries": JSON.stringify({ - "o0": { - "doc_id": "1768656253222505", - "query_params": { - "thread_and_message_id": { - "thread_id": tid, - "message_id": mid, + if(mid && tid) + { + const form = { + "av": ctx.globalOptions.pageID, + "queries": JSON.stringify({ + "o0": { + "doc_id": "1768656253222505", + "query_params": { + "thread_and_message_id": { + "thread_id": tid, + "message_id": mid, + } } } - } - }) - }; - - defaultFuncs - .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form) - .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) - .then((resData) => { - if (resData[resData.length - 1].error_results > 0) { - throw resData[0].o0.errors; - } - - if (resData[resData.length - 1].successful_results === 0) { - throw { error: "forcedFetch: there was no successful_results", res: resData }; - } - - var fetchData = resData[0].o0.data.message; - - (!ctx.globalOptions.selfListen && - formattedEvent.author.toString() === ctx.userID) || - !ctx.loggedIn ? - undefined : - globalCallback(null, { - type: "change_thread_image", - threadID: utils.formatID(tid.toString()), - snippet: fetchData.snippet, - timestamp: fetchData.timestamp_precise, - author: fetchData.message_sender.id, - image: { - attachmentID: fetchData.image_with_metadata.legacy_attachment_id, - width: fetchData.image_with_metadata.original_dimensions.x, - height: fetchData.image_with_metadata.original_dimensions.y, - url: fetchData.image_with_metadata.preview.uri - } - }); - }) - .catch((err) => { - log.error("forcedFetch", err); - }); + }) + }; + + defaultFuncs + .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form) + .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) + .then((resData) => { + if (resData[resData.length - 1].error_results > 0) { + throw resData[0].o0.errors; + } + + if (resData[resData.length - 1].successful_results === 0) { + throw { error: "forcedFetch: there was no successful_results", res: resData }; + } + + var fetchData = resData[0].o0.data.message; + + if(fetchData && fetchData.__typename === "ThreadImageMessage") + { + (!ctx.globalOptions.selfListen && + formattedEvent.author.toString() === ctx.userID) || + !ctx.loggedIn ? + undefined : + globalCallback(null, { + type: "change_thread_image", + threadID: utils.formatID(tid.toString()), + snippet: fetchData.snippet, + timestamp: fetchData.timestamp_precise, + author: fetchData.message_sender.id, + image: { + attachmentID: fetchData.image_with_metadata.legacy_attachment_id, + width: fetchData.image_with_metadata.original_dimensions.x, + height: fetchData.image_with_metadata.original_dimensions.y, + url: fetchData.image_with_metadata.preview.uri + } + }); + } + }) + .catch((err) => { + log.error("forcedFetch", err); + }); + } break; case "ThreadName": case "ParticipantsAddedToGroupThread": diff --git a/src/markAsDelivered.js b/src/markAsDelivered.js deleted file mode 100644 index 279a7524..00000000 --- a/src/markAsDelivered.js +++ /dev/null @@ -1,41 +0,0 @@ -"use strict"; - -var utils = require("../utils"); -var log = require("npmlog"); - -module.exports = function (defaultFuncs, api, ctx) { - return function markAsDelivered(threadID, messageID, callback) { - if (!callback) { - callback = function () { }; - } - - if (!threadID || !messageID) { - return callback("Error: messageID or threadID is not defined"); - } - - var form = {}; - - form["message_ids[0]"] = messageID; - form["thread_ids[" + threadID + "][0]"] = messageID; - - defaultFuncs - .post( - "https://www.facebook.com/ajax/mercury/delivery_receipts.php", - ctx.jar, - form - ) - .then(utils.saveCookies(ctx.jar)) - .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) - .then(function (resData) { - if (resData.error) { - throw resData; - } - - return callback(); - }) - .catch(function (err) { - log.error("markAsDelivered", err); - return callback(err); - }); - }; -}; diff --git a/src/mqtt/fbconnect.js b/src/mqtt/fbconnect.js index 5eb84f22..b1a4b800 100644 --- a/src/mqtt/fbconnect.js +++ b/src/mqtt/fbconnect.js @@ -1,3 +1,4 @@ +//From MQTT.js (https://github.com/mqttjs/MQTT.js) 'use strict' var mqtt = require('mqtt') @@ -63,7 +64,7 @@ function connect(brokerUrl, opts) { if (opts.cert && opts.key) { if (opts.protocol) { - if (['mqtts', 'wss', 'wxs', 'alis'].indexOf(opts.protocol) === -1) { + if (['mqtts', 'wss'].indexOf(opts.protocol) === -1) { switch (opts.protocol) { case 'mqtt': opts.protocol = 'mqtts' @@ -71,12 +72,6 @@ function connect(brokerUrl, opts) { case 'ws': opts.protocol = 'wss' break - case 'wx': - opts.protocol = 'wxs' - break - case 'ali': - opts.protocol = 'alis' - break default: throw new Error('Unknown protocol for secure connection: "' + opts.protocol + '"!') } @@ -93,11 +88,7 @@ function connect(brokerUrl, opts) { 'mqtt', 'mqtts', 'ws', - 'wss', - 'wx', - 'wxs', - 'ali', - 'alis' + 'wss' ].filter(function (key, index) { if (isSecure && index % 2 === 0) { // Skip insecure protocols when requesting a secure one. diff --git a/src/mqtt/fbws.js b/src/mqtt/fbws.js index 5704a132..1100f111 100644 --- a/src/mqtt/fbws.js +++ b/src/mqtt/fbws.js @@ -1,4 +1,4 @@ -//From mqtt.js +//From MQTT.js (https://github.com/mqttjs/MQTT.js) 'use strict' var websocket = require('websocket-stream') @@ -11,8 +11,6 @@ var WSS_OPTIONS = [ 'pfx', 'passphrase' ] -var IS_BROWSER = process.title === 'browser' - function buildUrl(opts, client) { var url = opts.protocol + '://' + opts.hostname + ':' + opts.port + opts.path if (typeof (opts.transformWsUrl) === 'function') { @@ -39,7 +37,7 @@ function setDefaultOpts(opts) { if (!opts.wsOptions) { opts.wsOptions = {} } - if (!IS_BROWSER && opts.protocol === 'wss') { + if (opts.protocol === 'wss') { // Add cert/key/ca etc options WSS_OPTIONS.forEach(function (prop) { if (opts.hasOwnProperty(prop) && !opts.wsOptions.hasOwnProperty(prop)) { @@ -64,30 +62,4 @@ function buildBuilder(client, opts) { return createWebSocket(client, opts) } -function buildBuilderBrowser(client, opts) { - if (!opts.hostname) { - opts.hostname = opts.host - } - - if (!opts.hostname) { - // Throwing an error in a Web Worker if no `hostname` is given, because we - // can not determine the `hostname` automatically. If connecting to - // localhost, please supply the `hostname` as an argument. - if (typeof (document) === 'undefined') { - throw new Error('Could not determine host. Specify host manually.') - } - var parsed = urlModule.parse(document.URL) - opts.hostname = parsed.hostname - - if (!opts.port) { - opts.port = parsed.port - } - } - return createWebSocket(client, opts) -} - -if (IS_BROWSER) { - module.exports = buildBuilderBrowser -} else { - module.exports = buildBuilder -} \ No newline at end of file +module.exports = buildBuilder \ No newline at end of file From f5450306af7802939b5c6182b0db67ff81226b4f Mon Sep 17 00:00:00 2001 From: Hossam Mansour <6911267+7osCraft@users.noreply.github.com> Date: Sat, 30 Nov 2019 23:47:09 +0200 Subject: [PATCH 09/10] Fixed line breaking and spacing --- index.js | 2 +- package-lock.json | 205 +++++++++++++--------------------------------- package.json | 4 +- src/listenMqtt.js | 110 ++++++++++++------------- 4 files changed, 112 insertions(+), 209 deletions(-) diff --git a/index.js b/index.js index d0013b1c..49293365 100644 --- a/index.js +++ b/index.js @@ -99,7 +99,7 @@ function buildAPI(globalOptions, html, jar) { 'getUserInfo', 'handleMessageRequest', 'listen', - 'listenMqtt', + 'listenMqtt', 'logout', 'markAsRead', 'markAsReadAll', diff --git a/package-lock.json b/package-lock.json index 1b49c33b..7718e665 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ }, "acorn-jsx": { "version": "3.0.1", - "resolved": "http://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", "dev": true, "requires": { @@ -50,9 +50,9 @@ "integrity": "sha1-DELU+xcWDVqa8eSEus4cZpIsGyE=" }, "ansi-escapes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", "dev": true }, "ansi-regex": { @@ -85,27 +85,6 @@ "sprintf-js": "~1.0.2" } }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "dev": true, - "requires": { - "array-uniq": "^1.0.1" - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, "asn1": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", @@ -255,9 +234,9 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -465,21 +444,6 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "dev": true, - "requires": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" - } - }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -649,7 +613,7 @@ }, "eslint": { "version": "4.19.1", - "resolved": "http://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", "dev": true, "requires": { @@ -704,9 +668,9 @@ } }, "eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz", + "integrity": "sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A==", "dev": true }, "espree": { @@ -744,15 +708,15 @@ } }, "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true }, "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, "event-emitter": { @@ -786,7 +750,7 @@ }, "external-editor": { "version": "2.2.0", - "resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "dev": true, "requires": { @@ -836,14 +800,14 @@ } }, "flat-cache": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", - "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz", + "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==", "dev": true, "requires": { "circular-json": "^0.3.1", - "del": "^2.0.2", "graceful-fs": "^4.1.2", + "rimraf": "~2.6.2", "write": "^0.2.1" } }, @@ -943,29 +907,15 @@ } }, "globals": { - "version": "11.8.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.8.0.tgz", - "integrity": "sha512-io6LkyPVuzCHBSQV9fmOwxZkUk6nIaGmxheLDgmuFv89j0fm2aqDbIXKAGfzCMHqz3HLF2Zf8WSG6VqMh2qFmA==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true }, - "globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "dev": true, - "requires": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", "dev": true }, "growl": { @@ -1132,30 +1082,6 @@ "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=" }, - "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", - "dev": true - }, - "is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", - "dev": true, - "requires": { - "is-path-inside": "^1.0.0" - } - }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "dev": true, - "requires": { - "path-is-inside": "^1.0.1" - } - }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", @@ -1383,9 +1309,9 @@ "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=" }, "lru-cache": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", - "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "dev": true, "requires": { "pseudomap": "^1.0.2", @@ -1548,9 +1474,9 @@ } }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "mute-stream": { @@ -1617,17 +1543,17 @@ } }, "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", "dev": true, "requires": { "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", + "fast-levenshtein": "~2.0.6", "levn": "~0.3.0", "prelude-ls": "~1.1.2", "type-check": "~0.3.2", - "wordwrap": "~1.0.0" + "word-wrap": "~1.2.3" } }, "ordered-read-streams": { @@ -1665,27 +1591,6 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, "pluralize": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", @@ -1710,9 +1615,9 @@ "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, "progress": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", - "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, "pseudomap": { @@ -1782,7 +1687,7 @@ }, "regexpp": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==", "dev": true }, @@ -1850,12 +1755,12 @@ } }, "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "dev": true, "requires": { - "glob": "^7.0.5" + "glob": "^7.1.3" } }, "run-async": { @@ -1893,9 +1798,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "semver": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, "shebang-command": { @@ -2050,7 +1955,7 @@ }, "through": { "version": "2.3.8", - "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, @@ -2198,10 +2103,10 @@ "isexe": "^2.0.0" } }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, "wrappy": { diff --git a/package.json b/package.json index 133a6ec9..8c96560e 100644 --- a/package.json +++ b/package.json @@ -32,9 +32,9 @@ "node": ">=4.x" }, "devDependencies": { + "eslint": "^4.19.1", "mocha": "^2.2.5", - "prettier": "^1.11.1", - "eslint": "^4.19.1" + "prettier": "^1.11.1" }, "eslintConfig": { "env": { diff --git a/src/listenMqtt.js b/src/listenMqtt.js index 81d2191c..51f0f011 100644 --- a/src/listenMqtt.js +++ b/src/listenMqtt.js @@ -3,7 +3,7 @@ var fbconnect = require("./mqtt/fbconnect"); var utils = require("../utils"); var log = require("npmlog"); -var identity = function () { }; +var identity = function() {}; var lastSeqId = 0; var client = undefined; @@ -51,12 +51,12 @@ function listenMqtt(ctx, globalCallback, defaultFuncs) { client = fbconnect.connect(host, options); - client.on('error', function (err) { + client.on('error', function(err) { log.error(err); client.end(); }); - client.on('connect', function () { + client.on('connect', function() { client.subscribe(["/legacy_web", "/webrtc", "/br_sr", "/sr_res", "/t_ms", "/thread_typing", "/orca_typing_notifications", "/notify_disconnect", "/orca_presence"], (err, granted) => { client.unsubscribe('/orca_message_notifications', (err) => { @@ -70,28 +70,28 @@ function listenMqtt(ctx, globalCallback, defaultFuncs) { device_params: null }; - client.publish('/messenger_sync_create_queue', JSON.stringify(queue), { qos: 0, retain: false }) + client.publish('/messenger_sync_create_queue', JSON.stringify(queue), {qos: 0, retain: false}) }); }); }); - client.on('message', function (topic, message, packet) { + client.on('message', function(topic, message, packet) { var jsonMessage = JSON.parse(message); - if (topic === "/t_ms") { - if (jsonMessage.lastIssuedSeqId) { + if(topic === "/t_ms") { + if(jsonMessage.lastIssuedSeqId) { lastSeqId = parseInt(jsonMessage.lastIssuedSeqId); } else { - if (jsonMessage.deltas) { + if(jsonMessage.deltas) { lastSeqId = parseInt(jsonMessage.deltas[0].irisSeqId); } } //If it contains more than 1 delta - for (var i in jsonMessage.deltas) { + for(var i in jsonMessage.deltas) { var delta = jsonMessage.deltas[i]; - parseDelta(ctx, globalCallback, defaultFuncs, { "delta": delta }); + parseDelta(ctx, globalCallback, defaultFuncs, {"delta": delta}); } - } else if (topic === "/thread_typing" || topic === "/orca_typing_notifications") { + } else if(topic === "/thread_typing" || topic === "/orca_typing_notifications") { var typ = { type: "typ", isTyping: !!jsonMessage.state, @@ -99,9 +99,9 @@ function listenMqtt(ctx, globalCallback, defaultFuncs) { threadID: utils.formatID((jsonMessage.thread || jsonMessage.sender_fbid).toString()) } globalCallback(null, typ); - } else if (topic === "/orca_presence") { - if (!ctx.globalOptions.updatePresence) { - for (var i in jsonMessage.list) { + } else if(topic === "/orca_presence") { + if(!ctx.globalOptions.updatePresence) { + for(var i in jsonMessage.list) { var data = jsonMessage.list[i]; var userID = data["u"]; @@ -118,25 +118,25 @@ function listenMqtt(ctx, globalCallback, defaultFuncs) { }); - client.on('close', function () { + client.on('close', function() { // client.end(); }); } function parseDelta(ctx, globalCallback, defaultFuncs, v) { - if (v.delta.class == "NewMessage") { + if(v.delta.class == "NewMessage") { //Not tested for pages - if (ctx.globalOptions.pageID && + if(ctx.globalOptions.pageID && ctx.globalOptions.pageID != v.queue ) return; (function resolveAttachmentUrl(i) { - if (i == v.delta.attachments.length) { + if(i == v.delta.attachments.length) { var fmtMsg; try { fmtMsg = utils.formatDeltaMessage(v); - } catch (err) { + } catch(err) { return globalCallback({ error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.", detail: err, @@ -149,13 +149,13 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { undefined : globalCallback(null, fmtMsg); } else { - if ( + if( v.delta.attachments[i].mercury.attach_type == "photo" ) { api.resolvePhotoUrl( v.delta.attachments[i].fbid, (err, url) => { - if (!err) + if(!err) v.delta.attachments[ i ].mercury.metadata.url = url; @@ -169,14 +169,14 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { })(0); } - if (v.delta.class == "ClientPayload") { + if(v.delta.class == "ClientPayload") { var clientPayload = utils.decodeClientPayload( v.delta.payload ); - if (clientPayload && clientPayload.deltas) { - for (var i in clientPayload.deltas) { + if(clientPayload && clientPayload.deltas) { + for(var i in clientPayload.deltas) { var delta = clientPayload.deltas[i]; - if (delta.deltaMessageReaction && !!ctx.globalOptions.listenEvents) { + if(delta.deltaMessageReaction && !!ctx.globalOptions.listenEvents) { globalCallback(null, { type: "message_reaction", threadID: delta.deltaMessageReaction.threadKey @@ -188,7 +188,7 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { senderID: delta.deltaMessageReaction.senderId, userID: delta.deltaMessageReaction.userId }); - } else if (delta.deltaRecallMessageData && !!ctx.globalOptions.listenEvents) { + } else if(delta.deltaRecallMessageData && !!ctx.globalOptions.listenEvents) { globalCallback(null, { type: "message_unsend", threadID: delta.deltaRecallMessageData.threadKey.threadFbId ? @@ -199,7 +199,7 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { deletionTimestamp: delta.deltaRecallMessageData.deletionTimestamp, timestamp: delta.deltaRecallMessageData.timestamp }); - } else if (delta.deltaMessageReply) { + } else if(delta.deltaMessageReply) { //Mention block - #1 var mdata = delta.deltaMessageReply.message === undefined ? [] : @@ -212,7 +212,7 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { var mentions = {}; - for (var i = 0; i < m_id.length; i++) { + for(var i = 0; i < m_id.length; i++) { mentions[m_id[i]] = delta.deltaMessageReply.message.body.substring( m_offset[i], m_offset[i] + m_length[i] @@ -231,7 +231,7 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { var rmentions = {}; - for (var i = 0; i < m_id.length; i++) { + for(var i = 0; i < m_id.length; i++) { rmentions[m_id[i]] = delta.deltaMessageReply.repliedToMessage.body.substring( m_offset[i], m_offset[i] + m_length[i] @@ -246,7 +246,7 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { .otherUserFbId, messageID: delta.deltaMessageReply.message.messageMetadata.messageId, senderID: delta.deltaMessageReply.message.messageMetadata.actorFbId, - attachments: delta.deltaMessageReply.message.attachments.map(function (att) { + attachments: delta.deltaMessageReply.message.attachments.map(function(att) { var mercury = JSON.parse(att.mercuryJSON); Object.assign(att, mercury); return att; @@ -258,14 +258,14 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { }; - if (delta.deltaMessageReply.repliedToMessage) { + if(delta.deltaMessageReply.repliedToMessage) { callbackToReturn.messageReply = { threadID: delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId ? delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey.threadFbId : delta.deltaMessageReply.repliedToMessage.messageMetadata.threadKey .otherUserFbId, messageID: delta.deltaMessageReply.repliedToMessage.messageMetadata.messageId, senderID: delta.deltaMessageReply.repliedToMessage.messageMetadata.actorFbId, - attachments: delta.deltaMessageReply.repliedToMessage.attachments.map(function (att) { + attachments: delta.deltaMessageReply.repliedToMessage.attachments.map(function(att) { var mercury = JSON.parse(att.mercuryJSON); Object.assign(att, mercury); return att; @@ -284,16 +284,16 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { } } - if (v.delta.class !== "NewMessage" && + if(v.delta.class !== "NewMessage" && !ctx.globalOptions.listenEvents ) return; - switch (v.delta.class) { + switch(v.delta.class) { case "ReadReceipt": var fmtMsg; try { fmtMsg = utils.formatDeltaReadReceipt(v.delta); - } catch (err) { + } catch(err) { return globalCallback({ error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.", detail: err, @@ -303,7 +303,7 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { } return globalCallback(null, fmtMsg); case "AdminTextMessage": - switch (v.delta.type) { + switch(v.delta.type) { case "change_thread_theme": case "change_thread_nickname": case "change_thread_icon": @@ -312,7 +312,7 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { var fmtMsg; try { fmtMsg = utils.formatDeltaEvent(v.delta); - } catch (err) { + } catch(err) { return globalCallback({ error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.", detail: err, @@ -330,8 +330,7 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { case "ForcedFetch": var mid = v.delta.messageId; var tid = v.delta.threadKey.threadFbId.toString(); - if(mid && tid) - { + if(mid && tid) { const form = { "av": ctx.globalOptions.pageID, "queries": JSON.stringify({ @@ -346,23 +345,22 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { } }) }; - + defaultFuncs .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form) .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) .then((resData) => { - if (resData[resData.length - 1].error_results > 0) { + if(resData[resData.length - 1].error_results > 0) { throw resData[0].o0.errors; } - - if (resData[resData.length - 1].successful_results === 0) { - throw { error: "forcedFetch: there was no successful_results", res: resData }; + + if(resData[resData.length - 1].successful_results === 0) { + throw {error: "forcedFetch: there was no successful_results", res: resData}; } - + var fetchData = resData[0].o0.data.message; - - if(fetchData && fetchData.__typename === "ThreadImageMessage") - { + + if(fetchData && fetchData.__typename === "ThreadImageMessage") { (!ctx.globalOptions.selfListen && formattedEvent.author.toString() === ctx.userID) || !ctx.loggedIn ? @@ -393,7 +391,7 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { var formattedEvent; try { formattedEvent = utils.formatDeltaEvent(v.delta); - } catch (err) { + } catch(err) { return globalCallback({ error: "Problem parsing message object. Please open an issue at https://github.com/Schmavery/facebook-chat-api/issues.", detail: err, @@ -409,9 +407,9 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { } } -module.exports = function (defaultFuncs, api, ctx) { +module.exports = function(defaultFuncs, api, ctx) { var globalCallback = identity; - return function (callback) { + return function(callback) { globalCallback = callback; const form = { "av": ctx.globalOptions.pageID, @@ -433,15 +431,15 @@ module.exports = function (defaultFuncs, api, ctx) { .post("https://www.facebook.com/api/graphqlbatch/", ctx.jar, form) .then(utils.parseAndCheckLogin(ctx, defaultFuncs)) .then((resData) => { - if (resData && resData[resData.length - 1].error_results > 0) { + if(resData && resData[resData.length - 1].error_results > 0) { throw resData[0].o0.errors; } - if (resData[resData.length - 1].successful_results === 0) { - throw { error: "getSeqId: there was no successful_results", res: resData }; + if(resData[resData.length - 1].successful_results === 0) { + throw {error: "getSeqId: there was no successful_results", res: resData}; } - if (resData[0].o0.data.viewer.message_threads.sync_sequence_id) { + if(resData[0].o0.data.viewer.message_threads.sync_sequence_id) { lastSeqId = resData[0].o0.data.viewer.message_threads.sync_sequence_id; listenMqtt(ctx, globalCallback, defaultFuncs); } @@ -452,7 +450,7 @@ module.exports = function (defaultFuncs, api, ctx) { return callback(err); }); - var stopListening = function () { + var stopListening = function() { globalCallback = identity; client.end(); }; From 760dedf8854585bb3d2efb0fdac9eabcf119e174 Mon Sep 17 00:00:00 2001 From: Hossam Mansour <6911267+7osCraft@users.noreply.github.com> Date: Mon, 2 Dec 2019 02:39:31 +0200 Subject: [PATCH 10/10] Fixed ForcedFetch and presence timestamp. --- src/listenMqtt.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/listenMqtt.js b/src/listenMqtt.js index 51f0f011..ec895c3f 100644 --- a/src/listenMqtt.js +++ b/src/listenMqtt.js @@ -108,7 +108,8 @@ function listenMqtt(ctx, globalCallback, defaultFuncs) { var presence = { type: "presence", userID: userID, - timestamp: data["l"], + //Convert to ms + timestamp: data["l"] * 1000, statuses: data["p"] }; globalCallback(null, presence); @@ -329,7 +330,7 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { //For group images case "ForcedFetch": var mid = v.delta.messageId; - var tid = v.delta.threadKey.threadFbId.toString(); + var tid = v.delta.threadKey.threadFbId; if(mid && tid) { const form = { "av": ctx.globalOptions.pageID, @@ -338,7 +339,7 @@ function parseDelta(ctx, globalCallback, defaultFuncs, v) { "doc_id": "1768656253222505", "query_params": { "thread_and_message_id": { - "thread_id": tid, + "thread_id": tid.toString(), "message_id": mid, } }